UNPKG

wx-mini-weview

Version:

weixin UI

287 lines (242 loc) 10 kB
/** * @author Myron * @copyright 2025 Myron */ const WvComponentHandler = (options = {}) => { const handleMethods = options.handleMethods || {}; const properties = {}; // Parse through event types (tap, longpress, etc.) Object.keys(handleMethods).forEach(eventName => { const eventMethodsConfig = handleMethods[eventName]; // Handle different configuration formats let methodConfigs = {}; if (Array.isArray(eventMethodsConfig)) { // Legacy array format: ['show', 'hide'] eventMethodsConfig.forEach(methodName => { methodConfigs[methodName] = {}; // Empty config means no default parameters }); } else { // New object format: { show: {}, hide: {}, xxx: { defaultParam1 } } methodConfigs = eventMethodsConfig; } // Process each method Object.keys(methodConfigs).forEach(methodName => { const defaultParams = methodConfigs[methodName]; const propertyName = `handler${methodName.charAt(0).toUpperCase() + methodName.slice(1)}`; const eventPropertyName = `${propertyName}Event`; const paramsPropertyName = `${propertyName}Params`; properties.handlerSelectAllComponents = { value: null, }; // Handler selector property properties[propertyName] = { type: String, value: '', observer: function(newHandler, oldHandler) { if (newHandler !== oldHandler) { const currentEventName = this.data[eventPropertyName] || eventName; this._bindHandlerToEvent(currentEventName, methodName, newHandler); } } }; // Handler event property (allows changing the event type) properties[eventPropertyName] = { type: String, value: eventName, // Default to the original event type observer: function(newEventName, oldEventName) { if (newEventName !== oldEventName) { const selector = this.data[propertyName]; if (selector) { // First remove old event bindings this._removeHandlerForMethod(methodName); // Then bind with new event name this._bindHandlerToEvent(newEventName, methodName, selector); } } } }; // Handler parameters property - only accept arrays for predictable behavior properties[paramsPropertyName] = { type: Array, value: Array.isArray(defaultParams) ? defaultParams : [] // Only use array default params }; }); }); return Behavior({ properties: properties, data: { currentPage: null, _boundHandlers: {}, // 存储已绑定的处理器信息 }, lifetimes: { attached() { this._initAllHandlers(); }, detached() { this._removeAllEventHandlers(); this.data.currentPage = null; } }, methods: { /** * 初始化所有事件处理器,如果页面不可用则重试 * @private * @param {Number} retryCount - 当前重试次数 * @param {Number} maxRetries - 最大重试次数 * @param {Number} retryDelay - 重试延迟时间(毫秒) */ _initAllHandlers(retryCount = 0, maxRetries = 10, retryDelay = 300) { const page = this.getCurrentPage(); if (!page) { if (retryCount >= maxRetries) { console.warn('Failed to initialize handlers: maximum retry count reached'); return; } // 延迟重试 setTimeout(() => { this._initAllHandlers(retryCount + 1, maxRetries, retryDelay); }, retryDelay); return; } // 初始化所有处理器 Object.keys(handleMethods).forEach(eventName => { const eventMethodsConfig = handleMethods[eventName]; // Handle different configuration formats let methodConfigs = {}; if (Array.isArray(eventMethodsConfig)) { // Legacy array format: ['show', 'hide'] eventMethodsConfig.forEach(methodName => { methodConfigs[methodName] = {}; // Empty config means no default parameters }); } else { // New object format: { show: {}, hide: {}, xxx: { defaultParam1 } } methodConfigs = eventMethodsConfig; } // Process each method Object.keys(methodConfigs).forEach(methodName => { const propertyName = `handler${methodName.charAt(0).toUpperCase() + methodName.slice(1)}`; const eventPropertyName = `${propertyName}Event`; const selector = this.data[propertyName]; if (selector) { // 使用当前配置的事件类型,默认为handleMethods中的事件 const currentEventName = this.data[eventPropertyName] || eventName; this._bindHandlerToEvent(currentEventName, methodName, selector); } }); }); }, /** * 将事件处理器绑定到指定事件 * @private * @param {String} eventName - 事件名称 * @param {String} methodName - 方法名称 * @param {String|Array} selector - 组件选择器或选择器数组 */ _bindHandlerToEvent(eventName, methodName, selector) { if (!selector) return; // 标准化选择器为数组 const selectors = Array.isArray(selector) ? selector : [selector]; let handlerSelectAllComponents = this.data.handlerSelectAllComponents; let handlerComponents = []; if(handlerSelectAllComponents){ selectors.forEach(sel => { const components = handlerSelectAllComponents(sel); if (components && components.length > 0) { handlerComponents = handlerComponents.concat(components); } }); }else{ const page = this.getCurrentPage(); if (!page) return; selectors.forEach(sel => { const components = page.selectAllComponents(sel); if (components && components.length > 0) { handlerComponents = handlerComponents.concat(components); } }); } if (!handlerComponents || handlerComponents.length === 0) return; // 先移除之前该方法绑定的处理器(如果存在) this._removeHandlerForMethod(methodName); // 为每个方法生成唯一的scope const scopeId = `WvHandler_${methodName}_${this.__wxExparserNodeId__}_${Date.now()}`; // 初始化绑定器存储结构 if (!this.data._boundHandlers[methodName]) { this.data._boundHandlers[methodName] = {}; } // 保存绑定信息 this.data._boundHandlers[methodName][eventName] = { components: handlerComponents, scope: scopeId }; // Get parameter property name const paramsPropertyName = `handler${methodName.charAt(0).toUpperCase() + methodName.slice(1)}Params`; handlerComponents.forEach(handlerComponent => { const eventHandler = (e) => { if (this[methodName]) { const params = this.data[paramsPropertyName] || []; // Only support arrays for parameters to ensure predictable behavior if (Array.isArray(params)) { this[methodName](...params); } else { console.warn(`Method parameters for "${methodName}" should be an array, received: ${typeof params}`); this[methodName](); // Call without parameters as fallback } } else { console.warn(`Method ${methodName} not found on component`); } }; handlerComponent.on(eventName, eventHandler, scopeId); }); }, /** * 移除指定方法的处理器 * @private * @param {String} methodName - 方法名称 */ _removeHandlerForMethod(methodName) { const handlerInfo = this.data._boundHandlers[methodName]; if (!handlerInfo) return; // 移除所有为该方法绑定的事件(可能有多个事件类型) Object.keys(handlerInfo).forEach(boundEventName => { const { components, scope } = handlerInfo[boundEventName]; if (components && components.length > 0) { components.forEach(component => { if (component && typeof component.off === 'function') { component.off(boundEventName, scope); } }); } }); // 清除绑定信息 delete this.data._boundHandlers[methodName]; }, /** * 移除所有事件处理器 * @private */ _removeAllEventHandlers() { if (!this.data._boundHandlers) return; Object.keys(this.data._boundHandlers).forEach(methodName => { this._removeHandlerForMethod(methodName); }); // 重置处理器存储 this.data._boundHandlers = {}; }, /** * 获取当前页面 * @return {Object} 当前页面实例 */ getCurrentPage() { if (!this.data.currentPage) { const pages = getCurrentPages(); this.data.currentPage = pages[pages.length - 1]; } return this.data.currentPage; } } }); }; module.exports = { WvComponentHandler };