React文字溢位元件封裝以及高亮提示
Abbr 元件:使用場景:
- 當我們需要設定支援最大行數時進行省略展示
- 當我們需要設定支援設定超過多少字元進行省略展示
- 當我們需要設定支援關鍵字高亮展示(有點問題,當關鍵字被裁剪成...之後,就無法高亮)
- 當我們需要支援忽略大小寫高亮
- 當我們需要支援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;