|
| 1 | +import PropTypes from '../_util/vue-types'; |
| 2 | +import { ConfigConsumerProps } from '../config-provider'; |
| 3 | +import BaseMixin from '../_util/BaseMixin'; |
| 4 | +import Pickr from '@simonwep/pickr/dist/pickr.es5.min'; |
| 5 | +import Icon from '../icon'; |
| 6 | +import LocaleReceiver from '../locale-provider/LocaleReceiver'; |
| 7 | +import enUS from './locale/en_US'; |
| 8 | +import debounce from 'lodash/debounce'; |
| 9 | + |
| 10 | +import { getOptionProps } from '../_util/props-util'; |
| 11 | +let colors = '#194d33'; |
| 12 | +export default { |
| 13 | + name: 'AColorPicker', |
| 14 | + mixins: [BaseMixin], |
| 15 | + model: { |
| 16 | + prop: 'value', |
| 17 | + event: 'change.value', //为了支持v-model直接返回颜色字符串 所以用了自定义的事件,与pickr自带change事件进行区分 |
| 18 | + }, |
| 19 | + props: { |
| 20 | + prefixCls: PropTypes.string, |
| 21 | + defaultValue: PropTypes.string, //默认值 |
| 22 | + config: PropTypes.object, //pickr配置 |
| 23 | + value: PropTypes.string, //颜色值 |
| 24 | + locale: PropTypes.object, //双语包 |
| 25 | + colorRounded: PropTypes.number, //颜色数值保留几位小数 |
| 26 | + size: PropTypes.oneOf(['default', 'small', 'large']).def('default'), //尺寸 |
| 27 | + getPopupContainer: PropTypes.func, //指定渲染容器 |
| 28 | + disabled: PropTypes.bool.def(false), //是否禁用 |
| 29 | + format: PropTypes.string, //颜色格式设置 |
| 30 | + alpha: PropTypes.bool.def(false), //是否开启透明通道 |
| 31 | + hue: PropTypes.bool.def(true), //是否开启色彩预选 |
| 32 | + }, |
| 33 | + inject: { |
| 34 | + configProvider: { default: () => ConfigConsumerProps }, |
| 35 | + }, |
| 36 | + data() { |
| 37 | + return { |
| 38 | + colors, |
| 39 | + myOpen: false, |
| 40 | + pickr: null, |
| 41 | + i18n: enUS, |
| 42 | + }; |
| 43 | + }, |
| 44 | + watch: { |
| 45 | + 'configProvider.locale.ColorPicker': { |
| 46 | + handler(val) { |
| 47 | + if (this.locale) return; |
| 48 | + this.i18n = val; |
| 49 | + this.reInitialize(); |
| 50 | + }, |
| 51 | + }, |
| 52 | + locale(val) { |
| 53 | + this.i18n = val.ColorPicker || val.lang; |
| 54 | + this.reInitialize(); |
| 55 | + }, |
| 56 | + value(val) { |
| 57 | + this.setColor(val); |
| 58 | + }, |
| 59 | + disabled(val) { |
| 60 | + this.pickr[val ? 'disable' : 'enable'](); |
| 61 | + }, |
| 62 | + config: { |
| 63 | + handler() { |
| 64 | + this.reInitialize(); |
| 65 | + }, |
| 66 | + deep: true, |
| 67 | + }, |
| 68 | + format(val) { |
| 69 | + const type = val.toLocaleUpperCase(); |
| 70 | + let res = this.pickr.setColorRepresentation(type); |
| 71 | + if (res) { |
| 72 | + this.pickr.applyColor(); |
| 73 | + } else { |
| 74 | + throw new TypeError('format was invalid'); |
| 75 | + } |
| 76 | + }, |
| 77 | + }, |
| 78 | + mounted() { |
| 79 | + if (this.locale) { |
| 80 | + this.i18n = this.locale.ColorPicker || this.locale.lang; |
| 81 | + } |
| 82 | + this.createPickr(); |
| 83 | + this.eventsBinding(); |
| 84 | + }, |
| 85 | + destroyed() { |
| 86 | + this.pickr.destroyAndRemove(); |
| 87 | + }, |
| 88 | + methods: { |
| 89 | + reInitialize() { |
| 90 | + this.pickr.destroyAndRemove(); |
| 91 | + const dom = document.createElement('div'); |
| 92 | + dom.id = 'color-picker' + this._uid; |
| 93 | + const box = this.$el.querySelector('#color-picker-box' + this._uid); |
| 94 | + box.appendChild(dom); |
| 95 | + this.createPickr(); |
| 96 | + this.eventsBinding(); |
| 97 | + }, |
| 98 | + setColor: debounce(function(val) { |
| 99 | + this.pickr.setColor(val); |
| 100 | + }, 1000), |
| 101 | + eventsBinding() { |
| 102 | + const pickrEvents = [ |
| 103 | + 'init', |
| 104 | + 'hide', |
| 105 | + 'show', |
| 106 | + 'save', |
| 107 | + 'clear', |
| 108 | + 'change', |
| 109 | + 'changestop', |
| 110 | + 'cancel', |
| 111 | + 'swatchselect', |
| 112 | + ]; |
| 113 | + Object.keys(this.$listeners).forEach(event => { |
| 114 | + pickrEvents.includes(event) && this.pickr.on(event, this.$listeners[event]); |
| 115 | + }); |
| 116 | + }, |
| 117 | + createPickr() { |
| 118 | + const { getPopupContainer } = getOptionProps(this); |
| 119 | + const { getPopupContainer: getContextPopupContainer } = this.configProvider; |
| 120 | + const container = getPopupContainer || getContextPopupContainer; |
| 121 | + this.pickr = Pickr.create( |
| 122 | + Object.assign( |
| 123 | + { |
| 124 | + el: '#color-picker' + this._uid, |
| 125 | + container: (container && container(this.$el)) || document.body, |
| 126 | + theme: 'monolith', // or 'monolith', or 'nano' |
| 127 | + default: this.value || this.defaultValue || null, // 有默认颜色pickr才可以获取到_representation |
| 128 | + components: { |
| 129 | + // Main components |
| 130 | + preview: true, |
| 131 | + opacity: this.alpha, |
| 132 | + hue: this.hue, |
| 133 | + // Input / output Options |
| 134 | + interaction: { |
| 135 | + hex: true, |
| 136 | + rgba: true, |
| 137 | + input: true, |
| 138 | + clear: true, |
| 139 | + save: true, |
| 140 | + }, |
| 141 | + }, |
| 142 | + }, |
| 143 | + this.config, |
| 144 | + { i18n: this.i18n }, |
| 145 | + ), |
| 146 | + ) |
| 147 | + .on('save', (color, instance) => { |
| 148 | + if (color) { |
| 149 | + let _representation = instance._representation || 'HEXA'; |
| 150 | + color = color['to' + _representation]().toString(this.colorRounded || 0); |
| 151 | + } |
| 152 | + this.$emit('change.value', color || ''); |
| 153 | + }) |
| 154 | + .on('hide', () => { |
| 155 | + this.setState({ myOpen: false }); |
| 156 | + }); |
| 157 | + }, |
| 158 | + handleOpenChange() { |
| 159 | + const open = !this.myOpen; |
| 160 | + this.setState({ myOpen: open }); |
| 161 | + this.pickr[open ? 'show' : 'hide'](); |
| 162 | + this.$emit('openChange', open); |
| 163 | + }, |
| 164 | + getDefaultLocale() { |
| 165 | + const result = { |
| 166 | + ...enUS, |
| 167 | + ...this.$props.locale, |
| 168 | + }; |
| 169 | + result.lang = { |
| 170 | + ...result.lang, |
| 171 | + ...(this.$props.locale || {}).lang, |
| 172 | + }; |
| 173 | + return result; |
| 174 | + }, |
| 175 | + renderColorPicker() { |
| 176 | + const { prefixCls: customizePrefixCls } = this.$props; |
| 177 | + const { getPrefixCls } = this.configProvider; |
| 178 | + const prefixCls = getPrefixCls('color-picker', customizePrefixCls); |
| 179 | + const { disabled } = getOptionProps(this); |
| 180 | + const classString = { |
| 181 | + [`${prefixCls}-box`]: true, |
| 182 | + [`${prefixCls}-open`]: this.myOpen, |
| 183 | + [`${prefixCls}-lg`]: this.size === 'large', |
| 184 | + [`${prefixCls}-sm`]: this.size === 'small', |
| 185 | + [`${prefixCls}-disabled`]: this.disabled, |
| 186 | + }; |
| 187 | + return ( |
| 188 | + <div class={classString} tabIndex={disabled ? -1 : 0} onClick={this.handleOpenChange}> |
| 189 | + <div class={`${prefixCls}-selection`}> |
| 190 | + <div id={'color-picker-box' + this._uid}> |
| 191 | + <div id={'color-picker' + this._uid}></div> |
| 192 | + </div> |
| 193 | + <Icon type="down" class={`${prefixCls}-icon`} /> |
| 194 | + </div> |
| 195 | + </div> |
| 196 | + ); |
| 197 | + }, |
| 198 | + }, |
| 199 | + render() { |
| 200 | + return ( |
| 201 | + <LocaleReceiver |
| 202 | + componentName="ColorPicker" |
| 203 | + defaultLocale={this.getDefaultLocale} |
| 204 | + scopedSlots={{ default: this.renderColorPicker }} |
| 205 | + /> |
| 206 | + ); |
| 207 | + }, |
| 208 | +}; |
0 commit comments