|
|
|
/**
|
|
|
|
* Widget超类
|
|
|
|
* @class Widget
|
|
|
|
* @extends OB
|
|
|
|
*
|
|
|
|
* @cfg {JSON} options 配置属性
|
|
|
|
*/
|
|
|
|
|
|
|
|
import { isFunction, isArray, each, extend, isPlainObject, isNull, uniqueId, isWidget, isWidthOrHeight, isKey, remove, any, isNotNull } from "./2.base";
|
|
|
|
import { OB } from "./3.ob";
|
|
|
|
import { Providers, _lazyCreateWidget } from "./5.inject";
|
|
|
|
|
|
|
|
const cancelAnimationFrame =
|
|
|
|
_global.cancelAnimationFrame ||
|
|
|
|
_global.webkitCancelAnimationFrame ||
|
|
|
|
_global.mozCancelAnimationFrame ||
|
|
|
|
_global.oCancelAnimationFrame ||
|
|
|
|
_global.msCancelAnimationFrame ||
|
|
|
|
_global.clearTimeout;
|
|
|
|
|
|
|
|
const requestAnimationFrame = _global.requestAnimationFrame || _global.webkitRequestAnimationFrame || _global.mozRequestAnimationFrame || _global.oRequestAnimationFrame || _global.msRequestAnimationFrame || _global.setTimeout;
|
|
|
|
|
|
|
|
function callLifeHook(self, life) {
|
|
|
|
let hooks = [], hook;
|
|
|
|
hook = self[life];
|
|
|
|
if (hook) {
|
|
|
|
hooks = hooks.concat(isArray(hook) ? hook : [hook]);
|
|
|
|
}
|
|
|
|
hook = self.options[life];
|
|
|
|
if (hook) {
|
|
|
|
hooks = hooks.concat(isArray(hook) ? hook : [hook]);
|
|
|
|
}
|
|
|
|
each(hooks, (i, hook) => {
|
|
|
|
hook.call(self);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
export class Widget extends OB {
|
|
|
|
_defaultConfig () {
|
|
|
|
return extend(super._defaultConfig(), {
|
|
|
|
root: false,
|
|
|
|
tagName: "div",
|
|
|
|
attributes: null,
|
|
|
|
data: null,
|
|
|
|
key: null,
|
|
|
|
|
|
|
|
tag: null,
|
|
|
|
disabled: false,
|
|
|
|
invisible: false,
|
|
|
|
animation: "",
|
|
|
|
animationDuring: 0,
|
|
|
|
invalid: false,
|
|
|
|
baseCls: "",
|
|
|
|
extraCls: "",
|
|
|
|
cls: "",
|
|
|
|
css: null,
|
|
|
|
|
|
|
|
// vdom: false
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
_constructor () {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// 覆盖父类的_constructor方法,widget不走ob的生命周期
|
|
|
|
_constructed () {
|
|
|
|
if (this.setup) {
|
|
|
|
pushTarget(this);
|
|
|
|
const delegate = this.setup(this.options);
|
|
|
|
if (isPlainObject(delegate)) {
|
|
|
|
// 如果setup返回一个json,即对外暴露的方法
|
|
|
|
extend(this, delegate);
|
|
|
|
} else {
|
|
|
|
this.render = delegate;
|
|
|
|
}
|
|
|
|
popTarget();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_lazyConstructor () {
|
|
|
|
if (!this.__constructed) {
|
|
|
|
this.__constructed = true;
|
|
|
|
this._init();
|
|
|
|
this._initRef();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// // 生命周期函数
|
|
|
|
// beforeInit = null;
|
|
|
|
|
|
|
|
// beforeRender = null;
|
|
|
|
|
|
|
|
// beforeCreate = null
|
|
|
|
|
|
|
|
// created = null
|
|
|
|
|
|
|
|
// render = null
|
|
|
|
|
|
|
|
// beforeMount = null
|
|
|
|
|
|
|
|
// mounted = null
|
|
|
|
// // 不想重写mounted时用
|
|
|
|
// _mounted = null
|
|
|
|
|
|
|
|
// shouldUpdate = null
|
|
|
|
|
|
|
|
// update = null
|
|
|
|
|
|
|
|
// beforeUpdate = null
|
|
|
|
|
|
|
|
// updated = null
|
|
|
|
|
|
|
|
// beforeDestroy = null
|
|
|
|
|
|
|
|
// destroyed = null
|
|
|
|
// // 不想重写destroyed时用
|
|
|
|
// _destroyed = null
|
|
|
|
|
|
|
|
_init() {
|
|
|
|
super._init(...arguments);
|
|
|
|
this._initVisual();
|
|
|
|
this._initState();
|
|
|
|
this._initRender();
|
|
|
|
}
|
|
|
|
|
|
|
|
_initRender() {
|
|
|
|
let initCallbackCalled = false;
|
|
|
|
let renderCallbackCalled = false;
|
|
|
|
|
|
|
|
const init = () => {
|
|
|
|
// 加个保险
|
|
|
|
if (initCallbackCalled === true) {
|
|
|
|
_global.console && console.error("组件: 请检查beforeInit内部的写法,callback只能执行一次");
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
initCallbackCalled = true;
|
|
|
|
|
|
|
|
const render = () => {
|
|
|
|
// 加个保险
|
|
|
|
if (renderCallbackCalled === true) {
|
|
|
|
_global.console && console.error("组件: 请检查beforeRender内部的写法,callback只能执行一次");
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
renderCallbackCalled = true;
|
|
|
|
this._render();
|
|
|
|
this.__afterRender();
|
|
|
|
};
|
|
|
|
|
|
|
|
if (this.options.beforeRender || this.beforeRender) {
|
|
|
|
this.__async = true;
|
|
|
|
const beforeRenderResult = (this.options.beforeRender || this.beforeRender).call(this, render);
|
|
|
|
if (beforeRenderResult instanceof Promise) {
|
|
|
|
beforeRenderResult.then(render).catch(e => {
|
|
|
|
_global.console && console.error(e);
|
|
|
|
render();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
this._render();
|
|
|
|
this.__afterRender();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
if (this.options.beforeInit || this.beforeInit) {
|
|
|
|
this.__asking = true;
|
|
|
|
const beforeInitResult = (this.options.beforeInit || this.beforeInit).call(this, init);
|
|
|
|
if (beforeInitResult instanceof Promise) {
|
|
|
|
beforeInitResult.then(init).catch(e => {
|
|
|
|
_global.console && console.error(e);
|
|
|
|
init();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
__afterRender() {
|
|
|
|
pushTarget(this);
|
|
|
|
const async = this.__async;
|
|
|
|
this.__async = false;
|
|
|
|
if (async && this._isMounted) {
|
|
|
|
callLifeHook(this, "beforeMount");
|
|
|
|
this._mount();
|
|
|
|
callLifeHook(this, "mounted");
|
|
|
|
this.fireEvent(BI.Events.MOUNT);
|
|
|
|
} else {
|
|
|
|
this._mount();
|
|
|
|
}
|
|
|
|
popTarget();
|
|
|
|
}
|
|
|
|
|
|
|
|
_render() {
|
|
|
|
this.__asking = false;
|
|
|
|
pushTarget(this);
|
|
|
|
callLifeHook(this, "beforeCreate");
|
|
|
|
this._initElement();
|
|
|
|
this._initEffects();
|
|
|
|
callLifeHook(this, "created");
|
|
|
|
popTarget();
|
|
|
|
}
|
|
|
|
|
|
|
|
_initCurrent() {
|
|
|
|
const o = this.options;
|
|
|
|
this._initElementWidth();
|
|
|
|
this._initElementHeight();
|
|
|
|
if (o._baseCls || o.baseCls || o.extraCls) {
|
|
|
|
this.element.addClass(`${o._baseCls || ""} ${o.baseCls || ""} ${o.extraCls || ""}`);
|
|
|
|
}
|
|
|
|
if (o.cls) {
|
|
|
|
if (isFunction(o.cls)) {
|
|
|
|
let cls = this.__watch(o.cls, (context, newValue) => {
|
|
|
|
this.element.removeClass(cls).addClass(cls = newValue);
|
|
|
|
});
|
|
|
|
this.element.addClass(cls);
|
|
|
|
} else {
|
|
|
|
this.element.addClass(o.cls);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// if (o.key != null) {
|
|
|
|
// this.element.attr("key", o.key);
|
|
|
|
// }
|
|
|
|
if (o.attributes) {
|
|
|
|
this.element.attr(o.attributes);
|
|
|
|
}
|
|
|
|
if (o.data) {
|
|
|
|
this.element.data(o.data);
|
|
|
|
}
|
|
|
|
if (o.css) {
|
|
|
|
if (isFunction(o.css)) {
|
|
|
|
let css = this.__watch(o.css, (context, newValue) => {
|
|
|
|
for (const k in css) {
|
|
|
|
if (isNull(newValue[k])) {
|
|
|
|
newValue[k] = "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.element.css(css = newValue);
|
|
|
|
});
|
|
|
|
this.element.css(css);
|
|
|
|
} else {
|
|
|
|
this.element.css(o.css);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
__watch(getter, handler, options) {
|
|
|
|
if (_global.Fix) {
|
|
|
|
this._watchers = this._watchers || [];
|
|
|
|
const watcher = new Fix.Watcher(null, () => getter.call(this, this), (handler && (v => {
|
|
|
|
handler.call(this, this, v);
|
|
|
|
})) || BI.emptyFn, extend({ deep: true }, options));
|
|
|
|
this._watchers.push(() => {
|
|
|
|
watcher.teardown();
|
|
|
|
});
|
|
|
|
|
|
|
|
return watcher.value;
|
|
|
|
} else {
|
|
|
|
return getter();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 初始化根节点
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
_initRoot() {
|
|
|
|
const o = this.options;
|
|
|
|
this.widgetName = o.widgetName || uniqueId("widget");
|
|
|
|
this._isRoot = o.root;
|
|
|
|
this._children = {};
|
|
|
|
if (isWidget(o.element)) {
|
|
|
|
this.element = this.options.element.element;
|
|
|
|
this._parent = o.element;
|
|
|
|
this._parent._children && this._parent.addWidget(this.widgetName, this);
|
|
|
|
} else if (o.element) {
|
|
|
|
this.element = Widget._renderEngine.createElement(this);
|
|
|
|
this._isRoot = true;
|
|
|
|
} else {
|
|
|
|
this.element = Widget._renderEngine.createElement(this);
|
|
|
|
}
|
|
|
|
this.element._isWidget = true;
|
|
|
|
// const widgets = this.element.data("__widgets") || [];
|
|
|
|
// widgets.push(this);
|
|
|
|
// this.element.data("__widgets", widgets);
|
|
|
|
this._initCurrent();
|
|
|
|
}
|
|
|
|
|
|
|
|
_initElementWidth() {
|
|
|
|
const o = this.options;
|
|
|
|
if (isWidthOrHeight(o.width)) {
|
|
|
|
this.element.css("width", BI.pixFormat(o.width));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_initElementHeight() {
|
|
|
|
const o = this.options;
|
|
|
|
if (isWidthOrHeight(o.height)) {
|
|
|
|
this.element.css("height", BI.pixFormat(o.height));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_initVisual() {
|
|
|
|
const o = this.options;
|
|
|
|
if (o.invisible) {
|
|
|
|
const invisible = o.invisible = isFunction(o.invisible) ? this.__watch(o.invisible, (context, newValue) => {
|
|
|
|
this.setVisible(!newValue);
|
|
|
|
}) : o.invisible;
|
|
|
|
if (invisible) {
|
|
|
|
// 用display属性做显示和隐藏,否则jquery会在显示时将display设为block会覆盖掉display:flex属性
|
|
|
|
this.__setElementVisible(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_initEffects() {
|
|
|
|
const o = this.options;
|
|
|
|
if (o.disabled || o.invalid) {
|
|
|
|
if (this.options.disabled) {
|
|
|
|
const disabled = o.disabled = isFunction(o.disabled) ? this.__watch(o.disabled, (context, newValue) => {
|
|
|
|
this.setEnable(!newValue);
|
|
|
|
}) : o.disabled;
|
|
|
|
if (disabled) {
|
|
|
|
this.setEnable(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (this.options.invalid) {
|
|
|
|
const invalid = o.invalid = isFunction(o.invalid) ? this.__watch(o.invalid, (context, newValue) => {
|
|
|
|
this.setValid(!newValue);
|
|
|
|
}) : o.invalid;
|
|
|
|
if (invalid) {
|
|
|
|
this.setValid(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (o.effect) {
|
|
|
|
if (isArray(o.effect)) {
|
|
|
|
if (isArray(o.effect[0])) {
|
|
|
|
each(o.effect, (i, effect) => {
|
|
|
|
this.__watch(effect[0], effect[1]);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
this.__watch(o.effect[0], o.effect[1]);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
this.__watch(o.effect);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_initState() {
|
|
|
|
this._isMounted = false;
|
|
|
|
this._isDestroyed = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
__initWatch() {
|
|
|
|
// initWatch拦截的方法
|
|
|
|
}
|
|
|
|
|
|
|
|
_initElement() {
|
|
|
|
this.__isMounting = true;
|
|
|
|
// 当开启worker模式时,可以通过$render来实现另一种效果
|
|
|
|
const workerMode = Providers.getProvider("bi.provider.system").getWorkerMode();
|
|
|
|
const render = isFunction(this.options.render) ? this.options.render : (workerMode ? (this.$render || this.render) : this.render);
|
|
|
|
let els = render && render.call(this);
|
|
|
|
els = this.options.configRender ? this.options.configRender.call(this, els) : els;
|
|
|
|
els = BI.Plugin.getRender(this.options.type, els);
|
|
|
|
if (isPlainObject(els)) {
|
|
|
|
els = [els];
|
|
|
|
}
|
|
|
|
this.__initWatch();
|
|
|
|
if (isArray(els)) {
|
|
|
|
each(els, (i, el) => {
|
|
|
|
if (el) {
|
|
|
|
_lazyCreateWidget(el, {
|
|
|
|
element: this,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_setParent(parent) {
|
|
|
|
this._parent = parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param force 是否强制挂载子节点
|
|
|
|
* @param deep 子节点是否也是按照当前force处理
|
|
|
|
* @param lifeHook 生命周期钩子触不触发,默认触发
|
|
|
|
* @param predicate 递归每个widget的回调
|
|
|
|
* @param layer 组件层级
|
|
|
|
* @returns {boolean}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
_mount(force, deep, lifeHook, predicate, layer) {
|
|
|
|
if (!force && (this._isMounted || !this.isVisible() || this.__asking === true || !(this._isRoot === true || (this._parent && this._parent._isMounted === true)))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
layer = layer || 0;
|
|
|
|
lifeHook !== false && !this.__async && callLifeHook(this, "beforeMount");
|
|
|
|
this._isMounted = true;
|
|
|
|
this.__isMounting = false;
|
|
|
|
for (const key in this._children) {
|
|
|
|
const child = this._children[key];
|
|
|
|
child._mount && child._mount(deep ? force : false, deep, lifeHook, predicate, layer + 1);
|
|
|
|
}
|
|
|
|
if (this._parent) {
|
|
|
|
if (!this._parent.isEnabled()) {
|
|
|
|
this._setEnable(false);
|
|
|
|
}
|
|
|
|
if (!this._parent.isValid()) {
|
|
|
|
this._setValid(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this._mountChildren && this._mountChildren();
|
|
|
|
if (layer === 0) {
|
|
|
|
// mounted里面会执行scrollTo之类的方法,如果放宏任务里会闪
|
|
|
|
// setTimeout(function () {
|
|
|
|
this.__afterMount(lifeHook, predicate);
|
|
|
|
// }, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
__afterMount(lifeHook, predicate) {
|
|
|
|
if (this._isMounted) {
|
|
|
|
for (const key in this._children) {
|
|
|
|
const child = this._children[key];
|
|
|
|
child.__afterMount && child.__afterMount(lifeHook, predicate);
|
|
|
|
}
|
|
|
|
if (lifeHook !== false && !this.__async) {
|
|
|
|
callLifeHook(this, "_mounted");
|
|
|
|
callLifeHook(this, "mounted");
|
|
|
|
this.fireEvent(BI.Events.MOUNT);
|
|
|
|
}
|
|
|
|
predicate && predicate(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// _mountChildren = null;
|
|
|
|
|
|
|
|
_update(nextProps, shouldUpdate) {
|
|
|
|
callLifeHook(this, "beforeUpdate");
|
|
|
|
let res;
|
|
|
|
if (shouldUpdate) {
|
|
|
|
res = this.update && this.update(nextProps, shouldUpdate);
|
|
|
|
}
|
|
|
|
callLifeHook(this, "updated");
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
isMounted() {
|
|
|
|
return this._isMounted;
|
|
|
|
}
|
|
|
|
|
|
|
|
isDestroyed() {
|
|
|
|
return this._isDestroyed;
|
|
|
|
}
|
|
|
|
|
|
|
|
setWidth(w) {
|
|
|
|
this.options.width = w;
|
|
|
|
this._initElementWidth();
|
|
|
|
}
|
|
|
|
|
|
|
|
setHeight(h) {
|
|
|
|
this.options.height = h;
|
|
|
|
this._initElementHeight();
|
|
|
|
}
|
|
|
|
|
|
|
|
_setEnable(enable) {
|
|
|
|
if (enable === true) {
|
|
|
|
this.options._disabled = false;
|
|
|
|
} else if (enable === false) {
|
|
|
|
this.options._disabled = true;
|
|
|
|
}
|
|
|
|
// 递归将所有子组件使能
|
|
|
|
each(this._children, (i, child) => {
|
|
|
|
!child._manualSetEnable && child._setEnable && child._setEnable(enable);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
_setValid(valid) {
|
|
|
|
if (valid === true) {
|
|
|
|
this.options._invalid = false;
|
|
|
|
} else if (valid === false) {
|
|
|
|
this.options._invalid = true;
|
|
|
|
}
|
|
|
|
// 递归将所有子组件使有效
|
|
|
|
each(this._children, (i, child) => {
|
|
|
|
!child._manualSetValid && child._setValid && child._setValid(valid);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
_setVisible(visible) {
|
|
|
|
if (visible === true) {
|
|
|
|
this.options.invisible = false;
|
|
|
|
} else if (visible === false) {
|
|
|
|
this.options.invisible = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setEnable(enable) {
|
|
|
|
this._manualSetEnable = true;
|
|
|
|
this.options.disabled = !enable;
|
|
|
|
this._setEnable(enable);
|
|
|
|
if (enable === true) {
|
|
|
|
this.element.removeClass("base-disabled disabled");
|
|
|
|
} else if (enable === false) {
|
|
|
|
this.element.addClass("base-disabled disabled");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
__setElementVisible(visible) {
|
|
|
|
this.element.css("display", visible ? "" : "none");
|
|
|
|
}
|
|
|
|
|
|
|
|
_innerSetVisible(visible) {
|
|
|
|
const o = this.options;
|
|
|
|
const lastVisible = !o.invisible;
|
|
|
|
this._setVisible(visible);
|
|
|
|
if (visible === true) {
|
|
|
|
// 用this.element.show()会把display属性改成block
|
|
|
|
this.__setElementVisible(true);
|
|
|
|
this._mount();
|
|
|
|
if (o.animation && !lastVisible) {
|
|
|
|
this.element.removeClass(`${o.animation}-leave`).removeClass(`${o.animation}-leave-active`).addClass(`${o.animation}-enter`);
|
|
|
|
if (this._requestAnimationFrame) {
|
|
|
|
cancelAnimationFrame(this._requestAnimationFrame);
|
|
|
|
}
|
|
|
|
this._requestAnimationFrame = () => {
|
|
|
|
this.element.addClass(`${o.animation}-enter-active`);
|
|
|
|
};
|
|
|
|
requestAnimationFrame(this._requestAnimationFrame);
|
|
|
|
if (this._animationDuring) {
|
|
|
|
clearTimeout(this._animationDuring);
|
|
|
|
}
|
|
|
|
this._animationDuring = setTimeout(() => {
|
|
|
|
this.element.removeClass(`${o.animation}-enter`).removeClass(`${o.animation}-enter-active`);
|
|
|
|
}, o.animationDuring);
|
|
|
|
}
|
|
|
|
} else if (visible === false) {
|
|
|
|
if (o.animation && lastVisible) {
|
|
|
|
this.element.removeClass(`${o.animation}-enter`).removeClass(`${o.animation}-enter-active`).addClass(`${o.animation}-leave`);
|
|
|
|
if (this._requestAnimationFrame) {
|
|
|
|
cancelAnimationFrame(this._requestAnimationFrame);
|
|
|
|
}
|
|
|
|
this._requestAnimationFrame = () => {
|
|
|
|
this.element.addClass(`${o.animation}-leave-active`);
|
|
|
|
};
|
|
|
|
requestAnimationFrame(this._requestAnimationFrame);
|
|
|
|
if (this._animationDuring) {
|
|
|
|
clearTimeout(this._animationDuring);
|
|
|
|
}
|
|
|
|
this._animationDuring = setTimeout(() => {
|
|
|
|
this.element.removeClass(`${o.animation}-leave`).removeClass(`${o.animation}-leave-active`);
|
|
|
|
this.__setElementVisible(false);
|
|
|
|
}, o.animationDuring);
|
|
|
|
} else {
|
|
|
|
this.__setElementVisible(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setVisible(visible) {
|
|
|
|
this._innerSetVisible(visible);
|
|
|
|
this.fireEvent(BI.Events.VIEW, visible);
|
|
|
|
}
|
|
|
|
|
|
|
|
setValid(valid) {
|
|
|
|
this._manualSetValid = true;
|
|
|
|
this.options.invalid = !valid;
|
|
|
|
this._setValid(valid);
|
|
|
|
if (valid === true) {
|
|
|
|
this.element.removeClass("base-invalid invalid");
|
|
|
|
} else if (valid === false) {
|
|
|
|
this.element.addClass("base-invalid invalid");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
doBehavior() {
|
|
|
|
const args = arguments;
|
|
|
|
// 递归将所有子组件使有效
|
|
|
|
each(this._children, (i, child) => {
|
|
|
|
child.doBehavior && child.doBehavior(...args);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
getWidth() {
|
|
|
|
return this.options.width;
|
|
|
|
}
|
|
|
|
|
|
|
|
getHeight() {
|
|
|
|
return this.options.height;
|
|
|
|
}
|
|
|
|
|
|
|
|
addWidget(name, widget) {
|
|
|
|
const self = this;
|
|
|
|
if (name instanceof Widget) {
|
|
|
|
widget = name;
|
|
|
|
name = widget.getName();
|
|
|
|
}
|
|
|
|
if (isKey(name)) {
|
|
|
|
name = `${name}`;
|
|
|
|
}
|
|
|
|
name = name || widget.getName() || uniqueId("widget");
|
|
|
|
if (this._children[name]) {
|
|
|
|
throw new Error("组件:组件名已存在,不能进行添加");
|
|
|
|
}
|
|
|
|
widget._setParent && widget._setParent(this);
|
|
|
|
widget.on(BI.Events.DESTROY, function () {
|
|
|
|
// TODO: self待删
|
|
|
|
remove(self._children, this);
|
|
|
|
});
|
|
|
|
|
|
|
|
return (this._children[name] = widget);
|
|
|
|
}
|
|
|
|
|
|
|
|
getWidgetByName(name) {
|
|
|
|
if (!isKey(name) || name === this.getName()) {
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
name = `${name}`;
|
|
|
|
let widget = void 0;
|
|
|
|
const other = {};
|
|
|
|
any(this._children, (i, wi) => {
|
|
|
|
if (i === name) {
|
|
|
|
widget = wi;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
other[i] = wi;
|
|
|
|
});
|
|
|
|
if (!widget) {
|
|
|
|
any(other, (i, wi) => (widget = wi.getWidgetByName(i)));
|
|
|
|
}
|
|
|
|
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
|
|
|
removeWidget(nameOrWidget) {
|
|
|
|
if (isWidget(nameOrWidget)) {
|
|
|
|
remove(this._children, nameOrWidget);
|
|
|
|
} else {
|
|
|
|
delete this._children[nameOrWidget];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
hasWidget(name) {
|
|
|
|
return isNotNull(this._children[name]);
|
|
|
|
}
|
|
|
|
|
|
|
|
getName() {
|
|
|
|
return this.widgetName;
|
|
|
|
}
|
|
|
|
|
|
|
|
setTag(tag) {
|
|
|
|
this.options.tag = tag;
|
|
|
|
}
|
|
|
|
|
|
|
|
getTag() {
|
|
|
|
return this.options.tag;
|
|
|
|
}
|
|
|
|
|
|
|
|
attr(key, value) {
|
|
|
|
if (isPlainObject(key)) {
|
|
|
|
each(key, (k, v) => this.attr(k, v));
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (isNotNull(value)) {
|
|
|
|
this.options[key] = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.options[key];
|
|
|
|
}
|
|
|
|
|
|
|
|
css(name, value) {
|
|
|
|
return this.element.css(name, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
getText() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
setText(text) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
getValue() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
setValue(value) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
isEnabled() {
|
|
|
|
return this.options.disabled === true ? false : !this.options._disabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
isValid() {
|
|
|
|
return this.options.invalid === true ? false : !this.options._invalid;
|
|
|
|
}
|
|
|
|
|
|
|
|
isVisible() {
|
|
|
|
return !this.options.invisible;
|
|
|
|
}
|
|
|
|
|
|
|
|
disable() {
|
|
|
|
this.setEnable(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
enable() {
|
|
|
|
this.setEnable(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
valid() {
|
|
|
|
this.setValid(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
invalid() {
|
|
|
|
this.setValid(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
invisible() {
|
|
|
|
this.setVisible(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
visible() {
|
|
|
|
this.setVisible(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
__d() {
|
|
|
|
each(this._children, (i, widget) => {
|
|
|
|
widget && widget._unMount && widget._unMount();
|
|
|
|
});
|
|
|
|
this._children = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
// 主要是因为_destroy已经提供了protected方法
|
|
|
|
__destroy() {
|
|
|
|
callLifeHook(this, "beforeDestroy");
|
|
|
|
this.beforeDestroy = null;
|
|
|
|
this.__d();
|
|
|
|
this._parent = null;
|
|
|
|
this._isMounted = false;
|
|
|
|
callLifeHook(this, "_destroyed");
|
|
|
|
callLifeHook(this, "destroyed");
|
|
|
|
this.destroyed = null;
|
|
|
|
this._isDestroyed = true;
|
|
|
|
// this._purgeRef(); // 清除ref的时机还是要仔细考虑一下
|
|
|
|
}
|
|
|
|
|
|
|
|
_unMount() {
|
|
|
|
this._assetMounted();
|
|
|
|
this.__destroy();
|
|
|
|
this.fireEvent(BI.Events.UNMOUNT);
|
|
|
|
this.purgeListeners();
|
|
|
|
}
|
|
|
|
|
|
|
|
_assetMounted() {
|
|
|
|
if (!this.isVisible()) {
|
|
|
|
this._setVisible(true);
|
|
|
|
this._mount(false, false, false);
|
|
|
|
this._setVisible(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_empty () {
|
|
|
|
this._assetMounted();
|
|
|
|
each(this._children, (i, widget) => {
|
|
|
|
widget && widget._unMount && widget._unMount();
|
|
|
|
});
|
|
|
|
this._children = {};
|
|
|
|
this.element.empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
isolate () {
|
|
|
|
if (this._parent) {
|
|
|
|
this._parent.removeWidget(this);
|
|
|
|
}
|
|
|
|
BI.DOM.hang([this]);
|
|
|
|
}
|
|
|
|
|
|
|
|
empty () {
|
|
|
|
this._empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
// 默认的reset方法就是干掉重来
|
|
|
|
reset () {
|
|
|
|
// 还在异步状态的不需要执行reset
|
|
|
|
if (this.__async === true || this.__asking === true) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// if (this.options.vdom) {
|
|
|
|
// const vnode = this._renderVNode();
|
|
|
|
// BI.patchVNode(this.vnode, vnode);
|
|
|
|
// this.vnode = vnode;
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
// this._isMounted = false;
|
|
|
|
// this.purgeListeners();
|
|
|
|
|
|
|
|
// 去掉组件绑定的watcher
|
|
|
|
each(this._watchers, (i, unwatches) => {
|
|
|
|
unwatches = isArray(unwatches) ? unwatches : [unwatches];
|
|
|
|
each(unwatches, (j, unwatch) => {
|
|
|
|
unwatch();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
this._watchers && (this._watchers = []);
|
|
|
|
this._assetMounted();
|
|
|
|
this.__d();
|
|
|
|
this.element.empty();
|
|
|
|
this.element.unbind();
|
|
|
|
this._initCurrent();
|
|
|
|
this._init();
|
|
|
|
// this._initRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
_destroy() {
|
|
|
|
this._assetMounted();
|
|
|
|
this.__destroy();
|
|
|
|
this.element.destroy();
|
|
|
|
this.purgeListeners();
|
|
|
|
}
|
|
|
|
|
|
|
|
destroy() {
|
|
|
|
const o = this.options;
|
|
|
|
this._assetMounted();
|
|
|
|
this.__destroy();
|
|
|
|
if (o.animation) {
|
|
|
|
this._innerSetVisible(false);
|
|
|
|
setTimeout(() => this.element.destroy(), o.animationDuring);
|
|
|
|
} else {
|
|
|
|
this.element.destroy();
|
|
|
|
}
|
|
|
|
this.fireEvent(BI.Events.UNMOUNT);
|
|
|
|
this.fireEvent(BI.Events.DESTROY);
|
|
|
|
this._purgeRef();
|
|
|
|
this.purgeListeners();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let context = null, current = null;
|
|
|
|
const contextStack = [], currentStack = [];
|
|
|
|
|
|
|
|
Widget.pushContext = function (_context) {
|
|
|
|
if (context) contextStack.push(context);
|
|
|
|
Widget.context = context = _context;
|
|
|
|
};
|
|
|
|
|
|
|
|
Widget.popContext = function () {
|
|
|
|
Widget.context = context = contextStack.pop();
|
|
|
|
};
|
|
|
|
|
|
|
|
Widget.execWithContext = function (context, execFunc) {
|
|
|
|
Widget.pushContext(context);
|
|
|
|
try {
|
|
|
|
execFunc();
|
|
|
|
} catch (e) {
|
|
|
|
throw e;
|
|
|
|
} finally {
|
|
|
|
Widget.popContext();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
function pushTarget(_current) {
|
|
|
|
if (current) currentStack.push(current);
|
|
|
|
Widget.current = current = _current;
|
|
|
|
}
|
|
|
|
|
|
|
|
function popTarget() {
|
|
|
|
Widget.current = current = currentStack.pop();
|
|
|
|
}
|
|
|
|
|
|
|
|
export function useStore(_store) {
|
|
|
|
if (current && current.store) {
|
|
|
|
return current.store;
|
|
|
|
}
|
|
|
|
if (current && current.$storeDelegate) {
|
|
|
|
return current.$storeDelegate;
|
|
|
|
}
|
|
|
|
if (current) {
|
|
|
|
const currentStore = current._store;
|
|
|
|
const delegate = {};
|
|
|
|
let origin;
|
|
|
|
if (_global.Proxy) {
|
|
|
|
const proxy = new Proxy(delegate, {
|
|
|
|
get (target, key) {
|
|
|
|
return Reflect.get(origin, key);
|
|
|
|
},
|
|
|
|
set (target, key, value) {
|
|
|
|
return Reflect.set(origin, key, value);
|
|
|
|
},
|
|
|
|
});
|
|
|
|
current._store = function () {
|
|
|
|
origin = (_store || currentStore).apply(this, arguments);
|
|
|
|
delegate.$delegate = origin;
|
|
|
|
|
|
|
|
return origin;
|
|
|
|
};
|
|
|
|
current.$storeDelegate = proxy;
|
|
|
|
|
|
|
|
return current.$storeDelegate;
|
|
|
|
}
|
|
|
|
current._store = function () {
|
|
|
|
const st = (_store || currentStore).apply(this, arguments);
|
|
|
|
extend(delegate, st);
|
|
|
|
|
|
|
|
return st;
|
|
|
|
};
|
|
|
|
current.$storeDelegate = delegate;
|
|
|
|
|
|
|
|
return current.$storeDelegate;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function useContext(inject) {
|
|
|
|
// 通过组件找最近的store
|
|
|
|
let vm = Widget.findStore(Widget.current || Widget.context);
|
|
|
|
if (vm) {
|
|
|
|
if (inject) {
|
|
|
|
if (vm.$$computed && inject in vm.$$computed) {
|
|
|
|
return vm;
|
|
|
|
}
|
|
|
|
if (vm.$$state && inject in vm.$$state) {
|
|
|
|
return vm;
|
|
|
|
}
|
|
|
|
if (vm.$$model && inject in vm.$$model) {
|
|
|
|
return vm;
|
|
|
|
}
|
|
|
|
while (vm) {
|
|
|
|
if (vm.$$context && inject in vm.$$context) {
|
|
|
|
return vm;
|
|
|
|
}
|
|
|
|
vm = vm._parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return vm;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function watch(vm, watch, handler) {
|
|
|
|
// 必须要保证组件当前环境存在
|
|
|
|
if (Widget.current) {
|
|
|
|
if (vm instanceof BI.Model) {
|
|
|
|
const watchers = [];
|
|
|
|
if (isKey(watch)) {
|
|
|
|
const k = watch;
|
|
|
|
watch = {};
|
|
|
|
watch[k] = handler;
|
|
|
|
}
|
|
|
|
for (const key in watch) {
|
|
|
|
const innerHandler = watch[key];
|
|
|
|
if (isArray(handler)) {
|
|
|
|
for (let i = 0; i < handler.length; i++) {
|
|
|
|
watchers.push(Fix.watch(vm.model, key, innerHandler, {
|
|
|
|
store: vm,
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
watchers.push(Fix.watch(vm.model, key, innerHandler, {
|
|
|
|
store: vm,
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// vm中一定有_widget
|
|
|
|
Widget.current._watchers || (Widget.current._watchers = []);
|
|
|
|
Widget.current._watchers = Widget.current._watchers.concat(watchers);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
handler = watch;
|
|
|
|
watch = vm;
|
|
|
|
Widget.current.$watchDelayCallbacks || (Widget.current.$watchDelayCallbacks = []);
|
|
|
|
Widget.current.$watchDelayCallbacks.push([watch, handler]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function onBeforeMount(beforeMount) {
|
|
|
|
if (current) {
|
|
|
|
if (current.__isMounting) {
|
|
|
|
beforeMount();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!current.beforeMount) {
|
|
|
|
current.beforeMount = [];
|
|
|
|
} else if (!isArray(current.beforeMount)) {
|
|
|
|
current.beforeMount = [current.beforeMount];
|
|
|
|
}
|
|
|
|
current.beforeMount.push(beforeMount);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function onMounted(mounted) {
|
|
|
|
if (current) {
|
|
|
|
if (current._isMounted && !this.__async) {
|
|
|
|
mounted();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!current.mounted) {
|
|
|
|
current.mounted = [];
|
|
|
|
} else if (!isArray(current.mounted)) {
|
|
|
|
current.mounted = [current.mounted];
|
|
|
|
}
|
|
|
|
current.mounted.push(mounted);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function onBeforeUnmount(beforeDestroy) {
|
|
|
|
if (current) {
|
|
|
|
if (!current.beforeDestroy) {
|
|
|
|
current.beforeDestroy = [];
|
|
|
|
} else if (!isArray(current.beforeDestroy)) {
|
|
|
|
current.beforeDestroy = [current.beforeDestroy];
|
|
|
|
}
|
|
|
|
current.beforeDestroy.push(beforeDestroy);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function onUnmounted(destroyed) {
|
|
|
|
if (current) {
|
|
|
|
if (!current.destroyed) {
|
|
|
|
current.destroyed = [];
|
|
|
|
} else if (!isArray(current.destroyed)) {
|
|
|
|
current.destroyed = [current.destroyed];
|
|
|
|
}
|
|
|
|
current.destroyed.push(destroyed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget.registerRenderEngine = function (engine) {
|
|
|
|
Widget._renderEngine = engine;
|
|
|
|
};
|
|
|
|
Widget.registerRenderEngine({
|
|
|
|
createElement (widget) {
|
|
|
|
if (isWidget(widget)) {
|
|
|
|
const o = widget.options;
|
|
|
|
if (o.element) {
|
|
|
|
return BI.$(o.element);
|
|
|
|
}
|
|
|
|
if (o.tagName) {
|
|
|
|
return BI.$(document.createElement(o.tagName));
|
|
|
|
}
|
|
|
|
|
|
|
|
return BI.$(document.createDocumentFragment());
|
|
|
|
}
|
|
|
|
|
|
|
|
return BI.$(widget);
|
|
|
|
},
|
|
|
|
createFragment () {
|
|
|
|
return document.createDocumentFragment();
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
export function mount(widget, container, predicate, hydrate) {
|
|
|
|
if (hydrate === true) {
|
|
|
|
// 将widget的element元素都挂载好,并建立相互关系
|
|
|
|
widget.element.data("__widgets", [widget]);
|
|
|
|
const res = widget._mount(true, false, false, function (w) {
|
|
|
|
each(w._children, (i, child) => {
|
|
|
|
let ws = child.element.data("__widgets");
|
|
|
|
if (!ws) {
|
|
|
|
ws = [];
|
|
|
|
}
|
|
|
|
ws.push(child);
|
|
|
|
child.element.data("__widgets", ws);
|
|
|
|
});
|
|
|
|
predicate && predicate.apply(this, arguments);
|
|
|
|
});
|
|
|
|
// 将新的dom树属性(事件等)patch到已存在的dom上
|
|
|
|
const c = Widget._renderEngine.createElement;
|
|
|
|
BI.DOM.patchProps(widget.element, c(c(container).children()[0]));
|
|
|
|
|
|
|
|
const triggerLifeHook = w => {
|
|
|
|
w.beforeMount && w.beforeMount();
|
|
|
|
w.mounted && w.mounted();
|
|
|
|
each(w._children, (i, child) => {
|
|
|
|
triggerLifeHook(child);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
// 最后触发组件树生命周期函数
|
|
|
|
triggerLifeHook(widget);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
if (container) {
|
|
|
|
Widget._renderEngine.createElement(container).append(widget.element);
|
|
|
|
}
|
|
|
|
|
|
|
|
return widget._mount(true, false, false, predicate);
|
|
|
|
}
|