diff --git a/changelog.md b/changelog.md index fd7e96c5c..6574a00bf 100644 --- a/changelog.md +++ b/changelog.md @@ -1,4 +1,7 @@ # 更新日志 +2.0(2021-02) +- 增加updateModel属性,可以配置自动模式,自动watch属性并响应变化 + 2.0(2021-01) - 修改了日期下拉面板中的当前时间按钮的交互效果 - 新增年区间和年季度区间控件 diff --git a/dev.html b/dev.html new file mode 100644 index 000000000..650cf45a6 --- /dev/null +++ b/dev.html @@ -0,0 +1,103 @@ + + + + + + + + +
+ + + diff --git a/dist/fix/fix.compact.js b/dist/fix/fix.compact.js index 2e00a6c1d..affb9a10b 100644 --- a/dist/fix/fix.compact.js +++ b/dist/fix/fix.compact.js @@ -183,6 +183,74 @@ needPop && popTarget(); }; + BI.Widget.prototype._initElement = function () { + var self = this; + var render = BI.isFunction(this.options.render) ? this.options.render : this.render; + var els; + if (this.options.updateMode === "auto" && this._store) { + // 自动更新模式 + var childComponents = {}; + var rendered = false; + this._watchers.push(Fix.watch(this.model, function () { + if (rendered) { + var newEls = render && render.call(this); + BI.each(childComponents, function (i, childComponent) { + var nextProps = BI.get([newEls], childComponent.path); + if (nextProps) { + var shouldUpdate = childComponent.component.shouldUpdate && childComponent.component.shouldUpdate(nextProps); + childComponent.component._update(nextProps, shouldUpdate); + childComponent.props = BI.extend(childComponent.props, nextProps); + } + }); + } else { + els = render && render.call(this); + + function traverse (parent, path) { + BI.each(parent, function (i, child) { + const childPath = path.concat(i); + if (BI.isArray(child)) { + traverse(child, childPath); + } else if (BI.isPlainObject(child)) { + if (child.type) { + child.__ref = function (_ref) { + if (_ref) { + var comp = childComponents[this.getName()] = {}; + comp.component = _ref; + comp.props = child; + comp.path = childPath; + } else { + delete childComponents[this.getName()]; + } + }; + } + traverse(child, childPath); + } + }); + } + + traverse([els], []); + rendered = true; + } + })); + } else { + els = render && render.call(this); + } + if (BI.isPlainObject(els)) { + els = [els]; + } + if (BI.isArray(els)) { + BI.each(els, function (i, el) { + if (el) { + BI._lazyCreateWidget(el, { + element: self + }); + } + }); + } + // if (this._isRoot === true || !(this instanceof BI.Layout)) { + this._mount(); + }; + var unMount = BI.Widget.prototype.__d; BI.Widget.prototype.__d = function () { try { diff --git a/src/base/single/button/button.basic.js b/src/base/single/button/button.basic.js index 2bd82b17d..4a5d68a0c 100644 --- a/src/base/single/button/button.basic.js +++ b/src/base/single/button/button.basic.js @@ -389,11 +389,6 @@ BI.BasicButton = BI.inherit(BI.Single, { return this.options.text; }, - setValue: function (value) { - BI.BasicButton.superclass.setValue.apply(this, arguments); - this.options.setValue && this.options.setValue.call(this, value); - }, - _setEnable: function (enable) { BI.BasicButton.superclass._setEnable.apply(this, arguments); if (enable === true) { diff --git a/src/base/single/button/buttons/button.js b/src/base/single/button/buttons/button.js index 05819b04f..6db1349a3 100644 --- a/src/base/single/button/buttons/button.js +++ b/src/base/single/button/buttons/button.js @@ -1,4 +1,3 @@ - /** * 文字类型的按钮 * @class BI.Button @@ -44,7 +43,10 @@ BI.Button = BI.inherit(BI.BasicButton, { BI.Button.superclass._init.apply(this, arguments); var o = this.options, self = this; if (BI.isNumber(o.height) && !o.clear && !o.block) { - this.element.css({height: o.height / BI.pixRatio + BI.pixUnit, lineHeight: (o.height - 2) / BI.pixRatio + BI.pixUnit}); + this.element.css({ + height: o.height / BI.pixRatio + BI.pixUnit, + lineHeight: (o.height - 2) / BI.pixRatio + BI.pixUnit + }); } else if (o.clear || o.block) { this.element.css({lineHeight: o.height / BI.pixRatio + BI.pixUnit}); } else { diff --git a/src/base/single/single.js b/src/base/single/single.js index d2b51f0d0..c4d15291d 100644 --- a/src/base/single/single.js +++ b/src/base/single/single.js @@ -192,6 +192,7 @@ BI.Single = BI.inherit(BI.Widget, { setValue: function (val) { if (!this.options.readonly) { this.options.value = val; + this.options.setValue && this.options.setValue(val); } }, @@ -199,11 +200,24 @@ BI.Single = BI.inherit(BI.Widget, { return this.options.value; }, + update: function (props, shouldUpdate) { + if (BI.isObject(shouldUpdate)) { + props = shouldUpdate; + } + if ("value" in props) { + this.setValue(props.value); + } + if ("text" in props) { + this.setText && this.setText(props.text); + } + }, + destroyed: function () { if (BI.isNotNull(this.showTimeout)) { clearTimeout(this.showTimeout); this.showTimeout = null; } BI.Tooltips.remove(this.getName()); - }, + } }); +BI.shortcut("bi.single", BI.Single); diff --git a/src/core/ob.js b/src/core/ob.js index c4aacf624..9eab5d35a 100644 --- a/src/core/ob.js +++ b/src/core/ob.js @@ -72,6 +72,9 @@ // 获得一个当前对象的引用 _initRef: function () { + if (this.options.__ref) { + this.options.__ref.call(this, this); + } if (this.options.ref) { this.options.ref.call(this, this); } @@ -79,6 +82,10 @@ //释放当前对象 _purgeRef: function () { + if (this.options.__ref) { + this.options.__ref.call(null); + this.options.__ref = null; + } if (this.options.ref) { this.options.ref.call(null); this.options.ref = null; diff --git a/src/core/widget.js b/src/core/widget.js index 3f2779c63..7b6b341f9 100644 --- a/src/core/widget.js +++ b/src/core/widget.js @@ -7,7 +7,7 @@ */ !(function () { - function callLifeHook(self, life) { + function callLifeHook (self, life) { var hook = self.options[life] || self[life]; if (hook) { var hooks = BI.isArray(hook) ? hook : [hook]; @@ -32,7 +32,8 @@ baseCls: "", extraCls: "", cls: "", - css: null + css: null, + updateMode: "manual" // manual / auto }); }, @@ -73,8 +74,11 @@ shouldUpdate: null, - update: function () { - }, + update: null, + + beforeUpdate: null, + + updated: null, beforeDestroy: null, @@ -223,26 +227,59 @@ * @private */ _mount: function (force, deep, lifeHook, predicate) { + if (this.__beforeMount(force, deep, lifeHook, predicate)) { + this.__afterMount(lifeHook, predicate); + return true; + } + return false; + }, + + __beforeMount: function (force, deep, lifeHook, predicate) { var self = this; if (!force && (this._isMounted || !this.isVisible() || this.__asking === true || !(this._isRoot === true || (this._parent && this._parent._isMounted === true)))) { return false; } lifeHook !== false && callLifeHook(this, "beforeMount"); this._isMounted = true; - this._mountChildren && this._mountChildren(); BI.each(this._children, function (i, widget) { !self.isEnabled() && widget._setEnable(false); !self.isValid() && widget._setValid(false); - widget._mount && widget._mount(deep ? force : false, deep, lifeHook, predicate); + widget.__beforeMount && widget.__beforeMount(deep ? force : false, deep, lifeHook, predicate); + }); + this._mountChildren && this._mountChildren(); + return true; + }, + + __afterMount: function (lifeHook, predicate) { + BI.each(this._children, function (i, widget) { + widget.__afterMount && widget.__afterMount(lifeHook, predicate); }); lifeHook !== false && callLifeHook(this, "mounted"); this.fireEvent(BI.Events.MOUNT); predicate && predicate(this); - return true; }, _mountChildren: null, + _update: function (nextProps, shouldUpdate) { + var o = this.options; + callLifeHook(this, "beforeUpdate"); + if (shouldUpdate) { + var res = this.update && this.update(nextProps, shouldUpdate); + } else if (BI.isNull(shouldUpdate)) { + // 默认使用shallowCompare的方式进行更新 + var nextChange = {}; + BI.each(nextProps, function (key, value) { + if (o[key] !== value) { + nextChange[key] = value; + } + }); + var res = this.update && BI.isNotEmptyObject(nextChange) && this.update(nextChange); + } + callLifeHook(this, "updated"); + return res; + }, + isMounted: function () { return this._isMounted; }, @@ -534,12 +571,12 @@ BI.Widget.context = context = contextStack.pop(); }; - function pushTarget(_current) { + function pushTarget (_current) { if (current) currentStack.push(current); BI.Widget.current = current = _current; } - function popTarget() { + function popTarget () { BI.Widget.current = current = currentStack.pop(); } diff --git a/src/core/wrapper/layout.js b/src/core/wrapper/layout.js index 5d4fdc470..6b10e753d 100644 --- a/src/core/wrapper/layout.js +++ b/src/core/wrapper/layout.js @@ -268,19 +268,13 @@ BI.Layout = BI.inherit(BI.Widget, { if (!child.shouldUpdate) { return null; } - return child.shouldUpdate(this._getOptions(item)) === true; + return child.shouldUpdate(this._getOptions(item)); }, updateItemAt: function (index, item) { if (index < 0 || index > this.options.items.length - 1) { return; } - - var child = this._children[this._getChildName(index)]; - var updated; - if (updated = child.update(this._getOptions(item))) { - return updated; - } var del = this._children[this._getChildName(index)]; delete this._children[this._getChildName(index)]; this.options.items.splice(index, 1); @@ -367,7 +361,14 @@ BI.Layout = BI.inherit(BI.Widget, { patchItem: function (oldVnode, vnode, index) { var shouldUpdate = this.shouldUpdateItem(index, vnode); - if (shouldUpdate === true || (shouldUpdate === null && !this._compare(oldVnode, vnode))) { + var child = this._children[this._getChildName(index)]; + if (shouldUpdate) { + return child._update(this._getOptions(vnode), shouldUpdate); + } + if (shouldUpdate === null && !this._compare(oldVnode, vnode)) { + if (child.update) { + return child.update(this._getOptions(vnode)); + } return this.updateItemAt(index, vnode); } },