Vue中不通过v-model怎么实现双向绑定
导读:本文共5256字符,通常情况下阅读需要18分钟。同时您也可以点击右侧朗读,来听本文内容。按键盘←(左) →(右) 方向键可以翻页。
摘要: 先来看解答:<template><divclass="test-v-model"><p>使用v-model</p><inputv-model="msg"placeholder="editme"/><p>{{msg}}<... ...
目录
(为您整理了一些要点),点击可以直达。先来看解答:
<template><divclass="test-v-model"><p>使用v-model</p><inputv-model="msg"placeholder="editme"/><p>{{msg}}</p><p>不使用v-model</p><input:value="msg1"@input="handleInput"placeholder="editme"/><p>{{msg1}}</p></div></template><script>exportdefault{name:'test-v-model',data(){return{msg:'',msg1:''}},methods:{handleInput(e){this.msg1=e.target.value}}}</script>
不使用 v-model,就需要通过 value 属性绑定值和 input 事件改变绑定值来实现双向绑定。
换句话说,v-model只是一种简写形式而已
事实上,v-model 的本质就是语法糖,它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。 -- 官方文档
v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:
text 和 textarea 元素使用
value
property 和input
事件;checkbox 和 radio 使用
checked
property 和change
事件;select 字段将
value
作为 prop 并将change
作为事件。
与本题相关联的知识延伸
双向绑定
单向数据绑定
vue 组件之间交互的单向数据流
问:什么是双向绑定?
双向绑定就是当数据变化之后,视图同步更新,当视图变化之后,数据也会更新。
问:什么是单向数据绑定?
单向数据绑定就是当数据变化之后,视图同步更新,当视图变化之后,数据不会更新。
在vue中是通过指令 v-model 来实现双向绑定,通过 v-bind
来实现单向数据绑定
看完下面这段代码和这段代码运行的gif演示,你就能明白他们的区别了。
<template><div><p>双向绑定</p><inputv-model="msg"placeholder="editme"/><p>{{msg}}</p><p>单向数据绑定</p><inputv-bind:value="msg1"placeholder="editme"/><p>{{msg1}}</p></div></template><script>exportdefault{name:'test-v-model',data(){return{msg:'',msg1:''}}}</script>
从gif图中可以看出,使用 v-model,当数据变化之后,视图同步更新,当视图变化之后,数据也会更新,这就是双向绑定。
使用 v-bind,当数据变化之后,视图同步更新,当视图变化之后,数据不会更新,这就是单向数据绑定。
问:什么是 vue 单向数据流?
子组件不能改变父组件传递给它的 prop 属性,推荐的做法是它抛出事件,通知父组件自行改变绑定的值。
总结起来就是数据向下,事件向上。
vue 文档在介绍 Prop 时就提出了单向数据流的概念,点击此处 查看 vue 文档对单向数据流的说明。
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。
额外的,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。
我们看下面这个例子:
子组件直接对 prop 值做双向绑定,会发生什么?
父组件代码:
<template><child-component:value="fatherValue"/></template><script>importChildComponentfrom'./child.vue'exportdefault{name:'father-component',components:{ChildComponent},data(){return{fatherValue:''}}}</script>
子组件代码:
<template><divclass="child-component"><inputv-model="value"placeholder="editme"/><p>{{value}}</p></div></template><script>exportdefault{name:'child-component',props:{value:{type:String,default:''}}}</script>
可以看到,childComponent中的 prop 值可以实现双向绑定,但是 FatherComponent 中的 data 值并未发生改变,而且控制台抛出了警告:
[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: "value"
翻译一下:避免直接改变 prop 值,因为每当父组件重新渲染时,该值将被覆盖。相反,使用基于 prop 值的 data 或 computed。
很显然,直接改变子组件的 prop 值的这种行为被 vue 禁止了。
如何操作传入子组件的 prop 值
但是很多时候,我们确实要操作传入子组件的 prop 值,该怎么办呢?
正如上面的警告所说,有两种办法:
这个 prop 用来传递一个初始值,定义一个本地的 data property 并将这个 prop 用作其初始值
props:{initialCounter:{type:Number,default:0},},data(){return{counter:this.initialCounter}}
这个 prop 以一种原始的值传入且需要进行转换,用这个 prop 的值来定义一个计算属性
props:{size:{type:String,default:''}},computed:{normalizedSize:function(){returnthis.size.trim().toLowerCase()}}
这样不管怎么操作数据都是操作的子组件数据了,不会影响到父组件数据。
所以,我们想用 prop 传入的数据实现双向绑定,可以这么写:
父组件代码不变
子组件里用 innerValue 来接收传入的 value :
<template><divclass="child-component"><inputv-model="innerValue"placeholder="editme"/><p>{{innerValue}}</p></div></template><script>exportdefault{name:'child-component',props:{value:{type:String,default:''}},data(){return{innerValue:this.value}}}</script>
这里要注意一个问题
在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变变更这个对象或数组本身将会影响到父组件的状态。
还是上面的例子,我们将传入的值改为对象:
父组件代码:
<template><child-component:obj="fatherObj"/></template><script>importChildComponentfrom'./child.vue'exportdefault{name:'father-component',components:{ChildComponent},data(){return{fatherObj:{name:'lin'}}}}</script>
子组件代码:
<template><divclass="child-component"><inputv-model="innerObj.name"placeholder="editme"/><p>{{innerObj.name}}</p></div></template><script>exportdefault{name:'child-component',props:{obj:{type:Object,default:()=>{}}},data(){return{innerObj:this.obj}}}</script>
这里的 this.obj
是引用类型,赋值给了 innerObj
,所以 innerObj
实际上还是指向了父组件的数据,对 innerObj.name
的修改依然会影响到父组件
所以,处理这种引用类型数据的时候,需要深拷贝一下
import{clone}from'xe-utils'exportdefault{name:'child-component',props:{obj:{type:Object,default:()=>{}}},data(){return{innerObj:clone(this.obj,true)}}}
如上图所示,这样子组件和父组件之间的数据就不会互相影响了。
</div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
Vue中不通过v-model怎么实现双向绑定的详细内容,希望对您有所帮助,信息来源于网络。