文本高亮搜索示例
功能介绍
1. 功能概述
本示例展示了一个搜索组件的实现,包含以下核心功能:
- 实时搜索建议:根据用户输入实时过滤并展示搜索建议
- 关键词高亮:在搜索建议中高亮显示匹配的关键词部分
- 搜索历史:记录用户的搜索历史,支持快速重新搜索
2. 效果展示
实现原理
1. 整体架构
graph LR
A[用户输入] --> B[状态管理<br>AppStorageV2]
B --> C[数据处理]
C --> D[UI渲染]
D --> E[结果点击]
E --> F[搜索记录更新]
F --> B
B --> G[历史记录存储]
G --> B
整体采用单向数据流设计:
- 用户输入触发搜索状态更新
- 状态变化驱动搜索建议过滤
- 数据处理层处理高亮显示
- UI层响应状态变化并更新显示
2. 核心功能实现原理
文本高亮处理流程
graph LR
A["原始文本<br>Hello"] --> B["大小写转换<br>hello"]
B --> C["位置匹配<br>(0, 2)"]
C --> D["文本分割<br>He,l,lo"]
D --> E["高亮渲染<br>He[l]lo"]
工作原理:
- 将原文本和关键词转换为小写进行匹配
- 记录所有匹配位置
- 根据匹配位置分割文本
- 对匹配部分应用高亮样式
状态管理流程
graph LR
A["状态定义<br>SearchState"] --> B["状态更新<br>ObservedV2"]
B --> C["持久化<br>AppStorageV2"]
C --> D["UI响应"]
D --> E["用户交互"]
E --> F["本地存储"]
F --> C
F --> G["历史记录读取"]
G --> A
数据流转:
- 统一的状态管理类
- 响应式状态更新
- 自动持久化存储
- UI组件自动响应变化
开发步骤
1. 定义数据模型
首先定义核心数据结构,确保类型安全和代码可维护性:
// 搜索建议项
interface SearchSuggestion {
id: string // 唯一标识
keyword: string // 搜索建议文本
tags: string[] // 标签列表
}
// 高亮文本片段
interface HighlightPart {
text: string // 文本内容
isHighlight: boolean // 是否高亮
}
2. 实现高亮文本组件
首先实现文本高亮的核心组件,这是整个搜索功能的基础:
// src/main/ets/components/Common/HighlightText.ets
@ComponentV2
export struct HighlightText {
@Require @Param content: string // 原始文本
@Param keyword: string = '' // 搜索关键词
private getHighlightParts(): Array<HighlightPart> {
// 1. 空关键词处理
if (!this.keyword) {
return [{ text: this.content, isHighlight: false }]
}
// 2. 初始化变量
const parts: Array<HighlightPart> = []
const lowerText = this.content.toLowerCase()
const lowerKeyword = this.keyword.toLowerCase()
// 3. 查找并分割文本
let lastIndex = 0
let index = lowerText.indexOf(lowerKeyword)
while (index !== -1) {
// 添加非高亮部分
if (index > lastIndex) {
parts.push({
text: this.content.substring(lastIndex, index),
isHighlight: false
})
}
// 添加高亮部分
parts.push({
text: this.content.substring(index, index + this.keyword.length),
isHighlight: true
})
lastIndex = index + this.keyword.length
index = lowerText.indexOf(lowerKeyword, lastIndex)
}
// 4. 添加剩余文本
if (lastIndex < this.content.length) {
parts.push({
text: this.content.substring(lastIndex),
isHighlight: false
})
}
return parts
}
build() {
Row() {
ForEach(this.getHighlightParts(), (part: HighlightPart) => {
Text(part.text)
.fontSize(16)
.fontColor(part.isHighlight ? '#FF7500' : '#333333')
})
}
}
}
3. 状态管理实现
接下来实现状态管理,使用 AppStorageV2 管理搜索状态和历史记录:
// src/main/ets/model/SearchState.ets
@ObservedV2
export class SearchState {
@Trace searchText: string = '' // 搜索文本
@Trace searchHistory: string[] = [] // 搜索历史
constructor() {
// 初始化时加载历史记录
this.loadSearchHistory()
}
// 添加搜索历史
addSearchHistory(keyword: string) {
if (!keyword) return
// 去重处理
const index = this.searchHistory.indexOf(keyword)
if (index > -1) {
this.searchHistory.splice(index, 1)
}
// 添加到开头并限制数量
this.searchHistory.unshift(keyword)
if (this.searchHistory.length > 10) {
this.searchHistory.pop()
}
this.saveSearchHistory()
}
// 其他状态管理方法...
}
4. 搜索建议列表实现
实现搜索建议列表的数据源和渲染:
- 自定义数据源:
// src/main/ets/model/SearchDataSource.ets
export class SuggestionsDataSource extends BasicDataSource<SearchSuggestion> {
constructor(suggestions: SearchSuggestion[]) {
super(suggestions)
}
}
- 搜索建议项组件:
// src/main/ets/components/Search/SearchItem.ets
@ComponentV2
export struct SearchItem {
@Require @Param suggestion: SearchSuggestion
@Require @Param keyword: string
@EventV2('click') onClick: () => void = () => {}
build() {
Row() {
// 搜索图标
SymbolGlyph($r('sys.symbol.search'))
.size({ width: 20, height: 20 })
.margin({ right: 8 })
// 高亮文本
HighlightText({
content: this.suggestion.keyword,
keyword: this.keyword
})
// 标签展示
if (this.suggestion.tags.length > 0) {
ForEach(this.suggestion.tags, (tag: string) => {
Text(tag)
.fontSize(12)
.fontColor($r('sys.color.alert'))
// 其他样式...
})
}
}
.width('100%')
.padding(16)
.onClick(() => this.onClick())
}
}
5. 功能整合
最后在主页面中整合所有功能:
// src/main/ets/components/MainPage.ets
@ComponentV2
export struct TextHighlight {
@Local searchState: SearchState = AppStorageV2.connect(SearchState, () => new SearchState())!
private suggestionsDataSource: SuggestionsDataSource = new SuggestionsDataSource([])
build() {
Column() {
// 搜索栏
SearchBar({
searchText: this.searchState.searchText,
onSearchChange: (value: string) => {
this.searchState.searchText = value
this.updateSuggestions(value)
},
onClear: () => {
this.searchState.searchText = ''
this.suggestionsDataSource = new SuggestionsDataSource([])
}
})
// 搜索建议或历史记录
if (this.searchState.searchText) {
this.buildSuggestionsList()
} else {
this.buildSearchHistory()
}
}
}
// 其他辅助方法...
}
技术总结
1. 核心技术点
文本处理算法
- 大小写不敏感匹配:通过 toLowerCase() 实现
- 文本分割策略:使用 indexOf 和 substring 进行精确分割
- 高亮渲染:使用数组映射实现文本片段的动态渲染
状态管理方案
- 使用 AppStorageV2 实现应用级状态管理
- @ObservedV2 装饰器实现响应式更新
- @Trace 实现细粒度的状态追踪
- 状态持久化确保数据可靠性
性能优化策略
- LazyForEach 实现列表懒加载
- 合理的组件拆分避免不必要的重渲染
- 数据源抽象实现高效的列表更新
2. 实现难点及解决方案
1. 文本高亮实现
难点:需要准确分割文本并保持原始大小写
解决方案:
- 转换为小写进行匹配
- 使用原始文本进行显示
- 记录匹配位置确保准确分割
2. 状态管理
难点:状态更新可能导致循环引用
解决方案:
- 单向数据流设计
- 状态隔离
- 合理的更新时机
3. 列表性能
难点:大量数据的渲染性能
解决方案:
- 使用 BasicDataSource 实现数据源
- LazyForEach 实现懒加载
- 精确的更新通知
通过以上技术点的实现,我们成功构建了一个高性能、可维护的搜索组件。该组件不仅实现了基础的搜索功能,还通过合理的架构设计和性能优化,确保了良好的用户体验和开发体验。