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'