UNPKG

@tarojs/components

Version:
177 lines (174 loc) 5.95 kB
import React, { createRef, createElement } from 'react'; /** * https://github.com/BBKolton/reactify-wc/ * modified event naming **/ const h = React.createElement; const SCROLL_VIEW = 'taro-scroll-view-core'; const IS_NON_DIMENSIONAL = /aspect|acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i; // 为了不要覆盖 wc 中 host 内置的 class 和 stencil 加入的 class function getClassName(wc, prevProps, props) { const classList = Array.from(wc.classList); const oldClassNames = (prevProps.className || prevProps.class || '').split(' '); let incomingClassNames = (props.className || props.class || '').split(' '); let finalClassNames = []; classList.forEach(classname => { if (incomingClassNames.indexOf(classname) > -1) { finalClassNames.push(classname); incomingClassNames = incomingClassNames.filter(name => name !== classname); } else if (oldClassNames.indexOf(classname) === -1) { finalClassNames.push(classname); } }); finalClassNames = [...finalClassNames, ...incomingClassNames]; return finalClassNames.join(' '); } function updateStyle(dom, key, val) { if (/^--/.test(key)) { // css variable dom.style.setProperty(key, val); } else if (typeof val !== 'number' || IS_NON_DIMENSIONAL.test(key)) { dom.style[key] = val; } else { dom.style[key] = val + 'px'; } } function updateProp(ctx, comp, propKey, prevProps, props) { const dom = ctx.ref.current; const val = props[propKey]; const prevVal = prevProps ? prevProps[propKey] : undefined; if (propKey === 'children') { return; } if (propKey.toLowerCase() === 'classname') { dom.className = prevProps ? getClassName(dom, prevProps, props) : val; return; } if (propKey === 'style') { if (typeof val === 'string') { dom.setAttribute(propKey, val); return; } if (!val) { dom.removeAttribute(propKey); return; } if (prevProps) { if (typeof prevVal === 'string') { dom.style.cssText = ''; } else { for (const styleKey in prevVal) { updateStyle(dom, styleKey, ''); } } } for (const styleKey in val) { updateStyle(dom, styleKey, val[styleKey]); } return; } if (/^(aria|data)-.+/.test(propKey)) { dom.setAttribute(propKey, val); } if (comp === SCROLL_VIEW) { if (propKey === 'scrollTop') { dom.mpScrollTop = val; return; } if (propKey === 'scrollLeft') { dom.mpScrollLeft = val; return; } if (propKey === 'scrollIntoView') { dom.mpScrollIntoView = val; return; } } if (typeof val === 'function' && propKey.match(/^on[A-Z]/)) { const event = propKey.substr(2).toLowerCase(); ctx.eventHandlers.push([event, val]); return dom.addEventListener(event, val); } if (typeof val === 'string' || typeof val === 'number') { dom.setAttribute(propKey, val); dom[propKey] = val; return; } if (typeof val === 'boolean') { if (val) { dom[propKey] = true; return dom.setAttribute(propKey, val); } dom[propKey] = false; return dom.removeAttribute(propKey); } dom[propKey] = val; } const reactifyWebComponent = WC => { class Index extends React.Component { constructor(props) { super(props); this.eventHandlers = []; this.ref = createRef(); } update(prevProps) { this.clearEventHandlers(); if (!this.ref.current) return; Object.keys(prevProps || {}).forEach((key) => { if (key !== 'children' && key !== 'key' && !(key in this.props)) { updateProp(this, WC, key, prevProps, this.props); } }); Object.keys(this.props).forEach((key) => { updateProp(this, WC, key, prevProps, this.props); }); } componentDidUpdate(prevProps) { this.update(prevProps); } componentDidMount() { const { forwardRef } = this.props; if (typeof forwardRef === 'function') { forwardRef(this.ref.current); } else if (forwardRef && typeof forwardRef === 'object' && forwardRef.hasOwnProperty('current')) { forwardRef.current = this.ref.current; } else if (typeof forwardRef === 'string') { console.warn('内置组件不支持字符串 ref'); } this.update(undefined); } componentWillUnmount() { this.clearEventHandlers(); } clearEventHandlers() { this.eventHandlers.forEach(([event, handler]) => { if (!this.ref.current) return; this.ref.current.removeEventListener(event, handler); }); this.eventHandlers = []; } render() { const { children, dangerouslySetInnerHTML } = this.props; const props = { ref: this.ref }; if (dangerouslySetInnerHTML) props.dangerouslySetInnerHTML = dangerouslySetInnerHTML; return createElement(WC, props, children); } } // eslint-disable-next-line react/display-name return React.forwardRef((props, ref) => (h(Index, Object.assign(Object.assign({}, props), { forwardRef: ref })))); }; export { reactifyWebComponent as default }; //# sourceMappingURL=reactify-wc.js.map