ColorPicker: add predefine colors (#10170)

* ColorPicker: add predefine colors(#8702)

* Add selected state of predefine color and test cases

* Fix the bugs mentioned in review
pull/10236/head
Harlan 2018-03-19 17:20:09 +08:00 committed by 杨奕
parent 3377cd0847
commit 441669f081
9 changed files with 351 additions and 9 deletions

View File

@ -5,7 +5,19 @@
color1: '#409EFF',
color2: null,
color3: 'rgba(19, 206, 102, 0.8)',
color4: '#409EFF'
color4: '#409EFF',
color5: 'hsva(180, 65, 20, 0.5)',
predefineColors: [
'rgba(19, 206, 102, 0.18)',
'rgb(25, 159, 147)',
'hsv(250, 54, 98)',
'hsva(180, 65, 20, 0.5)',
'hsl(170, 32%, 87%)',
'hsla(45, 62%, 47%, 0.13)',
'#7486de',
'#45aa9477',
'#892345'
]
};
},
mounted() {
@ -88,6 +100,36 @@ ColorPicker is a color selector supporting multiple color formats.
```
:::
### Predefine colors
:::demo ColorPicker supports predefine colors
```html
<el-color-picker v-model="color5" show-alpha :predefine="predefineColors"></el-color-picker>
<script>
export default {
data() {
return {
color5: 'hsva(180, 65, 20, 0.5)',
predefineColors: [
'rgba(19, 206, 102, 0.18)',
'rgb(25, 159, 147)',
'hsv(250, 54, 98)',
'hsva(180, 65, 20, 0.5)',
'hsl(170, 32%, 87%)',
'hsla(45, 62%, 47%, 0.13)',
'#7486de',
'#45aa9477',
'#892345'
]
}
}
};
</script>
```
:::
### Sizes
:::demo
@ -117,6 +159,7 @@ ColorPicker is a color selector supporting multiple color formats.
| 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) |
| popper-class | custom class name for ColorPicker's dropdown | string | — | — |
| predefine | predefine some colors | array | — | — |
### Events
| Event Name | Description | Parameters |

View File

@ -5,7 +5,19 @@
color1: '#409EFF',
color2: null,
color3: 'rgba(19, 206, 102, 0.8)',
color4: '#409EFF'
color4: '#409EFF',
color5: 'hsva(180, 65, 20, 0.5)',
predefineColors: [
'rgba(19, 206, 102, 0.18)',
'rgb(25, 159, 147)',
'hsv(250, 54, 98)',
'hsva(180, 65, 20, 0.5)',
'hsl(170, 32%, 87%)',
'hsla(45, 62%, 47%, 0.13)',
'#7486de',
'#45aa9477',
'#892345'
]
};
},
mounted() {
@ -88,6 +100,35 @@ ColorPicker es un selector de color que soporta varios formatos de color.
```
:::
### Colores predefinidos
:::demo ColorPicker admite colores predefinidos
```html
<el-color-picker v-model="color5" show-alpha :predefine="predefineColors"></el-color-picker>
<script>
export default {
data() {
return {
color5: 'hsva(180, 65, 20, 0.5)',
predefineColors: [
'rgba(19, 206, 102, 0.18)',
'rgb(25, 159, 147)',
'hsv(250, 54, 98)',
'hsva(180, 65, 20, 0.5)',
'hsl(170, 32%, 87%)',
'hsla(45, 62%, 47%, 0.13)',
'#7486de',
'#45aa9477',
'#892345'
]
}
}
};
</script>
```
:::
### Sizes
:::demo
@ -117,6 +158,7 @@ ColorPicker es un selector de color que soporta varios formatos de color.
| show-alpha | especifica si se muestra el control deslizante para el valor alpha | boolean | — | false |
| color-format | formato de color del `v-model` | string | hsl / hsv / hex / rgb | hex (si show-alpha es false)/ rgb (si show-alpha es true) |
| popper-class | nombre de clase para el dropdown del ColorPicker | string | — | — |
| predefine | colores predefinidos | array | — | — |
### Eventos
| Nombre de Evento | Descripción | Parametros |

View File

@ -5,7 +5,19 @@
color1: '#409EFF',
color2: null,
color3: 'rgba(19, 206, 102, 0.8)',
color4: '#409EFF'
color4: '#409EFF',
color5: 'hsva(180, 65, 20, 0.5)',
predefineColors: [
'rgba(19, 206, 102, 0.18)',
'rgb(25, 159, 147)',
'hsv(250, 54, 98)',
'hsva(180, 65, 20, 0.5)',
'hsl(170, 32%, 87%)',
'hsla(45, 62%, 47%, 0.13)',
'#7486de',
'#45aa9477',
'#892345'
]
};
},
mounted() {
@ -88,6 +100,35 @@
```
:::
### 预定义颜色
:::demo ColorPicker 支持预定义颜色
```html
<el-color-picker v-model="color5" show-alpha :predefine="predefineColors"></el-color-picker>
<script>
export default {
data() {
return {
color5: 'hsva(180, 65, 20, 0.5)',
predefineColors: [
'rgba(19, 206, 102, 0.18)',
'rgb(25, 159, 147)',
'hsv(250, 54, 98)',
'hsva(180, 65, 20, 0.5)',
'hsl(170, 32%, 87%)',
'hsla(45, 62%, 47%, 0.13)',
'#7486de',
'#45aa9477',
'#892345'
]
}
}
};
</script>
```
:::
### 不同尺寸
:::demo
@ -117,6 +158,7 @@
| show-alpha | 是否支持透明度选择 | boolean | — | false |
| color-format | 写入 v-model 的颜色的格式 | string | hsl / hsv / hex / rgb | hexshow-alpha 为 false/ rgbshow-alpha 为 true |
| popper-class | ColorPicker 下拉框的类名 | string | — | — |
| predefine | 预定义颜色 | array | — | — |
### Events
| 事件名称 | 说明 | 回调参数 |

View File

@ -215,6 +215,8 @@ export default class Color {
if (parts.length === 4) {
this._alpha = Math.floor(parseFloat(parts[3]) * 100);
} else if (parts.length === 3) {
this._alpha = 100;
}
if (parts.length >= 3) {
const { h, s, v } = hsl2hsv(parts[0], parts[1], parts[2]);
@ -226,6 +228,8 @@ export default class Color {
if (parts.length === 4) {
this._alpha = Math.floor(parseFloat(parts[3]) * 100);
} else if (parts.length === 3) {
this._alpha = 100;
}
if (parts.length >= 3) {
fromHSV(parts[0], parts[1], parts[2]);
@ -236,6 +240,8 @@ export default class Color {
if (parts.length === 4) {
this._alpha = Math.floor(parseFloat(parts[3]) * 100);
} else if (parts.length === 3) {
this._alpha = 100;
}
if (parts.length >= 3) {
const { h, s, v } = rgb2hsv(parts[0], parts[1], parts[2]);
@ -249,10 +255,16 @@ export default class Color {
r = parseHexChannel(hex[0] + hex[0]);
g = parseHexChannel(hex[1] + hex[1]);
b = parseHexChannel(hex[2] + hex[2]);
} else if (hex.length === 6) {
} else if (hex.length === 6 || hex.length === 8) {
r = parseHexChannel(hex.substring(0, 2));
g = parseHexChannel(hex.substring(2, 4));
b = parseHexChannel(hex.substring(4));
b = parseHexChannel(hex.substring(4, 6));
}
if (hex.length === 8) {
this._alpha = Math.floor(parseHexChannel(hex.substring(6)) / 255 * 100);
} else if (hex.length === 3 || hex.length === 6) {
this._alpha = 100;
}
const { h, s, v } = rgb2hsv(r, g, b);
@ -260,6 +272,13 @@ export default class Color {
}
}
compare(color) {
return Math.abs(color._hue - this._hue) < 2 &&
Math.abs(color._saturation - this._saturation) < 1 &&
Math.abs(color._value - this._value) < 1 &&
Math.abs(color._alpha - this._alpha) < 1;
}
doOnChange() {
const { _hue, _saturation, _value, _alpha, format } = this;

View File

@ -8,6 +8,7 @@
<sv-panel ref="sl" :color="color"></sv-panel>
</div>
<alpha-slider v-if="showAlpha" ref="alpha" :color="color"></alpha-slider>
<predefine v-if="predefine" :color="color" :colors="predefine"></predefine>
<div class="el-color-dropdown__btns">
<span class="el-color-dropdown__value">
<el-input
@ -40,6 +41,7 @@
import SvPanel from './sv-panel';
import HueSlider from './hue-slider';
import AlphaSlider from './alpha-slider';
import Predefine from './predefine';
import Popper from 'element-ui/src/utils/vue-popper';
import Locale from 'element-ui/src/mixins/locale';
import ElInput from 'element-ui/packages/input';
@ -55,14 +57,16 @@
HueSlider,
AlphaSlider,
ElInput,
ElButton
ElButton,
Predefine
},
props: {
color: {
required: true
},
showAlpha: Boolean
showAlpha: Boolean,
predefine: Array
},
data() {

View File

@ -0,0 +1,62 @@
<template>
<div class="el-color-predefine">
预设
<div class="el-color-predefine__colors">
<div class="el-color-predefine__color-selector"
:class="{selected: item.selected, 'is-alpha': item._alpha < 100}"
v-for="(item, index) in rgbaColors"
:key="colors[index]"
@click="handleSelect(index)">
<div :style="{'background-color': item.value}">
</div>
</div>
</div>
</div>
</template>
<script>
import Color from '../color';
export default {
props: {
colors: { type: Array, required: true },
color: { required: true }
},
data() {
return {
rgbaColors: this.parseColors(this.colors, this.color),
}
},
methods: {
handleSelect(index) {
this.color.fromString(this.colors[index]);
},
parseColors(colors, color) {
return colors.map(value => {
const c = new Color();
c.enableAlpha = true;
c.format = 'rgba';
c.fromString(value);
c.selected = c.value === color.value;
return c;
});
}
},
watch: {
'$parent.currentColor'(val) {
const color = new Color();
color.fromString(val);
this.rgbaColors.forEach(item => {
item.selected = color.compare(item);
});
},
colors(newVal) {
this.rgbaColors = this.parseColors(newVal, this.color);
},
color(newVal) {
this.rgbaColors = this.parseColors(this.colors, newVal);
}
}
};
</script>

View File

@ -24,7 +24,8 @@
@pick="confirmValue"
@clear="clearValue"
:color="color"
:show-alpha="showAlpha">
:show-alpha="showAlpha"
:predefine="predefine">
</picker-dropdown>
</div>
</template>
@ -43,7 +44,8 @@
colorFormat: String,
disabled: Boolean,
size: String,
popperClass: String
popperClass: String,
predefine: Array
},
inject: {

View File

@ -1,6 +1,40 @@
@import "mixins/mixins";
@import "common/var";
@include b(color-predefine) {
display: flex;
font-size: 12px;
margin-top: 8px;
@include e(colors) {
display: flex;
flex: 1;
flex-wrap: wrap;
}
@include e(color-selector) {
margin: 0 0 6px 6px;
width: 24px;
height: 24px;
border: 1px #8c939d solid;
border-radius: 2px;
cursor: pointer;
&.selected {
border: 3px $--color-primary solid;
}
> div {
display: flex;
height: 100%;
}
@include when(alpha) {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);
}
}
}
@include b(color-hue-slider) {
position: relative;
box-sizing: border-box;

View File

@ -265,4 +265,98 @@ describe('ColorPicker', () => {
});
}, ANIMATION_TIME);
});
it('should change color to the selected color', done => {
const vm = createVue({
template: `
<el-color-picker v-model="color" show-alpha :predefine="colors"></el-color-picker>
`,
data() {
return {
color: 'hsva(180, 65, 20, 0.5)',
colors: [
'rgba(19, 206, 102, 0.18)',
'rgb(25, 159, 147)',
'hsv(250, 54, 98)',
'hsva(180, 65, 20, 0.5)',
'hsl(170, 32%, 87%)',
'hsla(45, 62%, 47%, 0.13)',
'#7486de',
'#45aa9477',
'#892345'
]
};
}
}, true);
const trigger = vm.$el.querySelector('.el-color-picker__trigger');
trigger.click();
setTimeout(() => {
expect(document.querySelectorAll('.el-color-predefine__color-selector').length === 9).to.be.true;
const selector = document.querySelector('.el-color-predefine__color-selector:nth-child(4)');
selector.click();
vm.$nextTick(() => {
const picker = vm.$children[0];
expect(picker.color._hue === 180).to.be.true;
expect(picker.color._saturation === 65).to.be.true;
expect(picker.color._value === 20).to.be.true;
expect(picker.color._alpha === 50).to.be.true;
const selector2 = document.querySelector('.el-color-predefine__color-selector:nth-child(3)');
selector2.click();
vm.$nextTick(() => {
expect(picker.color._hue === 250).to.be.true;
expect(picker.color._saturation === 54).to.be.true;
expect(picker.color._value === 98).to.be.true;
expect(picker.color._alpha === 100).to.be.true;
done();
});
});
});
});
it('should change selected state of predefined color', done => {
const vm = createVue({
template: `
<el-color-picker v-model="color" show-alpha :predefine="colors"></el-color-picker>
`,
data() {
return {
color: 'hsva(180, 65, 20, 0.5)',
colors: [
'rgba(19, 206, 102, 0.18)',
'rgb(25, 159, 147)',
'hsv(250, 54, 98)',
'hsva(180, 65, 20, 0.5)',
'hsl(170, 32%, 87%)',
'hsla(45, 62%, 47%, 0.13)',
'#7486de',
'#45aa9477',
'#892345'
]
};
}
}, true);
const trigger = vm.$el.querySelector('.el-color-picker__trigger');
trigger.click();
setTimeout(() => {
const selector = document.querySelector('.el-color-predefine__color-selector:nth-child(4)');
selector.click();
vm.$nextTick(() => {
expect(selector.classList.contains('selected')).to.be.true;
const hueBar = document.querySelector('.el-color-hue-slider');
hueBar.__vue__.handleClick({ target: null, clientX: 0, clientY: 1000 });
vm.$nextTick(() => {
expect(selector.classList.contains('selected')).to.be.false;
done();
});
});
});
});
});