<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>
|