.sync和$attrs

1. sync

我們都知道vue中有單項(xiàng)數(shù)據(jù)流的概念,即數(shù)據(jù)只能有父組件傳遞給子組件,在子組件中,不能修改父組件的數(shù)據(jù)。如果非要這么做,那么可以在子組件中觸發(fā)($emit)一個(gè)事件,然后再父組件中監(jiān)聽。再然后觸發(fā)改變,最后又經(jīng)過props傳遞至子組件

<body>
  <div id="app">
    <child @add="addOne" :num="count"></child>
  </div>
  <script>
    Vue.component('child', {
      template: `
        <div class="child">
          <button @click="$emit('add')">{{num}}</button>
        </div>
      `,
      props: ['num']
    })
    new Vue({
      el: '#app',
      data: {
        count:0
      },
      methods: {
        addOne() {
          this.count += 1;
        }
      }
    })
  </script>
</body>

以上例子相當(dāng)簡單,如果碰到稍微復(fù)雜的改值操作,使用emit這種方式就非常繁瑣。這時(shí),.sync就派上用場了。其實(shí)它只是emit的語法糖而已,不過,對(duì)我們來說,卻實(shí)實(shí)在在的簡化了代碼。

 <div id="app">
    <child :title.sync="doc.title"></child>  <!--在需要雙向綁定的prop后加.sync-->
  </div>
  <script>
    Vue.component('child', {
      template: `
        <div class="child">
          <button @click="doSth">{{title}}</button>
        </div>
      `,
      props: ['title'],
      methods: {
        doSth() {
          this.$emit('update:title', '新標(biāo)題')  // 固定寫法“updata:”+要修改的props
        }
      }
    })
    new Vue({
      el: '#app',
      data: {
        doc: {
          title: '標(biāo)題'
        }
      }
    })
  </script>
//其實(shí):propName.sync="xxx"就相當(dāng)于“:propName="xxx" @update:propName="xxx=$event"”,即在父組件模板中監(jiān)聽數(shù)據(jù)更新事件。

2. $attrs

在使用vue時(shí),如果在父組件模板中,給子組件添加了屬性,這些屬性一般會(huì)自動(dòng)加在子組件的根元素上,比如:

<div id="app">
    <child abc-def disabled :title.sync="doc.title"></child>  <!--這里,我們添加了“abc-def”和disabled-->
  </div>
  <script>
    Vue.component('child', {
      template: `
        <div class="child">
          <button @click="doSth">{{title}}</button>
        </div>
      `,
      ...
    })
image.png

可以看到,disabled和abc-def默認(rèn)加在了根元素上。可是如果我們要加在特定元素上呢?比如一個(gè)input標(biāo)簽上,我們需要傳入placeholder,value,disabled這些屬性,并且不能加到根元素上。像這樣:

<div id="app">
    <super-input placeholder="輸入用戶名" title="userName" type="text" v-model="name"></super-input>
  </div>
  <script>
    Vue.component('superInput', {
      template: `
        <div class="ipt">
          <label>用戶名:<input ><label>
        </div>
      `
    })

如果你不希望組件的根元素繼承特性,你可以在組件的選項(xiàng)中設(shè)置 inheritAttrs: false。 ——vue中文文檔

注意 inheritAttrs: false 選項(xiàng)不會(huì)影響 style 和 class 的綁定。
inheritAttrs一般用來配合 $attrs 來完成特殊屬性傳遞。
就拿上邊的例子來說,vue會(huì)把 placeholder="輸入用戶名" title="userName" type="text" v-model="name"拆解成一個(gè)對(duì)象,并且賦值給$attrs:

{
    placeholder: '輸入用戶名',
    title: 'userName',
    type: 'text',
    value: 'name'     // v-model相當(dāng)于bind+input,大致就相當(dāng)于于get和set吧,這里只用bind的值
}
// 然后,子組件中要這樣使用
<div id="app">
    <super-input placeholder="輸入用戶名" title="userName" type="text" v-model="name"></super-input>
  </div>
  <script>
    Vue.component('superInput', {
      inheritAttrs: false,
      template: `
        <div class="ipt">
          <label>用戶名:<input v-bind="$attrs" @input="$emit('input', $event.target.value)"></label>  <!--前文解釋過了,此處的@input相當(dāng)于v-model的另一半。$attrs接收了福組件模板傳遞來的屬性,并且轉(zhuǎn)為對(duì)象-->
        </div>
      `
    })
    let vm = new Vue({
      el: '#app',
      data: {
        name: 'John'
      }
    })
image.png

屬性正確地被綁在了需要綁的元素上(包括value)!

需要注意的是,props和$attrs是互斥的,如果給一個(gè)子組件傳遞了很多屬性,如果子組件中沒有props,那么這些屬性都會(huì)出現(xiàn)在子組件的$attrs上,相應(yīng)的,如果某個(gè)屬性已經(jīng)被props接收了,那么attrs上便不存在了

3. $listeners

$listeners$attrs類似,$attrs包含了父組件傳遞給子組件的所有屬性,而$listeners包含了父傳給子組件的所有事件

<div id="app">
    <my-button @click="change(111)" @mouseup="change(222)"></my-button>
  </div>
  <script>
    new Vue({
      el: "#app",
      components: {
        "myButton": {
          template: `
            <div>
              <button @click="$listeners.click">點(diǎn)我</button> //只能觸發(fā)父組件的click
              <button @click="$emit('click')">點(diǎn)我1</button>  //只能觸發(fā)父組件的click
              <button v-on="$listeners">點(diǎn)我2</button> //相當(dāng)于 v-on:click="$listeners.click" + v-on:mouseup="$listeners.mouseup"
            </div>
          `,
          mounted() {
            console.log(this.$listeners)
          }
        }
      },
      methods: {
        change(a) {
          alert(a)
        }
      }
    })
  </script>

所以,$listeners可以用來批量觸發(fā)事件

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容