自定義組件
-
自定義組件的v-model
首先我們先說一下在自定義組件中使用v-model的必要條件
- 在自定義的組件中要有input(這里我們先不討論單選復選框)
- 在自定義組件的模板物件中要有props屬性,且里面要含有一個value
- 在自定義組件的input標簽上要系結value屬性值為props中傳入的值,且還需要發出一個input事件
這樣講可能會有點難理解,還是上代碼吧...
<div id="app"> <child-com v-model="message"></child-com> <span>{{ message }}</span> </div> <template id="childCom"> <div> <input type="text" :https://www.cnblogs.com/liuyilong/p/https://www.cnblogs.com/liuyilong/p/https://www.cnblogs.com/liuyilong/p/https://www.cnblogs.com/liuyilong/p/value="value" @input='inputEvent'> </div> </template> <script> const childCom = { template: '#childCom', props: ['value'], methods: { inputEvent(event) { this.$emit('aaa', event.target.value) } }, } const vm = new Vue({ el: '#app', data: { message: '可以雙向系結的了' }, components: { childCom } }) </script>這是最終實作效果需要必備的,看完這些代碼如果你是小白,你可能會有點不理解為什么要這樣做,下面我告訴你原理,
首先在我們使用的
v-model中,其內部實作的原理就是一個 value屬性和一個input事件,其主要步驟就是,用v-bind系結value,然后用input事件監聽值的變化,當文本框中的值發生變化的時候,input事件就會觸發,那么我們可以在input事件中獲取到改變后的值然后賦值給value,這樣是不是就完成了雙向資料系結了,上代碼:<div id="app"> <input type='text' :value='https://www.cnblogs.com/liuyilong/p/message' @input='inputEvent'> <span>{{ message }}</span> </div> <script> const vm = new Vue({ el: '#app', data: { message: '可以雙向系結的了' }, methods: { inputEvent(event) { this.message = event.target.value; } } }) </script>就這樣幾個步驟,就達到了v-model的效果了,這就是他的原理,然后讓我們深一步想,讓自定義組件使用雙向資料系結,因為我們知道其內部就是value和input事件,
所以有了如下代碼:
<div id="app"> <child-com :value='https://www.cnblogs.com/liuyilong/p/message' @input='message=$event'></child-com> <!-- 此代碼就這里和最開始代碼不同 --> <span>{{ message }}</span> </div> <template id="childCom"> <div> <input type="text" :https://www.cnblogs.com/liuyilong/p/https://www.cnblogs.com/liuyilong/p/https://www.cnblogs.com/liuyilong/p/https://www.cnblogs.com/liuyilong/p/value="value" @input='inputEvent'> </div> </template> <script> const childCom = { template: '#childCom', props: ['value'], methods: { inputEvent(event) { this.$emit('input', event.target.value) } }, } const vm = new Vue({ el: '#app', data: { message: '可以雙向系結的了' }, components: { childCom } }) </script>根據上面的原理,現在你應該知道了為什么要傳一個value在子組件了吧,明白之后,您就可以把
<child-com :value='https://www.cnblogs.com/liuyilong/p/message' @input='message=$event'></child-com>替換成<child-com v-model="message"></child-com>了, -
$listeners的使用
由來:當我們在專案開發程序中會出現很多組件嵌套的關系,那么如果還要在最外層的組件向內部傳遞資料的話,有如下幾種方式:
- 從父向子傳遞,子再向孫傳遞,一直傳遞下去,那么最里面的組件想往最外層傳東西則可以從最里面向外面逐層$emit發送出去,但是仔細想想,一個簡單的傳遞資訊,卻涉及到了這之間所有的組件,而他們只是一個中間者,這讓代碼維護起來非常困難
- 使用vuex來進行傳遞,這樣確實方便了很多,但是這樣做如果沒有其他用處的話就有點大材小用了
- 使用事件總線,這樣使用也不容易維護
而
$listeners和$attrs的出現,就完美的解決了第一種情況的發生<div id="app"> <child-com :name='name' :age='age' @test-listeners='testListeners'></child-com> </div> <script> const vm = new Vue({ el: '#app', // 父組件 data: { name: 'lyl', age: 20, }, methods: { testListeners(arg) { console.log(arg) } }, components: { childCom: { // 子組件 inheritAttrs: false, template: ` <div> <span> {{name}} </span> <grand-com v-bind='$attrs' v-on='$listeners'></grand-com> </div> `, props: ['name'], components: { grandCom: { // 孫子組件 inheritAttrs: false, template: ` <div> <span @click='listenClick'>{{$attrs.age}}</span> </div> `, methods: { listenClick() { this.$emit('test-listeners','aaaaaaa'); } }, } } } } }) </script>上面代碼中,孫子組件要發出一個是將讓父組件呼叫,這個時候我們可以在中間過渡的子組件模板使用的孫子組件上系結這個屬性,即:
v-on='$listeners',這樣一來父組件就能直接呼叫孫子組件發出的方法了,并且在中間層的子組件上并沒有什么多余的部分 -
.sync的使用方法
我們都知道,在一個組件上,我們只能使用一個v-model,但是如果我們的組件中有多個input標簽呢,并且每個input標簽中的值都不同,且每個都想進行雙向系結,這個時候,v-model就不行了,于是乎就出現了.sync的出現,
根據上面我說的那些需求,我們寫一下代碼:
- 不使用.sync的代碼
<div id="app"> <child-com :value='https://www.cnblogs.com/liuyilong/p/obj.value' @aaa='obj.value = https://www.cnblogs.com/liuyilong/p/$event' :name='obj.name' @bbb='obj.name = $event' :age='obj.age' @ccc='obj.age = $event'> </child-com> <p>{{ obj }}</p> <p>{{ obj.value }}</p> <p>{{ obj.name }}</p> <p>{{ obj.age }}</p> </div> <!-- childCom組件的模板 --> <template id="childCom"> <div> <input type="text" :https://www.cnblogs.com/liuyilong/p/https://www.cnblogs.com/liuyilong/p/https://www.cnblogs.com/liuyilong/p/https://www.cnblogs.com/liuyilong/p/value="value" @input='inputValueEvent'> <br> <input type="text" :value="https://www.cnblogs.com/liuyilong/p/name" @input='inputNameEvent'> <br> <input type="text" :value="https://www.cnblogs.com/liuyilong/p/age" @input='inputAgeEvent'> </div> </template> <script> const childCom = { template: '#childCom', props: ['value','name','age'], methods: { inputValueEvent(event) { this.$emit('aaa', event.target.value) }, inputNameEvent(event) { this.$emit('bbb', event.target.value) }, inputAgeEvent(event) { this.$emit('ccc', event.target.value) } }, } const vm = new Vue({ el: '#app', data: { obj: { value: '雙向系結' , name: 'coderlyl' , age: 20} }, components: { childCom } }) </script>根據上面的代碼,我們不難發現,我們在
標簽中書寫了過多的重復的東西,可讀性也不是很好,下面我們再使用 .sync的方式- 使用.sync的代碼
<div id="app"> <child-com v-bind:value.sync='obj.value' v-bind:name.sync="obj.name" v-bind:age.sync="obj.age"> <!--這里也發生了變化--> </child-com> <p>{{ obj }}</p> <p>{{ obj.value }}</p> <p>{{ obj.name }}</p> <p>{{ obj.age }}</p> </div> <template id="childCom"> <div> <input type="text" :https://www.cnblogs.com/liuyilong/p/https://www.cnblogs.com/liuyilong/p/https://www.cnblogs.com/liuyilong/p/https://www.cnblogs.com/liuyilong/p/value="value" @input='inputValueEvent'> <br> <input type="text" :value="https://www.cnblogs.com/liuyilong/p/name" @input='inputNameEvent'> <br> <input type="text" :value="https://www.cnblogs.com/liuyilong/p/age" @input='inputAgeEvent'> </div> </template> <script> const childCom = { template: '#childCom', props: ['value','name','age'], methods: { inputValueEvent(event) { this.$emit('update:value', event.target.value) // 這里發生了變化 }, inputNameEvent(event) { this.$emit('update:name', event.target.value) // 這里發生了變化 }, inputAgeEvent(event) { this.$emit('update:age', event.target.value) // 這里發生了變化 } }, } const vm = new Vue({ el: '#app', data: { message: '可以雙向系結的了', obj: { value: '雙向系結' , name: 'coderlyl' , age: 20} }, components: { childCom } }) </script>也許看完這里,你并沒有覺得好到哪里去了,下面還有更簡單的寫法
<child-com v-bind.sync="obj"></child-com> <!-- 其他代碼一樣 -->對,沒錯!這是終極簡化版,但是這只針對于物件才能用
注意帶有
.sync修飾符的v-bind不能和運算式一起使用 (例如v-bind:title.sync=”doc.title + ‘!’”是無效的),取而代之的是,你只能提供你想要系結的屬性名,類似v-model,將
v-bind.sync用在一個字面量的物件上,例如v-bind.sync=”{ title: doc.title }”,是無法正常作業的,因為在決議一個像這樣的復雜運算式的時候,有很多邊緣情況需要考慮,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/154331.html
標籤:JavaScript
上一篇:Prop驗證、inheritAttrs、$attrs的用法和坑
下一篇:具名插槽、作用域插槽的新寫法
