微信小程序 自定义组件 标签管理

在这里插入图片描述

环境

小程序环境:

  • 微信开发者工具:RC 1.06.2503281 win32-x64

  • 基础运行库:3.8.1

概述

基础功能

  • 标签增删改查:支持添加/删除单个标签、批量删除、重置默认标签

  • 数据展示:通过对话框展示结构化数据并支持复制

  • 动画系统:添加/删除时带缩放淡入淡出动画

结构分析(WXML)

数据展示优化

  • 使用scroll-view应对长内容

  • user-select开启文本选择

<!--pages/tabs/tabs.wxml-->
<navigation-bar title="标签管理" back="{{false}}" color="black" background="#FFF"></navigation-bar><view class="container"><!-- 新增输入框区域 --><view class="input-area"><input class="tag-input"placeholder="请输入新标签"value="{{inputValue}}"bindinput="handleInput"bindconfirm="handleAdd"/><button size="mini"class="add-btn"bind:tap="handleAdd">添加标签</button></view><!-- 标签容器 --><view class="tag-container" wx:if="{{tags.length}}"><view wx:for="{{tags}}"wx:key="id"class="tag-item"data-index="{{index}}"animation="{{item.animation}}">{{item.name}}<view class="close-btn" bind:tap="handleClose"data-id="{{item.id}}">×</view></view></view><button class="delete-all-btn" bind:tap="handleDeleteAll">删除全部标签</button><button class="reset-btn" bind:tap="handleReset">重置所有标签</button><button class="reset-btn" bind:tap="handleGetAll">获取数据</button>
</view><mp-dialog title="获取的数据" show="{{dialogShow}}" bindbuttontap="dialogButton" buttons="{{buttons}}"><view class="title"><scroll-view scroll-y="true" class="scroll"><text user-select="true">{{tags_data}}</text></scroll-view></view>
</mp-dialog>

逻辑分析(JS)

数据管理

  • ID生成:自增ID保证唯一性

  • 数据持久化:标签数据仅存内存,页面关闭后丢失

  • 数据结构:{ id: number, name: string, animation: any }

交互设计

  • 输入验证:非空校验 + 长度限制(15字)

  • 防误操作:删除全部需二次确认

  • 视觉反馈:按钮点击态(opacity变化)、关闭按钮悬浮效果

