# 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
## 展示效果

## 属性
| 属性名 | 类型 | 默认值 | 作用 |
| ---- | ---- | ---- | ---- |
| 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;
}
```

### 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
- 滑块的刻度
三者之间需要进行计算转换。