javascript 在React Native中显示更多/更少的文本

ikfrs5lh  于 12个月前  发布在  Java
关注(0)|答案(3)|浏览(104)

我试图找到一种方法,有显示更多/更少的文本,如果有超过3行的文本.我已经尝试了react-show-more-text包,但它是非常错误的,所以我已经能够得到的最接近的是在这篇文章的顶部答案.主要问题是,如果有只有3行,其显示阅读更多/少文本也。它应该显示,如果真的会有另一行文字,当你点击按钮。我的代码。

import React, { useCallback, useState } from 'react';
import { Text } from 'react-native';

const ReadMoreText = ({ readMoreStyle, text, textStyle }) => {
  const [textShown, setTextShown] = useState(false);
  const [lengthMore, setLengthMore] = useState(false);

  const toggleNumberOfLines = () => {
    setTextShown(!textShown);
  };

  const onTextLayout = useCallback((e) => {
    setLengthMore(e.nativeEvent.lines.length >= 3);
  }, []);

  return (
    <>
      <Text onTextLayout={onTextLayout} numberOfLines={textShown ? undefined : 3} style={textStyle}>
        {text}
      </Text>

      {lengthMore ? (
        <Text onPress={toggleNumberOfLines} style={readMoreStyle}>
          {textShown ? 'Read Less' : 'Read More'}
        </Text>
      ) : null}
    </>
  );
};

export default ReadMoreText;

字符串

t3psigkw

t3psigkw1#

问题是需要在状态中更新行数。我以前做的是每次都被覆盖到三行。

const ReadMoreText = ({ readMoreStyle, text, textStyle }) => {
  const [showMoreButton, setShowMoreButton] = useState(false);
  const [textShown, setTextShown] = useState(false);
  const [numLines, setNumLines] = useState(undefined);

  const toggleTextShown = () => {
    setTextShown(!textShown);
  };

  useEffect(() => {
    setNumLines(textShown ? undefined : 3);
  }, [textShown]);

  const onTextLayout = useCallback(
    (e) => {
      if (e.nativeEvent.lines.length > 3 && !textShown) {
        setShowMoreButton(true);
        setNumLines(3);
      }
    },
    [textShown],
  );

  return (
    <>
      <Text onTextLayout={onTextLayout} numberOfLines={numLines} style={textStyle} ellipsizeMode="tail">
        {text}
      </Text>

      {showMoreButton ? (
        <Text onPress={toggleTextShown} style={readMoreStyle}>
          {textShown ? 'Read Less' : 'Read More'}
        </Text>
      ) : null}
    </>
  );
};

字符串

z0qdvdin

z0qdvdin2#

这是react native从来不关心的一个兔子洞。react native有一些选项,但即使是最受欢迎的也不是用 typescript 完成的,而且缺乏很多照顾。

所以我做了自己的解决方案:https://www.npmjs.com/package/@rntext/more-or-less

如果你尝试一下,让我知道它是否适合你的模型,如果不适合,也许如何改进它,我将不胜感激。

jjjwad0x

jjjwad0x3#

当我试图找到一种限制行数的方法时,我看了一下react-native Text组件,但允许文本扩展,尽管它可以将文本截断到您指定的行数,但它并不显示文本是否实际上被截断。
这意味着您可以添加一个按钮来显示更多文本,但即使文本没有被截断(这似乎是您的问题),它也会显示出来。
如果可以接受基于字符数量的截断(而不是截断行数),则可以创建一个接受react元素(不需要只是字符串)的组件,解析输入,访问元素的子元素,直到达到字符串,然后计算字符串中的字符数量,在达到最大字符数量后截断并停止该过程。
下面是一个执行此操作的组件示例:

import React from 'react';

type ParseResult = {
    content: React.ReactNode | React.ReactNode[];
    remaining: number;
};

type Parse = (root: ParseResult, parse: Parse) => ParseResult;

const parseString = (text: string, remaining: number): ParseResult => {
    if (!text?.length) {
        return { content: text, remaining };
    }

    const newText =
        remaining <= 0
            ? ''
            : text.length > remaining
            ? text.substring(0, remaining)
            : text;

    return { content: newText, remaining: remaining - text.length };
};

