龙空技术网

javascript前端开发:原生JS模拟vue的双向绑定

鹅是程序猿 250

前言:

眼前兄弟们对“js兼容ie8”大体比较讲究,兄弟们都想要学习一些“js兼容ie8”的相关内容。那么小编在网上网罗了一些关于“js兼容ie8””的相关文章,希望看官们能喜欢,同学们一起来学习一下吧!

现在mvvm框架火得不行,小编我最近也开始研究vue,相比jquery框架,vue的面向数据编程的确可以让我们摆脱操作dom的痛苦专注逻辑本身。

javascript

无论学什么框架,我都喜欢研究底层的东西,vue最核心的功能就是双向绑定,经过几天研究,同javascript实现了一个双向绑定功能。

双向数据绑定底层的思想非常的基本,分为三个步骤:

1.需要一个方法来识别哪个UI元素被绑定了相应的属性

2.需要监视属性和UI元素的变化

3.需要将所有变化传播到绑定的对象和元素

方法一:利用发布订阅模式,订阅数据变更

Html代码:

<div class="app"><input type="text" data-bind-id="demo"><p data-id="demo"></p></div>

javascript代码

function DataBinder(object_id) {//创建一个简单地PubSub对象var pubSub = {callbacks: {},on: function (msg, callback) {this.callbacks[msg] = this.callbacks[msg] || [];this.callbacks[msg].push(callback);},publish: function (msg) {this.callbacks[msg] = this.callbacks[msg] || [];for (var i = 0, len = this.callbacks[msg].length; i < len; i++) {this.callbacks[msg][i].apply(this, Array.prototype.slice.call(arguments, 1));}}};var data_attr = "data-bind-" + object_id,view_attr = 'data-' + object_id,message = object_id + ":change";var changeHandler = function (e) {var target = e.target || e.srcElemnt, //IE8兼容prop_name = target.getAttribute(data_attr);if (prop_name && prop_name !== "") {pubSub.publish(message, target, prop_name, target.value);}};//监听变化事件并代理到PubSubif (document.addEventListener) {document.addEventListener("keyup", changeHandler, false);} else {//IE8使用attachEvent而不是addEventListenerdocument.attachEvent("keyup", changeHandler);}//PubSub将变化传播到所有绑定元素pubSub.on(message, function (event, prop_name, new_val) {var elements = document.querySelectorAll("[" + view_attr + "=" + prop_name + "]"), tag_name;for (var i = 0, len = elements.length; i < len; i++) {tag_name = elements[i].tagName.toLowerCase();if (tag_name === "input" || tag_name === "textarea" || tag_name === "select") {elements[i].value = new_val;} else {elements[i].innerHTML = new_val;}}});return pubSub;}DataBinder('id');

方法二:数据劫持 。

html代码:

<div class="app"><input type="demo" h-model="demo" spellcheck="true"><p h-text="demo"></p></div>

借助 Object.defineProperty 方法, Object.defineProperty 方法可以为任何已存在的属性重新定义get与set方法。

(function(window, undefined) {var addEvent = (function () {if(window.addEventListener) {return function (el, type, fn) {if(el && el.nodeName || el === window) {el.addEventListener(type, fn, false)}else if(el.length) {for(var item of el) {addEvent(item, type, fn);}}}}else {return function (el, type, fn) {if(el && el.nodeName || el === window) {el.attachEvent('on' + type, function () {return fn.call(el, event);})}else if(el.length) {for(var item of el) {addEvent(item, type, fn);}}}}})();var Hue = function(opt) {var el = document.querySelector(opt.el);var data = opt.data || {};this.el = el;this.data = data;this.bindText();this.bindModel();return this;};Hue.prototype = {constructor: Hue,// **前端数据劫持**defineObj: function(obj, prop, value) {var _value = value || '', _this = this;try {Object.defineProperty(obj, prop, {get: function() {return _value;},set: function(newVal) {_value = newVal;_this.bindText();},enumerable: true,configurable: true});} catch (error) {// IE8+ 才开始支持defineProperty,这也是Vue.js不支持IE8的原因console.log("Browser must be IE8+ !");}},bindModel: function() {var modelDOMs = this.el.querySelectorAll('[h-model]'), lenModel = modelDOMs.length;var _this = this, i, propModel;for (i = 0; i < lenModel; i++) {propModel = modelDOMs[i].getAttribute('h-model');//init valuemodelDOMs[i].value = this.data[propModel] || '';// 前端数据劫持this.defineObj(this.data, propModel);}addEvent(modelDOMs, 'keyup', function (e) {_this.data[propModel] = e.target.value;})},bindText: function() {var textDOMs = this.el.querySelectorAll('[h-text]'),lenText = textDOMs.length,prppText,j;for (j = 0; j < lenText; j++) {propText = textDOMs[j].getAttribute('h-text');textDOMs[j].innerHTML = this.data[propText] || '';}}};window.Hue = Hue;})(window);// test...new Hue({el: '.app',data: {demo: 'Kenny'}});

欢迎大家关注和转发。

标签: #js兼容ie8