09 HarmonyOS NEXT 仿uv-ui Tag组件开发教程系列(三)

温馨提示:本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦!

文章目录

    • Tag组件实战应用与最佳实践
      • [1. 复杂场景应用](#1. 复杂场景应用)
        • [1.1 标签筛选系统](#1.1 标签筛选系统)
      • [2. 性能优化实践](#2. 性能优化实践)
        • [2.1 状态管理优化](#2.1 状态管理优化)
        • [2.2 渲染性能优化](#2.2 渲染性能优化)
      • [3. 实用功能扩展](#3. 实用功能扩展)
        • [3.1 拖拽排序](#3.1 拖拽排序)
        • [3.2 动画效果](#3.2 动画效果)
      • [4. 最佳实践总结](#4. 最佳实践总结)
        • [4.1 代码组织](#4.1 代码组织)
        • [4.2 测试建议](#4.2 测试建议)
      • [5. 常见问题解决](#5. 常见问题解决)
    • 总结

Tag组件实战应用与最佳实践

1. 复杂场景应用

1.1 标签筛选系统
typescript 复制代码
// 多选标签组实现
import { Tag } from "../components/AutoTags"
interface tagGroupClass {
    groupId: string,
    title: string,
    tags: tagClass[]
}
interface tagClass {
    id: string,
    text: string,
    type: string
    groupId?: string
}

@Component
export struct FilterTags {
    @State selectedTags: Set<string> = new Set()
    @State tagGroups: tagGroupClass[] = [
        {
            groupId: 'g1',
            title: '类型',
            tags: [
                { id: '1', text: '重要', type: 'primary' },
                { id: '2', text: '普通', type: 'default' }
            ]
        },
        {
            groupId: 'g2',
            title: '状态',
            tags: [
                { id: '3', text: '进行中', type: 'warning' },
                { id: '4', text: '已完成', type: 'success' }
            ]
        }
    ]

    build() {
        Column({ space: 16 }) {
            ForEach(this.tagGroups, (group) => {
                Column({ space: 8 }) {
                    Text(group.title)
                        .fontSize(16)
                        .fontWeight(FontWeight.Medium)

                    Flex({ wrap: FlexWrap.Wrap }) {
                        ForEach(group.tags, (tag:tagClass) => {
                            Tag({
                                text: tag.text,
                                type: tag.type ?? 'default'
                            }).onClick(() => {
                                this.handleTagClick(tag.id)
                            })
                        })
                    }
                }
            })
        }
    }

    private handleTagClick(tagId: string) {
        if (this.selectedTags.has(tagId)) {
            this.selectedTags.delete(tagId)
        } else {
            this.selectedTags.add(tagId)
        }
        this.notifyFilterChange()
    }

    private notifyFilterChange() {
        // 处理筛选逻辑
        console.log(`筛选条件:${Array.from(this.selectedTags).join(',')}`)
    }
}

2. 性能优化实践

2.1 状态管理优化
typescript 复制代码
// 优化前
@State private tags: Array<string> = []

// 优化后:使用Set提高查找效率
@State private tagSet: Set<string> = new Set()

// 优化数据结构
interface TagItem {
    id: string
    text: string
    type: string
    selected?: boolean
}

// 使用Map优化查找
@State private tagMap: Map<string, TagItem> = new Map()
2.2 渲染性能优化
typescript 复制代码
@Component
struct OptimizedTags {
    // 使用@Builder抽取复用组件
    @Builder
    private TagItem(tag: TagItem) {
        Tag({
            text: tag.text,
            type: tag.type,
            closable: true
        })
        .margin(4)
    }

    // 使用懒加载优化大列表渲染
    build() {
        List({ space: 8 }) {
            LazyForEach(this.dataSource, (tag: TagItem) => {
                ListItem() {
                    this.TagItem(tag)
                }
            }, (tag: TagItem) => tag.id)
        }
    }
}

3. 实用功能扩展

3.1 拖拽排序
typescript 复制代码
@Component
struct DraggableTags {
    @State tags: TagClass[] = []
    @State dragIndex: number = -1

    build() {
        Flex({ wrap: FlexWrap.Wrap }) {
            ForEach(this.tags, (tag, index) => {
                Tag({
                    text: tag.text,
                    type: tag.type
                })
                .gesture(
                    PanGesture()
                        .onActionStart(() => {
                            this.dragIndex = index
                        })
                        .onActionUpdate((event: GestureEvent) => {
                            // 处理拖拽逻辑
                        })
                        .onActionEnd(() => {
                            this.dragIndex = -1
                        })
                )
            })
        }
    }
}
3.2 动画效果
typescript 复制代码
@Component
struct AnimatedTag {
    @State private isVisible: boolean = true
    @State private scale: number = 1

    build() {
        Tag({
            text: '动画标签',
            closable: true,
            onClose: () => {
                animateTo({
                    duration: 300,
                    curve: Curve.EaseInOut,
                    onFinish: () => {
                        this.isVisible = false
                    }
                }, () => {
                    this.scale = 0
                })
            }
        })
        .scale(this.scale)
        .opacity(this.isVisible ? 1 : 0)
    }
}

4. 最佳实践总结

4.1 代码组织
typescript 复制代码
// 集中管理颜色配置
const TagColors = {
    text: {
        default: '#333333',
        primary: '#2468f2',
        // ...
    },
    background: {
        default: '#ffffff',
        primary: '#eef2ff',
        // ...
    },
    // ...
} as const

// 抽取通用逻辑
class TagUtils {
    static getColor(type: string, state: string): string {
        return Reflect.get(TagColors[state], type) || TagColors[state].default
    }

    static validateType(type: string): boolean {
        return ['default', 'primary', 'success', 'warning', 'danger'].includes(type)
    }
}
4.2 测试建议
  1. 单元测试
typescript 复制代码
// 测试颜色系统
describe('TagUtils', () => {
    it('should return correct color', () => {
        expect(TagUtils.getColor('primary', 'text')).toBe('#2468f2')
        expect(TagUtils.getColor('invalid', 'text')).toBe('#333333')
    })

    it('should validate type correctly', () => {
        expect(TagUtils.validateType('primary')).toBe(true)
        expect(TagUtils.validateType('invalid')).toBe(false)
    })
})
  1. 性能测试
  • 大数据量下的渲染性能
  • 频繁状态更新的响应速度
  • 内存占用情况

5. 常见问题解决

  1. 状态同步问题
typescript 复制代码
// 问题:子组件状态未同步到父组件
// 解决:使用双向绑定
@Component
struct ParentComponent {
    @State tags: TagItem[] = []

    build() {
        Column() {
            ChildTags({ tags: $tags })
        }
    }
}

@Component
struct ChildTags {
    @Link tags: TagItem[]
    // ...
}
  1. 性能问题
typescript 复制代码
// 问题:大量标签渲染卡顿
// 解决:使用虚拟列表
@Component
struct VirtualTags {
    private virtualListController: VirtualListController = new VirtualListController()

    build() {
        VirtualList({ controller: this.virtualListController }) {
            ForEach(this.tags, (tag) => {
                TagItem({ tag })
            })
        }
    }
}

总结

在 HarmonyOS NEXT 仿uv-ui Tag组件开发教程系列中我们从零开始开发了Tag组件, 他的扩展性其实还是存在的, 当然在开发过程中需要注意的是,一定要注意性能优化的问题, 其次在案例源码中接口类型其实定义在当前的文件中 ,在正式开发的过程中建议创建一个 Types 文件夹 将定义的接口接口放在该文件夹下进行统一管理

相关推荐
全栈若城6 小时前
29.Harmonyos Next仿uv-ui 组件NumberBox 步进器组件自定义图标
ui·uv·harmonyos next
全栈若城6 小时前
26.Harmonyos Next仿uv-ui 组件NumberBox 步进器组件小数位数设置
ui·uv·harmonyos next
全栈若城9 小时前
31.Harmonyos Next仿uv-ui 组件NumberBox 步进器组件异步操作处理
ui·uv·harmonyos next
全栈若城19 小时前
27. Harmonyos Next仿uv-ui 组件NumberBox 步进器组件禁用状态
ui·uv·harmonyos next
全栈若城19 小时前
11 【HarmonyOS NEXT】 仿uv-ui组件开发之Avatar组件深度剖析(二)
ubuntu·ui·uv·harmonyos next
轻口味1 天前
【每日学点HarmonyOS Next知识】对话框与导航冲突、富文本、字体大小、列表刷新、Scroll包裹文本
pytorch·深度学习·harmonyos·harmonyos next
全栈若城1 天前
24.Harmonyos Next仿uv-ui 组件 NumberBox 步进器组件步长设置
harmonyos next
李洋-蛟龙腾飞公司2 天前
HarmonyOS NEXT开发实战:DevEco Studio中DeepSeek的使用
harmonyos next