props/$emit、v-model、.sync的適用場景 -- vue元件通訊系列

語言: CN / TW / HK

vue元件的資料通訊方式很多,本篇著重講props/$emit,神助是v-model/.sync語法糖。

TL;DR

  • props/$emit是父子元件最常用的通訊方式,而v-model、.sync只是其語法糖
  • 子元件只是單一的修改某個父元件值的話,表單類元件使用v-model語法糖
  • 子元件只是單一的修改某個父元件值的話,非表單類元件使用sync語法糖
  • 複雜邏輯還是老老實實props/$emit

其實語法糖只是在父元件用的時候更加方便,而子元件該咋樣還是咋樣。

props/$emit

子元件想要顯示父元件的資料,就props。 子元件想要改變父元件的資料,就$emit

props_emit

留意的點:

  • 子元件props裡定義的屬性名和父元件裡的一一對應,注意父元件使用屬性的時候用羊肉串格式
  • 父元件的監聽事件名和子元件的觸發事件名必須一模一樣
  • 子元件觸發事件的時候,傳過來的引數,父元件可以用$event接收

v-model語法糖

v-model是屬性value和事件input的語法糖。

v-model1

沒有語法糖的時候,這樣寫

用v-model的話,父元件就可以少了監聽事件,用起來更加方便

v-model的語法糖有其侷限性:

  • 適用於:觸發事件返回的值 正是 屬性要改的值,一般是單一屬性。比如觸發事件返回的值正好就是提title的新值
  • 更多邏輯的話,就不適用了
  • 更適用於:表單類的元件,因為屬性和事件預設是valueinput

當然特定情況下,可以修改v-model的預設屬性,但可讀性就不是很好。

export default {
  name:'ListItem',
  model:{
    prop:'title',
    input:'changeTitle'
  }
}
複製程式碼

.sync語法糖

.sync這個語法糖,同樣適用於觸發事件返回的值 正是 屬性要改的值,可讀性要強一些,可以用於非表單類的元件。 .sync語法糖預設是 屬性xxx和事件update:xxx

v-model1

沒有語法糖的時候,這樣寫

用.sync的話,父元件仍然可以少監聽事件,用起來更加方便

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 不勝感激 !