UNPKG

@tarojs/components

Version:
104 lines (101 loc) 4.77 kB
import { camelToDashCase } from './case.js'; /** * Modify from https://github.com/ionic-team/stencil-ds-output-targets/blob/main/packages/react-output-target/react-component-lib/utils/attachProps.ts * MIT License https://github.com/ionic-team/stencil-ds-output-targets/blob/main/LICENSE */ const arrayToMap = (arr) => { const map = new Map(); arr.forEach((s) => map.set(s, s)); return map; }; const getClassName = (classList, newProps, oldProps) => { const newClassProp = newProps.className || newProps.class; const oldClassProp = oldProps.className || oldProps.class; // map the classes to Maps for performance const currentClasses = arrayToMap(classList); const incomingPropClasses = arrayToMap(newClassProp ? newClassProp.split(' ') : []); const oldPropClasses = arrayToMap(oldClassProp ? oldClassProp.split(' ') : []); const finalClassNames = []; // loop through each of the current classes on the component // to see if it should be a part of the classNames added currentClasses.forEach((currentClass) => { if (incomingPropClasses.has(currentClass)) { // add it as its already included in classnames coming in from newProps finalClassNames.push(currentClass); incomingPropClasses.delete(currentClass); } else if (!oldPropClasses.has(currentClass)) { // add it as it has NOT been removed by user finalClassNames.push(currentClass); } }); incomingPropClasses.forEach((s) => finalClassNames.push(s)); return finalClassNames.join(' '); }; // Note(taro): 禁用 react 合成事件抛出 (避免自定义事件属性调用问题, 例如: event.detail.value 等) const isCoveredByReact = (__eventNameSuffix) => false; const syncEvent = (node, eventName, newEventHandler) => { const eventStore = node.__events || (node.__events = {}); const oldEventHandler = eventStore[eventName]; // Remove old listener so they don't double up. if (oldEventHandler) { node.removeEventListener(eventName, oldEventHandler); } // Bind new listener. node.addEventListener(eventName, (eventStore[eventName] = function handler(e) { if (newEventHandler) { newEventHandler.call(this, e); } })); }; const attachProps = (node, newProps, oldProps = {}) => { // some test frameworks don't render DOM elements, so we test here to make sure we are dealing with DOM first if (node instanceof Element) { Object.keys(oldProps).forEach((name) => { if (['style', 'children', 'ref', 'class', 'className', 'forwardedRef'].includes(name)) { return; } // Note: 移除节点上冗余事件、属性 if (!newProps.hasOwnProperty(name)) { if (/^on([A-Z].*)/.test(name)) { const eventName = name.substring(2); const eventNameLc = eventName.toLowerCase(); if (!isCoveredByReact(eventNameLc)) { syncEvent(node, eventNameLc, undefined); } } else { node[name] = null; node.removeAttribute(camelToDashCase(name)); } } }); // add any classes in className to the class list node.className = getClassName(node.classList, newProps, oldProps); Object.keys(newProps).forEach((name) => { /** Note(taro): 优化 style 属性的处理 * 1. 考虑到兼容旧版本项目,支持使用字符串配置 style 属性,但这并非推荐写法,且不考虑优化在 style 移除时同步删除属性 * 2. style 属性应当交与前端 UI 框架自行处理,不考虑实现类似于 reactify-wc 的更新策略 */ if ((name === 'style' && typeof newProps[name] !== 'string') || ['children', 'ref', 'class', 'className', 'forwardedRef'].includes(name)) { return; } if (/^on([A-Z].*)/.test(name)) { const eventName = name.substring(2); const eventNameLc = eventName.toLowerCase(); if (!isCoveredByReact(eventNameLc)) { syncEvent(node, eventNameLc, newProps[name]); } } else { node[name] = newProps[name]; const propType = typeof newProps[name]; if (propType === 'string') { node.setAttribute(camelToDashCase(name), newProps[name]); } } }); } }; export { attachProps, getClassName, isCoveredByReact, syncEvent }; //# sourceMappingURL=attachProps.js.map