前言javascript
简单介绍一下双向数据绑定实现的是一个什么样的东西。首先有两个东西,他们分别是:
V-视图层
M-数据层
一、视图层传向数据层:V发生改变,M也发生改变
二、数据层传向视图层:M发生改变,V也发生改变
那么接下来咱们也将本身书写代码实现这样两种功能,从而实现双向数据绑定。最终实现的效果如图:
修改input框里面的内容,p标签内容也实时相对应发生改变,data里面的数据也会发生改变
html
1、先奉献上本身完整的代码java
这里我是基于jQuery进行的代码编写,其中的方法将在下面进行详细的解析jquery
;(function($,doc,win) { var VM = function(opt) { this.setting = {}; $.extend(this.setting, opt.data); // 初始化VM this.init(); }; VM.prototype = { init: function() { this.render('input'); this._render('p'); }, render: function(dom) { var self = this , data = self.setting; $(dom).each(function() { var _attr = $(this).attr('xq-model'); if (_attr !== undefined) { if (data[_attr] !== undefined) { $(this).attr('value', data[_attr]); self.inputChange($(this), _attr); } } }); }, _render: function(dom) { var self = this; $(dom).each(function() { var val = $(this).html() || $(this).text() || $(this).val(); if (val.indexOf('}}') !== -1 && val.indexOf('}}') !== -1) { val = val.replace(/^s+|{{|s+/,''); val = val.replace(/}}|[\s+]/g,''); self.labelChange(this, val); } }) }, labelRender: function(dom, _attr) { var self = this , data = self.setting; $(dom).each(function() { var val = $(this).attr(_attr); if (val !== undefined) { if (data[_attr] !== undefined) { $(this).html(data[_attr]) || $(this).text(data[_attr]) || $(this).val(data[_attr]); } } }) }, inputChange: function(_this, _attr) { var self = this , data = self.setting; _this.unbind('keydown'); _this.keydown(function(){ _this.unbind('keyup'); _this.keyup(function() { var changeVal = _this.val() , oldVal = data[_attr]; data[_attr] = changeVal; self.render('input'); self.labelRender('p', _attr); }) }) }, labelChange: function(_this,val) { var self = this , data = self.setting; if (val !== undefined) { if (data[val] !== undefined) { $(_this).html(data[val]) || $(_this).text(data[val]) || $(_this).val(data[val]); } } $(_this).attr(val,'') } }; window.VM = VM; })(jQuery,document,window);
2、建立本身的绑定规则api
这里关于指令,我没有作做用域的包裹,比较完善的是须要用一个controller指令讲须要展现的view视图层包裹起来的。若是有想法的小伙伴们能够在最后自行去思考,接下来先直接上html代码dom
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>双向数据绑定</title> </head> <body> <input type="text" xq-model="msg"> <p> {{ msg }} </p> <input type="text" xq-model="my"> <p>{{ my }}</p> </body> <script src="js/jquery.js"></script> <script src="js/api.js"></script> </html>
这里我制定的双向指令是xq-model,内容的解析规则是{{}}。你们有本身喜欢的指令能够自行制定。ui
3、实现本身的绑定规则this
咱们如今须要作的就是一步一步去实现咱们本身规定的一些绑定规则prototype
首先咱们须要作的第一步就是渲染出input中的xq-model指令指定的数据code
/** * [render input框渲染] * @param {[type]} dom [input] */ render: function(dom) { var self = this , data = self.setting; // 遍历dom中全部的input,搜寻带xq-model指令的input $(dom).each(function() { var _attr = $(this).attr('xq-model'); // 判断是否有对应绑定data数据 if (_attr !== undefined) { if (data[_attr] !== undefined) { $(this).attr('value', data[_attr]); // 调用input值改变方法 self.inputChange($(this), _attr); } } }); }
实现inputChange方法
/** * [inputChange 值改变] * @param {[type]} _this [当前input] * @param {[type]} _attr [当前绑定对应的data数据] */ inputChange: function(_this, _attr) { var self = this , data = self.setting; // 绑定键盘事件进行监听 _this.unbind('keydown'); _this.keydown(function(){ _this.unbind('keyup'); _this.keyup(function() { var changeVal = _this.val() , oldVal = data[_attr]; data[_attr] = changeVal; // 调用input框渲染方法 self.render('input'); // 调用标签值改变渲染方法 self.labelRender('p', _attr); }) }) }
到这里,对于input框的渲染及data数据的双向算完成了第一个了,接下来咱们须要实现的即是对于标签的渲染
/** * [_render 标签渲染] * @param {[type]} dom [element] */ _render: function(dom) { var self = this; // 遍历标签,拿到里面的内容 $(dom).each(function() { var val = $(this).html() || $(this).text() || $(this).val(); // 判断是否存在{{}},并截取拿到{{}} 里面的内容 if (val.indexOf('}}') !== -1 && val.indexOf('}}') !== -1) { val = val.replace(/^s+|{{|s+/,''); val = val.replace(/}}|[\s+]/g,''); // 调用标签赋值方法 self.labelChange(this, val); } }) }
实现labelChange方法
/** * [inputChange 值改变] * @param {[type]} _this [当前input] * @param {[type]} _attr [当前绑定对应的data数据] */ labelChange: function(_this,val) { var self = this , data = self.setting; if (val !== undefined) { if (data[val] !== undefined) { $(_this).html(data[val]) || $(_this).text(data[val]) || $(_this).val(data[val]); } } // 给当前对象绑定一个属性对应其data数据 $(_this).attr(val,'') }
最后实现input框输入,实时修改对应的标签的值labelRender方法
/** * [labelRender 标签实时渲染] * @param {[type]} dom [element] * @param {[type]} _attr [当前data数据的key] */ labelRender: function(dom, _attr) { var self = this , data = self.setting; $(dom).each(function() { // 经过labelChange获取到对应data数据的attr属性 var val = $(this).attr(_attr); if (val !== undefined) { if (data[_attr] !== undefined) { $(this).html(data[_attr]) || $(this).text(data[_attr]) || $(this).val(data[_attr]); } } }) }
最后咱们调用一下实现好的VM
$(function() { new VM({ data: { msg: 'hello', my: 'hehe' } }); })
好了,属于咱们本身的一个简单的双向数据绑定至此便算是完成了,你们也能够本身将这个进行不断的完善,本身去实现一个完整的双向数据绑定。小伙伴们,加油↖(^ω^)↗