// pages/tabs/tabs.js
Page({data: {tags: [],nextId: 1,// 输入数据字段inputValue: '',// 标签数据tags_data: null,// 显示/隐藏 对话框dialogShow: false,// 对话框按钮组buttons: [{text: '关闭'}, {text: '复制'}],},onLoad() {this.handleReset()},// 输入框内容变化handleInput(e) {this.setData({inputValue: e.detail.value.trim() // 自动去除首尾空格});},// 添加新标签handleAdd() {const newTag = this.data.inputValue;// 验证输入内容if (!newTag) {wx.showToast({title: '请输入标签内容',icon: 'none'});return;}if (newTag.length > 15) {wx.showToast({title: '请不要输入过长的内容',icon: 'none',duration: 1500});return;}// 创建动画const animation = wx.createAnimation({duration: 400,timingFunction: 'ease-out'});// 初始状态(隐藏状态)animation.opacity(0).scale(0.5).step();// 生成新标签const newItem = {id: this.data.nextId++,name: newTag,animation: animation.export() // 导出动画对象};// 先添加带动画的数据this.setData({tags: [...this.data.tags, newItem],inputValue: ''}, () => {// 在回调中执行显示动画setTimeout(() => {const index = this.data.tags.length - 1;const showAnimation = wx.createAnimation({duration: 400,timingFunction: 'ease-out'});showAnimation.opacity(1).scale(1).step();this.setData({[`tags[${index}].animation`]: showAnimation.export()});// 动画完成后清除动画数据setTimeout(() => {this.setData({[`tags[${index}].animation`]: null});}, 400);}, 50); // 短暂延迟确保初始状态渲染});},// 关闭标签(带动画)handleClose(e) {const id = parseInt(e.currentTarget.dataset.id);const index = this.data.tags.findIndex(item => item.id === id);// 创建动画const animation = wx.createAnimation({duration: 400,timingFunction: 'ease'});animation.opacity(0).scale(0.8).step();// 先执行动画this.setData({[`tags[${index}].animation`]: animation.export()});// 动画完成后移除元素setTimeout(() => {const newTags = this.data.tags.filter(item => item.id !== id);this.setData({ tags: newTags });}, 400);},// 从后往前依次删除标签handleDeleteAll() {if (this.data.tags.length === 0) {wx.showToast({title: '没有可删除的标签',icon: 'none'});return;}wx.showModal({title: '提示',content: '确定要删除所有标签吗?',success: (res) => {if (res.confirm) {this.deleteOneByOne(this.data.tags.length - 1);}}});},// 递归方法:从最后一个开始逐个删除deleteOneByOne(index) {if (index < 0) {return; // 所有标签已删除完毕}const animation = wx.createAnimation({duration: 200,timingFunction: 'ease'});animation.opacity(0).scale(0.8).step();this.setData({[`tags[${index}].animation`]: animation.export()}, () => {setTimeout(() => {// 删除当前标签const newTags = [...this.data.tags];newTags.splice(index, 1);this.setData({ tags: newTags }, () => {// 继续删除前一个标签this.deleteOneByOne(index - 1);});}, 200); // 等待动画完成});},// 重置所有标签handleReset() {this.setData({nextId: 0})this.initTags(['Vue', 'React', 'Angular', 'Flutter', 'UniApp', 'Taro', 'CSDN', '奇妙方程式']);},// 初始化标签方法initTags(labels) {console.log('labels', labels);const tags = labels.map((text, index) => ({id: this.data.nextId++,name: text,animation: null}));this.setData({ tags }, () => {// 在回调中逐个添加动画tags.forEach((_, index) => {setTimeout(() => {this.animateTag(index);}, index * 100); // 每个标签间隔100ms});});},// 执行单个标签的动画animateTag(index) {const animation = wx.createAnimation({duration: 200,timingFunction: 'ease-out'});animation.opacity(0).scale(0.5).step();animation.opacity(1).scale(1).step();this.setData({[`tags[${index}].animation`]: animation.export()});setTimeout(() => {this.setData({[`tags[${index}].animation`]: null});}, 200);},// 获取数据handleGetAll() {let tags = this.data.tags.map(item => ({id: item.id,name: item.name }))console.log('获取的数据', tags);let tags_data = "tags: " + JSON.stringify(tags)this.setData({dialogShow: true,tags_data})},// 对话框 按钮dialogButton(e) {this.setData({dialogShow: false,})let choose = e.detail.item.textif (choose == "复制") {this.copy()}},// 复制 参数信息copy() {wx.setClipboardData({data: this.data.tags_data,success() {wx.getClipboardData({success() {wx.showToast({title: '复制成功',icon: 'success'})}})}})},
});

样式与动画(WXSS)

/* pages/tabs/tabs.wxss */
/* 容器样式 */
.container {padding: 20rpx;
}/* 新增输入区域样式 */
.input-area {display: flex;padding: 30rpx;background: #fff;
}.tag-input {flex: 1;height: 64rpx;padding: 0 20rpx;border: 2rpx solid #eee;border-radius: 8rpx;font-size: 28rpx;margin-right: 20rpx;
}.add-btn {background: #1890ff;color: white;transition: opacity 0.2s;padding: auto;
}.add-btn.active {opacity: 0.8;
}.tag-container {display: flex;flex-wrap: wrap;padding: 30rpx;
}/* 单个标签样式 */
.tag-item {position: relative;background: #e7f3ff;border-radius: 8rpx;padding: 12rpx 50rpx 12rpx 20rpx;color: #1890ff;transition: all 0.4s cubic-bezier(0.18, 0.89, 0.32, 1.28);margin: 10rpx;opacity: 0;
}/* 隐藏状态动画 */
.tag-item.hidden {opacity: 0;transform: scale(0.8);pointer-events: none;
}.close-btn {position: absolute;right: 8rpx;top: 50%;transform: translateY(-50%);width: 32rpx;height: 32rpx;line-height: 32rpx;text-align: center;border-radius: 50%;background: #ff4d4f;color: white;font-size: 24rpx;opacity: 0.8;transition: opacity 0.2s;
}.close-btn.active {opacity: 1;transform: translateY(-50%) scale(0.9);
}.reset-btn {margin: 20rpx auto;width: 70%;background: #1890ff;color: white;
}/* 删除全部按钮样式 */
.delete-all-btn {margin: 20rpx auto;width: 40%;background: #ff4d4f;color: white;
}.title {text-align: left;margin-top: 10px;
}.scroll {height: 300px;width: 100%;margin-bottom: 15px;
}.weui-dialog__btn_primary {background-color: #07c160;color: #fff;
}

json

{"usingComponents": {"navigation-bar": "/components/navigation-bar/navigation-bar","mp-dialog": "weui-miniprogram/dialog/dialog"}
}

部分代码由deepseek辅助生成

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/79436.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

wpf CommandParameter 传递MouseWheelEventArgs参数 ,用 MvvmLight 实现

在 WPF 中使用 MVVM Light 框架传递 MouseWheelEventArgs 参数至 CommandParameter,可通过以下步骤实现: ‌1. XAML 中配置事件绑定‌ 在控件上通过 EventToCommand 绑定鼠标滚轮事件,并启用 PassEventArgsToCommand 属性以传递事件参数: <!-- 命名空间声明 --> x…

vmware diffy配置ollama 本机ip无法访问

防火墙直接关闭 本地测试&#xff0c;给它直接关了 ollama配置 vim /etc/systemd/system/ollama.service这是的配置 [Unit] DescriptionOllama Service Afternetwork-online.target[Service] Environment"OLLAMA_HOST0.0.0.0:11434" #Environment"OLLAMA_OR…

React--》掌握react构建拖拽交互的技巧

在这篇文章中将深入探讨如何使用react-dnd&#xff0c;从基础的拖拽操作到更复杂的自定义功能带你一步步走向实现流畅、可控且用户友好的拖拽体验,无论你是刚接触拖拽功能的初学者还是想要精细化拖拽交互的经验开发者&#xff0c;都能从中找到适合自己的灵感和解决方案。 目录 …

数据结构与算法:回溯

回溯 先给出一些leetcode算法题&#xff0c;以后遇见了相关题目再往上增加 主要参考代码随想录 2.1、组合问题 关于去重&#xff1a;两种写法的性能分析 需要注意的是&#xff1a;使用set去重的版本相对于used数组的版本效率都要低很多&#xff0c;大家在leetcode上提交&#x…

iview 分页改变每页条数时请求两次问题

问题 在iview page分页的时候&#xff0c;修改每页条数时&#xff0c;会发出两次请求。 iview 版本是4.0.0 原因 iview 的分页在调用on-page-size-change之前会调用on-Change。默认会先调用on-Change回到第一页&#xff0c;再调用on-page-size-change改变分页显示数量 此时就会…

一周学会Pandas2 Python数据处理与分析-Pandas2复杂数据查询操作

锋哥原创的Pandas2 Python数据处理与分析 视频教程&#xff1a; 2025版 Pandas2 Python数据处理与分析 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 前面我们学了.loc[]等几个简单的数据筛选操作&#xff0c;但实际业务需求往 往需要按照一定的条件甚至复杂的组合条件…

【Vue bug】:deep()失效

vue 组件中使用了 element-plus 组件 <template><el-dialog:model-value"visible":title"title":width"width px":before-close"onClose"><div class"container" :style"{height:height px}"&g…

Trae 安装第三方插件支持本地部署的大语言模型

Trae 安装第三方插件支持本地部署的大语言模型 0. 引言1. 安装插件 0. 引言 字节发布的 Trae IDE 一直不支持本地部署的的大语言模型。 Qwen3 刚刚发布&#xff0c;想在 Trae 中使用本地部署的 Qwen3&#xff0c;我们可以在 Trae 中安装其他插件。 1. 安装插件 我们可以安装…

JavaScript 中的 Proxy 与 Reflect 教程

目录 get 和 set 捕获器详解 为什么要用 Reflect? 使用语法间接调用内部方法 使用 Reflect 直接调用内部方法 对比总结: Reflect API 及其与 Proxy 的配合 Proxy 的典型应用场景 Proxy 是 ES6 引入的一种元编程特性。它允许创建一个代理对象来包装目标对象,并拦截对目标…

基于STM32的心电图监测系统设计

摘要 本论文旨在设计一种基于 STM32 微控制器的心电图监测系统&#xff0c;通过对人体心电信号的采集、处理和分析&#xff0c;实现对心电图的实时监测与显示。系统采用高精度的心电信号采集模块&#xff0c;结合 STM32 强大的数据处理能力&#xff0c;能够有效去除噪声干扰&a…

C语言----操作符详解(万字详解)

目录 1. 操作符的分类 2. 二进制和进制转换 3. 原码 反码 补码 4. 移位操作符 4.1 左移操作符 >> 4.2 右移操作符 >> 5. 位操作符 5.1 按位与 & 5.2 按位或 | 5.3 按位异或 ^ 5.4 按位取反 ~ 练习 整数存储在内存中二进制中1的个数 练习 二进制位…

【进阶】C# 委托(Delegate)知识点总结归纳

1. 委托的基本概念 定义&#xff1a;委托是一种类型安全的函数指针&#xff0c;用于封装方法&#xff08;静态方法或实例方法&#xff09;。 核心作用&#xff1a;允许将方法作为参数传递&#xff0c;实现回调机制和事件处理。 类型安全&#xff1a;委托在编译时会检查方法签…

WebRTC 服务器之Janus视频会议插件信令交互

1.基础知识回顾 WebRTC 服务器之Janus概述和环境搭建-CSDN博客 WebRTC 服务器之Janus架构分析-CSDN博客 2.插件使用流程 我们要使⽤janus的功能时&#xff0c;通常要执⾏以下操作&#xff1a; 1. 在你的⽹⻚引入 Janus.js 库&#xff0c;即是包含janus.js&#xff1b; <…

Go语言中的无锁数据结构与并发效率优化

1. 引言 在高并发系统开发中&#xff0c;性能瓶颈往往出现在并发控制上。作为一个有着10年Go开发经验的后端工程师&#xff0c;我见证了无数因锁竞争导致的性能问题&#xff0c;也亲历了无锁编程为系统带来的巨大提升。 传统的锁机制就像是十字路口的红绿灯——虽然能确保安全…

STM32部分:2、环境搭建

飞书文档https://x509p6c8to.feishu.cn/wiki/DQsBw76bCiWaO4kS8TXcWDs0nAh Keil MDK用于编写代码&#xff0c;编译代码芯片支持包&#xff0c;用于支持某类芯片编程支持STM32CubeMX用于自动生成工程&#xff0c;减少手动重复工作 STM32F1系列芯片支持包 软件下载 直接下载&am…

U3D工程师简历模板

模板信息 简历范文名称&#xff1a;U3D工程师简历模板&#xff0c;所属行业&#xff1a;其他 | 职位&#xff0c;模板编号&#xff1a;B29EPQ 专业的个人简历模板&#xff0c;逻辑清晰&#xff0c;排版简洁美观&#xff0c;让你的个人简历显得更专业&#xff0c;找到好工作。…

Java设计模式: 实战案例解析

Java设计模式: 实战案例解析 在软件开发中&#xff0c;设计模式是一种用来解决特定问题的可复用解决方案。它们是经过实践验证的最佳实践&#xff0c;能够帮助开发人员设计出高质量、易于维护的代码。本文将介绍一些常见的Java设计模式&#xff0c;并通过实战案例解析它们在实际…

Vue3源码学习5-不使用 `const enum` 的原因

文章目录 前言✅ 什么是 const enum❌ 为什么 Vue 3 不使用 const enum1. &#x1f4e6; **影响构建工具兼容性**2. &#x1f501; **难以做模块间 tree-shaking**3. &#x1f9ea; **调试困难**4. &#x1f4e6; **Vue 是库&#xff0c;不掌控用户配置** ✅ 官方推荐做法&…

C++学习:六个月从基础到就业——C++11/14:lambda表达式

C学习&#xff1a;六个月从基础到就业——C11/14&#xff1a;lambda表达式 本文是我C学习之旅系列的第四十篇技术文章&#xff0c;也是第三阶段"现代C特性"的第二篇&#xff0c;主要介绍C11/14中引入的lambda表达式。查看完整系列目录了解更多内容。 引言 Lambda表达…

AIDC智算中心建设:计算力核心技术解析

目录 一、智算中心发展概览 二、计算力核心技术解析 一、智算中心发展概览 智算中心是人工智能发展的关键基础设施&#xff0c;基于人工智能计算架构&#xff0c;提供人工智能应用所需算力服务、数据服务和算法服务的算力基础设施&#xff0c;融合高性能计算设备、高速网络以…