stephen's blog

[object Object] object(s)
 

手把手实现一个 Color-Picker

前言

Color-Picker 组件在富文本编辑器、画图类等应用中十分常见,通过获取当前选中颜色的值来更新其他视图,本文基于 ES6 的语法手把手实现一个 Color-Picker 组件,demo 可以点击这里。在实现之前,先简单的分析一下组件整个的结构,Color-Picker 主要由三部分构成:color-label、color-options、color-field
屏幕快照 2017-09-20 16.06.50

下面我们就一步步实现这样的一个组件。

组件实现

首先我们先定义一个 ColorPicker 的类以及基本的一些方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class ColorPicker {
constructor(options){
this.options = Object.assign({}, ColorPicker.DEFAULT, options)
this.el = document.querySelector(this.options.el)
this.colors = this.options.colors || []
this.handler = this.options.handler || function() {}
this.selectedColor = this.options.default
this.container = document.createElement('span')
this.el.appendChild(this.container)
this.buildPicker()
this.label.addEventListener('mousedown', () => {
this.container.classList.toggle('expanded')
})
}
buildLabel() {
...
}
buildItem() {
...
}
buildOptions() {
...
}
buildField() {
...
}
buildPicker() {
this.container.classList.add('picker')
this.label = this.buildLabel()
this.options = this.buildOptions()
this.field = this.buildField()
}
}

构造函数里初始化一些传入的参数,这里我们默认的 options 组成是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ColorPicker.DEFAULT = {
el: '#container',
default: "#000000",
colors: [
"#000000", "#e60000", "#ff9900", "#ffff00", "#008a00", "#0066cc", "#9933ff",
"#ffffff", "#facccc", "#ffebcc", "#ffffcc", "#cce8cc", "#cce0f5", "#ebd6ff",
"#bbbbbb", "#f06666", "#ffc266", "#ffff66", "#66b966", "#66a3e0", "#c285ff",
"#888888", "#a10000", "#b26b00", "#b2b200", "#006100", "#0047b2", "#6b24b2",
"#444444", "#5c0000", "#663d00", "#666600", "#003700", "#002966", "#3d1466"
],
handler: function(color) {
let display = document.querySelector('.display')
display.innerHTML = color
display.style.color = color
}
}

其中 el 是绑定的元素, default 是默认的颜色,colors 是色板数组, handler 是选中颜色时执行的回调。可以看到,我们在构造函数里创建了一个 container 将其与 el 绑定起来,同时监听 label 的 mousedown 事件来控制展开颜色面板,下面我们分别实现组件元素的 build。

构建 color-label:

1
2
3
4
5
6
7
buildLabel() {
let label = document.createElement('span')
label.classList.add('picker-label')
label.style.backgroundColor = this.options.default
this.container.appendChild(label)
return label
}

构建 color-item:

1
2
3
4
5
6
7
8
buildItem(option) {
let item = document.createElement('span')
item.classList.add('picker-item')
item.setAttribute('data-value', option)
item.style.backgroundColor = option
item.addEventListener('click', () => this.selectItem(item, true))
return item
}

这里给每个 item 加上一个 data-value 的属性,方便我们拿到当前选中的颜色值,同时监听每个 item 的 click,然后执行 selectItem 更新其他部分(下面会说到)。

构建 color-options:

1
2
3
4
5
6
7
8
9
10
buildOptions() {
let options = document.createElement('span')
options.classList.add('picker-options')
this.colors.forEach((option) => {
let item = this.buildItem(option)
options.appendChild(item)
})
this.container.append(options)
return options
}

构建 color-field:

1
2
3
4
5
6
7
buildField() {
let field = document.createElement('span')
field.classList.add('picker-field')
field.innerHTML = this.selectedColor
this.options.appendChild(field)
return field
}

组成元素构建完成后就只剩下,每次点击元素后更新对应元素的状态,同时执行传入的回调,我们通过 selectItem 实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
selectItem(item, triggle = false) {
let selected = this.container.querySelector('.selected')
if (item === selected) return
if (selected != null) selected.classList.remove('selected')
if (item == null) return
item.classList.add('selected')
if (item.hasAttribute('data-value')) {
this.selectedColor = item.getAttribute('data-value')
this.label.style.backgroundColor = this.selectedColor
this.field.innerHTML = this.selectedColor
}
if (triggle) {
value && this.handler(value)
}
}

可以看到,这里我们通过拿到选中 item 的 data-value 的值来分别更新 color-label、color-field 的值,同时执行相应的回调。

总结

至此一个简单的 Color-Picker 组件就完成了,实现也很简单,具体源码放在我的 github