React文字溢位元件封裝以及高亮提示

郭杰前端开发發表於2024-05-09

React文字溢位元件封裝以及高亮提示

Abbr 元件:使用場景:

  1. 當我們需要設定支援最大行數時進行省略展示
  2. 當我們需要設定支援設定超過多少字元進行省略展示
  3. 當我們需要設定支援關鍵字高亮展示(有點問題,當關鍵字被裁剪成...之後,就無法高亮)
  4. 當我們需要支援忽略大小寫高亮
  5. 當我們需要支援ToolTip展示全部文字,且可以在toolTip上進行關鍵字高亮

Abbr 元件tsx

 import { Tooltip } from "antd";
import React from "react";
import "./index.less";
import { finxAllIndex, returnRenderName } from "./tools";

interface AbbrTextProps {
  /* 需要展示的文字 */
  text: string;
  /* 擷取的長度 */
  length?: number;
  /* 設定行數 */
  line?: number;
  /* 設定樣式 */
  className?: string;
  /* 高亮關鍵字 */
  keyWord?: string;
  /* 是否在tooltip中也高亮展示 預設不展示 */
  showTooltipHighlight?: boolean;
  /* 主題 */
  theme?: "default" | "warning" | "error" | "success";
  /* 是否忽略大小寫 */
  ignoreCase?: boolean;
}
const AbbrText: React.FC<AbbrTextProps> = ({
  text,
  length,
  line,
  className,
  keyWord = "",
  showTooltipHighlight = false,
  theme = "default",
  ignoreCase = false,
}) => {
  let displayText: JSX.Element | string = text;
  let style = {};
  let showTooltip = false;

  /* 如果有高亮的關鍵字 */
  const heightKeyWord = (
    readyText: string,
    keyWord: string,
    showAll?: boolean
  ): JSX.Element => {
    /* 目標結果在字串中的所有索引 */
    const findAllIndex = finxAllIndex(readyText, keyWord, ignoreCase);
    /* 高亮之後標籤 */
    const renderName = returnRenderName(readyText, keyWord, findAllIndex, {
      theme,
    });
    const renderText = (
      <>
        {renderName}
        {!showAll && length && text.length > length && <span>...</span>}
      </>
    );
    return renderText;
  };

  if (length && text.length > length) {
    displayText = text.substring(0, length);
    showTooltip = true;
  } else if (line) {
    style = {
      display: "-webkit-box",
      "-webkit-box-orient": "vertical",
      overflow: "hidden",
      textOverflow: "ellipsis",
    };
  }
  displayText = heightKeyWord(displayText, keyWord);

  /* length 優先順序大於line ,同時設定length 生效 */
  if (length && line) {
    console.warn("Abbr元件警告⚠️:length 和 line 同時設定時,length 優先順序高");
  }

  // 當文字被截短或者設定了行數限制時顯示提示
  const content = (
    <span
      className={`abbrtext ${className}`}
      style={{ ...style, WebkitLineClamp: line, lineClamp: line }}
    >
      {displayText}
    </span>
  );

  return (
    <Tooltip
      title={
        (showTooltip || line) && showTooltipHighlight
          ? heightKeyWord(text, keyWord, true)
          : text
      }
    >
      {content}
    </Tooltip>
  );
};

AbbrText.defaultProps = {
  length: undefined,
  line: 1,
  className: "",
};

export default AbbrText;

Abbr 元件less

.abbrtext {
    word-break: break-all;
    width: fit-content;
}

.hightlight {
    &.default {
        color: blue;
    }

    &.success {
        color: green;
    }

    &.error {
        color: red;
    }

    &.warning {
        color: orange;
    }

}

Abbr 元件工具函式

 /**
 * @param str 字串
 * @param itemStr 目標字串
 * @param ignoreCase 是否忽略大小寫
 * @returns 目標結果在字串中的所有索引
 */
export const finxAllIndex = (
  str: string,
  itemStr: string,
  ignoreCase = false
) => {
  // 初始化結果陣列
  const result = [];
  // 遍歷字串,尋找目標項並記錄索引
  for (let i = 0; i <= str.length - itemStr.length; ) {
    let index = str.indexOf(itemStr, i);
    if (ignoreCase) {
      index = str.toLocaleLowerCase().indexOf(itemStr.toLocaleLowerCase(), i);
    }
    if (index !== -1) {
      // 更簡潔的判斷條件
      result.push(index);
      i = index + itemStr.length; // 更新i值
    } else {
      i++;
    }
  }
  return result;
};

/**
 * @param str 字串
 * @param keyWords 關鍵字
 * @param allIndexArray 所有索引
 * @param config 配置
 * @param config.theme 主題
 * @returns 高亮之後標籤
 */
export const returnRenderName = (
  str: string,
  keyWords: string,
  allIndexArray: Array<number>,
  config?: {
    theme?: "default" | "warning" | "error" | "success";
  }
) => {
  const { theme = "default" } = config || {};
  if (allIndexArray.length === 0) {
    return str;
  }
  /* 最終結果 */
  let res: string | JSX.Element | null = null;
  let loopindex = 0;
  const loop = (index = 0): string | JSX.Element => {
    res = (
      <>
        {res}
        {str.substring(index, allIndexArray[loopindex])}
        <span className={`hightlight ${theme}`}>
          {str.substring(allIndexArray[loopindex], keyWords.length)}
        </span>
      </>
    );
    loopindex++;
    if (allIndexArray.length <= loopindex) {
      res = (
        <>
          {res}
          {str.substring(allIndexArray[loopindex - 1] + keyWords.length)}
        </>
      );
      return res;
    } else {
      return loop(allIndexArray[loopindex - 1] + keyWords.length);
    }
  };
  loop();
  return res;
};

Abbr 元件測試

import React from "react";
import AbbrText from "./components/Abbr";

function App() {
  return (
    <>
      <AbbrText
        text="Hello World"
        keyWord="hello"
        length={10}
        showTooltipHighlight
        ignoreCase
        theme="warning"
      />
    </>
  );
}

export default App;

效果圖

img

相關文章