diff --git a/packages/vantui-demo/src/app.config.js b/packages/vantui-demo/src/app.config.js index 744b4072..b05e2f66 100644 --- a/packages/vantui-demo/src/app.config.js +++ b/packages/vantui-demo/src/app.config.js @@ -76,6 +76,7 @@ export default { 'pages/image-cropper/index', 'pages/default-props/index', 'pages/count-up/index', + 'pages/highlight/index', ], window: { navigationBarBackgroundColor: '#f8f8f8', diff --git a/packages/vantui-demo/src/config.json b/packages/vantui-demo/src/config.json index d25484b4..29940097 100644 --- a/packages/vantui-demo/src/config.json +++ b/packages/vantui-demo/src/config.json @@ -246,6 +246,10 @@ "path": "empty", "title": "Empty 空状态" }, + { + "path": "highlight", + "title": "Highlight 高亮文本" + }, { "path": "ellipsis", "title": "Ellipsis 文本省略" diff --git a/packages/vantui-demo/src/pages/highlight/index.config.js b/packages/vantui-demo/src/pages/highlight/index.config.js new file mode 100644 index 00000000..2ad7ae24 --- /dev/null +++ b/packages/vantui-demo/src/pages/highlight/index.config.js @@ -0,0 +1,4 @@ +export default { + navigationBarTitleText: 'Highlight 高亮文本', + enableShareAppMessage: true, +} diff --git a/packages/vantui-demo/src/pages/highlight/index.tsx b/packages/vantui-demo/src/pages/highlight/index.tsx new file mode 100644 index 00000000..23110b9e --- /dev/null +++ b/packages/vantui-demo/src/pages/highlight/index.tsx @@ -0,0 +1,5 @@ +import Demo from '../../../../vantui/src/highlight/demo/index' + +export default function Index() { + return +} diff --git a/packages/vantui/antm.config.ts b/packages/vantui/antm.config.ts index 460b0e5a..ab891da7 100644 --- a/packages/vantui/antm.config.ts +++ b/packages/vantui/antm.config.ts @@ -336,6 +336,10 @@ function getMenus() { path: 'empty', title: 'Empty 空状态', }, + { + path: 'highlight', + title: 'Highlight 高亮文本', + }, { path: 'result', title: 'Result 操作结果', diff --git a/packages/vantui/src/count-up/README.md b/packages/vantui/src/count-up/README.md index 4dceb617..564eeb42 100644 --- a/packages/vantui/src/count-up/README.md +++ b/packages/vantui/src/count-up/README.md @@ -2,7 +2,7 @@ ### 介绍 -一般用于需要滚动数字到某一个值的场景。 +一般用于需要滚动数字到某一个值的场景。请升级 `@antmjs/vant` 到 `>= 3.6.3` 版本来使用该组件。 ### 引入 diff --git a/packages/vantui/src/highlight/README.md b/packages/vantui/src/highlight/README.md new file mode 100644 index 00000000..afc51037 --- /dev/null +++ b/packages/vantui/src/highlight/README.md @@ -0,0 +1,52 @@ +# Highlight 高亮文本 + +### 介绍 + +高亮指定文本内容。请升级 `@antmjs/vant` 到 `>= 3.6.6` 版本来使用该组件。 + +### 引入 + +在 Taro 文件中引入组件 + +```js +import { Highlight } from '@antmjs/vantui' +``` + +## 代码演示 + +### 基础用法 + +你可以通过 `keywords` 指定需要高亮的关键字,通过 `sourceString` 指定源文本。 + +::: $demo1 ::: + +### 多字符匹配 + +如果需要指定多个关键字,可以以数组的形式传入 `keywords`。 + +::: $demo2 ::: + +### 设置高亮标签类名 + +通过 `highlightClass` 可以设置高亮标签的类名,以便自定义样式。 + +::: $demo3 ::: + +### HighlightProps [[详情]](https://github.com/AntmJS/vantui/tree/main/packages/vantui/types/highlight.d.ts) + +| 参数 | 说明 | 类型 | 默认值 | 必填 | +| ---------------- | ---------------- | ----------------------------------------------------- | ------ | ------- | +| autoEscape | 是否自动转义 | _  boolean
_ | true | `false` | +| caseSensitive | 是否区分大小写 | _  boolean
_ | false | `false` | +| highlightClass | 高亮元素的类名 | _  string
_ | - | `false` | +| keywords | 期望高亮的文本 | _  string ¦ string[]
_ | - | `true` | +| sourceString | 源文本 | _  string
_ | - | `true` | +| unhighlightClass | 非高亮元素的类名 | _  string
_ | - | `false` | + +### 样式变量 + +组件提供了下列 CSS 变量,可用于自定义样式,使用方法请参考[ConfigProvider 组件](https://antmjs.github.io/vantui/#/config-provider) + +| 名称 | 默认值 | +| ---------------------- | ------------------------ | +| --highlight-text-color | ` var(--primary-color);` | diff --git a/packages/vantui/src/highlight/demo/demo.less b/packages/vantui/src/highlight/demo/demo.less new file mode 100644 index 00000000..209f5d07 --- /dev/null +++ b/packages/vantui/src/highlight/demo/demo.less @@ -0,0 +1,3 @@ +.demo-custom-highlight-class { + color: #ff0000; +} diff --git a/packages/vantui/src/highlight/demo/demo1.tsx b/packages/vantui/src/highlight/demo/demo1.tsx new file mode 100644 index 00000000..2907bb54 --- /dev/null +++ b/packages/vantui/src/highlight/demo/demo1.tsx @@ -0,0 +1,9 @@ +/* eslint-disable */ +import { Highlight } from '@antmjs/vantui' + +export default function Demo() { + const text = '慢慢来,不要急,生活给你出了难题,可也终有一天会给出答案。' + const keywords = '难题' + + return +} diff --git a/packages/vantui/src/highlight/demo/demo2.tsx b/packages/vantui/src/highlight/demo/demo2.tsx new file mode 100644 index 00000000..8943c625 --- /dev/null +++ b/packages/vantui/src/highlight/demo/demo2.tsx @@ -0,0 +1,9 @@ +/* eslint-disable */ +import { Highlight } from '@antmjs/vantui' + +export default function Demo() { + const text = '慢慢来,不要急,生活给你出了难题,可也终有一天会给出答案。' + const keywords = ['难题', '终有一天', '答案'] + + return +} diff --git a/packages/vantui/src/highlight/demo/demo3.tsx b/packages/vantui/src/highlight/demo/demo3.tsx new file mode 100644 index 00000000..3e824ce4 --- /dev/null +++ b/packages/vantui/src/highlight/demo/demo3.tsx @@ -0,0 +1,16 @@ +/* eslint-disable */ +import { Highlight } from '@antmjs/vantui' +import './demo.less' + +export default function Demo() { + const text = '慢慢来,不要急,生活给你出了难题,可也终有一天会给出答案。' + const keywords = '生活' + + return ( + + ) +} diff --git a/packages/vantui/src/highlight/demo/index.tsx b/packages/vantui/src/highlight/demo/index.tsx new file mode 100644 index 00000000..212edb12 --- /dev/null +++ b/packages/vantui/src/highlight/demo/index.tsx @@ -0,0 +1,28 @@ +/* eslint-disable */ + +import { Component } from 'react' +import DemoPage from '../../../../vantui-demo/src/components/demo-page/index' +import DemoBlock from '../../../../vantui-demo/src/components/demo-block/index' +import Demo1 from './demo1' +import Demo2 from './demo2' +import Demo3 from './demo3' + +export default class Index extends Component { + render() { + return ( + + + + + + + + + + + + + + ) + } +} diff --git a/packages/vantui/src/highlight/index.less b/packages/vantui/src/highlight/index.less new file mode 100644 index 00000000..606520a6 --- /dev/null +++ b/packages/vantui/src/highlight/index.less @@ -0,0 +1,5 @@ +@import '../style/var.less'; + +.van-highlight { + .theme(color, '@highlight-text-color'); +} diff --git a/packages/vantui/src/highlight/index.tsx b/packages/vantui/src/highlight/index.tsx new file mode 100644 index 00000000..c315bae8 --- /dev/null +++ b/packages/vantui/src/highlight/index.tsx @@ -0,0 +1,139 @@ +import { View, Text } from '@tarojs/components' +import { useMemo } from 'react' +import classNames from 'classnames' +import { HighlightProps } from '../../types/highlight' +import * as utils from '../wxs/utils' +import './index.less' + +interface Chunk { + start: number + end: number + highlight: boolean +} + +export function Highlight(props: HighlightProps) { + const { autoEscape, caseSensitive, keywords, sourceString } = props + + const highlightChunks = useMemo(() => { + // 是否区分大小写 + const flags = caseSensitive ? 'g' : 'gi' + // 转数组 + const _keywords = Array.isArray(keywords) ? keywords : [keywords] + + // 生成分组 + let chunks = _keywords + .filter((keyword) => keyword) + .reduce((chunks: Chunk[], keyword) => { + // 是否自动转义 + if (autoEscape) { + keyword = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + } + + // 用正则匹配 + const regex = new RegExp(keyword, flags) + + // 遍历关键词匹配值,最后生成 [{start, end, highlight: false}] 开始和结束值,高亮与否的数组 + let match + while ((match = regex.exec(sourceString))) { + const start = match.index + const end = regex.lastIndex + + if (start >= end) { + regex.lastIndex++ + continue + } + + chunks.push({ + start, + end, + highlight: true, + }) + } + + return chunks + }, []) + + // 合并分组 + chunks = chunks + .sort((a, b) => a.start - b.start) + .reduce((chunks: Chunk[], currentChunk) => { + const prevChunk = chunks[chunks.length - 1] + + if (!prevChunk || currentChunk.start > prevChunk.end) { + const unhighlightStart = prevChunk ? prevChunk.end : 0 + const unhighlightEnd = currentChunk.start + + if (unhighlightStart !== unhighlightEnd) { + chunks.push({ + start: unhighlightStart, + end: unhighlightEnd, + highlight: false, + }) + } + + chunks.push(currentChunk) + } else { + prevChunk.end = Math.max(prevChunk.end, currentChunk.end) + } + + return chunks + }, []) + + const lastChunk = chunks[chunks.length - 1] + + // 没有关键词时,没匹配到 chunks 的时候 + if (!lastChunk) { + chunks.push({ + start: 0, + end: sourceString.length, + highlight: false, + }) + } + + if (lastChunk && lastChunk.end < sourceString.length) { + chunks.push({ + start: lastChunk.end, + end: sourceString.length, + highlight: false, + }) + } + + return chunks + }, [autoEscape, caseSensitive, keywords, sourceString]) + + const renderContent = () => { + const { + sourceString, + // 高亮和非高亮样式名和标签名 + highlightClass, + unhighlightClass, + } = props + + return highlightChunks.map((chunk, index) => { + const { start, end, highlight } = chunk + // 取出文本 + const text = sourceString.slice(start, end) + + if (highlight) { + return ( + + {text} + + ) + } + + return ( + + {text} + + ) + }) + } + + return {renderContent()} +} + +export default Highlight diff --git a/packages/vantui/src/style/var.less b/packages/vantui/src/style/var.less index 127f5eac..87e86b23 100644 --- a/packages/vantui/src/style/var.less +++ b/packages/vantui/src/style/var.less @@ -820,3 +820,6 @@ page { @check-list-placeholder-color: @placeholder-color; @check-list-item-padding: 20px 0px; @check-list-item-border: 1px solid #e9e9f1; + +// highlight +@highlight-text-color: var(--primary-color); diff --git a/packages/vantui/types/highlight.d.ts b/packages/vantui/types/highlight.d.ts new file mode 100644 index 00000000..f9dbcabe --- /dev/null +++ b/packages/vantui/types/highlight.d.ts @@ -0,0 +1,37 @@ +import { FunctionComponent } from 'react' +import { ViewProps } from '@tarojs/components' +/** + * @description Highlight Props + */ +export interface HighlightProps extends ViewProps { + /** + * @description 是否自动转义 + * @default true + */ + autoEscape?: boolean + /** + * @description 是否区分大小写 + * @default false + */ + caseSensitive?: boolean + /** + * @description 高亮元素的类名 + */ + highlightClass?: string + /** + * @description 期望高亮的文本 + */ + keywords: string | string[] + /** + * @description 源文本 + */ + sourceString: string + /** + * @description 非高亮元素的类名 + */ + unhighlightClass?: string +} + +declare const Highlight: FunctionComponent + +export { Highlight } diff --git a/packages/vantui/types/index.d.ts b/packages/vantui/types/index.d.ts index 76e6561b..66aefa6d 100644 --- a/packages/vantui/types/index.d.ts +++ b/packages/vantui/types/index.d.ts @@ -81,4 +81,5 @@ export * from './image-viewer' export * from './badge' export * from './check-list' export * from './image-cropper' +export * from './highlight' export * from './default-props'