js实现拾色器插件(ColorPicker)
对一个前端来说,颜色选择的插件肯定不陌生,许多小伙伴对这类插件的实现可能会比较好奇,这里奉上原生js版本的拾色器。
效果图:
讲下实现方式:
1.颜色除了rgb跟十六进制的表现外,还有一个hsv的表现形式。h(hue)是色相,值域是0度到360度,这个值控制的是你看到的是什么颜色,通俗点讲就是红橙黄绿...;s(saturation)是饱和度,值域是0到1,这个值控制颜色的鲜艳程度,可以理解为大红跟淡红的差别;v(value)可以理解为亮度,值域也是0到1。
2.rgb颜色跟hsv颜色的相互转化有专门的公式,可自行去百度了解下
3.面向对象的编程方式公认为易扩展,高复用。
整个目录结构如下:
colorpicker
--css
--common.css(样式)
--js
--colorpicker.js(插件主体)
--event.js(简易的发布者-订阅者实现)
--inherite.js(继承手段,寄生组合式)
colorpicker.html
使用说明:
插件目前只支持传入h、s、v值来初始化颜色,若什么都不传,默认h、s、v都为0,实例化colorpicker构造函数后,通过select方法初始化;目前只暴露了两个回调接口onhchange(色相改变触发)、onsvchange(饱和度或亮度改变触发):
var aa = new colorpicker(); aa.select( // { // h: 120, // s: 1, // b: 1 // } ); aa.onhchange = function(e) {}; aa.onsvchange = function(e) {};
代码如下:
colorpicker.html:
<!doctype html> <!--[if lt ie 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]--> <!--[if ie 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]--> <!--[if ie 8]> <html class="no-js lt-ie9"> <![endif]--> <!--[if gt ie 8]><!--> <html class="no-js"> <!--<![endif]--> <head> <meta charset="utf-8"> <meta http-equiv="x-ua-compatible" content="ie=edge"> <title>color picker</title> <meta name="description" content=""> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="./css/common.css" rel="external nofollow" > </head> <body> </body> <script type="text/javascript" src="js/event.js"></script> <script type="text/javascript" src="js/inherite.js"></script> <script type="text/javascript" src="js/colorpicker.js"></script> </html>
common.css:
body { height: calc(100vh); overflow: hidden; background: gray; } .color-picker-container { border: 0; width: 300px; margin: 0 auto; } .color-picker-container .val-container { border: 1px solid silver; text-align: center; line-height: 30px; font-weight: bold; } .color-picker-container .val-container .val { width: 100%; border: 0; line-height: 32px; text-align: center; font-weight: bold; } .color-picker-container .picker-container { position: relative; width: 100%; margin-top: 15px; } .color-picker-container .picker-container .pointer { position: absolute; width: 14px; height: 14px; border-radius: 50%; border: 3px solid #ffffff; margin-left: -9px; margin-top: -9px; top: 255px; left: 0; cursor: pointer; } .color-picker-container .picker-container .saturation-range { float: left; width: 255px; height: 255px; /* background-color: rgba(0, 0, 0, .2); */ box-shadow: 1px 1px 5px rgba(0, 0, 0, .6); } .color-picker-container .picker-container .saturation-range .cover { width: 100%; height: 100%; background: -webkit-linear-gradient(top, rgb(0, 0, 0, 0) 0%, rgb(0, 0, 0) 100%); background: linear-gradient(top, rgb(0, 0, 0, 0) 0%, rgb(0, 0, 0) 100%); } .color-picker-container .picker-container .hue-range { float: right; width: 30px; height: 255px; box-shadow: 1px 1px 5px rgba(0, 0, 0, .6); background: -webkit-linear-gradient(top, rgb(255, 0, 0) 0%, rgb(255, 0, 255) 17%, rgb(0, 0, 255) 34%, rgb(0, 255, 255) 50%, rgb(0, 255, 0) 67%, rgb(255, 255, 0) 84%, rgb(255, 0, 0) 100%); background: linear-gradient(top, rgb(255, 0, 0) 0%, rgb(255, 0, 255) 17%, rgb(0, 0, 255) 34%, rgb(0, 255, 255) 50%, rgb(0, 255, 0) 67%, rgb(255, 255, 0) 84%, rgb(255, 0, 0) 100%); } .color-picker-container .picker-container .hue-range .cursor { position: relative; width: 44px; margin-top: -11px; top: 255px; cursor: n-resize; } .color-picker-container .picker-container .hue-range .cursor::before { content: ''; display: inline-block; width: 0; height: 0; border-style: solid; border-top-width: 5px; border-right-width: 0; border-bottom-width: 5px; border-left-width: 7px; border-top-color: transparent; border-bottom-color: transparent; border-left-color: rgba(0, 0, 0, .5); margin-left: -8px; } .color-picker-container .picker-container .hue-range .cursor::after { content: ''; display: inline-block; width: 0; height: 0; border-style: solid; border-top-width: 5px; border-right-width: 7px; border-bottom-width: 5px; border-left-width: 0; border-top-color: transparent; border-bottom-color: transparent; border-right-color: rgba(0, 0, 0, .5); margin-left: 33px; } .color-picker-container .picker-container::after { content: ''; display: block; clear: both; line-height: 0; visibility: hidden; }
event.js:
function event() { this.bindevent = []; } event.prototype.addevent = function(name, callback) { if(typeof callback !== 'function') return; var bexistevent = false; var untieevent = function() { if(window.removeeventlistener) { this.element.removeeventlistener(name, callback); } else if(window.detachevent) { this.element.detachevent('on' + name, callback); } else { this.element['on' + name] = null; } }; for(var i = 0, len = this.bindevent.length; i < len; i++) { if(this.bindevent[i].name == name) { this.removeevent(name); this.bindevent[i].untie = untieevent; this.bindevent[i].event = callback; bexistevent = true; break; } } if(window.addeventlistener) { this.element.addeventlistener(name, callback); } else if(window.attachevent) { this.element.attachevent('on' + name, callback); } else { this.element['on' + name] = callback; } if(!bexistevent) { this.bindevent.push({ name: name, event: callback, untie: function() { if(window.removeeventlistener) { this.element.removeeventlistener(name, callback); } else if(window.detachevent) { this.element.detachevent('on' + name, callback); } else { this.element['on' + name] = null; } } }); } } event.prototype.removeevent = function(name) { if(typeof name === 'undefined' || name === '') return; // 从已绑定事件列表中剔除 for(var i = 0, len = this.bindevent.length; i < len; i++) { if(this.bindevent[i].name == name) { this.bindevent[i].untie.call(this); // 移除绑定事件 this.bindevent.splice(i, 1); // 从事件列表删除 break; } } } event.prototype.triggerevent = function(name) { var callback = null; for(var i = 0, len = this.bindevent.length; i < len; i++) { if(this.bindevent[i].name === name) { callback = this.bindevent[i].event; } } if(typeof callback === 'function') { callback.apply(this, [].slice.call(arguments).slice(1)); } }
inherite.js:
function inheritobj(o) { function f() {}; f.prototype = o; return new f(); } function inheritproto(subclass, supclass) { subclass.prototype = inheritobj(supclass.prototype); subclass.prototype.constructor = subclass; } function extend(p, o) { for(var item in o) { if(!p.hasownproperty(item)) { p[item] = o[item]; } } } function container(classname) { this.element = null; this.classname = classname || ''; this.parent = null; this.children = []; this.init(); } container.prototype.init = function() { this.element = document.createelement(this.tagname || 'div'); this.classname && (this.element.classname = this.classname); } container.prototype.getelement = function() { return this.element; } container.prototype.add = function(item) { item.parent = this; this.children.push(item); this.element.appendchild(item.getelement()); return this; } function item(classname, tagname) { this.tagname = tagname || 'div'; container.call(this, classname); delete this.children; } inheritproto(item, container); item.prototype.add = function() { throw new error('[[type item]] can not add any other item'); }
colorpicker.js:
(function() { this.colorpicker = function() { container.call(this); this.hsv = [0, 0, 0]; this.rgb = [0, 0, 0]; this.svfieldhsv = [0, 1, 1]; this.svfieldrgb = [0, 0, 0]; } inheritproto(colorpicker, container); colorpicker.prototype.init = function() { this.element = document.createelement('div'); this.element.classname = 'color-picker-container'; var _container = createcontainer(), _self = this; event.call(_container); extend(_container, event.prototype); createval.call(this); createsv.call(_container); createh.call(_container); _container.addevent('sv-change', function(e) { // 暴露出饱和度change接口 _self.onsvchange(e); }); _container.addevent('h-change', function(e) { // 暴露出色相change接口 _self.onhchange(e); }); this.add(_container); } colorpicker.prototype.select = function(opt) { if(opt && typeof opt !== 'undefined') { this.hsv[0] = opt.h || 0; this.hsv[1] = opt.s || 0; this.hsv[2] = opt.b || 0; this.svfieldhsv[0] = opt.hue || 0; } if(this.children[0].children[0].getelement().value !== '') { var val = this.children[0].children[0].getelement().value, regrgb = /rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/, r = val.replace(regrgb, '$1'), g = val.replace(regrgb, '$2'), b = val.replace(regrgb, '$3'); this.hsv = rgb2hsv(r, g, b); this.svfieldhsv[0] = this.hsv[0]; } this.svfieldrgb = hsv2rgb(this.svfieldhsv[0], this.svfieldhsv[1], this.svfieldhsv[2]); this.updatesvfield(); this.rgb = hsv2rgb(this.hsv[0], this.hsv[1], this.hsv[2]); this.updatesvpointer(); this.updateval(opt); this.children[1].children[0].getelement().style.csstext += ';left: ' + this.hsv[1] * 255 + 'px;top: ' + (255 - this.hsv[2] * 255) + 'px;'; this.children[1].children[2].children[0].getelement().style.csstext += ';top: ' + (255 - this.hsv[0]) + 'px;'; document.body.appendchild(this.element); return this; } colorpicker.prototype.updatesvfield = function() { this.children[1].children[1].getelement().style.csstext = ';background: -webkit-linear-gradient(left, rgb(255, 255, 255) 0%, rgb(' + ~~this.svfieldrgb[0] + ', ' + ~~this.svfieldrgb[1] + ', ' + ~~this.svfieldrgb[2] + ') 100%)'; } colorpicker.prototype.updatesvpointer = function() { this.children[1].children[0].getelement().style.csstext += ';background-color: rgb(' + ~~this.rgb[0] + ', ' + ~~this.rgb[1] + ', ' + ~~this.rgb[2] + ')'; } colorpicker.prototype.updateval = function() { var _hsv_temp = [0, 0, 0]; if(this.hsv[1] < 0.5 && this.hsv[2] > 0.5) { _hsv_temp = [this.hsv[0], 1, 0]; } else { _hsv_temp = [this.hsv[0], 0, 1]; } var _rgb_temp = hsv2rgb(_hsv_temp[0], _hsv_temp[1], _hsv_temp[2]); this.children[0].children[0].getelement().style.csstext += ';text-shadow: 0 0 5px;color: rgb(' + ~~_rgb_temp[0] + ', ' + ~~_rgb_temp[1] + ', ' + ~~_rgb_temp[2] + ');background-color: rgb(' + ~~this.rgb[0] + ', ' + ~~this.rgb[1] + ', ' + ~~this.rgb[2] + ')'; this.children[1].children[0].getelement().style.csstext += ';border-color: rgb(' + ~~_rgb_temp[0] + ', ' + ~~_rgb_temp[1] + ', ' + ~~_rgb_temp[2] + ')'; this.children[0].children[0].getelement().value = 'rgb(' + ~~this.rgb[0] + ', ' + ~~this.rgb[1] + ', ' + ~~this.rgb[2] + ')'; } colorpicker.prototype.onsvchange = function(callval) { arguments.callee.call(this, callval); return this; } colorpicker.prototype.onhchange = function(callval) { arguments.callee.call(this, callval); return this; } function createval() { var _container = new container('val-container'), _input = new item('val', 'input'); event.call(_input); extend(_input, event.prototype); _input.addevent('blur', this.select.bind(this)); _container.add(_input); this.add(_container); } function createcontainer() { var _container = new container('picker-container'); return _container; } function createsv() { var _pointer = new item('pointer'), _saturationrange = new container('saturation-range'), _cover = new item('cover'), _self = this; event.call(_pointer); extend(_pointer, event.prototype); _saturationrange.add(_cover); function cursordown(e) { var _top = typeof e.target.style.top === 'undefined' ? 255 : parsefloat(e.target.style.top), _left = typeof e.target.style.left === 'undefined' ? 0 : parsefloat(e.target.style.left), _distancey, _distancex, realtop, realleft; function move(e2) { _distancey = e2.clienty - e.clienty; _distancex = e2.clientx - e.clientx; realtop = _top + _distancey; realleft = _left + _distancex; realtop < 0 && (realtop = 0); realtop > 255 && (realtop = 255); realleft < 0 && (realleft = 0); realleft > 255 && (realleft = 255); e.target.style.top = realtop + 'px'; e.target.style.left = realleft + 'px'; _self.parent.hsv[1] = realleft / 255; _self.parent.hsv[2] = (255 - realtop) / 255; _self.parent.rgb = hsv2rgb(_self.parent.hsv[0], _self.parent.hsv[1], _self.parent.hsv[2]); _self.parent.updatesvpointer(); _self.parent.updateval(); } function up() { document.removeeventlistener('mousemove', move); document.removeeventlistener('mouseup', up); _self.triggerevent('sv-change', [realleft / 255, (255 - realtop) / 255]); } document.addeventlistener('mousemove', move); document.addeventlistener('mouseup', up); } _pointer.addevent('mousedown', cursordown); this.add(_pointer) .add(_saturationrange); } function createh() { var _huerange = new container('hue-range'), _cursor = new item('cursor'), _self = this; event.call(_cursor); extend(_cursor, event.prototype); function cursordown(e) { var _top = typeof e.target.style.top === 'undefined' ? 255 : parsefloat(e.target.style.top), _distance, realtop; function move(e2) { _distance = e2.clienty - e.clienty; realtop = _top + _distance; realtop < 0 && (realtop = 0); realtop > 255 && (realtop = 255); e.target.style.top = realtop + 'px'; _self.parent.svfieldhsv[0] = 255 - realtop; _self.parent.svfieldrgb = hsv2rgb(_self.parent.svfieldhsv[0], _self.parent.svfieldhsv[1], _self.parent.svfieldhsv[2]); _self.parent.updatesvfield(); _self.parent.hsv[0] = 255 - realtop; _self.parent.rgb = hsv2rgb(_self.parent.hsv[0], _self.parent.hsv[1], _self.parent.hsv[2]); _self.parent.updatesvpointer(); _self.parent.updateval(); } function up() { document.removeeventlistener('mousemove', move); document.removeeventlistener('mouseup', up); _self.triggerevent('h-change', 255 - realtop); } document.addeventlistener('mousemove', move); document.addeventlistener('mouseup', up); } _cursor.addevent('mousedown', cursordown); _huerange.add(_cursor); this.add(_huerange); } function hsv2rgb(h, s, v) { h = h / 255 * 360; var hi = math.floor(h / 60) % 6, f = h / 60 - math.floor(h / 60), p = v * (1 - s), q = v * (1 - f * s), t = v * (1 - (1 - f) * s), c = [ [v, t, p], [q, v, p], [p, v, t], [p, q, v], [t, p, v], [v, p, q] ][hi]; return [c[0] * 255, c[1] * 255, c[2] * 255]; } function rgb2hsv(r, g, b) { var max = math.max(r, g, b), min = math.min(r, g, b), h, s, v, d = max - min; if (max == min) { h = 0; } else if (max == r) { h = 60 * ((g - b) / d); } else if (max == g) { h = 60 * ((b - r) / d) + 120; } else { h = 60 * ((r - g) / d) + 240; } s = max == 0 ? 0 : (1 - min / max); v = max; if(h < 0) { h += 360; } return [h * 255 / 360, s, v / 255]; } })() var aa = new colorpicker(); aa.select( // { // h: 120, // s: 1, // b: 1 // } ); aa.onhchange = function(e) {}; aa.onsvchange = function(e) {};
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: 从ASP.NET Core3.1迁移到5.0的方法
下一篇: (8)初始化系统时钟
推荐阅读
-
jQuery animate()实现背景色渐变效果的处理方法【使用jQuery.color.js插件】
-
JS 实现计算器详解及实例代码(一)
-
在浏览器中实现图片粘贴的jQuery插件-- pasteimg使用指南
-
jb51站长推荐的用js实现的多浏览器支持的图片轮换展示效果ie,firefox
-
Vue.js 实现微信公众号菜单编辑器功能(一)
-
js与jQuery实现的兼容多浏览器Ajax请求实例
-
jQuery使用unlock.js插件实现滑动解锁
-
用JS实现复制内容到剪切板,兼容PC和手机端,支持SAFARI浏览器的方法
-
js富文本编辑器实现(js登录注册界面源代码)
-
Three.js使用TWEEN插件实现动画(代码教程)