var tracker = {
getValue: function () {
return currentValue;
},
setValue: function (value) {
currentValue = '' + value;
},
stopTracking: function () {
detachTracker(node);
delete node[valueField];
}
};
return tracker;
}
这个东西又是通过Object.defineProperty打进元素的value/checked的内部,因此就知晓用户对它的取值赋值操作。
但value/checked还是两个很核心的属性,涉及到太多内部机制(比如说value与oninput, onchange, 输入法事件oncompositionstart,
compositionchange, oncompositionend, onpaste, oncut),为了平缓地修改value/checked,
还要用到 Object.getOwnPropertyDescriptor 。如果我要兼容IE8,没有这么高级的玩艺儿。我采取另一种更安全的方式,
只用Object.defineProperty修改 defaultValue/defaultChecked 。
首先我为元素添加一个 _uncontrolled 的属性,用来表示我已经劫持过defaultXXX。 然后描述对象 ( Object.defineProperty的第三个参数 )的set方法里面再添加一个开关, _observing 。在框架内部更新视图,此值为false,更新完,它置为true。
这样就知晓 input.defaultValue = “xxx”时,这是由用户还是框架修改的。
if (!dom._uncontrolled) {
dom._uncontrolled = true;
inputMonitor.observe(dom, name); //重写defaultXXX的setter/getter
}
dom._observing = false;//此时是框架在修改视图,因此需要关闭开关
dom[name] = val;
dom._observing = true;//打开开关,来监听用户的修改行为
inputMonitor的实现如下
export var inputMonitor = {};
var rcheck = /checked|radio/;
var describe = {
set: function(value) {
var controllProp = rcheck.test(this.type) ? "checked" : "value";
if (this.type === "textarea") {
this.innerHTML = value;
}
if (!this._observing) {
if (!this._setValue) {
//defaultXXX只会同步一次_persistValue
var parsedValue = (this[controllProp] = value);
this._persistValue = Array.isArray(value) ? value : parsedValue;
this._setValue = true;
}
} else {
//如果用户私下改变defaultValue,那么_setValue会被抺掉
this._setValue = value == null ? false : true;
}
this._defaultValue = value;
},
get: function() {
return this._defaultValue;
},
configurable: true
};
inputMonitor.observe = function(dom, name) {
try {
if ("_persistValue" in dom) {
dom._setValue = true;
}
Object.defineProperty(dom, name, describe);
} catch (e) {}
};
又不小心贴了这么烧脑的代码,这是码农的坏毛病。不过,到这步,大家都明白,无论是官方react还是anu/qreact都是通过Object.defineProperty来控制用户的输入的。
于是我们可以理解以下的代码的行为了
内容版权声明:除非注明,否则皆为本站原创文章。
