v-model 的原理 和 .sync 修饰符
v-model 的原理
特点:双向绑定
数据-->视图
视图-->数据
常见的使用场景:
- 收集表单数据
- 用在组件上
原理:
v-model只是个语法糖,本质是:v-model=v-bind(:value属性) + v-on(@input事件)
<div id="app">
<cdn></cdn>
</div>
<template id="temp">
<div>
<input type="text" v-model="text">
{{text}}
</div>
</template>
let app=new Vue({
el:'#app',
components:{
cdn:{
template:'#temp',
data(){
return{
text:'完全透明的包裹器'
}
},
}
}
})
视图页面中实现了双向绑定
- 以下代码的本质与上面一致(
v-model的原理分析)
<div id="app">
<cdn></cdn>
</div>
<template id="temp">
<div>
<!-- <input type="text" v-bind:value="text" v-on:input="handleInput"> -->
<input type="text" v-bind:value="text" @input="(e)=>(this.text=e.target.value)">//ES6写法
{{text}}
</div>
</template>
let app=new Vue({
el:'#app',
components:{
cdn:{
//....省略
// input 事件传过来了事件对象
methods:{
handleInput(event){
this.text=event.target.value;
}
}
}
}
})
当在输入框中输入数据时,视图页面的
{{text}}也会实时更新
v-model 作用在组件上的原理
利用v-model实现父子组件的双向绑定通信
在组件上使用
v-model,使v-model绑定的变量发生改变时,能够影响组件的状态或行为,数据-->视图当组件内部状态或行为发生改变时,能够影响到
v-model绑定的变量,视图-->数据
官网的解释是:父组件将值通过v-model进行绑定,之后子组件通过props的key为value进行接收,通过事件input触发更改父组件。
组件与视图的绑定
组件与视图绑定,在v-model的原理中已经实现;
注意:
- 官方注明使用
props的属性进行传递数据 - 但是
props属性只能由父组件传递数据不能在模板里面修改props的数据,组件内props属性的数据只能用来展示不能修改
props:{
num1:Number,
num2:Number
},
template:
`
<div>
<h2>num1:{{num1}}</h2>
<input type="number" v-model="num1">
<br>
<h2>num2:{{num2}}</h2>
<input type="number" v-model="num2">
</div>
以上代码的确实现了组件与视图的双向绑定,但是会报错
[Vue warn]:
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "num2"意思就是
props里的属性不支持修改,当父组件重新渲染时,props属性也会被重新渲染;
应当使用一个data方法或者计算属性将属性的值重新赋给另外一个属性
- 将绑定改到新的属性,而不是
props属性,此时已经对dnum1进行了双向绑定,页面也可以同步更新
data() {
return {
dnum1:this.num1,
dnum2:this.num2,
}
},
template:` <input type="number" v-model="dnum1">`//模板中的v-model绑定改为 dnum1
//也可以使用自定义事件(效果是一致的):
<!-- <input type="number" v-bind:value="text" v-on:input="handleInput"> -->
<input type="number" v-bind:value="dnum1" @input="(e)=>(this.dnum1=e.target.value)">//ES6写法
v-model绑定变量与组件的绑定
父子组件的双向绑定
- 父组件向子组件传值使用Props,子组件定义期望接收传值的名字、类型、默认值等等,父组件Props值的改变会自动同步到子组件。
- 子组件向父组件传值使用事件触发,即使用
$emit注册事件,在父组件触发,这个事件可以携带值,而且一个事件的触发本身就是在传递信息。
-
子组件中使用
$emit触发事件发送数据components: { cdn: { //.....省略 methods: { childHandleInput(event) { this.outText = event.target.value;//改变赋予了`props属性的数据`的属性 this.$emit('handle-input', this.outText)//参数传递给handle-input事件 } } }, } -
父组件中接收数据并绑定到变量
<div id="app">
<!-- 这里事件不是input,不能使用 v-model -->
<cdn :value="handleText" @handle-input="handleInput">
</cdn>
</div>
<script>
let app = new Vue({
el: '#app',
data: {
handleText: ''
},
methods: {
handleInput: function (value) {
this.handleText = value;
}
},
</script>
完整代码:
<div id="app">
<!-- 这里事件不是input,不能使用 v-model -->
<cdn :value="handleText" @handle-input="handleInput">
</cdn>
<p>handleText-->{{handleText}}</p>
</div>
<template id="temp">
<div>
<input type="text" :value="outText" @input="childHandleInput">
<p>outText-->{{outText}}</p>
</div>
</template>
let app = new Vue({
el: '#app',
data: {
handleText: ''
},
methods: {
handleInput: function (value) {
this.handleText = value;
}
},
components: {
cdn: {
template: '#temp',
props: {
value: String,
},
data() {
return {
outText: this.value
}
},
methods: {
childHandleInput(event) {
this.outText = event.target.value;
this.$emit('handle-input', this.outText)
}
}
},
}
})
.sync 修饰符
在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以变更父组件,且在父组件和子组件两侧都没有明显的变更来源。
- 官方推荐使用:
update:myPropName的模式触发事件取而代之。举个例子,在一个包含titleprop 的假设的组件中,我们可以用以下方法表达对其赋新值的意图:
this.$emit('update:title', newTitle)
发送
update事件,携带数据发送给父组件注意:
title是props属性
- 然后父组件可以监听那个事件并根据需要更新一个本地的数据 property。例如:
<text-document
v-bind:title="doc.title"
v-on:update:title="doc.title = $event"
></text-document>
doc.title是父组件中的属性
这样写在父组件中就不需要再自定义处理事件函数了
- 为了方便起见,我们为这种模式提供一个缩写,即
.sync修饰符:
<text-document v-bind:title.sync="doc.title"></text-document>
完整代码:
<div id="app">
<!-- <cdn :value="handleText" @update:value="handleText=$event">-->
<cdn v-bind:value.sync="handleText">
</cdn>
<p>handleText-->{{handleText}}</p>
</div>
<template id="temp">
<div>
<input type="text" :value="outText" @input="childHandleInput">
<p>outText-->{{outText}}</p>
</div>
</template>
let app = new Vue({
el: '#app',
data: {
handleText: ''
},
//不需要自定义处理事件了
methods: {
/*handleInput: function (value) {
this.handleText = value;
}*/
},
components: {
cdn: {
template: '#temp',
props: {
value: String,
},
data() {
return {
outText: this.value
}
},
methods: {
childHandleInput(event) {
this.outText = event.target.value;
this.$emit('update:value', this.outText)
}
}
},
}
})
注意:
.sync修饰符的v-bind不能和表达式一起使用 (例如v-bind:title.sync=”doc.title + ‘!’”是无效的)。取而代之的是,你只能提供你想要绑定的 property 名,类似v-model。
- 当我们用一个对象同时设置多个 prop 的时候,也可以将这个
.sync修饰符和v-bind配合使用:
<text-document v-bind.sync="doc"></text-document>
这样会把
doc对象中的每一个 property (如title) 都作为一个独立的 prop 传进去,然后各自添加用于更新的v-on监听器。

浙公网安备 33010602011771号