马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
需求
- 支持文本插入,比如 xxx {product_name} xxx ,如果提供了product_name变量的值为feedback,则可以渲染出 xxx feedback xxx。
- 支持链接解析,比如 [baidu](https://www.baidu.com/),可以直接渲染成超链接的形式。
- 支持插入reactnode元素,比如 xxx {jump_node} xxx,且jump_node是一个reactnode元素,则可以将node节点插入到{}位置上。
实现
步骤:
- 先解析链接, 返回如许子的数据布局。超链接返回url-text的对象,非超链接直接返回文本字符串
- export interface LinkPart {
- text: string;
- url?: string;
- onClick?: string;
- }
- export type ParsedTextPart = string | LinkPart;
- [
- {
- text: 'baidu',
- url: 'https://www.baidu.com/',
- },
- 'other content',
- 'other content',
- ];
复制代码
- 遍历解析后的超链接数组,如果是对象,则渲染超链接;如果是字符串,继续解析
- 解析字符串,判定必要解析的{}里面的文本是否是纯文本,如果是纯文本,则直接Text渲染;如果是react元素,则渲染该元素
TextTemplate.tsx:
- import React, { ReactNode } from 'react';
- import { routeCenter } from '@shopeepay-rn/route-center';
- import { usePageContainerContext } from '@shopeepay-rn/page-container';
- import { StyleProp, Text, TextStyle, View, ViewStyle } from 'react-native';
- import { parseLinkText } from '../../utils';
- import styles from './styles';
- interface Props {
- template: string;
- // eg: {product_name:'spp', click_node:<Text></Text>}
- replaceValueMap: Record<string, string | number | ReactNode>;
- textStyle?: StyleProp<TextStyle>;
- containerStyle?: StyleProp<ViewStyle>;
- }
- /**
- * 支持解析字符串、解析react元素、解析超链接
- * @param template 需要解析的字符串
- * @param replaceValueMap 需要替换的key-value,value支持字符串和react元素
- * @param textStyle 字体样式
- * @param containerStyle 容器样式
- * @returns react元素
- */
- export const TextTemplate = ({
- template,
- replaceValueMap,
- textStyle,
- containerStyle,
- }: Props) => {
- const { rootTag } = usePageContainerContext();
- const parseText = (text: string, index: number) => {
- const result: React.ReactNode[] = [];
- let lastIndex = 0;
- text.replace(/{(\w+)}/g, (match: string, key: string, offset: number) => {
- const replaceValue = replaceValueMap[key];
- if (offset > lastIndex) {
- // 未被匹配到的
- result.push(
- <Text key={index} style={textStyle}>
- {text.substring(lastIndex, offset)}
- </Text>
- );
- }
- if (React.isValidElement(replaceValue)) {
- // 需要替换的是reactnode元素
- result.push(React.cloneElement(replaceValue, { key: index }));
- } else if (typeof replaceValue === 'string') {
- // 需要替换的是字符串
- result.push(
- <Text key={index} style={textStyle}>
- {replaceValue}
- </Text>
- );
- }
- lastIndex = offset + match.length;
- return '';
- });
- if (lastIndex < text.length) {
- result.push(
- <Text key={index} style={textStyle}>
- {text.substring(lastIndex)}
- </Text>
- );
- }
- return result;
- };
- const parseTemplate = (text: string) => {
- // 解析链接
- const linkTexts = parseLinkText(text);
- return linkTexts?.map((part, index) => {
- return typeof part === 'string' ? (
- // 对于字符串,需要解析 纯字符串 还是 reactnode元素
- parseText(part, index)
- ) : (
- <Text
- key={index}
- style={styles.link}
- onPress={() =>
- routeCenter.navigateWeb(
- part.url || '',
- {
- navbar: {
- title: part.text || '',
- },
- },
- rootTag
- )
- }
- >
- {part.text}
- </Text>
- );
- });
- };
- return (
- <View style={[styles.textView, containerStyle]}>
- <Text>{parseTemplate(template)}</Text>
- </View>
- );
- };
复制代码 parseLinkText.ts:
- export interface LinkPart {
- text: string;
- url?: string;
- onClick?: string;
- }
- export type ParsedTextPart = string | LinkPart;
- const parseLinkText = (text: string): ParsedTextPart[] => {
- const regex = /\[([^\]]+)\]\(([^)]+)\)/g;
- const parts: ParsedTextPart[] = [];
- let lastIndex = 0;
- text.replace(
- regex,
- (match: string, p1: string, p2: string, offset: number) => {
- if (offset > lastIndex) {
- parts.push(text.substring(lastIndex, offset));
- }
- parts.push({ text: p1, url: p2 });
- lastIndex = offset + match.length;
- return '';
- }
- );
- if (lastIndex < text.length) {
- parts.push(text.substring(lastIndex));
- }
- return parts;
- };
- // FIXME: 添加 unit test
- export { parseLinkText };
复制代码 使用
- <TextTemplate
- template={"you can test the TextTemplate component, parse {string_text}, parse [baidu](https://www.baidu.com/) link, parse {click_node} to show popup"}
- replaceValueMap={{string_text:"test string",click_node:<Text>other react node</Text>}}
- textStyle={styles.titleText}
- />
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |