ColorPicker: display current color in real time (#2941)

pull/2961/head
杨奕 2017-02-22 15:14:54 +08:00 committed by baiyaaaaa
parent 1b8657ce0d
commit f2fc8b5fb6
10 changed files with 165 additions and 139 deletions

View File

@ -2,63 +2,42 @@
export default {
data() {
return {
color1: '#ff0',
color1: '#20a0ff',
color2: null,
color3: 'rgba(128, 33, 22, 0.8)',
color4: null
color3: 'rgba(19, 206, 102, 0.8)'
};
}
},
mounted() {
this.$nextTick(() => {
const demos = document.querySelectorAll('.source');
demos[0].style.padding = '0';
});
},
}
</script>
<style scoped>
.demo-box.demo-color-picker .source {
padding: 0;
}
.demo-box.demo-color-picker .block {
padding: 30px 24px;
overflow: hidden;
border-bottom: solid 1px #EFF2F6;
&:last-child {
border-bottom: none;
}
}
.demo-box.demo-color-picker .demonstration {
display: inline-block;
font-size: 14px;
width: 25%;
color: #8492a6;
line-height: 44px;
}
</style>
## ColorPicker
ColorPicker is a color picker component that is used to solve the need to select a color in certain scenes.
ColorPicker is a color selector supporting multiple color formats.
### Color
### Basic usage
:::demo ColorPicker usage is similar to DatePicker and requires v-model to bind a variable in a Vue instance. The bind variable's data type needs to be a string.
:::demo ColorPicker requires a string typed variable to be bound to v-model.
```html
<div class="block">
<span class="demonstration">Default value</span>
<span class="demonstration">With default value</span>
<el-color-picker v-model="color1"></el-color-picker>
</div>
<div class="block">
<span class="demonstration">Empty</span>
<span class="demonstration">With no default value</span>
<el-color-picker v-model="color2"></el-color-picker>
</div>
<style>
</style>
<script>
export default {
data() {
return {
color1: '#ff0',
color1: '#20a0ff',
color2: null
}
}
@ -67,25 +46,17 @@ ColorPicker is a color picker component that is used to solve the need to select
```
:::
### Color and alpha
### Alpha
:::demo ColorPicker supports normal colors, also supports alpha-channel colors, through the show-alpha attribute to control whether to support the use of transparency.
:::demo ColorPicker supports alpha channel selecting. To activate alpha selecting, just add the `show-alpha` attribute.
```html
<div class="block">
<span class="demonstration">Default value</span>
<el-color-picker v-model="color3" show-alpha></el-color-picker>
</div>
<div class="block">
<span class="demonstration">Empty</span>
<el-color-picker v-model="color4" show-alpha></el-color-picker>
</div>
<el-color-picker v-model="color3" show-alpha></el-color-picker>
<script>
export default {
data() {
return {
color3: 'rgba(128, 33, 22, 0.8)',
color4: null
color3: 'rgba(19, 206, 102, 0.8)'
}
}
};
@ -96,5 +67,5 @@ ColorPicker is a color picker component that is used to solve the need to select
### Attributes
| Attribute | Description | Type | Accepted Values | Default |
|---------- |-------- |---------- |------------- |-------- |
| show-alpha | Whether to display the alpha slider. | Boolean | — | false |
| color-format | Write the v-model's color format. In the case of show-alpha is true, the default value is rgb, otherwise hex. | string | hsl, hsv, hex, rgb | hex |
| show-alpha | whether to display the alpha slider | boolean | — | false |
| color-format | color format of v-model | string | hsl / hsv / hex / rgb | hex (when show-alpha is false)/ rgb (when show-alpha is true) |

View File

@ -2,45 +2,47 @@
export default {
data() {
return {
color1: '#ff0',
color1: '#20a0ff',
color2: null,
color3: 'rgba(128, 33, 22, 0.8)',
color4: null
color3: 'rgba(19, 206, 102, 0.8)'
};
}
},
mounted() {
this.$nextTick(() => {
const demos = document.querySelectorAll('.source');
demos[0].style.padding = '0';
});
},
}
</script>
<style scoped>
.demo-box.demo-color-picker .source {
padding: 0;
}
.demo-box.demo-color-picker .block {
padding: 30px 24px;
overflow: hidden;
border-bottom: solid 1px #EFF2F6;
<style>
.demo-color-picker .block {
padding: 30px 0;
text-align: center;
border-right: solid 1px #EFF2F6;
float: left;
width: 50%;
box-sizing: border-box;
&:last-child {
border-bottom: none;
border-right: none;
}
}
.demo-box.demo-color-picker .demonstration {
display: inline-block;
font-size: 14px;
width: 25%;
.demo-color-picker .demonstration {
display: block;
color: #8492a6;
line-height: 44px;
font-size: 14px;
margin-bottom: 20px;
}
</style>
## ColorPicker
## ColorPicker 颜色选择器
ColorPicker 是一个颜色选择器,该组件是用来解决某些场景下需要选择颜色的需求
用于颜色选择,支持多种格式
### 选择颜色
### 基础用法
:::demo ColorPicker 用法与 DatePicker 类似,需要使用 v-model 与 Vue 实例中的一个变量进行双向绑定,绑定的变量需要是字符串类型。
:::demo 使用 v-model 与 Vue 实例中的一个变量进行双向绑定,绑定的变量需要是字符串类型。
```html
<div class="block">
<span class="demonstration">有默认值</span>
@ -51,14 +53,11 @@ ColorPicker 是一个颜色选择器,该组件是用来解决某些场景下
<el-color-picker v-model="color2"></el-color-picker>
</div>
<style>
</style>
<script>
export default {
data() {
return {
color1: '#ff0',
color1: '#20a0ff',
color2: null
}
}
@ -67,25 +66,17 @@ ColorPicker 是一个颜色选择器,该组件是用来解决某些场景下
```
:::
### 选择颜色和透明度
### 选择透明度
:::demo ColorPicker 支持普通颜色,也支持带 Alpha 通道的颜色,通过 show-alpha 属性即可控制是否支持透明度的使用
:::demo ColorPicker 支持普通颜色,也支持带 Alpha 通道的颜色,通过`show-alpha`属性即可控制是否支持透明度的选择
```html
<div class="block">
<span class="demonstration">有默认值</span>
<el-color-picker v-model="color3" show-alpha></el-color-picker>
</div>
<div class="block">
<span class="demonstration">无默认值</span>
<el-color-picker v-model="color4" show-alpha></el-color-picker>
</div>
<el-color-picker v-model="color3" show-alpha></el-color-picker>
<script>
export default {
data() {
return {
color3: 'rgba(128, 33, 22, 0.8)',
color4: null
color3: 'rgba(19, 206, 102, 0.8)'
}
}
};
@ -96,5 +87,5 @@ ColorPicker 是一个颜色选择器,该组件是用来解决某些场景下
### Attributes
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|---------- |-------- |---------- |------------- |-------- |
| show-alpha | 是否显示透明度 Slider。 | Boolean | — | false |
| color-format | 写入 v-model 的颜色的格式。在 show-alpha 为 true 的情况下,默认值为 rgb否则为 hex。 | string | hsl, hsv, hex, rgb | hex |
| show-alpha | 是否支持透明度选择 | boolean | — | false |
| color-format | 写入 v-model 的颜色的格式 | string | hsl / hsv / hex / rgb | hexshow-alpha 为 false/ rgbshow-alpha 为 true |

View File

@ -108,6 +108,10 @@
"path": "/rate",
"title": "Rate 评分"
},
{
"path": "/color-picker",
"title": "ColorPicker 颜色选择器"
},
{
"path": "/form",
"title": "Form 表单"
@ -219,10 +223,6 @@
{
"path": "/collapse",
"title": "Collapse 折叠面板"
},
{
"path": "/color-picker",
"title": "ColorPicker"
}
]
}
@ -338,6 +338,10 @@
"path": "/rate",
"title": "Rate"
},
{
"path": "/color-picker",
"title": "ColorPicker"
},
{
"path": "/form",
"title": "Form"
@ -449,10 +453,6 @@
{
"path": "/collapse",
"title": "Collapse"
},
{
"path": "/color-picker",
"title": "ColorPicker"
}
]
}

View File

@ -63,14 +63,24 @@ const parseHexChannel = function(hex) {
};
const hsl2hsv = function(hue, sat, light) {
sat *= light < 0.5 ? light : 1 - light;
sat = sat / 100;
light = light / 100;
let smin = sat;
const lmin = Math.max(light, 0.01);
let sv;
let v;
return [ // [hue, saturation, value]
// Range should be between 0 - 1
hue, // Hue stays the same
2 * sat / (light + sat), // Saturation
light + sat // Value
];
light *= 2;
sat *= (light <= 1) ? light : 2 - light;
smin *= lmin <= 1 ? lmin : 2 - lmin;
v = (light + sat) / 2;
sv = light === 0 ? (2 * smin) / (lmin + smin) : (2 * sat) / (light + sat);
return {
h: hue,
s: sv * 100,
v: v * 100
};
};
// `rgbToHsv`
@ -201,38 +211,36 @@ export default class Color {
if (value.indexOf('hsl') !== -1) {
const parts = value.replace(/hsla|hsl|\(|\)/gm, '')
.split(/\s|,/g, '').filter((val) => val !== '').map((val, index) => index > 2 ? parseFloat(val) : parseInt(val, 10));
.split(/\s|,/g).filter((val) => val !== '').map((val, index) => index > 2 ? parseFloat(val) : parseInt(val, 10));
if (parts.length > 3) {
if (parts.length === 4) {
this._alpha = Math.floor(parseFloat(parts[3]) * 100);
}
if (parts.length >= 3) {
const { h, s, v } = hsl2hsv(parts[0], parts[1], parts[2]);
fromHSV(h, s, v);
}
if (parts.length === 4) {
this._alpha = Math.floor(parseFloat(parts[3]) * 100);
}
} else if (value.indexOf('hsv') !== -1) {
const parts = value.replace(/hsva|hsv|\(|\)/gm, '')
.split(/\s|,/g, '').filter((val) => val !== '').map((val, index) => index > 2 ? parseFloat(val) : parseInt(val, 10));
if (parts.length >= 3) {
fromHSV(parts[0], parts[1], parts[2]);
}
.split(/\s|,/g).filter((val) => val !== '').map((val, index) => index > 2 ? parseFloat(val) : parseInt(val, 10));
if (parts.length === 4) {
this._alpha = Math.floor(parseFloat(parts[3]) * 100);
}
if (parts.length >= 3) {
fromHSV(parts[0], parts[1], parts[2]);
}
} else if (value.indexOf('rgb') !== -1) {
const parts = value.replace(/rgba|rgb|\(|\)/gm, '')
.split(/\s|,/g).filter((val) => val !== '').map((val, index) => index > 2 ? parseFloat(val) : parseInt(val, 10));
if (parts.length === 4) {
this._alpha = Math.floor(parseFloat(parts[3]) * 100);
}
if (parts.length >= 3) {
const { h, s, v } = rgb2hsv(parts[0], parts[1], parts[2]);
fromHSV(h, s, v);
}
if (parts.length === 4) {
this._alpha = Math.floor(parseFloat(parts[3]) * 100);
}
} else if (value.indexOf('#') !== -1) {
const hex = value.replace('#', '').trim();
let r, g, b;
@ -259,10 +267,10 @@ export default class Color {
switch (format) {
case 'hsl':
const hsl = hsv2hsl(_hue, _saturation / 100, _value / 100);
this.value = `hsla(${ _hue }, ${ hsl[1] * 100 }%, ${ hsl[2] * 100 }%, ${ _alpha / 100})`;
this.value = `hsla(${ _hue }, ${ Math.round(hsl[1] * 100) }%, ${ Math.round(hsl[2] * 100) }%, ${ _alpha / 100})`;
break;
case 'hsv':
this.value = `hsva(${ _hue }, ${ _saturation }%, ${ _value }%, ${ _alpha / 100})`;
this.value = `hsva(${ _hue }, ${ Math.round(_saturation) }%, ${ Math.round(_value) }%, ${ _alpha / 100})`;
break;
default:
const { r, g, b } = hsv2rgb(_hue, _saturation, _value);
@ -272,10 +280,10 @@ export default class Color {
switch (format) {
case 'hsl':
const hsl = hsv2hsl(_hue, _saturation / 100, _value / 100);
this.value = `hsl(${ _hue }, ${ hsl[1] * 100 }%, ${ hsl[2] * 100 }%)`;
this.value = `hsl(${ _hue }, ${ Math.round(hsl[1] * 100) }%, ${ Math.round(hsl[2] * 100) }%)`;
break;
case 'hsv':
this.value = `hsv(${ _hue }, ${ _saturation }%, ${ _value }%)`;
this.value = `hsv(${ _hue }, ${ Math.round(_saturation) }%, ${ Math.round(_value) }%)`;
break;
case 'rgb':
const { r, g, b } = hsv2rgb(_hue, _saturation, _value);

View File

@ -62,13 +62,13 @@
left = Math.max(thumb.offsetWidth / 2, left);
left = Math.min(left, rect.width - thumb.offsetWidth / 2);
this.color._alpha = Math.round((left - thumb.offsetWidth / 2) / (rect.width - thumb.offsetWidth) * 100);
this.color.set('alpha', Math.round((left - thumb.offsetWidth / 2) / (rect.width - thumb.offsetWidth) * 100));
} else {
let top = event.clientY - rect.top;
top = Math.max(thumb.offsetHeight / 2, top);
top = Math.min(top, rect.height - thumb.offsetHeight / 2);
this.color._alpha = Math.round((top - thumb.offsetHeight / 2) / (rect.height - thumb.offsetHeight) * 100);
this.color.set('alpha', Math.round((top - thumb.offsetHeight / 2) / (rect.height - thumb.offsetHeight) * 100));
}
},

View File

@ -9,6 +9,7 @@
</div>
<alpha-slider v-if="showAlpha" ref="alpha" :color="color"></alpha-slider>
<div class="el-color-dropdown__btns">
<span class="el-color-dropdown__value">{{ currentColor }}</span>
<a href="JavaScript:" class="el-color-dropdown__link-btn" @click="$emit('clear')">{{ t('el.colorpicker.clear') }}</a>
<button class="el-color-dropdown__btn" @click="confirmValue">{{ t('el.colorpicker.confirm') }}</button>
</div>
@ -17,7 +18,7 @@
</template>
<style>
</style>
<script type="babel">
<script>
import SvPanel from './sv-panel';
import HueSlider from './hue-slider';
import AlphaSlider from './alpha-slider';
@ -42,6 +43,13 @@
showAlpha: Boolean
},
computed: {
currentColor() {
const parent = this.$parent;
return !parent.value && !parent.showPanelColor ? '' : parent.color.value;
}
},
methods: {
confirmValue() {
this.$emit('pick');
@ -65,5 +73,5 @@
}
}
}
}
};
</script>

View File

@ -18,7 +18,7 @@
<style>
</style>
<script type="babel">
<script>
import draggable from '../draggable';
export default {
@ -91,7 +91,7 @@
cursorTop: 0,
cursorLeft: 0,
background: 'hsl(0, 100%, 50%)'
}
};
}
}
};
</script>

