# OpenHarmonyOS - ArkUI基于JSPAI实现的色相滑块组件 **Repository Path**: yango520/ygSlider ## Basic Information - **Project Name**: OpenHarmonyOS - ArkUI基于JSPAI实现的色相滑块组件 - **Description**: OpenHarmonyOS - ArkUI基于JSPAI实现的色相滑块组件 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 3 - **Forks**: 0 - **Created**: 2022-07-04 - **Last Updated**: 2024-01-05 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # OpenHarmonyOS - ArkUI基于JSPAI实现的色相滑块组件 ## 前言 因为项目上需要,并且该组件目前还没见到社区有其他童鞋写过,所以想着自己造一下轮子,帮openHarmony建立生态出一份微薄之力。组件其实基本功能已经实现,但是并非最理想的,后续会进行维护更新,继续完善更多功能。 ## 开发环境说明 - 工具版本:OpenHarmony DevEco Studio 3.0 Beta3 - SDK版本:3.0.0.901(API Version 8 Beta3) - 组要组件:组件名称yg-slider ## 展示效果 ![展示效果gif](./files/g.gif) ## 属性 | 属性名 | 类型 | 默认值 | 作用 | | ---- | ---- | ---- | ---- | | g-color | Array | [] | 渐变色值组,eg: #ff9800 | | step | Number | 20 | 步长,g-color属性里每两渐变色之间步长,步长越大 越精准,渲染压力越大 | | show-card | Boolean | false | 是否显示滑块上方的颜色卡片 | ## 组件事件 | 属性名 | 类型 | 返回值 | 备注 | | ---- | ---- | ---- | ---- | | get-result | Function | {num:String, rgbColor:String, hexColor:String, hex:Object} | num: 当前滑块下标值, rgbColor: rgb颜色值【rgb(0,0,0)】, hex颜色值【##ff9800】,hex: R,G,B对应16进制hex值 | ## 调用实现 在需要引用的hml中element引入组件 ```html
``` js中的传参和绑定的事件 ```javascript import Log from "../../common/utils/log" const lg = new Log('index页面'); // 可以传入一个值作为该页面的标识 export default { data: { gColor: [ '#FF0000', '#FFE300', '#74FF00', '#00FFA6', '#00FDFF', '#0034FC', '#4200FF', '#BC00FF', '#FD00FF', '#FF0000' ], step: 20, showCard: true, }, onInit() { }, getResult(res){ lg.info(res._detail) }, } ``` - gColor是渐变色值组,这里需要跟css样式里的一至。 - 本来尝试在内联样式绑定linear-gradient,切报错提示无法绑定渐变的内联样式 - 该问题已提Issues:https://gitee.com/openharmony/docs/issues/I5F8KC?from=project-issue ## 实现思路 1. 根据UI写好样式。 2. 绑定滑块的触摸事件 3. 获取滑块条的长度和位置,和当前触摸的位置做比较,通过计算获取滑块所在的位置 4. 封装获取两颜色之间的渐变值组 5. 根据渐变值组总长度,设置为滑块的刻度值。 6. 滑块滑动到某位置计算该位置刻度,得到渐变值组的对应色值,赋值给颜色卡片展示 ## 实现过程 ### 1. 根据UI写好页面和样式 ygSlider.hml页面 ```html
``` ygSlider.css ```css .yg-slider{ width: 320px; } .yg-slider-bg{ background: linear-gradient(90deg, #FF0000, #FFE300, #74FF00, #00FFA6, #00FDFF, #0034FC, #4200FF, #BC00FF, #FD00FF,#FF0000); width: 100%; height: 4px; border-radius: 16px; } .yg-slider-button{ /* 设置热区 */ position: absolute; top: -16px; transform: translateX(-18px); left: 0%; width: 36px; height: 36px; background-color: rgba(52,0,250,.5); border-radius: 16px; display: flex; justify-content: center; align-items: center; } .yg-slider-button-child{ border-radius: 8px; width: 16px; height: 16px; background-color: rgba(255,255,255,1); box-shadow: 0 0 1px 1px rgba(0,0,0,.2); } .yg-slider-color{ position: absolute; top: -80px; transform: translateX(-20px); width: 40px; height: 40px; border-radius: 40px; background-color: red; } ``` ![](./files/i1.png) ### 2. 绑定滑块的触摸事件 ygSlider.hml ```html
``` ygSlider.js 在sliderStart事件里,通过getBoundingClientRect()方法获取滑块条的宽高和位置 ```javascript sliderStart(){ const t = this.$refs.ygSlider.getBoundingClientRect(); this.startX = t.left; this.endX = t.left + t.width; this.sliderW = t.width; }, ``` 在sliderMove事件里设置pct为滑块按钮的位置,并确保按钮不会超出滑块条 ```javascript sliderMove(e){ let x = e.touches[0].globalX; let s_x = x - this.startX; if(x <= this.startX){ this.pct = 0; } else if(x >= this.endX){ this.pct = 100; } else { this.pct = s_x * 100 / this.sliderW; } }, ``` ### 3. 封装获取两颜色之间的渐变值组的方法 封装颜色渐变之间值方法,有备注。这个方法在之前的一个组件中就开始实现了,搞好需要就拿过来修改了一下。 传送门:https://gitee.com/yango520/compontentCircle ```javascript /** * @description: 封装颜色渐变之间值 * @param {String} startColor 开始颜色hex * @param {Number} endColor 结束颜色hex * @param {Number} step 渐变精度 * @return {Array} */ gradientColor(startColor,endColor,step){ let startRGB = this.hexToRgb(startColor);//转换为rgb数组模式 let endRGB = this.hexToRgb(endColor); let sR = (endRGB[0]-startRGB[0])/step;//总差值 let sG = (endRGB[1]-startRGB[1])/step; let sB = (endRGB[2]-startRGB[2])/step; var colorArr = []; for(var i=0;i -1){ var aNum = rgb.replace(/#/,'').toUpperCase().split(''); if(aNum.length === 6){ return { R: aNum[0] + aNum[1], G: aNum[2] + aNum[3], B: aNum[4] + aNum[5] }; }else if(aNum.length === 3){ return { R: aNum[0] + aNum[0], G: aNum[1] + aNum[1], B: aNum[2] + aNum[2] }; } else { return rgb; } } else if(/^(rgb|RGB)/.test(rgb)){ let aColor = rgb.replace(/(?:\(|\)|rgb|RGB)*/g,"").split(","); let R = this.getHexNumber(aColor[0]); let G = this.getHexNumber(aColor[1]); let B = this.getHexNumber(aColor[2]); return {R,G,B}; } else { return rgb; } }, getHexNumber(str){ if(typeof str === 'string'){ return Number(str).toString(16).padStart(2,'0').toUpperCase() } else { return str; } } ``` 因为传进来的颜色组不止两个,所以做了一个循环处理 ```javascript onPageShow(){ this.setColorList(); }, //将传进来的颜色生成一个渐变色值组 setColorList(){ for(let i = 0; i < this.gColor.length - 1; i++){ let res = this.gradientColor(this.gColor[i], this.gColor[i+1], this.step) this.colorList.push(...res) } // 设置滑块可以展示的最大值 this.maxValue = this.colorList.length - 1; // 展示卡片默认显示数组里的第一个色值 this.nowColor = this.colorList[0] }, ``` ### 4. 根据渐变值组总长度,设置为滑块的刻度值 ```javascript sliderMove(e){ let x = e.touches[0].globalX; let s_x = x - this.startX; if(x <= this.startX){ this.pct = 0; } else if(x >= this.endX){ this.pct = 100; } else { this.pct = s_x * 100 / this.sliderW; } // 计算当前的刻度值 let r = this.getValue(s_x); // 设置滑块按钮滑到所在的位置的的色值 this.nowColor = this.colorList[r]; //最后将每次滑块所变更的值都抛出给父组件去调用做相应的处理 this.$emit('getResult', { num: r, rgbColor: this.nowColor, hexColor: this.rgbToHex(this.nowColor), hex: this.colorToHex(this.nowColor), }) }, sliderEnd(e){ let x = e.touches[0].globalX; let s_x = x - this.startX; let r = this.getValue(s_x); this.nowColor = this.colorList[r]; this.$emit('getResult', { num: r, rgbColor: this.nowColor, hexColor: this.rgbToHex(this.nowColor), hex: this.colorToHex(this.nowColor), }) }, // 获取当前刻度值 getValue(s_x){ let r = Math.ceil(this.maxValue * s_x / this.sliderW); if(r <= 0){ r = 0; } else if(r >= this.maxValue) { r = this.maxValue; } return r; }, ``` ## 代码地址 [https://gitee.com/yango520/ohos-panoramic](https://gitee.com/yango520/ohos-panoramic) ## 总结 难点:逻辑都比较简单,主要难点在于就是计算两颜色值之间的渐变色值组。 和计算当前刻度,这里需要注意三个值 - 滑块按钮的当前位置 0% -100% - 滑块条的长度,比如是320px - 滑块的刻度 三者之间需要进行计算转换。