目前前端的三大框架中:vue、react都是单向数据流。首先我们了解一下数据流的概念。
数据流的简介
- 单向数据流:简单来说model状态更新会触发view的更新,但是view状态更新的时候u 不会触发model更新。状态更新只是一个单向的过程。
如图:一个组件下面有两个子组件。父组件同时传递一个 “year” 数据到不同的子组件。我们分别可以在不同的组件中获取到父元素传递下来的数据值。同时我们在 “子组件1” 中修改传递下来的 “year”,这样并不会影响 “父组件” 和 “子组件2” 中的 “year” 变量的值。但是如果修改父组件中的 “year”变量的值,两个子组件中的值都会发生变化。
2. 双向数据流:双向数据流和单向数据流刚好相反。model的状态更新会触发view状态更新,同时view状态也会触发model状态更新,他们的作用是相互的。
3. 双向数据流有一定的缺点:Model(理解为状态的集合)中可以修改自己或者其他Model的状态。lg:用户操作input改变某个状态,可能造成其他状态的改变,可能会触发一连串状态的变化。最终很难预测状态变化成什么样。这样使代编变的很难调试。与双向数据流相比,在单向数据流中,当你需要修改状态,完全重新开始走一个修改流程这限制状态修改的方式,让状态变的可预测,有利于我们调试。
4. 单向数据流使用在很多场景中:多个组件共享状态时。共享状态和组件间通信变的不容易,所以我们需要把单向数据流抽取出来,用单向数据流的方式会变的容易。
了解了数据流之后,那vue中的双向绑定是怎样实现的呢?下面我们就举例来看下双向数据绑定实现。
vue中的数据双向绑定
数据的双向绑定主要是由MVVM框架实现的。在vue中主要由三部分组成,view,viewModel,和model组成。其中view和model不能直接通信,他们要通过中间件viewModel来进行。当model部分数据发生变化的时候,由于vue中的Data Binding将底层数据和Dom层进行绑定。viewModel通知view层更新数据,当视图层数据发发生变化的时候也会同步到。Model中。view和Model之间同步完全是自动的。不需要人手动操作。
vue中v-model实现数据双向绑定
使用v-mode实现数据双向绑定,这里其实v-model是一个语法糖而已。
- input标签中的v-model,
<input v-model = "data" /> //实际使用的时候我们的写法,同时句是下面的语法糖
<input :value=" data " @input="data = $event.target.value" /> // 这个是剥离语法糖的代码。
我们观察上面的两行代码,根据他们的区别我们可以得出:当我们给input添加v-model属性时默认会把value作为元素的属性。用input事件实时传递value。
- 在组件中使用v-model
<element-input v-model="price"></element-input>
Vue.component('element-input',{
template:'\
<span>\
<input ref= "input" \
:value="value"\
@input = "changeValue($event.target.value)"\
/>
</span>\
',
props:['value'], // 这里的value为template中的value值
methods:{
changeValue: function(value){
var formattedValue = value.trim().splice(0, value.indexOf( '.' ) === -1 ? value.length : value.indexOf(' . ') + 3)
if(formattedValue ! == value){
this.$ref.input.value = formattedValue;
}
// 通过下面的input事件把值传递上去。
this.$emit(' input ', Number(formattedValue));
}
}
})
<element-input v-model="price" ></element-input> // 语法糖
<element-input :value="price" @input = "price = arguments[0]"></element-input>
在给组件添加v-model的时候。默认会把value作为组件的属性。然后把 ‘input’ 值作为给组件绑定事件时的事件名。
v-model的缺点和解决办法
在创建类似复选框或者单选框的等组件的时候,v-model就会出现问题。
<input type = "checkbox" v-model="data"/>
// v-model提供好了value属性和input事件,但是我们这里需要的不是value属性,而是checked属性。并且当你点击这个单选框的时候不会触发oninput,它只会触发onchange事件。所以这种问题我们用下面的方法来解决。
// 因为v-model只是用到了input元素上
<input type="checkbox" :checkbox = "value" @change="change(value,$event)" />
组件中的缺点
<checkbox v-model="value"><checkbox>
Vue.component("chekbox",{
tempalte: ' <input type = "checkbox" @change = "change" :chenge = "currentValue"/> ',
props:['value'],
data:function(){
return{
currentValue:this.value
// 这里定义一个局部变量并且用props初始化。因为在vue2.2之后我们定义组件的时候,可以通过model选项的方式来定制props或者是event
};
},
methods:{
change:function($event){
this.currentValue = $event.target.checked;
this.$emit( 'input', this.currentValue )
}
}
})
总结
vue双向绑定就是在单向绑定的基础上给可输入元素添加了change(input)事件。动态修改view和model,通过触发$emit调用父组件的事件方法达到修改数据的目的。这样做的目的是为了组件之间能更好的解耦,在开发过程中可能由多个子组件依赖一个父组件中的一个数据,假如子组件可以修改父组件中的方法,就会影响其他组件的变化。
很久没有写总结性的文章了,最近小半年有点忙。一个刚刚毕业的小白,不知不觉就把自己迷失在了工作的海洋中。感觉自己也没有了当初学习的冲劲。忘记了自己的初❤️,做了一个温水中?..。这一两个月想了很多,从现在开始我还需要继续紧张起来。学习的路还很长。我也会慢慢调整过来,以后多学习,多看书,多总结。虽然此刻依然不知道以后路在何方。但是我坚信路越走越明。相信自己的灯塔也会慢慢出现。