View File

@ -1,6 +1,8 @@
import Vue from 'vue';
let isDragging = false;
export default function(element, options) {
if (Vue.prototype.$isServer) return;
const moveFn = function(event) {
if (options.drag) {
options.drag(event);

View File

@ -4,9 +4,9 @@
<span class="el-color-picker__color" :class="{ 'is-alpha': showAlpha }">
<span class="el-color-picker__color-inner"
:style="{
backgroundColor: value ? value : 'transparent'
backgroundColor: displayedColor
}"></span>
<span class="el-color-picker__empty el-icon-close" v-if="!value"></span>
<span class="el-color-picker__empty el-icon-close" v-if="!value && !showPanelColor"></span>
</span>
<span class="el-color-picker__icon el-icon-caret-bottom"></span>
</div>
@ -47,11 +47,30 @@
directives: { Clickoutside },
computed: {
displayedColor() {
if (!this.value && !this.showPanelColor) {
return 'transparent';
} else {
const { r, g, b } = this.color.toRgb();
return this.showAlpha
? `rgba(${ r }, ${ g }, ${ b }, ${ this.color.get('alpha') / 100 })`
: `rgb(${ r }, ${ g }, ${ b })`;
}
}
},
watch: {
value(val) {
if (val && val !== this.color.value) {
this.color.fromString(val);
}
},
color: {
deep: true,
handler() {
this.showPanelColor = true;
}
}
},
@ -62,10 +81,22 @@
},
clearValue() {
this.$emit('input', null);
this.showPanelColor = false;
this.showPicker = false;
this.resetColor();
},
hide() {
this.showPicker = false;
this.resetColor();
},
resetColor() {
this.$nextTick(_ => {
if (this.value) {
this.color.fromString(this.value);
} else {
this.showPanelColor = false;
}
});
}
},
@ -84,7 +115,8 @@
});
return {
color,
showPicker: false
showPicker: false,
showPanelColor: false
};
},

View File

@ -4,7 +4,7 @@
@component hue-slider {
position: relative;
box-sizing: border-box;
width: 240px;
width: 280px;
height: 12px;
background-color: #f00;
padding: 0 2px;
@ -58,7 +58,7 @@
@component svpanel {
position: relative;
width: 240px;
width: 280px;
height: 180px;
@descendent white, black {
@ -94,7 +94,7 @@
@component alpha-slider {
position: relative;
box-sizing: border-box;
width: 240px;
width: 280px;
height: 12px;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);
@ -141,7 +141,7 @@
}
@component dropdown {
width: 260px;
width: 300px;
@descendent main-wrapper {
margin-bottom: 6px;
@ -158,6 +158,13 @@
text-align: right;
}
@descendent value {
float: left;
line-height: 26px;
font-size: 12px;
color: var(--color-base-black);
}
@descendent btn {
border: 1px solid #dcdcdc;
color: #333;
@ -173,6 +180,10 @@
color: #cccccc;
cursor: not-allowed;
}
&:hover {
color: var(--color-primary);
border-color: var(--color-primary);
}
}
@descendent link-btn {
@ -181,6 +192,9 @@
text-decoration: none;
padding: 15px;
font-size: 12px;
&:hover {
color: tint(var(--color-primary), var(--button-hover-tint-percent));
}
}
}