UNPKG

react-native-visitor

Version:

基于React开发方式,jsx对象一旦生成将无法修改。但如果你有对jsx生成对象二次修改的需求时,ReactDOM可以通过ref获取到Element引用进行修改,但ReactNative则无能为力……ReactNativeVisitor便是提供你对jsx产生的对象进行二次修改的能力,想改啥就改啥!

481 lines 15.6 kB
var __spreadArrays = (this && this.__spreadArrays) || function () { for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; for (var r = Array(s), k = 0, i = 0; i < il; i++) for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) r[k] = a[j]; return r; }; import { Platform, StyleSheet } from 'react-native'; function handleStyleSheet(style) { // 遍历styles for (var name in style) { var value = style[name]; if (name === "fontWeight" && Platform.OS === "android" && style["fontFamily"] == null) { // 安卓中如果给了fontWeight但没有给fontFamily,有可能会导致某些手机布局错乱,因此给一个空字符串 style["fontFamily"] = ""; } if (typeof value === "object") { // 是个复杂类型,需要特殊处理 Object.defineProperty(style, name, { configurable: true, enumerable: Array.isArray(value) || name === "shadowOffset", writable: false, value: handleStyleSheet(value) }); } } return mergeStyles(style); } /** * 创建一个可嵌套的样式表 * * @author Raykid * @date 2019-08-13 * @export * @template T * @param {(T | StyleSheet.NamedStyles<T>)} styles * @returns {{[P in keyof T]:any}} */ export function createStyleSheet(styles) { // 遍历styles for (var name in styles) { styles[name] = handleStyleSheet(styles[name]); } // 返回处理后的值 return StyleSheet.create(styles); } var textStyleKeys = [ "color", "fontFamily", "fontSize", "fontStyle", "fontWeight", "letterSpacing", "lineHeight", "textAlign", "textDecorationLine", "textDecorationStyle", "textDecorationColor", "textShadowColor", "textShadowOffset", "textShadowRadius", ]; /** * 筛选文本可以继承的样式 * * @author Raykid * @date 2019-09-09 * @export * @param {Style} style * @returns {TextStyle} */ export function filterTextStyles(style) { if (!style) return style; var result = {}; for (var _i = 0, textStyleKeys_1 = textStyleKeys; _i < textStyleKeys_1.length; _i++) { var key = textStyleKeys_1[_i]; if (style[key] !== undefined) { result[key] = style[key]; } } return result; } /** * 合并样式 * * @author Raykid * @date 2019-08-13 * @export * @param {...Style[]} styles * @returns {Style} */ export function mergeStyles() { var styles = []; for (var _i = 0; _i < arguments.length; _i++) { styles[_i] = arguments[_i]; } // 过滤掉空样式,这里不能和null对比,因为还要过滤掉false的情况 styles = styles.filter(function (style) { return style; }); // 合并样式 var style = Object.assign.apply(Object, __spreadArrays([{}], styles)); // 这里返回一个Proxy,如果用户尝试获取一个没有的key,则返回原始style列表中所有相同key属性的合并 return new Proxy(style, { get: function (target, propertyKey) { if (target.hasOwnProperty(propertyKey)) { return target[propertyKey]; } else { var hasSubStyle_1 = false; var subStyles = styles.map(function (style) { if (style.hasOwnProperty ? style.hasOwnProperty(propertyKey) : style[propertyKey]) { hasSubStyle_1 = true; } return style[propertyKey]; }); return hasSubStyle_1 ? mergeStyles.apply(void 0, subStyles) : undefined; } } }); } function flattenStyle(style, states) { if (!style) return []; var result = [style]; for (var _i = 0, _a = states || []; _i < _a.length; _i++) { var state = _a[_i]; // 过滤掉为false或没有的字段 if (state) { var subStyle = style[state]; if (subStyle) { result.push.apply(result, flattenStyle(subStyle, states)); } } } return result; } /** * 将某个样式与其内部具有指定名称的子样式进行合并 * * @author Raykid * @date 2019-08-19 * @export * @param {Style} style * @param {string} states * @returns {Style} */ export function crossMergeStyles(style, states) { return mergeStyles.apply(this, flattenStyle(style, states)); } /** * 追加样式 * * @author Raykid * @date 2019-08-16 * @export * @param {ReactNodeVisitor} target * @param {...Style[]} styles * @returns {Style} */ export function appendStyles(target) { var styles = []; for (var _i = 1; _i < arguments.length; _i++) { styles[_i - 1] = arguments[_i]; } if (!target) return null; var style = mergeStyles.apply(void 0, __spreadArrays([target.style], styles)); target.style = style; return style; } /** * 追加ScrollView系列组件的内容容器样式 * * @author Raykid * @date 2019-08-28 * @export * @param {ReactNodeVisitor} target * @param {...Style[]} styles * @returns {Style} */ export function appendContentContainerStyles(target) { var styles = []; for (var _i = 1; _i < arguments.length; _i++) { styles[_i - 1] = arguments[_i]; } if (!target) return null; var style = mergeStyles.apply(void 0, __spreadArrays([target.props.contentContainerStyle], styles)); target.props.contentContainerStyle = style; return style; } function isVisitor(target) { return target != null && target.hasOwnProperty("key") && target.hasOwnProperty("type") && target.hasOwnProperty("props") && target.hasOwnProperty("node") && target.hasOwnProperty("style") && target.hasOwnProperty("children") && target.hasOwnProperty("parent") && target.hasOwnProperty("keyDict"); } function getChildren(children) { if (typeof children === "string" || Array.isArray(children)) { return children; } else if (children != null) { return [children]; } else { return []; } } function handleChildren(children) { if (Array.isArray(children) && children.length === 1) { children = children[0]; } return children; } var visitorFunctions = { hasChild: function (child) { return this.getChildIndex(child) >= 0; }, getChildIndex: function (child) { return Array.isArray(this.children) ? this.children.indexOf(child) : -1; }, getChildAt: function (index) { return Array.isArray(this.children) ? this.children[index] : null; }, addChild: function (child) { return this.addChildAt(child, Number.MAX_SAFE_INTEGER); }, addChildAt: function (child, index) { if (!child) { return null; } if (typeof this.children === "string") { throw new Error("非容器节点不能添加子节点"); } // 处理边界情况 if (index < 0) index = 0; else if (index > this.children.length) index = this.children.length; // 如果传入的是个ReactNode,要先包装一下 var visitor = isVisitor(child) ? child : wrapVisitor()(child); // 如果之前有父节点,先移除之 if (visitor.parent) { visitor.parent.removeChild(visitor); } // 插入visitor数组 this.children.splice(index, 0, visitor); // 插入node数组 var children = getChildren(this.node.props.children); children.splice(index, 0, visitor.node); this.node.props.children = handleChildren(children); // 设置父节点引用 visitor.parent = this; // 返回child return visitor; }, addChildBefore: function (child, refChild) { var index = this.getChildIndex(refChild); if (index < 0) { throw new Error("refChild不在当前子节点列表中"); } return this.addChildAt(child, index); }, addChildAfter: function (child, refChild) { var index = this.getChildIndex(refChild); if (index < 0) { throw new Error("refChild不在当前子节点列表中"); } return this.addChildAt(child, index + 1); }, remove: function () { return this.parent && this.parent.removeChild(this); }, removeChild: function (child) { var index = this.getChildIndex(child); return this.removeChildAt(index); }, removeChildAt: function (index) { var child = Array.isArray(this.children) && this.children[index]; if (child) { // 移除子节点 this.children.splice(index, 1); // 移除node var children = getChildren(this.node.props.children); children.splice(index, 1); this.node.props.children = handleChildren(children); // 删除父引用 child.parent = null; // 返回子节点 return child; } return null; }, removeChildren: function () { var _this = this; if (Array.isArray(this.children)) { var children = this.children.concat(); return children.map(function (child) { return _this.removeChild(child); }); } return []; }, replace: function (child, refChild) { // 先将目标对象插入引用前面 var result = this.addChildBefore(child, refChild); // 如果插入成功了,则移除引用 if (result) { this.removeChild(refChild); } return result; } }; function wrapFunction(visitor) { for (var key in visitorFunctions) { visitor[key] = visitorFunctions[key]; } return visitor; } function doWrapVisitor(node, parent) { if (node == null || typeof node !== "object") return null; // 如果node本来就是访问器,修改parent然后返回 if (isVisitor(node)) { node.parent = parent; return node; } var keyDict = {}; var visitorChildren; // 自身 var visitor; if (node["__visitor__"]) { visitor = node["__visitor__"]; visitorChildren = getChildren(visitor.children); visitor.parent = parent; } else { visitorChildren = typeof node.props.children === "string" ? node.props.children : []; // 如果有style字段但没有给style,则给一个空的,防止改的时候报错 if (node.props.hasOwnProperty("style") && !node.props.style) { node.props.style = {}; } visitor = new Proxy(wrapFunction({ get key() { return node.key; }, set key(value) { node.key = value; }, get type() { return node["type"]["displayName"]; }, node: node, get props() { return node.props; }, set props(value) { node.props = value; }, get style() { return node.props.style; }, set style(value) { node.props.style = value; }, get children() { return visitorChildren; }, set children(value) { visitorChildren = value; if (!value || typeof value === "string") { // 如果是字符串,直接更新原始属性 node.props.children = value; } else { // 是数组,用node列表更新原始属性 node.props.children = value.map(function (child) { return child.node; }); } // 处理一下子数组 node.props.children = handleChildren(node.props.children); }, parent: parent, keyDict: keyDict }), { get: function (target, key) { if (!target.hasOwnProperty(key)) { // 如果没有这个key,尝试从keyDict中取 return target.keyDict[key]; } else { return target[key]; } } }); node["__visitor__"] = visitor; } if (visitor.key) { keyDict[visitor.key] = visitor; } // 子节点 var children = node.props.children; if (children && typeof children === "object") { if (!Array.isArray(children)) { children = [children]; } children.forEach(function (child, i) { if (child) { var childVisitor = doWrapVisitor(child, visitor); // 填充key字典 for (var key in childVisitor && childVisitor.keyDict) { keyDict[key] = childVisitor.keyDict[key]; } // 填充子访问器 if (Array.isArray(visitorChildren)) { visitorChildren[i] = childVisitor; } } }); } else if (node.props.renderItem instanceof Function) { // 是个列表 var oriRenderItem_1 = node.props.renderItem; node.props.renderItem = function (info) { var renderItem = oriRenderItem_1.call(this, info); // 解析渲染器对象 var childVisitor = doWrapVisitor(renderItem, visitor); // 填充key字典 for (var key in childVisitor && childVisitor.keyDict) { keyDict[key] = childVisitor.keyDict[key]; } // 填充子列表 if (Array.isArray(visitorChildren)) { visitorChildren[info.index] = childVisitor; } // 返回渲染器 return renderItem; }; } return visitor; } /** * 将ReactNode包装成一个便捷访问的对象,保证方法为连续执行 * * @author Raykid * @date 2019-08-15 * @export * @returns {ReactNodeVisitorWrapper} */ export function wrapVisitor() { // 篡改Object.freeze方法,使其失效 var oriFreeze = Object.freeze; Object.freeze = function (a) { return a; }; return function (node) { // 恢复Object.freeze方法 Object.freeze = oriFreeze; // 解析node节点 return doWrapVisitor(node); }; } /** * 添加ref回调 * * @author Raykid * @date 2019-08-28 * @export * @param {ReactNodeVisitor} target * @param {(ref:any)=>void} handler */ export function appendRefHandler(target, handler) { var oriRef = target.node["ref"]; target.node["ref"] = function (ref) { // 当用当前的方法 handler(ref); // 调用原来的方法 oriRef && oriRef(ref); }; } //# sourceMappingURL=ReactNativeVisitor.js.map