|
|
|
import { isFunction, isArray, isObject, isArguments, reduce, bind } from "./2.base";
|
|
|
|
|
|
|
|
function obExtend() {
|
|
|
|
const target = arguments[0] || {}, length = arguments.length;
|
|
|
|
let i = 1, name, copy;
|
|
|
|
for (; i < length; i++) {
|
|
|
|
// Only deal with non-null/undefined values
|
|
|
|
const options = arguments[i];
|
|
|
|
if (options !== null) {
|
|
|
|
// Extend the base object
|
|
|
|
for (name in options) {
|
|
|
|
copy = options[name];
|
|
|
|
|
|
|
|
// Prevent never-ending loop
|
|
|
|
if (target === copy) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (copy !== undefined) {
|
|
|
|
target[name] = copy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return target;
|
|
|
|
}
|
|
|
|
|
|
|
|
export class OB {
|
|
|
|
// props = {};
|
|
|
|
|
|
|
|
// init = null;
|
|
|
|
|
|
|
|
// destroyed = null;
|
|
|
|
|
|
|
|
constructor(config) {
|
|
|
|
this._constructor(config);
|
|
|
|
}
|
|
|
|
|
|
|
|
_constructor(config) {
|
|
|
|
this._initProps(config);
|
|
|
|
this._init();
|
|
|
|
this._initRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
_defaultConfig(config) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
_initProps(config) {
|
|
|
|
let props = this.props;
|
|
|
|
if (isFunction(this.props)) {
|
|
|
|
props = this.props(config);
|
|
|
|
}
|
|
|
|
const defaultProps = obExtend(this._defaultConfig(config), props);
|
|
|
|
const modifiedDefaultProps = (config && config.type && OB.configFunctions[`${config.type}.props`]) ? reduce(OB.configFunctions[`${config.type}.props`], (value, conf, index) => obExtend(conf, value.fn(defaultProps, config, value.opt)), {}) : null;
|
|
|
|
this.options = obExtend(defaultProps, modifiedDefaultProps, config);
|
|
|
|
}
|
|
|
|
|
|
|
|
_init() {
|
|
|
|
this._initListeners();
|
|
|
|
this.init && this.init();
|
|
|
|
}
|
|
|
|
|
|
|
|
_initListeners() {
|
|
|
|
if (this.options.listeners !== null) {
|
|
|
|
BI._.each(this.options.listeners, (lis, eventName) => {
|
|
|
|
if (isFunction(lis)) {
|
|
|
|
this.on(eventName, lis);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (isArray(lis)) {
|
|
|
|
BI._.each(lis, l => {
|
|
|
|
this.on(eventName, l);
|
|
|
|
});
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
(lis.target ? lis.target : this)[lis.once ? "once" : "on"](lis.eventName, bind(lis.action, this));
|
|
|
|
});
|
|
|
|
delete this.options.listeners;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 获得一个当前对象的引用
|
|
|
|
_initRef() {
|
|
|
|
const o = this.options;
|
|
|
|
if (o.__ref) {
|
|
|
|
isFunction(o.__ref) ? o.__ref.call(this, this) : o.__ref.current = this;
|
|
|
|
}
|
|
|
|
if (o.ref) {
|
|
|
|
isFunction(o.ref) ? o.ref.call(this, this) : o.ref.current = this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 释放当前对象
|
|
|
|
_purgeRef() {
|
|
|
|
const o = this.options;
|
|
|
|
if (o.__ref) {
|
|
|
|
isFunction(o.__ref) ? o.__ref.call(null, null) : o.__ref.current = null;
|
|
|
|
o.__ref = null;
|
|
|
|
}
|
|
|
|
if (o.ref) {
|
|
|
|
isFunction(o.ref) ? o.ref.call(null, null) : o.ref.current = null;
|
|
|
|
o.ref = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_getEvents() {
|
|
|
|
if (!isObject(this.events)) {
|
|
|
|
this.events = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.events;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 给观察者绑定一个事件
|
|
|
|
* @param {String} eventName 事件的名字
|
|
|
|
* @param {Function} fn 事件对应的执行函数
|
|
|
|
*/
|
|
|
|
on(eventName, fn) {
|
|
|
|
eventName = eventName.toLowerCase();
|
|
|
|
let fns = this._getEvents()[eventName];
|
|
|
|
if (!isArray(fns)) {
|
|
|
|
fns = [];
|
|
|
|
this._getEvents()[eventName] = fns;
|
|
|
|
}
|
|
|
|
fns.push(fn);
|
|
|
|
|
|
|
|
return () => this.un(eventName, fn);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 给观察者绑定一个只执行一次的事件
|
|
|
|
* @param {String} eventName 事件的名字
|
|
|
|
* @param {Function} fn 事件对应的执行函数
|
|
|
|
*/
|
|
|
|
once(eventName, fn) {
|
|
|
|
const proxy = () => {
|
|
|
|
fn.apply(this, arguments);
|
|
|
|
this.un(eventName, proxy);
|
|
|
|
};
|
|
|
|
this.on(eventName, proxy);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 解除观察者绑定的指定事件
|
|
|
|
* @param {String} eventName 要解除绑定事件的名字
|
|
|
|
* @param {Function} fn 事件对应的执行函数,该参数是可选的,没有该参数时,将解除绑定所有同名字的事件
|
|
|
|
*/
|
|
|
|
un(eventName, fn) {
|
|
|
|
eventName = eventName.toLowerCase();
|
|
|
|
|
|
|
|
/* alex:如果fn是null,就是把eventName上面所有方法都un掉*/
|
|
|
|
if (fn === null) {
|
|
|
|
delete this._getEvents()[eventName];
|
|
|
|
} else {
|
|
|
|
const fns = this._getEvents()[eventName];
|
|
|
|
if (isArray(fns)) {
|
|
|
|
const newFns = [];
|
|
|
|
BI._.each(fns, ifn => {
|
|
|
|
if (ifn !== fn) {
|
|
|
|
newFns.push(ifn);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
this._getEvents()[eventName] = newFns;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 清除观察者的所有事件绑定
|
|
|
|
*/
|
|
|
|
purgeListeners() {
|
|
|
|
/* alex:清空events*/
|
|
|
|
this.events = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 触发绑定过的事件
|
|
|
|
*
|
|
|
|
* @param {String} eventName 要触发的事件的名字
|
|
|
|
* @returns {Boolean} 如果事件函数返回false,则返回false并中断其他同名事件的执行,否则执行所有的同名事件并返回true
|
|
|
|
*/
|
|
|
|
fireEvent() {
|
|
|
|
const eventName = arguments[0].toLowerCase();
|
|
|
|
const fns = this._getEvents()[eventName];
|
|
|
|
if (isArray(fns)) {
|
|
|
|
if (isArguments(arguments[1])) {
|
|
|
|
for (let i = 0; i < fns.length; i++) {
|
|
|
|
if (fns[i].apply(this, arguments[1]) === false) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
const args = Array.prototype.slice.call(arguments, 1);
|
|
|
|
for (let i = 0; i < fns.length; i++) {
|
|
|
|
if (fns[i].apply(this, args) === false) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
destroy() {
|
|
|
|
this.destroyed && this.destroyed();
|
|
|
|
this._purgeRef();
|
|
|
|
this.purgeListeners();
|
|
|
|
}
|
|
|
|
}
|