初步实现了数据自动映射到html中,动态修改对象数据也很自动更新到html。提供addProps方法-添加新增属性并初始化自动监听
代码如下:
1、abserve.js:包含数据监听实现、类似jquery的find函数--querySelector实现等(数据深度迭代版)
(function(window) { var methods = { htmlToData: function(ctner) { // html反向映射到data var pName = this.name, vName = ctner ? ctner.getAttribute('varibleName') : null; if (vName) {} else { for (let key in window) { if (typeof window[key] == 'object') { try { var rObj = methods.getPropByPath(window[key], pName); if (rObj && rObj.v != undefined) { vName = key; if (ctner) ctner.setAttribute('varibleName', key); break; } } catch (e) {} } } } var pPath = vName + '.' + pName + '=\'' + this.value + '\''; console.log(pPath); eval(pPath); }, parseHtml: function({ key, value, container, fn }) { var inputs = methods.querySelector("[name=" + key + "]", container); inputs.forEach(function(item, index, array) { try { /* callback 提供设值接口 */ fn.apply(item, [value]); } catch (e) { item.value = value; } $(item).off("blur.render"); $(item).on("blur.render", function() { methods.htmlToData.apply(this, [container]); }); }); }, /*查找子节点,用法类似jquery的find函数,仅支持id,class,attr选择器,返回匹配的元素集*/ querySelector: function find(selector, el) { var el = el || document; var m = selector.match(/([#\.\[])([\w\W]+)/i); var type, key, attrName, result = []; if (m) { /* 正则判断选择器类型 */ if (m[1] == ".") { type = "class"; key = m[2]; } else if (m[1] == "#") { type = "id"; key = m[2]; } if (m[1] == "[") { type = "attr"; m = m[2].match(/(\w+)=((\w+(\[\d+\])*\.*)+)/i); attrName = m[1]; key = m[2]; } } else { type = "tag"; key = selector; } function findChild(node) { var c; for (var i = 0; i < node.childNodes.length; i++) { c = node.childNodes[i]; if (type == "class" && c.className == key) result.push(c); else if (type == "id" && c.id == key) { result.push(c); continue; } else if (type == "attr" && c.getAttribute && c.getAttribute( attrName) == key) { result.push(c); continue; } else if (type == "tag" && c.tagName && c.tagName.toLowerCase() == key) { result.push(c); continue; } findChild(c); } } findChild(el); return result; }, getPropByPath: function(obj, path) { let tempObj = obj; path = path.replace(/\[(\w+)\]/g, '.$1'); path = path.replace(/^\./, ''); let keyArr = path.split('.'); let i = 0; for (let len = keyArr.length; i < len - 1; ++i) { let key = keyArr[i]; if (key in tempObj) tempObj = tempObj[key]; else { throw new Error( '[render warn]: please transfer a valid prop path to form item!' ); } } return { o: tempObj, k: keyArr[i], v: tempObj[keyArr[i]] }; }, _copyProps: function(obj, target) { for (var key in target) obj[key] = target[key]; }, _defProps: function(obj, ctx, key, value, props, path, bool) { /* prop参数是为了解决二次赋值操作导致key值改变,parseHtml无法获得name名 */ (function(key, prop, props) { Object.defineProperty(obj, key, { set: function(newValue) { if (bool) methods._addProps(obj[key], newValue, ctx, path); else key = props[prop] = newValue; }, get: function() { return props[prop]; } }); })(key, key, props); /* 实现obj.prop 和 obj.data.prop双向更新 */ (function(ctx, key, value, props, path) { Object.defineProperty(props, key, { set: function(newValue) { if (key == newValue) return; key = newValue; path = path.replace(/\.*(undefined)*\.+/, '.') .replace(/\.(\d+)\./g, '[+$1+].').replace( /[+]/g, ''); var propPath = path.slice(path.indexOf('.') + 1); if (propPath.indexOf('data.') == 0) propPath = propPath.replace('data.', ''); methods.parseHtml({ key: propPath, value: newValue, container: document.querySelector(ctx), fn: Vue.prototype.setValue }); }, get: function() { return key; } }); props[key] = value; })(ctx, key, value, props, path); }, _addProps: function(obj, props, ctx, path) { for (var key in props) { if (typeof props[key] == 'object') { methods._addProps(obj[key] = {}, props[key], ctx, path + '.' + key); methods._defProps(obj, ctx, key, props[key], props, path + '.' + key, true); } else if (typeof props[key] == 'function') obj[key] = props[ key]; else methods._defProps(obj, ctx, key, props[key], props, path + '.' + key); } return obj; }, /* obj:目标对象;props:json格式属性;path:属性路径;el:渲染域容器 */ addProps: function(obj, props, path) { var target = obj; if (path) target = methods.getPropByPath(obj, path).v; methods._addProps(target, props, obj.el || 'document', '.' + path); } }; _ = { addProps: methods.addProps, getPropByPath: methods.getPropByPath, querySelector: methods.querySelector, parseHtml: methods.parseHtml, htmlToData: methods.htmlToData }; Vue = function(param) { methods._copyProps(this, param); if (this.data) methods._addProps(this, this.data, this.el); } Vue.prototype = { addProps: function(props, path) { methods.addProps(this, props, path); } }; }(window));