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

這篇文章主要介紹了Vue2.4+新增屬性.sync、$attrs、$listeners的具體使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨着小編來一起學習學習吧

sync

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

//父組件

<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以後的寫法明顯舒服許多,上面同樣的功能,直接上代碼

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

//父組件

<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如下:

1

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

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

1

2

//父組件

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

<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屬性。所以子組件還有下面寫法,我傾向於這種寫法,因爲它更優雅

1

2

3

4

5

6

7

8

9

10

11

<template>

  <div>

    <label>輸入框:</label><input v-bind="$attrs" :value="value" @input="$emit('input',$event.target.value)"/>

  </div>

</template>

<script>

export default {

  inheritAttrs:false,

  props:['value']

}

</script>

$listener

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

1

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

<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>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章