UNPKG

wx-mini-weview

Version:

weixin UI

303 lines (259 loc) 10.1 kB
function capitalize(str) { return str.charAt(0).toUpperCase() + str.slice(1) } /** * 生成支持父子组件传值优先级管理的行为 * @param {Object} config - 配置对象 * @param {Object} config.properties - 可继承的属性定义 * @param {Object} config.childrenProperties - 下发给子组件的属性,格式为 {relationName: {propName: {type, value}}} * @param {Object} config.childrenPropsObjPrefix - 设置子组件属性前缀,格式为 {relationName: prefix},空字符串表示无前缀 */ const WvInheritable = (config) => { const propsObj = config.properties || {} const childrenPropsObj = config.childrenProperties || {} const childrenPropsObjPrefix = config.childrenPropsObjPrefix || {} const data = { wvInheritableApply: {}, _wvInheritableParentNodes: {}, // 存储父组件引用 _wvInheritableChildNodes: {} // 存储子组件引用 } const properties = {} const observers = {} const childrenObservers = {} const lifetimesAttached = [] // 处理自身的可继承属性 Object.keys(propsObj).forEach(key => { const propConfig = propsObj[key] const type = propConfig.type || null const defaultValue = propConfig.value const capKey = capitalize(key) // 保存原始的observer函数(如果存在) const originalObserver = propConfig.observer // 使用更明确的前缏来避免命名冲突 const hasUserKey = `_wvInheritable_hasUserProp_${key}` const defaultKey = `wvInheritableDefault${capKey}` const inheritedKey = `wvInheritableInherited${capKey}` const applyKey = `wvInheritableApply.${key}` properties[key] = { type, value: 'INHERITED_PROPS_NULL', observer(val, oldVal) { this.setData({ [hasUserKey]: true }) // 调用原始observer(如果存在) if (typeof originalObserver === 'function') { originalObserver.call(this, val, oldVal) } else if (typeof originalObserver === 'string' && typeof this[originalObserver] === 'function') { this[originalObserver](val, oldVal) } } } // 数据字段 data[hasUserKey] = false data[defaultKey] = defaultValue data[inheritedKey] = undefined data[applyKey] = defaultValue // 初始化代码 lifetimesAttached.push(function() { const final = this.data[hasUserKey] ? this.data[key] !== 'INHERITED_PROPS_NULL' ? this.data[key] : this.data[defaultKey] : this.data[inheritedKey] !== undefined ? this.data[inheritedKey] : this.data[defaultKey] this.setData({ [applyKey]: final }) }) // 观察者 observers[`${key},${inheritedKey},${hasUserKey}`] = function () { const final = this.data[hasUserKey] ? this.data[key] !== 'INHERITED_PROPS_NULL' ? this.data[key] : this.data[defaultKey] : this.data[inheritedKey] !== undefined ? this.data[inheritedKey] : this.data[defaultKey] this.setData({ [applyKey]: final }) } }) // 处理子组件属性传递 Object.keys(childrenPropsObj).forEach(relationName => { const relationProps = childrenPropsObj[relationName] || {} // 获取该关系的前缀配置,优先使用 childrenPropsObjPrefix 中的配置 // 如果 childrenPropsObjPrefix[relationName] 存在(包括空字符串),则使用它 // 否则使用 relationName 作为前缀 const prefix = childrenPropsObjPrefix.hasOwnProperty(relationName) ? childrenPropsObjPrefix[relationName] : relationName // 为每个子组件关系创建属性 Object.keys(relationProps).forEach(propName => { const propConfig = relationProps[propName] const type = propConfig.type || null const defaultValue = propConfig.value // 创建带前缀的属性名,根据是否有前缀来处理大小写 let prefixedPropName if (!prefix) { prefixedPropName = propName } else { prefixedPropName = `${prefix}${capitalize(propName)}` } // 添加到properties properties[prefixedPropName] = { type, value: defaultValue } // 添加观察者,当属性变化时,传递给子组件 const observerKey = `${prefixedPropName}` childrenObservers[observerKey] = function(newVal) { // 获取子组件并设置属性 this._updateChildrenProp(relationName, propName, newVal) } }) }) // 合并所有观察者 const allObservers = { ...observers, ...childrenObservers } return Behavior({ properties, data, observers: allObservers, lifetimes: { attached() { lifetimesAttached.forEach(fn => fn.call(this)) } }, methods: { /** * 设置被继承的字段 * @param {object} inheritedProps - 例如 { status: 'x', color: 'y' } */ setInheritedProps(inheritedProps) { const update = {} Object.keys(inheritedProps).forEach(k => { const inheritedKey = `wvInheritableInherited${capitalize(k)}` update[inheritedKey] = inheritedProps[k] }) this.setData(update) }, /** * 更新子组件的属性 * @param {string} relationName - 关系名称 * @param {string} propName - 属性名称 * @param {any} value - 属性值 */ _updateChildrenProp(relationName, propName, value) { const children = this.getChildrenNodes(relationName) || [] children.forEach(child => { if (child && typeof child.setInheritedProps === 'function') { const props = {} props[propName] = value child.setInheritedProps(props) } }) }, linkParentNode(relationName, parent) { this.data._wvInheritableParentNodes[relationName] = parent }, unlinkParentNode(relationName) { delete this.data._wvInheritableParentNodes[relationName] }, linkChildNode(relationName, child) { if(!this.data._wvInheritableChildNodes[relationName]) { this.data._wvInheritableChildNodes[relationName] = [] } this.data._wvInheritableChildNodes[relationName].push(child) // 当新子节点加入时,立即设置所有该关系的属性 this._syncAllPropsToChild(relationName, child) }, unlinkChildNode(relationName, child) { const childNodes = this.data._wvInheritableChildNodes[relationName] || [] const index = childNodes.indexOf(child) if (index > -1) { childNodes.splice(index, 1) } }, getParentNode(relationName) { return this.data._wvInheritableParentNodes[relationName] }, getChildrenNodes(relationName) { return this.data._wvInheritableChildNodes[relationName] || [] }, queryChildNodeByAttrs(relationName, attrs) { const children = this.getChildrenNodes(relationName) return children.filter(child => { return Object.keys(attrs).every(attr => { // 支持多级嵌套的属性路径 const attrValue = this._getNestedProperty(child.data, attr); return attrValue === attrs[attr]; }); }); }, queryNodeByAttrs(selector, attrs) { const nodes = this.selectAllComponents(selector); return nodes.find(node => { return Object.keys(attrs).every(attr => { const attrValue = this._getNestedProperty(node, attr); return attrValue === attrs[attr]; }); }); }, /** * 将所有当前子组件关系的属性同步到一个新子组件 * @param {string} relationName - 关系名称 * @param {Object} child - 子组件引用 */ _syncAllPropsToChild(relationName, child) { if (!child || !relationName || !config.childrenProperties || !config.childrenProperties[relationName]) { return } const relationProps = config.childrenProperties[relationName] const prefix = childrenPropsObjPrefix.hasOwnProperty(relationName) ? childrenPropsObjPrefix[relationName] : relationName const propsToSync = {} Object.keys(relationProps).forEach(propName => { let prefixedPropName if (!prefix) { // 处理所有falsy值('', null, undefined等) prefixedPropName = propName } else { prefixedPropName = `${prefix}${capitalize(propName)}` } if (this.data[prefixedPropName] !== undefined) { propsToSync[propName] = this.data[prefixedPropName] } }) // 只有当有属性需要设置时才调用setInheritedProps if (Object.keys(propsToSync).length > 0 && typeof child.setInheritedProps === 'function') { child.setInheritedProps(propsToSync) } }, /** * 获取对象的嵌套属性值 * @param {Object} obj - 要获取属性的对象 * @param {String} path - 属性路径,例如:"prop1.prop2.prop3" * @return {any} 属性值,如果路径不存在则返回undefined */ _getNestedProperty(obj, path) { // 如果obj为null或undefined,直接返回undefined if (obj == null) { return undefined; } // 分割路径字符串 const pathArray = path.split('.'); // 遍历路径数组 let result = obj; for (let i = 0; i < pathArray.length; i++) { result = result[pathArray[i]]; // 如果当前路径不存在,返回undefined if (result === undefined) { return undefined; } } return result; }, } }) } module.exports = { WvInheritable };