# SwellBtn **Repository Path**: zhan-weisong/swell-btn ## Basic Information - **Project Name**: SwellBtn - **Description**: 鸿蒙JS组件——长按膨胀按钮组件 - **Primary Language**: JavaScript - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2022-10-23 - **Last Updated**: 2023-05-01 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 前言 今天给大家分享下我个人在学习鸿蒙应用开发初期写的一个小组件,希望能帮助大家学习如何完成一个自定义组件。 ## 组件介绍 常见的长按事件onlongpress不能设定长按的时间,除此之外,绑定了长按事件的按钮在完成长按操作前后并没有明显的样式变化,用户无法从中得到长按操作进行的反馈,在有此类需求的场景时是无法满足的。因此我根据这些需求开发一个自定义长按按钮组件,同时兼顾按钮和进度条两个功能。最初的设计图如下: ![组件设计图.png](resource/组件设计图.png) ## 项目结构 ![项目结构.png](resource/项目结构.png) ## 组件开发 ### 页面布局:使用stack栈布局,以canvas画布做背景,button按钮组件在上。 ``` ``` ### 组件属性参数设置 | 参数名 | 描述 | 参数类型 | 默认值 | | ------------- | --------------------- | -------- | ------- | | duration | 长按事件触发时长 | Number | 2000 | | btnColor | 按钮颜色 | String | #9D9D9D | | ringColor | 长按过程中外圈颜色 | String | #82D900 | | finishColor | 事件就绪时外圈阴影颜色 | String | #FFFF37 | ### 动作拆解:在按钮上绑定ontouchstart事件和ontouchend事件,以实现长按操作。 - 点击动作:点击时显示外圈,按钮逐渐变大,直至达到设定时长膨胀至最大。 ```JS Show() { //打印按钮当前状态为“正在点击” this.$emit('btnType', {btnstate: '点击'}); console.log("————按钮状态:点击中————"); const el = this.$refs.canvas1; const ctx = el.getContext('2d', { antialias: true }); //画外圈,用于提示长按进度 ctx.lineWidth = 5; ctx.strokeStyle = this.ringColor; ctx.beginPath(); ctx.arc(150, 150, 100, 0, 6.28); ctx.stroke(); console.log("外圈显现,按钮膨胀"); //膨胀动画 let options1 = { duration: this.duration, //运行时间 easing: 'linear', //动画时间曲线 fill: 'forwards', //指定动画起始态或终止态 iterations: 1, //播放次数 begin: 50.0, //播放起点 end: 100.0, //播放终点 } this.animator.update(options1); let _this = this; this.animator.onframe = function(value) { _this.divR = value; //外部色圈显现,提示启动事件准备就绪 if(100 == _this.divR) { ctx.beginPath(); ctx.arc(150, 150, 120, 0, 6.28); ctx.shadowBlur = 1; ctx.shadowColor = _this.finishColor; ctx.stroke(); console.log("准备就绪,松开触发"); } }; this.animator.play(); }, ``` - 松开动作:长按达到设定时间,生成外圈阴影,松开即可启动事件;若中途松开,按钮瞬间恢复到初始状态。 ```JS Erase() { //打印按钮当前状态为“松开” this.$emit('btnType', {btnstate: '松开'}); console.log("————按钮状态:松开————"); //重置动画 let options2 = { duration: 0, //运行时间 easing: 'linear', //动画时间曲线 fill: 'forwards', //指定动画起始态或终止态 iterations: 1, //播放次数 end: 50.0, //播放终点为初始起点 } this.animator.update(options2); let _this = this; this.animator.onframe = function(value) { _this.divR = value; }; //成功启动事件 if(100 == _this.divR) { this.disabled = true; //按钮失效,不可点击 //向父组件传递事件的状态值为true this.$emit('eventType', {eventstate: true}); console.log("启动成功"); } //启动失败,擦除提示外圈 else { const el = this.$refs.canvas1; const ctx = el.getContext('2d'); ctx.clearRect(45, 45, 210, 210); console.log("启动失败") console.log("外圈擦除,按钮重置"); } }, ``` ## 组件引用 - 引用声明 ``` ``` - 参数传递 ``` ``` - 注意,在官方文档中对在父组件中绑定子组件的事件方法或属性命名时,有以下要求: ![关于命名要求.png](resource/关于命名要求.png) ## 最终效果 ![效果展示.gif](resource/效果展示.gif) ## 结语 该自定义组件的开发较为简单,而自定义组件开发的意义在于解决某些特定场景的需求,希望这篇文章能帮助大家理解自定义组件设计和开发的流程。