初步实现了数据自动映射到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));

2、html代码:(实现对easyui组件的设值,其他组件也可以通过设值接口实现对应设值操作)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>javascript test</title>
<link rel="stylesheet" type="text/css" href="css/metro/easyui.css">
<link rel="stylesheet" type="text/css" href="css/icon.css">
<link rel="stylesheet" type="text/css" href="css/demo.css">
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/jquery.easyui.min.js"></script>
</head>
<body>
<div class="easyui-panel" title="数据驱动dom更新" style="width:500px">
<div style="padding:10px 60px 20px 60px">
<h1>F12 console 中输入:a.user.name = 'jack'; <br>
可以看到界面也会更新数据,其他更新参考脚本。</h1>
<form id="ff" class="easyui-form" method="post" data-options="novalidate:true" action="save.do">
<table cellpadding="5">
<tr>
<td>对象的名称:</td>
<td><input type="text" name="user.name" class="easyui-textbox" ></input></td>
</tr>
<tr>
<td>对象的年龄:</td>
<td><input name="user.age" class="easyui-numberbox"></td>
</tr>
<tr>
<td>对象的描述:</td>
<td>
<input name="user.addr" class="easyui-textbox" data-options="height:60,multiline:true">
</td>
</tr> <tr>
<td>纯变量数量:</td>
<td><input name="count" class="easyui-numberspinner"></td>
</tr>
<tr>
<td>纯变量选项:</td>
<td>
<select class="easyui-combobox" name="dept" style="width:150px;">
<option value="1">aitem1</option>
<option value="2">bitem2</option>
<option value="3">bitem3</option>
<option value="4">ditem4</option>
<option value="5">eitem5</option>
<option value="6">eitem6</option>
<option value="7">eitem7</option>
<option value="8">eitem8</option>
<option value="9">eitem9</option>
</select>
</td>
</tr> <tr>
<td>menber-0-name:</td>
<td><input name="menbers[0].id.code" class="easyui-textbox"></td>
</tr>
<tr>
<td>menber-0-age:</td>
<td>
<input name="menbers[0].age" class="easyui-numberbox">
</td>
</tr>
<tr>
<td>menber-1-name:</td>
<td><input name="menbers[1].name" class="easyui-textbox"></td>
</tr>
<tr>
<td>menber-1-age:</td>
<td>
<input name="menbers[1].childs[0].name" class="easyui-textbox">
</td>
</tr>
<tr>
<td>danomick:</td>
<td>
<input name="menbers[0].addrs" class="easyui-textbox">
</td>
</tr>
<tr>
<td>danomick user:</td>
<td>
<input name="user.email" class="easyui-textbox">
</td>
</tr>
<tr>
<td>danomick a:</td>
<td>
<input name="phones" class="easyui-numberbox">
</td>
</tr>
</table>
</form>
</div>
</div>
<script type="text/javascript" src="render.js"></script>
<script>
"use strict"
/* 扩展对easyui组件设值支持 */
Vue.prototype.setValue = function (value) {
var $ctn = $(this).parent().prev(), ctnClass = $ctn.attr("class"),
itemFn = ctnClass.match(/easyui-(\w+)/),itemFn = itemFn[1];
$ctn[itemFn]('setValue',value);
};
/* 组件值反射到data中机制构建 */
$.parser.onComplete = function(context){
try {
$('[type=hidden].textbox-value').each(function(){
var prev = $(this).prev(), $ctn = $(this).parent().prev(), ctnClass = $ctn.attr("class"),
itemFn = ctnClass.match(/easyui-(\w+)/),itemFn = itemFn[1];
if (prev) {
prev.off("blur.prev");
prev.on("blur.prev", function() {
var item = $(this).next()[0];
setTimeout(function(){
item.value = $ctn[itemFn]('getValue');
_.htmlToData.apply(item);
},150);
});
}
});
} catch (e) {}
}
/* 模仿Vue */
var a = new Vue({
el: '#ff', /* 指定扫描的容器 */
data:{ /* 要处理的数据 */
user:{
name: 'json',
age: 26,
addr: 'usa'
},
menbers:[],
count: 10,
dept: 6
}
});
/* 覆盖原有属性会自动建立映射关系 */
a.menbers = [
{
mName: 'jack',
age: 26,
id: {
code: 'idCard'
}
},
{
name: 'timy',
age: 20,
childs:[
{name: 'kimi'},
{name: 'coco'}
]
}
];
/* 针对没有的属性提供属性添加API(API会建立映射关系) */
a.addProps({email:'czm@139.com'},'user');
a.addProps({addrs:'lin ken street'},'data.menbers[0]');
a.addProps({phones:13900139000});
$("#scriptContent").text(JSON.stringify(a.data));
/* 模拟数据更新 */
// var int = setInterval(function () {
// a.user.age = Math.round(Math.random()*100);
// a.data.user.addr = new Date();
// a.count = Math.round(Math.random()*10000);
// a.data.dept = Math.round(Math.random()*8 + 1);
// },1500);
</script>
</body>
</html>

