标签:test doc template 过多 表达 实现 不容易 事件总线 console
自定义组件的v-model
首先我们先说一下在自定义组件中使用v-model的必要条件
这样讲可能会有点难理解,还是上代码吧...
<div id="app">
<child-com v-model="message"></child-com>
<span>{{ message }}</span>
</div>
<template id="childCom">
<div>
<input type="text" :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='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='message' @input='message=$event'></child-com> <!-- 此代码就这里和最开始代码不同 -->
<span>{{ message }}</span>
</div>
<template id="childCom">
<div>
<input type="text" :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=‘message‘ @input=‘message=$event‘></child-com>
替换成 <child-com v-model="message"></child-com>
了。
$listeners的使用
由来:当我们在项目开发过程中会出现很多组件嵌套的关系,那么如果还要在最外层的组件向内部传递数据的话,有如下几种方式:
而 $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的出现。
根据上面我说的那些需求,我们写一下代码:
<div id="app">
<child-com
:value='obj.value' @aaa='obj.value = $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" :value="value" @input='inputValueEvent'>
<br>
<input type="text" :value="name" @input='inputNameEvent'>
<br>
<input type="text" :value="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
的方式
<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" :value="value" @input='inputValueEvent'>
<br>
<input type="text" :value="name" @input='inputNameEvent'>
<br>
<input type="text" :value="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 }”
,是无法正常工作的,因为在解析一个像这样的复杂表达式的时候,有很多边缘情况需要考虑。
组件使用v-model、$listeners、.sync(区别于v-model的双向数据绑定)
标签:test doc template 过多 表达 实现 不容易 事件总线 console
原文地址:https://www.cnblogs.com/liuyilong/p/12215583.html