This commit is contained in:
dev
2025-10-28 09:25:46 +08:00
commit 9431e325df
1089 changed files with 143917 additions and 0 deletions
+18
View File
@@ -0,0 +1,18 @@
## 1.0.82023-08-14
1. 取消scrollTop参数,使用clientY
## 1.0.72023-08-13
1. 增加scrollTop参数,设置滚动条的位置。不设置如果页面出现滚动就需要传该值,会出现颜色面板无法进行选颜色的情况。
## 1.0.62023-08-04
1. 修复颜色值错误的BUG
## 1.0.52023-08-02
1. 更新依赖
## 1.0.42023-07-02
uv-pick-color 由于弹出层uv-popup的修改,打开和关闭方法更改,详情参考文档:https://www.uvui.cn/components/pickColor.html
## 1.0.32023-06-12
1. 修复在选择颜色时候百度小程序报错的BUG
## 1.0.22023-05-27
1. 兼容非移动h5端不能选择的BUG
## 1.0.12023-05-24
1. 去掉template中存在的this.导致头条小程序编译警告
## 1.0.02023-05-23
uv-pick-color 新增颜色选择器
@@ -0,0 +1,217 @@
/**
* hsb 转 rgb
* @param {Object} hsb 颜色模式 H(hues)表示色相,S(saturation)表示饱和度,Bbrightness)表示亮度
*/
export function hsbToRgb(hsb) {
let rgb = {};
let h = hsb.h;
let s = hsb.s * 255 / 100;
let v = hsb.b * 255 / 100;
if (s == 0) {
rgb.r = rgb.g = rgb.b = v;
} else {
let t1 = v;
let t2 = ((255 - s) * v) / 255;
let t3 = ((t1 - t2) * (h % 60)) / 60;
if (h == 360) h = 0;
if (h < 60) {
rgb.r = t1;
rgb.b = t2;
rgb.g = t2 + t3;
} else if (h < 120) {
rgb.g = t1;
rgb.b = t2;
rgb.r = t1 - t3;
} else if (h < 180) {
rgb.g = t1;
rgb.r = t2;
rgb.b = t2 + t3;
} else if (h < 240) {
rgb.b = t1;
rgb.r = t2;
rgb.g = t1 - t3;
} else if (h < 300) {
rgb.b = t1;
rgb.g = t2;
rgb.r = t2 + t3;
} else if (h < 360) {
rgb.r = t1;
rgb.g = t2;
rgb.b = t1 - t3;
} else {
rgb.r = 0;
rgb.g = 0;
rgb.b = 0;
}
}
return {
r: Math.round(rgb.r),
g: Math.round(rgb.g),
b: Math.round(rgb.b)
};
}
/**
* rgb转hsb
* @param {Object} rgb 颜色rgb值
*/
export function rgbToHsb(rgb) {
let hsb = {
h: 0,
s: 0,
b: 0
};
let h = 0,
s = 0,
v = 0;
let r = rgb.r,
g = rgb.g,
b = rgb.b;
let min = Math.min(rgb.r, rgb.g, rgb.b);
let max = Math.max(rgb.r, rgb.g, rgb.b);
v = max / 255;
if (max === 0) {
s = 0;
} else {
s = 1 - (min / max);
}
if (max === min) {
h = 0; //事实上,max===min的时候,h无论为多少都无所谓
} else if (max === r && g >= b) {
h = 60 * ((g - b) / (max - min)) + 0;
} else if (max === r && g < b) {
h = 60 * ((g - b) / (max - min)) + 360
} else if (max === g) {
h = 60 * ((b - r) / (max - min)) + 120
} else if (max === b) {
h = 60 * ((r - g) / (max - min)) + 240
}
hsb.h = parseInt(h);
hsb.s = parseInt(s * 100);
hsb.b = parseInt(v * 100);
return hsb;
}
/**
* rgb 转 二进制 hex
* @param {Object} rgb
*/
export function rgbToHex(rgb) {
let hex = [rgb.r.toString(16), rgb.g.toString(16), rgb.b.toString(16)];
hex.map(function(str, i) {
if (str.length == 1) {
hex[i] = '0' + str;
}
});
return hex.join('');
}
//预制颜色
export const colorList = [{
r: 60,
g: 156,
b: 255,
a: 1
}, {
r: 245,
g: 108,
b: 108,
a: 1
}, {
r: 249,
g: 174,
b: 61,
a: 1
}, {
r: 90,
g: 199,
b: 37,
a: 1
}, {
r: 144,
g: 147,
b: 153,
a: 1
}, {
r: 48,
g: 49,
b: 51,
a: 1
}, {
r: 233,
g: 30,
b: 99,
a: 1
}, {
r: 156,
g: 39,
b: 176,
a: 1
}, {
r: 103,
g: 58,
b: 183,
a: 1
}, {
r: 63,
g: 81,
b: 181,
a: 1
}, {
r: 0,
g: 188,
b: 212,
a: 1
}, {
r: 0,
g: 150,
b: 136,
a: 1
}, {
r: 139,
g: 195,
b: 74,
a: 1
}, {
r: 205,
g: 220,
b: 57,
a: 1
}, {
r: 255,
g: 235,
b: 59,
a: 1
}, {
r: 255,
g: 193,
b: 7,
a: 1
}, {
r: 255,
g: 152,
b: 0,
a: 1
}, {
r: 255,
g: 87,
b: 34,
a: 1
}, {
r: 121,
g: 85,
b: 72,
a: 1
}, {
r: 158,
g: 158,
b: 158,
a: 1
}, {
r: 0,
g: 0,
b: 0,
a: 0.5
}, {
r: 0,
g: 0,
b: 0,
a: 0
}]
@@ -0,0 +1,47 @@
export default {
props: {
// 颜色选择器初始颜色
color: {
type: Object,
default: () => {
return { r: 0, g: 0, b: 0, a: 0 }
}
},
// 预制颜色
prefabColor: {
type: Array,
default: () => []
},
// 是否允许点击遮罩关闭
closeOnClickOverlay: {
type: Boolean,
default: true
},
// 顶部标题
title: {
type: String,
default: ''
},
// 取消按钮的文字
cancelText: {
type: String,
default: '取消'
},
// 确认按钮的文字
confirmText: {
type: String,
default: '确定'
},
// 取消按钮的颜色
cancelColor: {
type: String,
default: '#909193'
},
// 确认按钮的颜色
confirmColor: {
type: String,
default: '#3c9cff'
},
...uni.$uv?.props?.pickColor
}
}
@@ -0,0 +1,551 @@
<template>
<!-- #ifndef APP-NVUE -->
<uv-popup
ref="pickerColorPopup"
mode="bottom"
:close-on-click-overlay="closeOnClickOverlay"
@change="popupChange">
<view class="uv-pick-color">
<uv-toolbar
:show="showToolbar"
:cancelColor="cancelColor"
:confirmColor="confirmColor"
:cancelText="cancelText"
:confirmText="confirmText"
:title="title"
:show-border="true"
@cancel="cancelHandler"
@confirm="confirmHandler"></uv-toolbar>
<view
class="uv-pick-color__box"
:style="{
background:`rgb(${bgcolor.r},${bgcolor.g},${bgcolor.b})`
}"
>
<!-- #ifdef H5 -->
<view
class="uv-pick-color__box__bg drag-box"
@tap.stop.prevent="touchstart($event, 0)"
@touchstart.stop.prevent="touchstart($event, 0)"
@touchmove.stop.prevent="touchmove($event, 0)"
@touchend.stop.prevent="touchend($event, 0)"
>
<!-- #endif -->
<!-- #ifndef H5 -->
<view
class="uv-pick-color__box__bg drag-box"
@touchstart.stop.prevent="touchstart($event, 0)"
@touchmove.stop.prevent="touchmove($event, 0)"
@touchend.stop.prevent="touchend($event, 0)"
>
<!-- #endif -->
<view class="uv-pick-color__box__bg-mask"></view>
<view
class="uv-pick-color__box__bg-pointer"
:style="[pointerStyle]"
>
</view>
</view>
</view>
<view class="uv-pick-color__control">
<view class="uv-pick-color__control__alpha">
<view
class="uv-pick-color__control__alpha--color"
:style="{ background:`rgba(${rgba.r},${rgba.g},${rgba.b},${rgba.a})` }"
></view>
</view>
<view class="uv-pick-color__control__item">
<!-- #ifdef H5 -->
<view
class="uv-pick-color__control__item__drag drag-box"
@tap.stop="touchstart($event, 1)"
@touchstart.stop="touchstart($event, 1)"
@touchmove.stop="touchmove($event, 1)"
@touchend.stop="touchend($event, 1)"
>
<!-- #endif -->
<!-- #ifndef H5 -->
<view
class="uv-pick-color__control__item__drag drag-box"
@touchstart.stop="touchstart($event, 1)"
@touchmove.stop="touchmove($event, 1)"
@touchend.stop="touchend($event, 1)"
>
<!-- #endif -->
<view class="uv-pick-color__control__item__drag--hue"></view>
<view
class="uv-pick-color__control__item__drag--circle"
:style="{
left: $uv.getPx(site[1].left - 10,true)
}"
></view>
</view>
<!-- #ifdef H5 -->
<view
class="uv-pick-color__control__item__drag drag-box"
@tap.stop="touchstart($event, 2)"
@touchstart.stop="touchstart($event, 2)"
@touchmove.stop="touchmove($event, 2)"
@touchend.stop="touchend($event, 2)"
>
<!-- #endif -->
<!-- #ifndef H5 -->
<view
class="uv-pick-color__control__item__drag drag-box"
@touchstart.stop="touchstart($event, 2)"
@touchmove.stop="touchmove($event, 2)"
@touchend.stop="touchend($event, 2)"
>
<!-- #endif -->
<view class="uv-pick-color__control__item__drag--alpha"></view>
<view
class="uv-pick-color__control__item__drag--circle"
:style="{
left: $uv.getPx(site[2].left - 10,true)
}"
></view>
</view>
</view>
</view>
<view class="uv-pick-color__result">
<view
class="uv-pick-color__result__select"
hover-class="uv-hover-class"
@click.stop="select"
>
<text class="text">切换</text>
<text class="text">模式</text>
</view>
<view class="uv-pick-color__result__item" v-if="mode">
<view class="uv-pick-color__result__item--value uv-border">
<text>{{hex}}</text>
</view>
<view class="uv-pick-color__result__item--hex">
<text>HEX</text>
</view>
</view>
<template v-else>
<view class="uv-pick-color__result__item">
<view class="uv-pick-color__result__item--value uv-border">
<text>{{rgba.r}}</text>
</view>
<view class="uv-pick-color__result__item--rgba">
<text>R</text>
</view>
</view>
<view class="uv-pick-color__result__gap"></view>
<view class="uv-pick-color__result__item">
<view class="uv-pick-color__result__item--value uv-border">
<text>{{rgba.g}}</text>
</view>
<view class="uv-pick-color__result__item--rgba">
<text>G</text>
</view>
</view>
<view class="uv-pick-color__result__gap"></view>
<view class="uv-pick-color__result__item">
<view class="uv-pick-color__result__item--value uv-border">
<text>{{rgba.b}}</text>
</view>
<view class="uv-pick-color__result__item--rgba">
<text>B</text>
</view>
</view>
<view class="uv-pick-color__result__gap"></view>
<view class="uv-pick-color__result__item">
<view class="uv-pick-color__result__item--value uv-border">
<text>{{rgba.a}}</text>
</view>
<view class="uv-pick-color__result__item--rgba">
<text>A</text>
</view>
</view>
</template>
</view>
<view class="uv-pick-color__prefab">
<view
class="uv-pick-color__prefab__item"
v-for="(item,index) in colorList"
:key="index"
>
<view
class="uv-pick-color__prefab__item--color"
:style="{ background:`rgba(${item.r},${item.g},${item.b},${item.a})` }"
@click.stop="setColorBySelect(item)"
></view>
</view>
</view>
</view>
</uv-popup>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<view>
<text>nvue暂不支持uv-pick-color组件</text>
</view>
<!-- #endif -->
</template>
<script>
import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js';
import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js';
import { rgbToHsb, hsbToRgb, rgbToHex, colorList } from './colors.js';
import props from './props.js';
export default {
name: 'uv-pick-color',
emits: ['confirm', 'cancel', 'close', 'change'],
mixins: [mpMixin, mixin, props],
computed: {
pointerStyle() {
const style = {};
style.top = this.$uv.addUnit(this.site[0].top - 8);
style.left = this.$uv.addUnit(this.site[0].left - 8);
return style;
}
},
data() {
return {
showToolbar: false,
// rgba 颜色
rgba: {
r: 0,
g: 0,
b: 0,
a: 1
},
// hsb 颜色
hsb: {
h: 0,
s: 0,
b: 0
},
site: [{
top: 0,
left: 0
}, {
left: 0
}, {
left: 0
}],
index: 0,
bgcolor: {
r: 255,
g: 0,
b: 0,
a: 1
},
hex: '#000000',
mode: true,
colorList: colorList
};
},
watch: {
prefabColor(newVal) {
this.colorList = newVal;
}
},
created() {
// #ifdef APP-NVUE
return this.$uv.error('nvue暂不支持uv-pick-color组件');
// #endif
this.rgba = this.color;
if (this.prefabColor.length) this.colorList = this.prefabColor;
},
methods: {
open() {
this.$refs.pickerColorPopup.open();
this.showToolbar = true;
this.$nextTick(async () => {
await this.$uv.sleep(350);
this.getSelectorQuery();
})
},
close() {
this.$refs.pickerColorPopup.close();
},
popupChange(e) {
if(!e.show) this.$emit('close');
},
// 点击工具栏的取消按钮
cancelHandler() {
this.$emit('cancel');
this.close();
},
// 点击工具栏的确定按钮
confirmHandler() {
this.$emit('confirm', {
rgba: this.rgba,
hex: this.hex
})
this.close();
},
// 初始化
init() {
// hsb 颜色
this.hsb = rgbToHsb(this.rgba);
this.setValue(this.rgba);
},
async getSelectorQuery() {
const data = await this.$uvGetRect('.drag-box',true);
this.position = data;
this.setColorBySelect(this.rgba);
},
// 选择模式
select() {
this.mode = !this.mode;
},
touchstart(e, index) {
const { clientX, clientY } = e.touches[0];
this.pageX = clientX;
this.pageY = clientY;
this.setPosition(clientX, clientY, index);
},
touchmove(e, index) {
const { clientX, clientY } = e.touches[0];
this.moveX = clientX;
this.moveY = clientY;
this.setPosition(clientX, clientY, index);
},
touchend(e, index) {},
/**
* 设置位置
*/
setPosition(x, y, index) {
this.index = index;
const { top, left, width, height } = this.position[index];
// 设置最大最小值
this.site[index].left = Math.max(0, Math.min(parseInt(x - left), width));
if (index === 0) {
this.site[index].top = Math.max(0, Math.min(parseInt(y - top), height));
// 设置颜色
this.hsb.s = parseInt((100 * this.site[index].left) / width);
this.hsb.b = parseInt(100 - (100 * this.site[index].top) / height);
this.setColor();
this.setValue(this.rgba);
} else {
this.setControl(index, this.site[index].left);
}
},
/**
* 设置 rgb 颜色
*/
setColor() {
const rgb = hsbToRgb(this.hsb);
this.rgba.r = rgb.r;
this.rgba.g = rgb.g;
this.rgba.b = rgb.b;
},
/**
* 设置二进制颜色
* @param {Object} rgb
*/
setValue(rgb) {
this.hex = `#${(rgbToHex(rgb))}`;
},
setControl(index, x) {
const {
top,
left,
width,
height
} = this.position[index];
if (index === 1) {
this.hsb.h = parseInt((360 * x) / width);
this.bgcolor = hsbToRgb({
h: this.hsb.h,
s: 100,
b: 100
});
this.setColor()
} else {
this.rgba.a = +(x / width).toFixed(1);
}
this.setValue(this.rgba);
},
setColorBySelect(getrgb) {
const { r, g, b, a } = getrgb;
let rgb = {};
rgb = {
r: r ? parseInt(r) : 0,
g: g ? parseInt(g) : 0,
b: b ? parseInt(b) : 0,
a: a ? a : 0
};
this.rgba = rgb;
this.hsb = rgbToHsb(rgb);
this.changeViewByHsb();
},
changeViewByHsb() {
const [a, b, c] = this.position;
this.site[0].left = parseInt(this.hsb.s * a.width / 100);
this.site[0].top = parseInt((100 - this.hsb.b) * a.height / 100);
this.setColor(this.hsb.h);
this.setValue(this.rgba);
this.bgcolor = hsbToRgb({
h: this.hsb.h,
s: 100,
b: 100
});
this.site[1].left = this.hsb.h / 360 * b.width;
this.site[2].left = this.rgba.a * c.width;
}
}
};
</script>
<style scoped lang="scss">
$show-border: 1;
@import '@/uni_modules/uv-ui-tools/libs/css/variable.scss';
@import '@/uni_modules/uv-ui-tools/libs/css/components.scss';
$height: 400rpx;
/* #ifndef APP-NVUE */
.uv-pick-color {
&__box {
position: relative;
height: $height;
background: rgb(255, 0, 0);
margin: 20rpx;
&__bg {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(to right, #fff, rgba(255, 255, 255, 0));
&-mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
height: $height;
background: linear-gradient(to top, #000, rgba(0, 0, 0, 0));
}
&-pointer {
position: absolute;
top: -8px;
left: -8px;
z-index: 2;
width: 16px;
height: 16px;
border: 1px #fff solid;
border-radius: 8px;
}
}
}
&__control {
@include flex;
padding: 10rpx 20rpx;
&__alpha {
width: 100rpx;
height: 100rpx;
border-radius: 50rpx;
background-color: #fff;
background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee),linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee);
background-size: 36rpx 36rpx;
background-position: 0 0, 18rpx 18rpx;
border: 1px #eee solid;
overflow: hidden;
&--color {
width: 100%;
height: 100%;
}
}
&__item {
flex: 1;
@include flex(column);
justify-content: space-between;
height: 100rpx;
padding: 6rpx 0 6rpx 30rpx;
}
&__item__drag {
position: relative;
height: 16px;
background-color: #fff;
background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee),
linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee);
background-size: 32rpx 32rpx;
background-position: 0 0, 16rpx 16rpx;
&--hue {
width: 100%;
height: 100%;
background: linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%);
}
&--alpha {
width: 100%;
height: 100%;
background: linear-gradient(to right, rgba(0, 0, 0, 0) 0%, rgb(0, 0, 0));
}
&--circle {
position: absolute;
top: -2px;
width: 20px;
height: 20px;
box-sizing: border-box;
border-radius: 10px;
background: #fff;
box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.1);
}
}
}
&__result {
@include flex;
padding: 20rpx;
text-align: center;
&__select {
@include flex(column);
justify-content: center;
width: 100rpx;
height: 100rpx;
margin-right: 10px;
border-radius: 10rpx;
box-shadow: 1px 1px 2px 1px rgba(0, 0, 0, 0.1);
font-size: 14px;
color: #999;
}
&__item {
flex: 1;
height: 100rpx;
&--value {
height: 50rpx;
line-height: 50rpx;
border-radius: 4rpx;
font-size: 28rpx;
color: #999;
}
&--hex,
&--rgba {
height: 50rpx;
line-height: 50rpx;
font-size: 30rpx;
}
}
&__gap {
width: 10px;
height: 10px;
}
}
&__prefab {
@include flex;
margin: 0 -8rpx;
padding: 0 20rpx 20rpx;
flex-wrap: wrap;
&__item {
width: 50rpx;
height: 50rpx;
margin: 8rpx;
border-radius: 6rpx;
background-color: #fff;
background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee),
linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee);
background-size: 36rpx 36rpx;
background-position: 0 0, 18rpx 18rpx;
border: 1px #eee solid;
&--color {
width: 100%;
height: 100%;
border-radius: 6rpx;
}
}
}
}
/* #endif */
</style>
+89
View File
@@ -0,0 +1,89 @@
{
"id": "uv-pick-color",
"displayName": "uv-pick-color 颜色选择器 全面兼容vue3+2、app、h5、小程序等多端",
"version": "1.0.8",
"description": "该组件为颜色选择器,支持预制颜色,初始化颜色,简单配置,开箱即用",
"keywords": [
"uv-pick-color",
"uvui",
"uv-ui",
"颜色",
"color"
],
"repository": "",
"engines": {
"HBuilderX": "^3.1.0"
},
"dcloudext": {
"type": "component-vue",
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "插件不采集任何数据",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [
"uv-ui-tools",
"uv-popup",
"uv-toolbar"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"Vue": {
"vue2": "y",
"vue3": "y"
},
"App": {
"app-vue": "y",
"app-nvue": "u"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y",
"钉钉": "u",
"快手": "u",
"飞书": "u",
"京东": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
}
}
+19
View File
@@ -0,0 +1,19 @@
## PickColor 颜色选择器
> **组件名:uv-pick-color**
该组件为颜色选择器,支持预制颜色,初始化颜色,简单配置,开箱即用。
# <a href="https://www.uvui.cn/components/pickColor.html" target="_blank">查看文档</a>
## [下载完整示例项目](https://ext.dcloud.net.cn/plugin?name=uv-ui) <small>(请不要 下载插件ZIP</small>
### [更多插件,请关注uv-ui组件库](https://ext.dcloud.net.cn/plugin?name=uv-ui)
<a href="https://ext.dcloud.net.cn/plugin?name=uv-ui" target="_blank">
![image](https://mp-a667b617-c5f1-4a2d-9a54-683a67cff588.cdn.bspapp.com/uv-ui/banner.png)
</a>
#### 如使用过程中有任何问题反馈,或者您对uv-ui有一些好的建议,欢迎加入uv-ui官方交流群:<a href="https://www.uvui.cn/components/addQQGroup.html" target="_blank">官方QQ群</a>