后续会逐步更新 ... ...

Object.defineProperty(obj,prop,descriptor)使用的更多相关文章

  1. Object.defineProperty(o,p,descriptor ) 理解应用

    1. Object.defineProperty  在一个对象上定义一个新属性,或修改一个已经存在的属性, 最终返回这个对象. var __define = this.__define || func ...

  2. javascript之Object.defineProperty的奥妙

    直切主题 今天遇到一个这样的功能: 写一个函数,该函数传递两个参数,第一个参数为返回对象的总数据量,第二个参数为初始化对象的数据.如: var o = obj (4, {name: 'xu', age ...

  3. 理解Object.defineProperty()

    理解Object.defineProperty() Object.defineProperty() 方法直接在一个对象上定义一个新属性,或者修改一个已经存在的属性, 并返回这个对象. 基本语法:Obj ...

  4. 理解Object.defineProperty的作用

    对象是由多个名/值对组成的无序的集合.对象中每个属性对应任意类型的值.定义对象可以使用构造函数或字面量的形式: var obj = new Object; //obj = {} obj.name = ...

  5. js中的Object.defineProperty()和defineProperties()详解

    ECMAS-262第5版在定义只有内部采用的特性时,提供了描述了属性特征的几种属性.ECMAScript对象中目前存在的属性描述符主要有两种,数据描述符(数据属性)和存取描述符(访问器属性),数据描述 ...

  6. Object.defineProperty实现数据绑定

    1.Object.defineProperty方法 Object.defineProperty(obj, prop, descriptor); (1)参数:  obj:目标对象 prop:需要定义的属 ...

  7. Object.defineProperties()和Object.defineProperty()方法

    Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象. 语法:Object.defineProperty(obj, pro ...

  8. Object.defineProperty()属性介绍

    对象是由多对key/value组成得无序集合,通过object.key=value来设置属性外,还可通过Object.defineProperty定义新属性或修改原有的属性. 语法:Object.de ...

  9. 【Vue】-- 数据双向绑定的原理 --Object.defineProperty()

    Object.defineProperty()方法被许多现代前端框架(如Vue.js,React.js)用于数据双向绑定的实现,当我们在框架Model层设置data时,框架将会通过Object.def ...

随机推荐

  1. 将String类型的json字符串转换成java对象

    1,import com.fasterxml.jackson.databind.ObjectMapper; ObjectMapper mapper = new ObjectMapper(); Mycl ...

  2. OpenWRT平台搭建及简单应用[转帖]+华为HG255D编译实践(20190323更新)

    转自:http://www.cnblogs.com/zmkeil/archive/2013/04/17/3027385.html对于HG255D参照这里:http://www.right.com.cn ...

  3. win7 升级Power Shell到4.0

    因为用到EntityFrameworkCore ,想使用scaffold 来生成models. 提示我power Shell 2.0不支持命令,然后需要升级PS. PS  win7 升级文件下载地址是 ...

  4. gson格式化参数 对象转Map

    前台传json到后台接收: String  params = request.getParameters("paramtes"); Map<String, Map<St ...

  5. python2和python3关于列表推导的差别

    看下面两个例子: python2的环境:列表中的同名变量名被替换了 >>> x = 'my precious' >>> dummy = [x for x in 'A ...

  6. 2019/4/17 Linux学习

    一.Linux的文件系统 其中/prov./srv./sys 文件为文件系统,技术不过硬不要去修改:二.关于Xshell.Xft1.服务器的端口可有65535个可设置,开的越多安全性越差:2.远程登录 ...

  7. 虚拟机JVM

    虚拟机组成:类加载器,运行时数据区,执行引擎 运行时数据区:堆,栈,方法区,程序计数器,本地方法栈 堆:对象实例 栈:入栈出栈,线程的执行 栈帧:一个方法一个 栈的结构:放 局部变量表,操作数栈,动态 ...

  8. Java简单操作dubbo(一)

    dubbo-service公共Service package com.itman.service; public interface UserService { // 提供服务 使用userId查找用 ...

  9. Java框架spring 学习笔记(十二):aop实例操作

    使用aop需要在网上下载两个jar包: aopalliance.jar aspectjweaver.jar 为idea添加jar包,快捷键ctrl+shift+alt+s,打开添加jar包的对话框,将 ...

  10. 100-days: twenty-two

    Title: Why urban millennials love Uniqlo(优衣库) urban adj.都市的:具有城市或城市生活特点的; 市内; millennial n.千禧世代 mill ...