const parse: Parse = (root, parseCallback) => {
    const { content, remaining = 0 } = root;

    if (typeof content === 'string') {
        const result = parseString(content, remaining);
        return result;
    } else if (React.isValidElement(content)) {
        const children = (content.props as { children?: React.ReactNode })
            ?.children;

        if (children != null) {
            const innerResult = parseCallback(
                {
                    content: children,
                    remaining,
                },
                parseCallback,
            );
            const newContent = React.cloneElement(content, {}, innerResult.content);
            return { content: newContent, remaining: innerResult.remaining };
        }
    } else if (Array.isArray(content)) {
        const list: React.ReactNode[] = [];
        let newRemaining = remaining;

        for (const child of content) {
            const parsed = parseCallback(
                { content: child, remaining: newRemaining },
                parseCallback,
            );
            newRemaining = parsed.remaining;
            const newContent = (
                <React.Fragment key={list.length}>{parsed.content}</React.Fragment>
            );
            list.push(newContent);

            if (newRemaining < 0) {
                break;
            }
        }

        return { content: list, remaining: newRemaining };
    }

    return root;
};

export interface ReadMoreAdditionalProps {
    expanded?: boolean;
    showMore?: React.ReactNode;
    showLess?: React.ReactNode;
}

const ReadMoreInner: React.FC<
    {
        children: React.ReactNode;
        truncate: number;
    } & ReadMoreAdditionalProps
> = ({ truncate, expanded, showMore, showLess, children }) => {
    const root: ParseResult = {
        content: children,
        remaining: truncate,
    };
    const result = parse(root, parse);

    return (
        <>
            {expanded ? children : result.content}
            {result.remaining < 0 ? (expanded ? showLess : showMore) : undefined}
        </>
    );
};

export interface ReadMoreOptions extends ReadMoreAdditionalProps {
    truncate?: number;
}

export type ReadMoreProps = ReadMoreOptions & {
    children: React.ReactNode;
};

export const ReadMore: React.FC<ReadMoreProps> = ({
    truncate,
    children,
    ...props
}) => {
    return truncate != null ? (
        <ReadMoreInner {...props} truncate={truncate}>
            {children}
        </ReadMoreInner>
    ) : (
        <>{children}</>
    );
};

字符串
请记住,这个组件要求子组件包含最终文本(或者不包含文本)。它不会访问其他属性(如texttitle属性),它们将被忽略。
您可以只在代码中包含此组件,添加按钮以显示更多或更少的文本,然后根据需要设置按钮的样式。
如果您不想在项目中维护组件代码,我创建了一个库来完成此任务。
使用以下各项安装库:

npm install react-shorten


下面是如何使用该库的示例:

import React from 'react';
import { ReadMore } from 'react-shorten';
import type { StyleProp, TextStyle } from 'react-native';
import { Text } from 'react-native';

export interface ReadMoreNativeProps {
    truncate: number | undefined;
    showMoreText?: React.ReactNode;
    showLessText?: React.ReactNode;
    style?: StyleProp<TextStyle>;
    btnStyle?: StyleProp<TextStyle>;
    children: React.ReactNode;
}

export const ReadMoreNative: React.FC<ReadMoreNativeProps> = ({
    truncate,
    showMoreText,
    showLessText,
    style,
    btnStyle,
    children,
}) => {
    const [expanded, setExpanded] = React.useState(false);

    const onShowMore = React.useCallback(() => setExpanded(true), []);

    const onShowLess = React.useCallback(() => setExpanded(false), []);

    return (
        <ReadMore
            truncate={truncate}
            expanded={expanded}
            showMore={
                <Text style={style}>
                    {'... '}
                    <Text onPress={onShowMore} style={btnStyle}>
                        {showMoreText ?? 'Show more'}
                    </Text>
                </Text>
            }
            showLess={
                <Text style={style}>
                    {' '}
                    <Text onPress={onShowLess} style={btnStyle}>
                        {showLessText ?? 'Show less'}
                    </Text>
                </Text>
            }
        >
            Lorem ipsum dolor sit amet,{' '}
            <Text style={{ fontStyle: 'italic' }}>
                <Text style={{ textDecorationLine: 'underline' }}>
                    consectetur adipiscing elit. Sed ullamcorper, odio eu aliquam
                    ultricies, enim sapien aliquet arcu, quis aliquam diam massa eu
                    nisl. Sed vitae nunc eget nunc ullamcorper aliquet.
                </Text>
            </Text>{' '}
            Sed euismod, nisl eget aliquam ultricies, justo nisl aliquet nunc,
            quis aliquam diam massa eu nisl. Sed vitae nunc eget nunc
            ullamcorper aliquet.
        </ReadMore>
    );
};


您可以看到here网络演示和here本地演示。“

相关问题