Vue双向绑定实例教程
双向绑定简介
我们知道Vue是一个典型的MVVM框架,Vue在动态绑定这一块提供了丰富的API,让我们可以用简短的代码写出响应式的效果,我们只需关注数据对象,而视图层则通过双向绑定的形式进行更新,以下将通过四个方面介绍双向绑定在vue的使用及可能遇到的坑
- 双向绑定在实际项目中的运用
- 借助Vue调试工具定位问题
- 双向绑定与Getter/Setter器的关系,深入响应式原理
- 绑定失败问题的解决方案
双向绑定在项目的实际运用
在项目中,我们对element-ui做了一次再封装处理,以表单组件为例
在业务使用中很大的痛点在于表单各个不同组件的使用,在Jquery中,我们对不同的表单控件需要使用不同的取值形式,例如多选下拉和单选下拉、日期控件和范围日期控件,取值逻辑不尽相同,针对这种问题
我们创建了一个pm_form_item组件统一化处理 如下图
外部通过传入不同的参数决定控件的类型及逻辑,外部只关注绑定对象,无须关注取值设值的过程,未来拓展的过程中,假如有新的表单控件,只需增加新的参数类型,而对外部隐藏实现.
接下来就尝试新增一个表单组件试试吧!
设置组件的行数、宽度及控件类型等参数,设置是否可读,设置属性名,这里我们期望这个控件的值绑定到formModel的createTime属性上
观察下效果吧!
看起来好像一切顺利,现在我们可以进行业务开发了
假如这是一个新增页面,我期望在打开这个页面的时候给这个控件一个默认值,这似乎听起来并不难,只需要对formModel.createTime初始化值即可,如下 (created为Vue内置生命周期函数)
观察一下现象
默认值的确已经被初始化完成,但当我们想要再次修改控件的值时却失败了,这个控件现在对任何的输入值都不生效。双向绑定诡异的失败了。下面一节将介绍Vue的调试插件定位我们遇到的这个问题.
Vue调试工具 - Vue Devtools
Vue Devtools是Vue官方出品的一款Vue的调试工具,使用是通过Chrome的插件进行的,这里对安装插件等准备工作不做赘述
这里是Vue使用截图
总共分为3部分 Components,Vuex,Events
Components中左侧是组件树,右侧可以看到组件的data,props等,这个界面可以用以监控组件的内部状态,是最常用的功能
Vuex是一个Vue状态管理功能,我们可以在这里看到有关Vuex里的一些信息类似 state ,getters 等
Event界面我们可以看到Vue的事件触发,鼠标的点击移出移入输入等事件,都可以在这里看到
针对上述问题
我们观察Event,每次选择输入值时都会触发pick事件,我们可以看到我们选择的日期也在此事件参数中
看起来似乎是因为输入事件回调没有正常影响对象的值,我们尝试写监视器,监听对象的另一个属性然后打印该变量
我们拿这个对象与正常场景下的对象进行对比,发现异常场景下的对象少了createTime属性的getter/setter方法
看起来这就是造成双向绑定失败问题的真凶
双向绑定与Getter/Setter关系
在说双向绑定与Getter/Setter器的关系时,我们先讲一下Vue双向绑定实现的基本原理
在传统认知中,双向绑定通常使用引用传递或类似原理完成双向绑定,但这种方式通常会带来非常多的问题,子组件如果可以随意修改父组件的值,对开发人员是一个很大的心智负担,故在现代化的MVVW框架中,双向绑定都采用类似事件通知的形式进行。
不同于angularJs的 一处监听,全局检查,Vue使用的是点对点的订阅绑定模式,当子组件的值发生修改时,触发外部传入的回调函数修改外部的值
一个双向绑定实际的实现类似如下
而v-model关键字是对上述的一种语法糖封装
通过上述过程我们知道Vue需要在子组件绑定值childValue发生改变时触发回调函数,所以通过赋值模式进行改动是行不通的,需要通过Set方法,在Set方法中进行回调触发事件调用等,类似下面的伪代码
value{
var val;
get(){
return this.val;
}
set(newVal){
vue.$emit("parentEvent",newVal);
this.val = newVal;
}
}
这个Getter/Setter则是Vue为绑定变量动态生成的方法,Vue正是通过这种点对点的订阅行为完成双向绑定
绑定失败问题的解决方案
由于我们已经定位了问题是由于Setter/Getter问题引起,那么只要让Vue自己能够动态添加或我们自己手动添加即可
1.在声明formModel的 data对象时声明createTime属性
2.在初始化时不使用赋值初始化,转用Vue API
这种做法Vue会在赋值时为对象自动生成getter/setter
回顾我们第一节的内容我们可能会有些疑问,第一次我们没有进行赋值操作,但我们也没有对createTime进行声明或初始化getter/setter操作,但为什么结果是对的呢?
我们尝试在组件渲染完时,打印查看createTime属性不存在,同时也没有getter/setter,但当我们触发了子组件的选择事件后再尝试打印
此时vue已经为formModel对象添加了createTime和getter/setter方法,看来这个地方只是Vue为我们做了一次贴心的优化