OpenHarmony - 基于ArkUI(JS)实现色相滑块组件

系统 OpenHarmony
因为项目上需要,并且该组件目前还没见到社区有其他童鞋写过,所以想着自己造一下轮子,帮OpenHarmony建立生态出一份微薄之力。

​想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com​

前言

因为项目上需要,并且该组件目前还没见到社区有其他童鞋写过,所以想着自己造一下轮子,帮OpenHarmony建立生态出一份微薄之力。组件其实基本功能已经实现,但是并非最理想的,后续会进行维护更新,继续完善更多功能。

开发环境说明

  • 工具版本:OpenHarmony DevEco Studio 3.0 Beta3
  • SDK版本:3.0.0.901(API Version 8 Beta3)
  • 组要组件:组件名称yg-slider

展示效果

#夏日挑战赛# OpenHarmony - 基于ArkUI(JS)实现色相滑块组件-开源基础软件社区

属性

属性名

类型

默认值

作用

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引入组件。

<element name="yg-slider" src="../../common/component/ygSlider/ygSlider"></element>
<div class="container">
<yg-slider
g-color="{{gColor}}"
step="{{step}}"
show-card="{{showCard}}"
@get-result="getResult"
></yg-slider>
</div>

js中的传参和绑定的事件。

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页面:

<div class="container">
<div class="yg-slider" ref="ygSlider" id="ygSlider">
<div class="yg-slider-bg"></div>
<div class="yg-slider-button">
<div class="yg-slider-button-child"></div>
</div>
<div class="yg-slider-color"></div>
</div>
</div>

ygSlider.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;
}

2. 绑定滑块的触摸事件

ygSlider.hml:

<div class="yg-slider-button"
style="left: {{pct}}%;"
@touchstart="sliderStart"
@touchmove="sliderMove"
@touchend="sliderEnd"
>

ygSlider.js:

在sliderStart事件里,通过getBoundingClientRect()方法获取滑块条的宽高和位置。

sliderStart(){
const t = this.$refs.ygSlider.getBoundingClientRect();
this.startX = t.left;
this.endX = t.left + t.width;
this.sliderW = t.width;
},

在sliderMove事件里设置pct为滑块按钮的位置,并确保按钮不会超出滑块条

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、封装获取两颜色之间的渐变值组的方法

封装颜色渐变之间值方法,有备注。这个方法在之前的一个组件中就开始实现了,搞好需要就拿过来修改了一下。

传送门:​​ HarmonyOS 基于JSAPI自定义封装渐变圆环进度条组件​​。

/**
* @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<step;i++){
//计算每一步的hex值
var hex = `rgb(${parseInt((sR*i+startRGB[0]))},${parseInt((sG*i+startRGB[1]))},${parseInt((sB*i+startRGB[2]))})`;
colorArr.push(hex);
}
return colorArr;
},
// 将hex表示方式转换为rgb表示方式(这里返回rgb数组模式)
hexToRgb(sColor){
var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
sColor = sColor.toLowerCase();
if(sColor && reg.test(sColor)){
if(sColor.length === 4){
var sColorNew = "#";
for(var i=1; i<4; i+=1){
sColorNew += sColor.slice(i,i+1).concat(sColor.slice(i,i+1));
}
sColor = sColorNew;
}
//处理六位的颜色值
var sColorChange = [];
for(let i=1; i<7; i+=2){
sColorChange.push(parseInt("0x"+sColor.slice(i,i+2)));
}
return sColorChange;
}else{
return sColor;
}
},
// 将rgb表示方式转换为hex表示方式
rgbToHex(rgb){
var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
if(/^(rgb|RGB)/.test(rgb)){
let aColor = rgb.replace(/(?:\(|\)|rgb|RGB)*/g,"").split(",");
let strHex = "#";
for(let i=0; i<aColor.length; i++){
let hex = this.getHexNumber(aColor[i]);
if(hex === "0"){
hex += hex;
}
strHex += hex;
}
if(strHex.length !== 7){
strHex = rgb;
}
return strHex;
}else if(reg.test(rgb)){
var aNum = rgb.replace(/#/,'').split('');
if(aNum.length === 6){
return rgb;
}else if(aNum.length === 3){
var numHex = "#";
for(let i=0; i<aNum.length; i+=1){
numHex += (aNum[i]+aNum[i]);
}
return numHex;
}
}else{
return rgb;
}
},
//将hexColor或者rgbColor转换hex的RGB值对象
colorToHex(rgb){
if(rgb && rgb.indexOf('#') > -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;
}
}

因为传进来的颜色组不止两个,所以做了一个循环处理。

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、根据渐变值组总长度,设置为滑块的刻度值

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;
},

代码地址

​#夏日挑战赛# openHarmony - 基于ArkUI(JS)实现色相滑块组件​​。

总结

难点:逻辑都比较简单,主要难点在于就是计算两颜色值之间的渐变色值组。

和计算当前刻度,这里需要注意三个值:

  • 滑块按钮的当前位置 0% -100%
  • 滑块条的长度,比如是320px
  • 滑块的刻度

三者之间需要进行计算转换。

​想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com​​。

责任编辑:jianghua 来源: 鸿蒙社区
相关推荐

2022-09-15 15:04:16

ArkUI鸿蒙

2022-09-20 14:35:59

ArkUI鸿蒙JS

2022-10-17 14:36:09

ArkUI虚拟摇杆组件

2022-08-04 13:55:08

拼数字小游戏鸿蒙

2024-01-11 15:54:55

eTS语言TypeScript应用开发

2022-10-24 14:49:54

ArkUI心电图组件

2022-05-27 14:55:34

canvas画布鸿蒙

2022-09-14 15:17:26

ArkUI鸿蒙

2022-08-05 19:27:22

通用API鸿蒙

2022-09-21 14:51:21

ArkUI信件弹出

2022-07-13 16:24:12

ArkUI(JS)打地鼠游戏

2022-09-16 15:34:32

CanvasArkUI

2022-07-25 14:17:04

JS应用开发

2022-08-22 17:28:34

ArkUI鸿蒙

2022-05-26 14:50:15

ArkUITS扩展

2022-02-14 14:14:02

鸿蒙数据可视化JS

2023-01-03 07:40:27

自定义滑块组件

2022-09-09 14:47:50

CircleArkUI

2022-07-06 20:24:08

ArkUI计时组件

2022-11-02 16:06:54

ArkUIETS
点赞
收藏

51CTO技术栈公众号