/**
* Created by ShawnZhang on 2017/9/8.
*/
const DEFAULT_EVENT_NAMES = [
'_onTouchStart',
'_onTouchMove',
'_onTouchEnd',
'_onTouchCancel',
];
const UIKiller = {
_prefix: '_',
_plugins: [],
registerPlugin(plugins) {
if (!Array.isArray(plugins)) {
plugins = [plugins];
}
plugins.forEach((plugin) => {
//插件能不重复
let findPlugin = this._plugins.find(item => item.name === plugin.name || item === plugin);
if (findPlugin) {
return;
}
//执行插件注册事件
this._plugins.push(plugin);
if (plugin.onRegister) {
plugin.onRegister();
}
});
},
/**
* 获取组件名字
* @param {cc.Component} component
*/
_getComponentName(component) {
return component.name.match(/<.*>$/)[0].slice(1, -1);
},
/**
* 绑定组件
* @param {cc.Component} component 要绑定的组件
* @param {Object} options 绑定选项
*/
bindComponent(component, options) {
component.$options = options || {};
let root = component.node;
root._components.forEach((nodeComponent) => {
let name = this._getComponentName(nodeComponent);
name = `$${name}`;
root[name] = nodeComponent;
});
//绑定根节点触摸事件
this._bindTouchEvent(root, component, DEFAULT_EVENT_NAMES);
//绑定所有组件子节点
this._bindNode(component.node, component);
},
/**
* 编写子节点到 target 对象
* @param node
* @param target
*/
bindNode(node, target, options) {
//初始选项
target.$options = options || {};
//检查属性收集器
if (target.$collector) {
//重复绑定,退出
if (target.$collector.node === node) {
return;
}
//更换绑定,删除之前绑定的节点
delete target.$collector.node;
//遍历收集器上的属性名,删除绑定属性
Object.keys(target.$collector).forEach((key) => {
delete target[key];
});
}
//初始化收集器
target.$collector = { node };
//遍历根节点上的组件并绑定到target
node._components.forEach((component) => {
let name = this._getComponentName(component);
name = `$${name}`;
target[name] = component;
target.$collector[name] = component;
});
//开始绑定节点
this._bindStartByPlugins(node, target);
this._bindNode(node, target);
this._bindEndByPlugins(node, target);
},
/**
* 执行插件onBindStart事件
* @param {cc.Node} node
* @param {Object} target
*/
_bindStartByPlugins(node, target) {
this._plugins.forEach((plugin) => {
if (plugin.onBindStart) {
plugin.onBindStart(node, target);
}
});
},
/**
* 执行插件onBindEnd事件
* @param {cc.Node} node
* @param {Object} target
*/
_bindEndByPlugins(node, target) {
this._plugins.forEach((plugin) => {
if (plugin.onBindEnd) {
plugin.onBindEnd(node, target);
}
});
},
/**
* 递归绑定节点
* @param {cc.Node} nodeObject
* @param {Object} target
*/
_bindNode(nodeObject, target) {
const node = nodeObject;
let isBindNode = false;
//绑定组件到自身node节点上
if (node.name[0] === this._prefix) {
node._components.forEach((component) => {
let name = this._getComponentName(component);
name = `$${name}`;
if (node[name] && target.$options.debug) {
cc.warn(`${name} property is already exists`);
return;
}
node[name] = component;
//检查组件 onBind 函数,通知组件,target 对象在绑定自己
if (UIKiller.isFunction(component.onBind)) {
component.onBind(target);
}
if (component instanceof Thor) {
//判定是否将要自行绑定的节点
if (!isBindNode && component !== target) {
isBindNode = true;
}
if (!node.active) {
component.bindHammer();
}
}
});
}
//执行插件
let bool = this._checkNodeByPlugins(node, target);
if (!bool || isBindNode) {
return;
}
node.children.forEach((child) => {
let name = child.name;
if (name[0] === this._prefix) {
let index = name.indexOf('$');
//检查控件别名
if (index !== -1) {
child.$eventName = name.substr(0, index);
child.$ = name.substr(index + 1);
name = child.$eventName + child.$[0].toUpperCase() + child.$.substr(1);
if (!CC_EDITOR) {
child.name = name;
}
}
if (target[name] && target.$options.debug) {
cc.warn(`${target.name}.${name} property is already exists`);
return;
}
this._bindTouchEvent(child, target);
target[name] = child;
//保存绑定的指针
if (target.$collector) {
target.$collector[name] = child;
}
} else if (!node[name]) {
//绑定非前缀子节点
node[name] = child;
}
this._bindNode(child, target);
});
},
/**
* 绑定触摸事件
* @param {cc.Node} node
* @param {String} event
*/
_getTouchEventName(node, event) {
let name = node.$eventName || node.name;
if (name) {
name = name[this._prefix.length].toUpperCase() + name.slice(this._prefix.length + 1);
}
if (event) {
return `_on${name}${event}`;
}
return [
`_on${name}TouchStart`,
`_on${name}TouchMove`,
`_on${name}TouchEnd`,
`_on${name}TouchCancel`,
];
},
/**
* 绑定事件
* @param {cc.Node} node
*/
_bindTouchEvent(node, target, defaultNames) {
//todo: EditBox 组件不能注册触摸事件,在原生上会导致不能被输入
if (node.getComponent(cc.EditBox)) {
return;
}
const eventNames = defaultNames || this._getTouchEventName(node);
const eventTypes = [
cc.Node.EventType.TOUCH_START,
cc.Node.EventType.TOUCH_MOVE,
cc.Node.EventType.TOUCH_END,
cc.Node.EventType.TOUCH_CANCEL,
];
eventNames.forEach((eventName, index) => {
const tempEvent = target[eventName];
if (!tempEvent && !node.getComponent(cc.Button)) {
return;
}
node.on(eventTypes[index], (event) => {
//被禁用的node 节点不响应事件
let eventNode = event.currentTarget;
if (eventNode.interactable === false || eventNode.active === false) {
return;
}
//检查button组件是否有事件处理函数,有则执行插件事件处理
const button = eventNode.getComponent(cc.Button);
if (button &&