reactjs 如果文本超过一定数量的行,我如何在React中截断文本并显示更多阅读按钮?

rqdpfwrv  于 2023-03-29  发布在  React
关注(0)|答案(2)|浏览(241)

我正在React中构建一个Notes应用程序,并将笔记存储在Firestore中。如果我从Firestore中阅读的内容超过三行,我希望显示“阅读更多”按钮。如果没有,那么我不想显示“阅读更多”按钮。
也使用Tailwind的样式,我知道他们有一个线营插件和类称为“截断”,但我不知道如何实现它与条件渲染按钮。所以任何帮助如何实现这将不胜感激。这里是我的代码,需要截断的文本。

<div>
   <p className="break-words text-xl">{note?.noteContent}</p>
</div>
m2xkgtsf

m2xkgtsf1#

您可以使用以下内容对文本设置字符限制。

const charMax = 40

<p>`${note?.noteContent.substring(0, charMax)}...`</p>
// This just takes the string from the beginning to charMax (40)

然后就像

if (note?.noteContent.length > charMax) {
  // Render button logic here
}
ha5z0ras

ha5z0ras2#

使用CSS(或Tailwind)截断到特定行是一个很好的方法。然后您需要使用JavaScript来检测文本是否被截断,以便您可以决定显示/隐藏“阅读更多”按钮。这可以通过比较元素的scrollHeightoffsetHeight来完成。

  • scrollHeight度量元素内容的高度,包括溢出(MDN link)隐藏的任何内容。
  • offsetHeight度量元素的呈现高度,它排除了溢出隐藏的任何内容(MDN link

所以,如果scrollHeight大于offsetHeight,我们知道我们的元素有一些溢出。在这种情况下,我们的文本被截断了。为了在React中使用这些值,我们需要使用refuseLayoutEffect钩子。

完整示例代码

这里假设你只需要一个“Read more”按钮。我将包括另一个带有“Read less”选项的例子。

import React, { useState, useLayoutEffect } from 'react'

const useTruncatedElement = ({ ref }) => {
  const [isTruncated, setIsTruncated] = useState(false);
  const [isReadingMore, setIsReadingMore] = useState(false);

  useLayoutEffect(() => {
    const { offsetHeight, scrollHeight } = ref.current || {};

    if (offsetHeight && scrollHeight && offsetHeight < scrollHeight) {
      setIsTruncated(true);
    } else {
      setIsTruncated(false);
    }
  }, [ref]);

  return {
    isTruncated,
    isReadingMore,
    setIsReadingMore,
  };
};

export default function Note() {
  const ref = React.useRef(null);
  const { isTruncated, isReadingMore, setIsReadingMore } = useTruncatedElement({
    ref,
  });

  // Code to get your note content...

  return (
    <div>
      <p ref={ref} className={`break-words text-xl ${!isReadingMore && 'line-clamp-3'}`}>
        {note?.noteContent}
      </p>
      {isTruncated && !isReadingMore && (
        <button onClick={() => setIsReadingMore(true)}>
          Read more
        </button>
      )}
    </div>
  )
}

代码演练

如上所述,useTruncatedElement钩子会判断段落是否被截断。它还会返回一些状态,以确定“Read more”按钮是否已被单击。这样我们就可以通过删除line-clamp-3类来扩展文本,并在单击按钮后隐藏按钮(或将文本更改为“Read less”)。

Tailwind的线夹插件

这个插件用一个line-clamp-{n}形式的类来处理截断。它将以下CSS添加到元素中(如果你没有使用tailwind,你可以添加它):

.line-clamp-{n} {
    overflow: hidden;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: {n};
}

要安装插件:
x1米11米1x

yarn add -D @tailwindcss/line-clamp
然后将其添加到tailwind.config.cjs文件中的插件数组中:

module.exports = {
  ...
  plugins: [require("@tailwindcss/line-clamp")],
};

多显示/少显示

如果你想要一个切换,这样用户就可以在展开文本后再次截断它(一种显示更多/显示更少的场景),那么你可以从钩子返回一个切换函数:

import React, { useState, useLayoutEffect } from 'react'

const useTruncatedElement = ({ ref }) => {
  const [isTruncated, setIsTruncated] = useState(false);
  const [isShowingMore, setIsShowingMore] = useState(false);

  useLayoutEffect(() => {
    const { offsetHeight, scrollHeight } = ref.current || {};

    if (offsetHeight && scrollHeight && offsetHeight < scrollHeight) {
      setIsTruncated(true);
    } else {
      setIsTruncated(false);
    }
  }, [ref]);

  const toggleIsShowingMore = () => setIsShowingMore(prev => !prev);

  return {
    isTruncated,
    isShowingMore,
    toggleIsShowingMore,
  };
};

export default function Note() {
  const ref = React.useRef(null);
  const { isTruncated, isShowingMore, toggleIsShowingMore } = useTruncatedElement({
    ref,
  });

  // Code to get your note content...

  return (
    <div>
      <p ref={ref} className={`break-words text-xl ${!isShowingMore && 'line-clamp-3'}`}>
        {note?.noteContent}
      </p>
      {isTruncated && (
        <button onClick={toggleIsShowingMore}>
          {isShowingMore ? 'Show less' : 'Show more'}
        </button>
      )}
    </div>
  )
}

相关问题