3

props/$emit、v-model、.sync的适用场景 -- vue组件通信系列

 2 years ago
source link: https://my.oschina.net/u/5079097/blog/5283398
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

vue组件的数据通信方式很多,本篇着重讲props/$emit,神助是v-model/.sync语法糖。

TL;DR

  • props/$emit是父子组件最常用的通信方式,而v-model、.sync只是其语法糖
  • 子组件只是单一的修改某个父组件值的话,表单类组件使用v-model语法糖
  • 子组件只是单一的修改某个父组件值的话,非表单类组件使用sync语法糖
  • 复杂逻辑还是老老实实props/$emit

其实语法糖只是在父组件用的时候更加方便,而子组件该咋样还是咋样。

props/$emit

子组件想要显示父组件的数据,就props。 子组件想要改变父组件的数据,就$emit

props_emit

up-fe92fdc67c7caa52e7f46ab3599a68b665d.png

留意的点:

  • 子组件props里定义的属性名和父组件里的一一对应,注意父组件使用属性的时候用羊肉串格式
  • 父组件的监听事件名和子组件的触发事件名必须一模一样
  • 子组件触发事件的时候,传过来的参数,父组件可以用$event接收

v-model语法糖

v-model是属性value和事件input的语法糖。

v-model1

没有语法糖的时候,这样写

up-ef1880e099091bbb708cf234f259913bf77.png

用v-model的话,父组件就可以少了监听事件,用起来更加方便

up-a7a8a48d4f8d520089b0603361693fea9c3.png

v-model的语法糖有其局限性:

  • 适用于:触发事件返回的值 正是 属性要改的值,一般是单一属性。比如触发事件返回的值正好就是提title的新值
  • 更多逻辑的话,就不适用了
  • 更适用于:表单类的组件,因为属性和事件默认是valueinput

当然特定情况下,可以修改v-model的默认属性,但可读性就不是很好。

export default {
  name:'ListItem',
  model:{
    prop:'title',
    input:'changeTitle'
  }
}
复制代码

.sync语法糖

.sync这个语法糖,同样适用于触发事件返回的值 正是 属性要改的值,可读性要强一些,可以用于非表单类的组件。 .sync语法糖默认是 属性xxx和事件update:xxx

v-model1

没有语法糖的时候,这样写

up-a06c58a8420d5f27f4942c8e4e597b7cc82.png

用.sync的话,父组件仍然可以少监听事件,用起来更加方便

up-6050c633980aeca0d2cf674aa5ae18c440b.png

sync的语法糖有其局限性:

  • 适用于:触发事件返回的值 正是 属性要改的值,一般是单一属性。比如触发事件返回的值正好就是提title的新值
  • 更多逻辑的话,就不适用了
  • 更适用于:非表单类的组件
  • props/$emit是父子组件最常用的通信方式,而v-model、.sync只是其语法糖
  • 子组件只是单一的修改某个父组件值的话,表单类组件使用v-model语法糖
  • 子组件只是单一的修改某个父组件值的话,非表单类组件使用sync语法糖
  • 复杂逻辑还是老老实实props/$emit

其实语法糖只是在父组件用的时候更加方便,而子组件该咋样还是咋样。

props/$emit的代码

List.vue

<template lang="pug">
//- 父组件
div
  //- item就是传递给ListItem的数据,属性是info
  //- clickLike,就是监听ListItem的clickLike事件
  list-item(v-for="(item,index) in list" :key="index"
  :info="item"
  v-on:clickLike="change(item,$event)")
</template>
<script>
import ListItem from "@/components/ListItem";
export default {
  name: "List",
  components: { ListItem },
  data() {
    return {
      list: [
        { title: "vue3来了", collects: 20 },
        { title: "怜怜来了", collects: 2000 }
      ]
    };
  },
  methods: {
    // 当clickLike事件发生的时候,执行此方法
    // 这里的event是ListItem传过来的值
    change(item, event) {
      item.collects = event;
    }
  }
};
</script>

复制代码

DetailItem.vue

<template lang="pug">
//- 子组件
div
  h2 {{info.title}}
  span 喜欢数 {{info.collects}}
  div
    button(@click="addCollect") 喜欢
  hr
</template>
<script>
export default {
  name: "ListItem",
  props: {
    // 这里定义父组件传过来的属性
    info: { type: Object, default: () => ({}) }
  },
  methods: {
    addCollect() {
      // 触发此组件的clickLike时间,并且传一个值给父组件
      this.$emit("clickLike", this.info.collects + 1);
    }
  }
};
</script>

复制代码

v-model代码

没有简写时候的代码

<template lang="pug">
//- 父组件
div
  list-item(:value="title" v-on:input="change")
</template>
<script>
import ListItem from "@/components/ListItem";
export default {
  name: "List",
  components: { ListItem },
  data() {
    return {
      title: "怜怜来了"
    };
  },
  methods: {
    // 当clickLike事件发生的时候,执行此方法
    // 这里的event是ListItem传过来的值
    change(event) {
      this.title = event;
    }
  }
};
</script>

复制代码
<template lang="pug">
//- 子组件
div {{value}}
  button(@click="changeTitle") 修改标题
</template>
<script>
export default {
  name: "ListItem",
  props: {
    value: { type: String, default: "" }
  },
  methods: {
    changeTitle() {
      this.$emit("input", "换标题啦");
    }
  }
};
</script>

复制代码

简写时候的父组件代码

<template lang="pug">
//- 父组件
div
  list-item(v-model="title")
</template>
<script>
import ListItem from "@/components/ListItem";
export default {
  name: "List",
  components: { ListItem },
  data() {
    return {
      title: "怜怜来了"
    };
  }
};
</script>

复制代码

.sync的代码

没有简写的时候

<template lang="pug">
//- 父组件
div
  list-item(:theme="title" v-on:update:theme="change")
</template>
<script>
import ListItem from "@/components/ListItem";
export default {
  name: "List",
  components: { ListItem },
  data() {
    return {
      title: "怜怜来了"
    };
  },
  methods: {
    // 当clickLike事件发生的时候,执行此方法
    // 这里的event是ListItem传过来的值
    change(event) {
      this.title = event;
    }
  }
};
</script>

复制代码
<template lang="pug">
//- 子组件
div {{theme}}
  button(@click="changeTitle") 修改标题
</template>
<script>
export default {
  name: "ListItem",
  props: {
    theme: { type: String, default: "" }
  },
  methods: {
    changeTitle() {
      this.$emit("update:theme", "换标题啦");
    }
  }
};
</script>

复制代码

简写的时候,父组件的代码

<template lang="pug">
//- 父组件
div
  //- list-item(:theme="title" v-on:update:theme="change")
  list-item(:theme.sync="title")
</template>
<script>
import ListItem from "@/components/ListItem";
export default {
  name: "List",
  components: { ListItem },
  data() {
    return {
      title: "怜怜来了"
    };
  }
  // methods: {
  //   // 当clickLike事件发生的时候,执行此方法
  //   // 这里的event是ListItem传过来的值
  //   change(event) {
  //     this.title = event;
  //   }
  // }
};
</script>
复制代码

如果你觉得此文对你有一丁点帮助,点个赞。或者可以加入我的开发交流群:1025263163相互学习,我们会有专业的技术答疑解惑

如果你觉得这篇文章对你有点用的话,麻烦请给我们的开源项目点点star: http://github.crmeb.net/u/defu 不胜感激 !


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK