UNPKG

lu2

Version:

Simple and flexible UI component library based on native HTML and JavaScript

1,004 lines (848 loc) 36.4 kB
/** * @Color.js * @author zhangxinxu * @version * @created 16-06-03 * @edited 20-07-16 @Gwokhov */ import './Follow.js'; const BG_COLOR = 'background-color'; class Color extends HTMLInputElement { // 指定观察的属性,这样attributeChangedCallback才会起作用 static get observedAttributes () { return ['disabled']; } constructor () { super(); this.setProperty(); } static addClass (...arg) { return ['ui', 'color', ...arg].join('-'); } // hsl颜色转换成十六进制颜色 static funHslToHex (h, s, l, a) { let r, g, b; if (s == 0) { // 非彩色的 r = g = b = l; } else { const hue2rgb = function (p, q, t) { if (t < 0) t += 1; if (t > 1) t -= 1; if (t < 1 / 6) return p + (q - p) * 6 * t; if (t < 1 / 2) return q; if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; return p; }; const q = l < 0.5 ? l * (1 + s) : l + s - l * s; const p = 2 * l - q; r = hue2rgb(p, q, h + 1 / 3); g = hue2rgb(p, q, h); b = hue2rgb(p, q, h - 1 / 3); } const arrRgb = [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]; // Alpha值 if (a) { arrRgb.push(Math.round(a * 255)); } return arrRgb.map(rgb => { rgb = rgb.toString(16); if (rgb.length == 1) { return '0' + rgb; } return rgb; }).join(''); } // 16进制颜色转换成hsl颜色表示 static funHexToHsl (hex) { hex = (hex || '').replace('#', ''); if (hex.length == 3 || hex.length == 4) { hex = hex.split('').map(function (char) { return char + char; }).join(''); } const r = parseInt(hex.slice(0, 2), 16) / 255; const g = parseInt(hex.slice(2, 4), 16) / 255; const b = parseInt(hex.slice(4, 6), 16) / 255; const max = Math.max(r, g, b); const min = Math.min(r, g, b); let h, s; const l = (max + min) / 2; if (max == min) { // 非彩色 h = s = 0; } else { const d = max - min; s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } if (hex.length == 8) { const a = parseInt(hex.slice(6, 8), 16) / 255; return [h, s, l, a]; } return [h, s, l]; } // rgb/rgba颜色转hex static funRgbToHex (rgb) { if (!rgb) { return Color.defaultValue; } let arr = []; let arrA = []; // 如果是不全的hex值,不全 // 有没有#都支持 rgb = rgb.replace('#', '').toLowerCase(); if (/^[0-9A-F]{1,6}$/i.test(rgb)) { return '#' + rgb.repeat(Math.ceil(6 / rgb.length)).slice(0, 6); } if (/^[0-9A-F]{1,8}$/i.test(rgb)) { return '#' + rgb.repeat(Math.ceil(8 / rgb.length)).slice(0, 8); } // 如果是rgb(a)色值 arr = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)/i); arrA = rgb.match(/^rgba\((\d+),\s*(\d+),\s*(\d+),\s*([0|1]?\.?\d+)/i); const hex = (x) => ('0' + parseInt(x, 10).toString(16)).slice(-2); if (arr && arr.length == 4) { return `#${hex(arr[1])}${hex(arr[2])}${hex(arr[3])}`; } if (arrA && arrA.length == 5) { return `#${hex(arrA[1])}${hex(arrA[2])}${hex(arrA[3])}${Math.round(arrA[4] * 255).toString(16).padStart(2, '0')}`; } return Color.defaultValue; } get type () { return this.getAttribute('type') || 'color'; } set type (v) { return this.setAttribute('type', v || 'color'); } /** * container内的一些事件 * @return {Object} 返回当前DOM元素对象 */ events () { const objElement = this.element; // 元素 const eleContainer = objElement.target; // 元素 const eleCircle = objElement.circle; const eleFill = objElement.fill; const eleArrow = objElement.arrow; // 面板内部唯一的输入框元素 const eleField = objElement.field; // 透明度滑动条 const eleOpacity = objElement.opacity; eleContainer.addEventListener('click', (event) => { const eleTarget = event.target; // 选择的颜色值 let strValue = ''; // 当前类名 const strCl = eleTarget.className; // 按钮分类别处理 if (/cancel/.test(strCl)) { // 1. 取消按钮 this.hide(); } else if (/lump/.test(strCl)) { // 3. 小色块 strValue = eleTarget.getAttribute('data-color'); this.value = '#' + strValue; } else if (/switch/.test(strCl)) { // 4. 面板类名切换按钮 if (eleTarget.textContent === '更多') { objElement.more.style.display = 'block'; objElement.basic.style.display = 'none'; eleTarget.textContent = '基本'; objElement.mode.setAttribute('data-mode', 'basic'); } else { objElement.more.style.display = 'none'; objElement.basic.style.display = 'block'; eleTarget.textContent = '更多'; objElement.mode.setAttribute('data-mode', 'more'); } // 面板的色块啊,圆和尖角位置匹配 this.match(); } }); // 输入框事件 eleField.addEventListener('input', () => { const value = this.value; if (/^[0-9A-F]{6}$/i.test(value) || /^[0-9A-F]{8}$/i.test(value)) { this.match(); } else if (/^[0-9A-F]{3, 4}$/i.test(value)) { this.match(Color.funRgbToHex('#' + value).replace('#', '')); } }); eleField.addEventListener('keyup', (event) => { if (event.keyCode == 13) { let strValue = eleField.value; if (strValue) { if (eleOpacity) { strValue = Color.funRgbToHex('#' + strValue).replace('#', ''); } else { strValue = Color.funRgbToHex('#' + strValue.slice(0, 6)).replace('#', ''); } this.value = '#' + strValue; } this.hide(); } }); // 透明度改变的时候 if (eleOpacity) { eleOpacity.addEventListener('input', () => { let strValue = eleField.value; let curOpacity = Math.round(eleOpacity.value / 100 * 255).toString(16).padStart(2, '0'); if (strValue) { let strValueColor = strValue.slice(0, 6) + curOpacity; this.value = strValueColor; } }); } // 滑块拖动事件 const objPosArrow = {}; const objPosCircle = {}; // 三角上下 eleArrow.addEventListener('pointerdown', (event) => { event.preventDefault(); objPosArrow.pageY = event.pageY; objPosArrow.top = parseFloat(window.getComputedStyle(eleArrow).top); }); eleFill.addEventListener('pointerdown', (event) => { event.preventDefault(); // 5. 渐变色的覆盖层 // offsetLeft, offsetTop let eleTarget = event.target; const objRect = eleTarget.getBoundingClientRect(); const numOffsetTop = event.pageY - window.pageYOffset - objRect.top; eleArrow.style.top = numOffsetTop + 'px'; // 赋值 this.isTrustedEvent = true; this.value = this.getValueByStyle(); objPosArrow.pageY = event.pageY; objPosArrow.top = parseFloat(window.getComputedStyle(eleArrow).top); }); // 范围上下左右 eleCircle.parentElement.querySelectorAll('a').forEach((eleRegion) => { eleRegion.addEventListener('pointerdown', (event) => { event.preventDefault(); objPosCircle.pageY = event.pageY; objPosCircle.pageX = event.pageX; // 当前位移位置 eleCircle.style.left = event.offsetX + 'px'; eleCircle.style.top = event.offsetY + 'px'; objPosCircle.top = parseFloat(event.offsetY); objPosCircle.left = parseFloat(event.offsetX); // UI变化 this.isTrustedEvent = true; this.value = this.getValueByStyle(); }); }); document.addEventListener('pointermove', (event) => { if (typeof objPosArrow.top == 'number') { event.preventDefault(); let numTop = objPosArrow.top + (event.pageY - objPosArrow.pageY); const numMaxTop = eleArrow.parentElement.clientHeight; // 边界判断 if (numTop < 0) { numTop = 0; } else if (numTop > numMaxTop) { numTop = numMaxTop; } eleArrow.style.top = numTop + 'px'; // 赋值,此次赋值,无需重定位 this.isTrustedEvent = true; this.value = this.getValueByStyle(); } else if (typeof objPosCircle.top == 'number') { event.preventDefault(); const objPos = { top: event.pageY - objPosCircle.pageY + objPosCircle.top, left: event.pageX - objPosCircle.pageX + objPosCircle.left }; const objMaxPos = { top: eleCircle.parentElement.clientHeight, left: eleCircle.parentElement.clientWidth }; // 边界判断 if (objPos.left < 0) { objPos.left = 0; } else if (objPos.left > objMaxPos.left) { objPos.left = objMaxPos.left; } if (objPos.top < 0) { objPos.top = 0; } else if (objPos.top > objMaxPos.top) { objPos.top = objMaxPos.top; } // 根据目标位置位置和变色 const numColorH = objPos.left / objMaxPos.left; const strColorS = 1 - objPos.top / objMaxPos.top; // 圈圈定位 eleCircle.style.left = objPos.left + 'px'; eleCircle.style.top = objPos.top + 'px'; const strHsl = `hsl('${[360 * numColorH, 100 * strColorS + '%', '50%'].join()})`; eleCircle.style[BG_COLOR] = strHsl; // 赋值 this.isTrustedEvent = true; this.value = this.getValueByStyle(); } }, { passive: false }); document.addEventListener('pointerup', () => { objPosArrow.top = null; objPosCircle.top = null; }); // 滑块的键盘支持 eleFill.parentElement.querySelectorAll('a').forEach((eleButton) => { eleButton.addEventListener('keydown', (event) => { // 上下控制 if (event.keyCode == 38 || event.keyCode == 40) { event.preventDefault(); let numTop = parseFloat(window.getComputedStyle(eleArrow).top); const numMaxTop = eleFill.clientHeight; if (event.keyCode == 38) { numTop--; if (numTop < 0) { numTop = 0; } } else { numTop++; if (numTop > numMaxTop) { numTop = numMaxTop; } } const ariaLabel = eleArrow.getAttribute('aria-label'); eleArrow.style.top = numTop + 'px'; eleArrow.setAttribute('aria-label', ariaLabel.replace(/\d+/, Math.round(100 * numTop / numMaxTop))); // 赋值,此次赋值,无需重定位 this.isTrustedEvent = true; this.value = this.getValueByStyle(); } }); }); // 圈圈的键盘访问 // 区域背景的键盘支持 eleCircle.parentElement.querySelectorAll('a').forEach((eleRegion) => { eleRegion.addEventListener('keydown', (event) => { // 上下左右控制 if (event.keyCode >= 37 && event.keyCode <= 40) { event.preventDefault(); const objStyleCircle = window.getComputedStyle(eleCircle); let numTop = parseFloat(objStyleCircle.top); let numLeft = parseFloat(objStyleCircle.left); const numMaxTop = eleRegion.clientHeight; const numMaxLeft = eleRegion.clientWidth; if (event.keyCode == 38) { // up numTop--; if (numTop < 0) { numTop = 0; } } else if (event.keyCode == 40) { // down numTop++; if (numTop > numMaxTop) { numTop = numMaxTop; } } else if (event.keyCode == 37) { // left numLeft--; if (numLeft < 0) { numLeft = 0; } } else if (event.keyCode == 39) { // down numLeft++; if (numLeft > numMaxLeft) { numLeft = numMaxLeft; } } eleCircle.style.left = numLeft + 'px'; eleCircle.style.top = numTop + 'px'; // 赋值 this.isTrustedEvent = true; this.value = this.getValueByStyle(); } }); }); return this; } /** * container内HTML的创建 * @return {Object} 返回当前DOM元素对象 */ create () { // 元素 const eleContainer = this.element.target; const isSupportOpacity = this.type === 'color-opacity'; // switch button const strHtmlConvert = `<button class="${Color.addClass('switch')} colorMode" data-mode="more" role="button">更多</button>`; // current color const strHtmlCurrent = `<div class="${Color.addClass('current')}"> <i class="${isSupportOpacity ? Color.addClass('current', 'square', 'opacity') : Color.addClass('current', 'square')} colorCurrent"></i> #<input class="${Color.addClass('current', 'input')}" value="${this.value.replace('#', '')}"> </div>`; // const arrBasicColor = this.params.color.basic; const arrBasicColorPreset = this.params.color.basicPreset; const arrFixedColor = this.params.color.fixed; // body const strHtmlBody = `<div class="${Color.addClass('body')}">` + (function () { // basic color picker let strHtml = `<div class="${Color.addClass('basic')} colorBasicX" role="listbox">`; let arrCommonColors = (localStorage.commonColors || '').split(','); // color left strHtml += `<aside class="${Color.addClass('basic', 'l')}">` + (function () { return arrFixedColor.concat(arrCommonColors[0] || '0ff', arrCommonColors[1] || '800180').map(function (color) { const strColor = Color.funRgbToHex(color).replace('#', ''); return `<a href="javascript:" class="${Color.addClass('lump')}" data-color="${strColor}" aria-label="${strColor}" style="${BG_COLOR}:#${strColor}" role="option"></a>`; }).join(''); })() + '</aside>'; // color main strHtml = strHtml + `<div class="${Color.addClass('basic', 'r')}">` + (function () { let strHtmlRG = ''; arrBasicColorPreset.forEach(colorItem => { strHtmlRG += `<a href="javascript:" title="#${colorItem}${isSupportOpacity ? 'ff' : ''}" class="${Color.addClass('lump', 'preset')}" data-color="${colorItem}${isSupportOpacity ? 'ff' : ''}" style="${BG_COLOR}:#${colorItem}${isSupportOpacity ? 'ff' : ''}" aria-label="${colorItem}${isSupportOpacity ? 'ff' : ''}" role="option"></a>`; }); return strHtmlRG; })() + '</div>'; return strHtml + '</div>'; })() + (function () { // more color picker let html = `<div class="${Color.addClass('more')} colorMoreX">`; // color left html += `<div class="${Color.addClass('more', 'l')}"> <a href="javascript:" class="${Color.addClass('cover', 'white')}" aria-label="色域背景块" role="region"></a><div class="${Color.addClass('circle')} colorCircle"></div> <div class="${Color.addClass('gradient')}"> </div> </div><div class="${Color.addClass('more', 'r')}"> <div class="${Color.addClass('more', 'fill')} colorFill"> <a href="javascript:" class="${Color.addClass('more', 'cover')}" aria-label="明度控制背景条" role="region"></a> <div class="${Color.addClass('gradient')}" style="background: linear-gradient(#ffffff 0%, rgba(255,255,255,0) 50%, rgba(0,0,0,0) 50%, ${Color.defaultValue} 100%);"> </div> </div> <a href="javascript:" class="${Color.addClass('more', 'arrow')} colorArrow" role="slider" aria-label="明度控制按钮:100%"></a> </div>`; return html + '</div>'; })() + (function () { // 透明度-滑动条 if (isSupportOpacity) { let opacityHtml = '<div' + ` class="${Color.addClass('opacity')}">透明度:<input class="${Color.addClass('opacity', 'range')} colorOpacity"` + 'type="range" value="100" min="0" max="100" step="1" data-tips="${value}%" is="ui-range"></div>'; return opacityHtml; } return ''; })() + '</div>'; // footer const strHtmlFooter = ''; // append eleContainer.innerHTML = strHtmlConvert + strHtmlCurrent + strHtmlBody + strHtmlFooter; // 一些元素 Object.assign(this.element, { field: eleContainer.querySelector('input'), basic: eleContainer.querySelector('.colorBasicX'), more: eleContainer.querySelector('.colorMoreX'), mode: eleContainer.querySelector('.colorMode'), opacity: eleContainer.querySelector('.colorOpacity'), circle: eleContainer.querySelector('.colorCircle'), fill: eleContainer.querySelector('.colorFill'), arrow: eleContainer.querySelector('.colorArrow'), current: eleContainer.querySelector('.colorCurrent') }); // filed做一些事情 const propValue = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value'); let eleField = this.element.field; Object.defineProperty(eleField, 'value', { ...propValue, set (value) { // 赋值 propValue.set.call(this, value); // 回调触发 eleField.dispatchEvent(new CustomEvent('change')); } }); if (document.body.contains(eleContainer) == false) { document.body.appendChild(eleContainer); } // 事件 this.events(); return this; } /** * 面板的色块啊,圆和尖角位置匹配 * @param {String} value 面板UI相匹配的色值,可缺省,表示使用当前输入框的颜色值进行UI变化 * @return {Object} 返回当前DOM元素对象 */ match (value) { // 首先要面板显示 if (this.display != true) { return this; } // 元素对象 const objElement = this.element; // 元素 const eleContainer = objElement.target; const eleCurrent = objElement.current; // 更多元素 const eleMore = objElement.more; // 元素 const eleCircle = objElement.circle; const eleFill = objElement.fill; const eleArrow = objElement.arrow; // 面板内部唯一的输入框元素 const eleField = objElement.field; const eleOpacity = objElement.opacity; // 重定位 let isRePosition = true; if (value === false) { isRePosition = false; } // 当前的颜色值 let strValue = value || eleField.value; if (strValue == '') { // 如果输入框没有值 // 使用之前一个合法的颜色值作为现在值 strValue = Color.funRgbToHex(getComputedStyle(eleCurrent)[BG_COLOR]).replace('#', ''); eleField.value = strValue; } strValue = strValue.replace('#', ''); // 色块值示意&透明度条状态更新 if (eleOpacity) { if (/^[0-9A-F]{8}$/i.test(strValue)) { eleOpacity.value = parseInt(strValue.slice(6, 8), 16) / 255 * 100; } if (/^[0-9A-F]{6}$/i.test(strValue)) { eleField.value += Math.round(eleOpacity.value / 100 * 255).toString(16).padStart(2, '0'); } } else { eleCurrent.style[BG_COLOR] = '#' + strValue; } // 当前是基本色面板还是任意色面板 if (window.getComputedStyle(eleMore).display == 'none') { // 1. 基本色 // 所有当前高亮的元素不高亮 const eleActive = eleContainer.querySelector('.active'); if (eleActive) { eleActive.classList.remove('active'); } // 所有颜色一致的高亮 const eleColorMatch = eleContainer.querySelector(`a[data-color="${strValue.toUpperCase()}"]`); if (eleColorMatch) { eleColorMatch.classList.add('active'); } } else { let numWidth = eleCircle.parentElement.clientWidth; let numHeight = eleCircle.parentElement.clientHeight; let numColorH = 0; let numColorS = 1; let numColorL = 0.5; // 滑块和尖角的颜色和位置 if (isRePosition == true) { // to HSL let arrHSL = Color.funHexToHsl(strValue); // hsl value numColorH = arrHSL[0]; numColorS = arrHSL[1]; numColorL = arrHSL[2]; eleCircle.style.left = numWidth * numColorH + 'px'; eleCircle.style.top = numHeight * (1 - numColorS) + 'px'; eleArrow.style.top = eleArrow.parentElement.clientHeight * (1 - numColorL) + 'px'; } else { numColorH = parseFloat(eleCircle.style.left || 0) / numWidth; numColorS = 1 - parseFloat(eleCircle.style.top || 0) / numHeight; } // 滑块和尖角的颜色和位置 let strColor = `hsl(${[360 * numColorH, Math.round(100 * numColorS) + '%', '50%'].join()}`; eleFill.style[BG_COLOR] = strColor; eleCircle.style[BG_COLOR] = strColor; } return this; } /** * 浮层定位方法 * @return undefined */ position () { // 面板定位 this.follow(); return this; } /** * 颜色面板显示 * @return undefined */ show () { // 元素 let eleContainer = this.element.target; // 输入框赋值 if (eleContainer.innerHTML.trim() == '') { this.create(); } // 改变显示状态 this.display = true; // 面板显示 eleContainer.style.display = 'inline'; // 键盘ESC隐藏支持 eleContainer.classList.add('ESC'); // aria this.setAttribute('aria-expanded', 'true'); // 定位 this.position(); // 面板UI匹配 const eleCurrent = this.element.current; if (!eleCurrent.getAttribute('style')) { eleCurrent.style[BG_COLOR] = this.value; } this.match(); // show callback this.dispatchEvent(new CustomEvent('show', { detail: { type: 'ui-color' } })); return this; } /** * 颜色面板隐藏 * @return undefined */ hide () { let eleContainer = this.element.target; // 面板隐藏 eleContainer.style.display = 'none'; eleContainer.classList.remove('ESC'); // aria this.setAttribute('aria-expanded', 'false'); // 改变显示状态 this.display = false; // 聚焦,键盘访问顺序回归正常 this.focus(); // hide callback // 因为this.drop.hide的时候还会执行一次这里的hide()方法, // 因此这里加了个display判断 // 避免连续两次hide事件的实习 this.dispatchEvent(new CustomEvent('hide', { detail: { type: 'ui-color' } })); return this; } /** * 给当前元素对象扩展方法、重置原生value属性 */ setProperty () { /** * 根据坐标位置获得hsl值 * 私有 * @return {String} [返回当前坐标对应的hex表示的颜色值] */ Object.defineProperty(this, 'getValueByStyle', { value: () => { // 需要的元素 const eleCircle = this.element.circle; const eleArrow = this.element.arrow; const eleOpacity = this.element.opacity; if (eleCircle.length * eleArrow.length == 0) { return Color.defaultValue; } let numColorH, numColorS, numColorL; // get color // hsl color if (eleCircle.style.left) { numColorH = parseFloat(window.getComputedStyle(eleCircle).left) / eleCircle.parentElement.clientWidth; } else { numColorH = 0; } if (eleCircle.style.top) { numColorS = 1 - parseFloat(window.getComputedStyle(eleCircle).top) / eleCircle.parentElement.clientHeight; } else { numColorS = 1; } if (eleArrow.style.top) { numColorL = 1 - parseFloat(window.getComputedStyle(eleArrow).top) / eleArrow.parentElement.clientHeight; } else { numColorL = 0; } // 支持透明度 if (eleOpacity && eleOpacity.value) { return '#' + Color.funHslToHex(numColorH, numColorS, numColorL, eleOpacity.value / 100); } return '#' + Color.funHslToHex(numColorH, numColorS, numColorL); } }); const props = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value'); Object.defineProperty(Color.prototype, 'value', { ...props, set (value) { let strValue = value; // 元素 // 目前的颜色值 let strOldValue = this.value; // 取值还是赋值 if (typeof value == 'string') { // 如果是纯字母,则认为是关键字 if (/^[a-z]{3,}$/.test(strValue)) { document.head.style.backgroundColor = strValue; strValue = window.getComputedStyle(document.head).backgroundColor; document.head.style.backgroundColor = ''; } // 使用hex值 strValue = Color.funRgbToHex(strValue); // 赋值 props.set.call(this, strValue); // 可能存在还未和页面建立联系的时候执行value赋值 if (!this.params) { return; } // 作为常用颜色记录下来 const strCommonColors = localStorage.commonColors || ''; let arrCommonColors = strCommonColors.split(','); // 前提颜色非纯灰色若干色值 const arrFixedColor = this.params.color.fixed; if (arrFixedColor.some((strFixedColor) => { return Color.funRgbToHex(strFixedColor) == strValue; }) == false) { // 过滤已经存在的相同颜色的色值 arrCommonColors = arrCommonColors.filter((strValueWithSharp) => { return strValueWithSharp && strValueWithSharp != strValue.replace('#', ''); }); // 从前面插入 arrCommonColors.unshift(strValue.replace('#', '')); // 本地存储 localStorage.commonColors = arrCommonColors.join(); // 2个动态色值更新 const eleBasic = this.element.basic; if (eleBasic) { const eleAsideColors = eleBasic.querySelectorAll('aside a'); const eleBasicColorLast = eleAsideColors[eleAsideColors.length - 2]; const eleBasicColorSecond = eleAsideColors[eleAsideColors.length - 1]; eleBasicColorLast.setAttribute('data-color', arrCommonColors[0]); eleBasicColorLast.setAttribute('aria-label', arrCommonColors[0]); eleBasicColorLast.style[BG_COLOR] = strValue; const strColorSecond = arrCommonColors[1] || '0ff'; eleBasicColorSecond.setAttribute('data-color', strColorSecond); eleBasicColorSecond.setAttribute('aria-label', strColorSecond); eleBasicColorSecond.style[BG_COLOR] = '#' + strColorSecond; } } this.style.setProperty('--ui-color-opacity', strValue); this.element.target.style.setProperty('--ui-color-opacity', strValue); if (this.element.field) { this.element.field.value = strValue.replace('#', ''); } // 面板上的值,各种定位的匹配 if (this.isTrustedEvent) { this.match(false); this.isTrustedEvent = null; } else { this.match(); } } else if (!strOldValue) { // 取值 // 如果默认无值,使用颜色作为色值,一般出现在初始化的时候 strOldValue = Color.defaultValue; // 赋值 props.set.call(this, strOldValue); } if (strOldValue && strValue != strOldValue) { this.dispatchEvent(new CustomEvent('change', { 'bubbles': true })); this.dispatchEvent(new CustomEvent('input', { 'bubbles': true })); } } }); // 标题设置 if (!this.title) { this.title = (this.disabled ? '禁止' : '') + '颜色选择'; } } attributeChangedCallback (name) { if (name == 'disabled') { if (this.title == '颜色选择' && this.disabled) { this.title = '禁止颜色选择'; } else if (this.title == '禁止颜色选择' && !this.disabled) { this.title = '颜色选择'; } } } connectedCallback () { if (!this.id) { // 创建随机id this.id = 'lulu_' + (Math.random() + '').split('.')[1]; } // 阻止默认的颜色选择出现 this.addEventListener('click', event => { event.preventDefault(); if (this.display != true) { this.show(); } }); // 默认朝下居中对齐 if (!this.dataset.position) { this.dataset.position = '7-5'; } // 浮层容器 const eleContainer = document.createElement('div'); eleContainer.classList.add(Color.addClass('container')); eleContainer.id = ('lulu_' + Math.random()).replace('0.', ''); this.dataset.target = eleContainer.id; // 全局暴露的一些元素 this.element = { target: eleContainer }; if (this.getAttribute('type') === 'color-opacity') { this.style.setProperty('--ui-color-opacity', this.value); eleContainer.style.setProperty('--ui-color-opacity', this.value); } // 全局的基础色值 const arrBasicColor = ['0', '3', '6', '9', 'c', 'f']; const arrBasicColorPreset = ['2a80eb', '0057c3', '7fdbff', 'f7f9fa', '1cad70', '3d9970', '39cccc', 'dddddd', 'eb4646', 'ab2526', 'ef8a5e', 'a2a9b6', 'f59b00', 'de6d00', 'ffdc00', '4c5161']; const arrFixedColor = arrBasicColor.concat('eb4646', '1cad70', '2a80eb', 'f59b00'); this.params = this.params || {}; this.params.color = { basic: arrBasicColor, basicPreset: arrBasicColorPreset, fixed: arrFixedColor }; // 点击空白隐藏浮层的处理 document.addEventListener('click', event => { const eleClicked = event && event.target; if (!eleClicked || !this.display) { return; } if (eleClicked != this && eleContainer.contains(eleClicked) == false) { this.hide(); } }); // 窗口尺寸变化时候的处理 window.addEventListener('resize', () => { if (this.display) { this.position(); } }); // 全局事件 this.dispatchEvent(new CustomEvent('connected', { detail: { type: 'ui-color' } })); this.isConnectedCallback = true; } } Color.defaultValue = '#000000'; if (!customElements.get('ui-color')) { customElements.define('ui-color', Color, { extends: 'input' }); } export default Color;