1. 程式人生 > 程式設計 >Vue2.4+新增屬性.sync、$attrs、$listeners的具體使用

Vue2.4+新增屬性.sync、$attrs、$listeners的具體使用

sync

在vue2.4以前,父元件向子元件傳值用props;子元件不能直接更改父元件傳入的值,需要通過$emit觸發自定義事件,通知父元件改變後的值。比較繁瑣,寫法如下:

//父元件
<template>
 <div class="parent">
  <p>父元件傳入子元件的值:{{name}}</p>
  <fieldset>
   <legend>子元件</legend>
   <child :val="name" @update="modify">
   </child>
  </fieldset>
 </div>
</template>

<script>
import Child from './Child'
export default {
 components:{Child},data () {
  return {
   name:'linda'
  }
 },methods:{
  modify(newVal){
   this.name=newVal
  }
 }
}
</script>

//子元件
<template>
  <label class="child">
    輸入框:
    <input :value=val @input="$emit('update',$event.target.value)"/>
  </label>
</template>
<script>
export default {
  props:['val']
}
</script>

vue2.4以後的寫法明顯舒服許多,上面同樣的功能,直接上程式碼

//父元件
<template>
 <div class="parent">
  <p>父元件傳入子元件的值:{{name}}</p>
  <fieldset>
   <legend>子元件</legend>
   <child :val.sync="name">
   </child>
  </fieldset>
 </div>
</template>

<script>
import Child from './Child'
export default {
 components:{Child},data () {
  return {
   name:'linda'
  }
 }
}
</script>

//子元件
<template>
  <label class="child">
    輸入框:
    <input :value=val @input="$emit('update:val',$event.target.value)"/>
  </label>
</template>
<script>
export default {
  props:['val']
}
</script>

寫法上簡化了一部分,很明顯父元件不用再定義方法檢測值變化了。其實只是對以前的$emit方式的一種縮寫,.sync其實就是在父元件定義了一update:val方法,來監聽子元件修改值的事件。

$attrs

想象一下,你打算封裝一個自定義input元件——MyInput,需要從父元件傳入type,placeholder,title等多個html元素的原生屬性。此時你的MyInput元件props如下:

props:['type','placeholder','title',...]

很醜陋不是嗎?$attrs專門為了解決這種問題而誕生,這個屬性允許你在使用自定義元件時更像是使用原生html元素。比如:

//父元件
<my-input placeholder="請輸入你的姓名" type="text" title="姓名" v-model="name"/>

my-input的使用方式就像原生的input一樣。而MyInput並沒有設定props,如下

<template>
  <div>
    <label>輸入框:</label><input v-bind="$attrsAll" @input="$emit('input',$event.target.value)"/>
  </div>
</template>
<script>
export default {
  inheritAttrs:false,computed: {
    $attrsAll() {
      return {
        value: this.$vnode.data.model.value,...this.$attrs
      }
    }
  }
}
</script>

基礎掃盲

v-model是v-bind:value和v-on:input的簡寫,所以在父元件你完全可以直接寫 :value="name",@input="val => name = val"。檢視文件

疑難

引用下vue的官方api中對$attrs的說明

$attrs包含了父作用域中不作為 prop 被識別 (且獲取) 的特性繫結 (class 和 style 除外)

比較迷惑的一點是給子元件設定:value="name"相當於給子元件設定props:['value'],所以在MyInput中直接從$attrs獲取不到value,需要重新包裝$attrsAll,新增value屬性。所以子元件還有下面寫法,我傾向於這種寫法,因為它更優雅

<template>
  <div>
    <label>輸入框:</label><input v-bind="$attrs" :value="value" @input="$emit('input',props:['value']
}
</script>

$listener

同上面$attrs屬性一樣,這個屬性也是為了在自定義元件中使用原生事件而產生的。比如要讓前面的MyInput元件實現focus事件,直接這麼寫是沒用的

<my-input @focus="focus" placeholder="請輸入你的姓名" type="text" title="姓名" v-model="name"/>

必須要讓focus事件作用於MyInput元件的input元素上,最終的MyInput原始碼如下:

<template>
  <div>
    <label>輸入框:</label><input v-bind="$attrsAll" v-on="$listenserAll"/>
  </div>
</template>
<script>
export default {
  inheritAttrs:false,props:['value'],computed:{
     $attrsAll() {
      return {
        value: this.value,...this.$attrs
      }
    },$listenserAll(){
      return Object.assign(
        {},this.$listeners,{input:(event) => this.$emit('input',event.target.value)})
    }
  }
}
</script>

到此這篇關於Vue2.4+新增屬性.sync、$attrs、$listeners的具體使用的文章就介紹到這了,更多相關Vue2.4 .sync、$attrs、$listeners內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!