--2017.5.12
完成百度前端学院的糯米学院动态数据绑定第四题和第五题的一部分。
目前实现的功能有:
- 监测对象的属性的访问和改变
- 添加$watch
- 实现深层次数据变化逐层往上传播(记录每个属性的父亲,并检查祖先的所有监听回调,如果存在,就触发)
- DOM中数据渲染,尚未测试完全。目前并不支持双向数据绑定。
缺点:
1.不支持数组
2.不支持输入框数据绑定
function FVue(options, parent, parentKey) {
this.$watch = this._watch;
this.parent = parent;
this.parentKey = parentKey;
this.listeners = {};
this.$data = options.data || options;
this._walk(this.$data);
//this.render(options);
}
FVue.prototype.render = function(opts)
{
var el = document.querySelector(opts.el);
if (el) this._compileNode(el);
}
FVue.prototype._compileNode = function (el) {
switch (el.nodeType) {
case document.ELEMENT_NODE:
this._compileElement(el);
break;
case document.TEXT_NODE:
this._compileTextNode(el);
break;
}
}
FVue.prototype._compileElement = function (el) {
if (el.hasChildNodes()) {
Array.from(el.childNodes).forEach(this._compileNode, this)
}
}
FVue.prototype._compileTextNode = function (el) {
var pattern = /{{\w+}}/g;
var text = el.nodeValue;
var exps = text.match(pattern);
var newNode = document.createTextNode('');
exps.map(function (item) {
var htmlText = item.nodeValue;
var propText = item.replace(/[{}]/g, '');
var props = propText.split('.');
var len = props.length;
if (len <= 0) return;
var tmp = this.$data[props[0]];
for (var i = 1; i < len; i++) {
tmp = tmp[props[i]];
}
newNode.nodeValue += tmp;
});
el.parentNode.insertBefore(el, newNode);
el.parentNode.removeChild(el);
}
function isArray(obj) {
return Object.prototype.toString.call(obj) == "[object Array]";
}
FVue.prototype._walk = function (obj) {
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
var val = obj[key];
if (typeof val === 'object') {
this._bindData(this.$data, key, val);//bug fixed.every name must define getter/setter
new FVue(val, this, key);
}
else if (typeof val === 'function') {
this._bindData(this.$data, key, val());
}
else {
this._bindData(this.$data, key, val);
}
}
}
}
FVue.prototype._publish = function (key, val) {
if (!this.listeners[key])//不要在Object.defineProperty里访问key,那时候key还没有定义
{
return;
}
else {
for (var i = 0, len = this.listeners[key].length;
i < len; i++) {
this.listeners[key][i](val);
}
}
}
FVue.prototype._watch = function (prop, callback) {
if (!this.listeners[prop]) {
this.listeners[prop] = [];
}
this.listeners[prop].push(callback);
}
FVue.prototype._bindData = function (obj, key, val) {
var self = this;
self._watch(key, function (newVal) { // 为每个值设置一个监听事件
console.log(`你设置了 ${key}, 新的值为${newVal}`);
})
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function () {
console.log('你访问了' + key);
return val;
},
set: function (newVal) {
// console.log('你设置了' + key);
// console.log('新的' + key + ' = ' + newVal);
if (self.parent != undefined) {
//bug fixed.listeners={name,[callback]}.callback is an Array
self.parent.listeners[self.parentKey].map(
function (item) { item(newVal) }
);
}
if (val === newVal) {
return;
}
val = newVal;
self._publish(key, val);//在Object内部无法访问到this
if (typeof newVal === 'object') {
new FVue(val);
}
}
})
}
网友评论