- // ==UserScript==
- // @name MyDropdown
- // @namespace http://https://wish123.cnblogs.com/?MyDropdown
- // @version 0.1.1
- // @description 原生js实现简洁的下拉菜单
- // @author Wilson
-
- //构造方法
- function MyDropdown(options){
- //_count是某实例下的菜单个数
- this._count = 0;
- this._zIndex = 1000;
- this._config = options;
- window._MyDropdownPosIndex = (window._MyDropdownPosIndex||this._zIndex)+1;
- //实例总个数
- window._MyDropdownInsCount = (window._MyDropdownInsCount||0)+1;
- //当前第几个实例
- this.insCount = window._MyDropdownInsCount;
- if(this._config) {
- this.config(options);
- this.createStyle();
- }
- //返回对象类型
- this.type = function(obj) {
- return Object.prototype.toString
- .call(obj)
- .replace(/^\[object (.+)\]$/, '$1')
- .toLowerCase();
- }
- }
- MyDropdown.prototype.createStyle = function() {
- if(document.querySelector("#MyDropdownStyle")) {
- return;
- }
- let = style = `
- <style>
- .my-dropdown-wrapper {
- display: none;
- position: absolute;
- background-color: #f1f1f1;
- min-width: 160px;
- overflow: auto;
- box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
- z-index: 1;
- }
-
- .my-dropdown-wrapper a {
- color: black;
- padding: 12px 16px;
- text-decoration: none;
- display: block;
- }
-
- .my-dropdown-wrapper a:hover {background-color: #ddd;}
- .my-dropdown-wrapper a.selected {background-color: #ddd;}
- .show {display: block;}
- .my-dropdown-item-icon svg{width: 24px;height: 24px;float: left;}
- .close {
- width: 24px;
- height: 24px;
- display: inline-block;
- line-height: 24px;
- text-align: center;
- font-size: 18px;
- float: right;
- }
- </style>
- `
- document.body.insertAdjacentHTML("beforeend", style);
- }
- //设置用户配置
- MyDropdown.prototype.config = function(options) {
- var _this = this;
- //设置用户配置
- _this._config = options || _this._config;
- if(_this._config.toggleEvent && _this._config.toggleEvent.toLowerCase() === 'mouseover') {
- _this._config.toggleEvent = 'mouseenter';
- }
-
- //绑定事件源按钮点击事件
- document.querySelectorAll(_this._config.el||".my-dropdown-btn").forEach(function(item){
- item.addEventListener(_this._config.toggleEvent||'click', function(e){
- _this.create(this);
- _this.show(this);
- e.stopPropagation();
- return false;
- });
- });
-
- //点击空白,菜单消失
- document.addEventListener('click', function(e){
- if (!e.target.matches(_this._config.el||'.my-dropdown-btn')) {
- _this.hide();
- }
- });
- }
- //创建菜单
- MyDropdown.prototype.create = function(objBtn, options) {
- var _this = this;
- options = options || _this._config;
- if(options.el) {
- _this._config.el = options.el;
- }
-
- if(objBtn) {
- if (!objBtn.dataset.count) {
- objBtn.dataset.count = _this._count++;
- objBtn.classList.add('my-btn'+_this.insCount+objBtn.dataset.count);
- }
- }
- var count = objBtn.dataset.count || 0;
-
- //已存在则返回
- if(document.querySelector(`#myDropdownWrapper${_this.insCount}${count}`)) {
- return;
- }
- var mouseenterClass = "";
- if(_this._config.toggleEvent && _this._config.toggleEvent.toLowerCase() === 'mouseenter') {
- mouseenterClass = " mouseenter";
- }
- //生成菜单 这里count是某实例下的菜单个数,_this.insCount是实例个数
- var menu = `<div id="myDropdownWrapper${_this.insCount}${count}" class="my-dropdown-wrapper${mouseenterClass}" style="overflow:auto;${options.maxWidth?'max-width:'+options.maxWidth+';':''}${options.maxHeight?'max-height:'+options.maxHeight+';':''}" data-count="${count}">`;
- if(options.items) {
- for(var i in options.items){
- var item = options.items[i];
- //处理icon选项
- var iconHtml = '';
- if(item.icon){
- if(_this.type(item.icon) === 'object'){
- iconHtml = item.icon.html ? item.icon.html : '';
- } else {
- iconHtml = item.icon ? item.icon : '';
- }
- }
-
- //处理op选项
- var opHtml = '';
- if(item.op){
- if(_this.type(item.op) === 'object'){
- opHtml = item.op.html ? item.op.html : '';
- } else {
- opHtml = item.op ? item.op : '';
- }
- }
- //生成菜单项
- menu += `<a href="javascript:;" class="my-dropdown-item ${item.selected?'selected':''}" data-index="${i}" data-value="${item.value}"><span class="my-dropdown-item-icon">${iconHtml}</span>${item.name}<span class="my-dropdown-item-op">${opHtml}</span></a>`;
- }
- }
- menu += `</div>`;
- //追加到body中
- document.body.insertAdjacentHTML("beforeend", menu);
-
- //绑定菜单事件
- if(_this._config.toggleEvent && _this._config.toggleEvent.toLowerCase() === 'mouseenter') {
- //绑定菜单列表
- document.querySelector("#myDropdownWrapper" + _this.insCount + count).addEventListener("mouseleave", function(e){
- _this.hide(this);
- });
- }
-
- //绑定菜单item点击事件
- document.querySelectorAll("#myDropdownWrapper" + _this.insCount + count + " .my-dropdown-item").forEach(function(item){
- item.addEventListener("click", function(e){
- if(typeof this.dataset.index !== 'undefined' && options.items[this.dataset.index]) {
- options.items[this.dataset.index].fn(e);
- }
- });
- });
-
- //绑定菜单项icon按钮点击事件
- document.querySelectorAll("#myDropdownWrapper" + _this.insCount + count + " .my-dropdown-item-icon").forEach(function(item){
- //if(!item.innerHTML) return;
- item.addEventListener("click", function(e){
- if(typeof this.parentElement.dataset.index !== 'undefined' && options.items[this.parentElement.dataset.index] &&
- options.items[this.parentElement.dataset.index].icon && options.items[this.parentElement.dataset.index].icon.fn) {
- var _this_item = this;
- (function(e){
- options.items[_this_item.parentElement.dataset.index].icon.fn(e);
- e.stopPropagation();
- return false;
- })(e);
- }
- });
- });
-
- //绑定菜单项操作按钮点击事件
- document.querySelectorAll("#myDropdownWrapper" + _this.insCount + count + " .my-dropdown-item-op").forEach(function(item){
- //if(!item.innerHTML) return;
- item.addEventListener("click", function(e){
- if(typeof this.parentElement.dataset.index !== 'undefined' && options.items[this.parentElement.dataset.index] &&
- options.items[this.parentElement.dataset.index].op && options.items[this.parentElement.dataset.index].op.fn) {
- var _this_item = this;
- (function(e){
- options.items[_this_item.parentElement.dataset.index].op.fn(e);
- e.stopPropagation();
- return false;
- })(e);
- }
- });
- });
-
- if(options.created) options.created(document.querySelector(`#myDropdownWrapper${_this.insCount}${count}`));
- };
- //菜单显示
- MyDropdown.prototype.show = function(objBtn, callback) {
- var count = objBtn.dataset.count || 0;
- var myDropdownWrapper = document.getElementById("myDropdownWrapper"+this.insCount+count);
- if(objBtn){
- myDropdownWrapper.style.top = (objBtn.offsetTop + objBtn.offsetHeight) + "px";
- myDropdownWrapper.style.left = objBtn.offsetLeft + "px";
- }
- if (myDropdownWrapper.classList.contains('show')) {
- if(this._config.toggleEvent && this._config.toggleEvent.toLowerCase() === 'mouseenter'){
- return;
- }
- //隐藏菜单
- myDropdownWrapper.classList.remove('show');
- if(this._config.hidden) this._config.hidden();
- } else {
- if(this._config.toggleEvent && this._config.toggleEvent.toLowerCase() === 'mouseenter'){
- this.hide();
- }
- //显示菜单
- myDropdownWrapper.style.zIndex = window._MyDropdownPosIndex++;
- myDropdownWrapper.classList.add('show');
- callback = callback || this._config.shown;
- if(callback) callback(myDropdownWrapper);
- }
- //myDropdownWrapper.classList.toggle("show");
- }
- //菜单隐藏
- MyDropdown.prototype.hide = function(objMenu, callback) {
- if(objMenu) {
- //单个菜单隐藏
- if (objMenu.classList.contains('show')) {
- objMenu.classList.remove('show');
- callback = callback || this._config.hidden;
- if(callback) callback(objMenu);
- }
- } else {
- var mouseenterClass = '';
- if(this._config.toggleEvent && this._config.toggleEvent.toLowerCase() === 'mouseenter'){
- mouseenterClass = ".mouseenter";
- }
- //所有菜单隐藏
- var dropdowns = document.querySelectorAll(".my-dropdown-wrapper" + mouseenterClass);
- for (var i = 0; i < dropdowns.length; i++) {
- var openDropdown = dropdowns[i];
- if (openDropdown.classList.contains('show')) {
- openDropdown.classList.remove('show');
- callback = callback || this._config.hidden;
- if(callback) callback(openDropdown);
- }
- }
- }
- };
-
-
- //使用示例
- //测试1
- // var clicked = function(e) {
- // console.log("clicked", e.target.dataset.value)
- // }
- // new MyDropdown({
- // el: ".my-dropdown-btn",
- // maxWidth: '200px',
- // maxHeight: '400px',
- // //支持click mouseenter dblclick等,默认click
- // toggleEvent: 'mouseenter',
- // items: [
- // {
- // name: 'Home',
- // value: 'home',
- // icon: '',
- // fn: clicked
- // },
- // {
- // name: 'About',
- // value: 'about',
- // icon: '',
- // selected: false,
- // fn: clicked
- // },
- // {
- // name: 'Contact',
- // value: 'contact',
- // icon: '',
- // fn: clicked,
- // //icon也支持对象传值,同样具有html和fn属性
- // op: {
- // html: `<span class="close">×</span>`,
- // fn: function(e) {
- // console.log('op clicked');
- // }
- // }
- // }
- // ],
- // created: function(menu) {
- // console.log('After created callback');
- // },
- // shown: function(menu) {
- // console.log('After shown callback');
- // },
- // hidden: function(menu) {
- // console.log('After hidden callback');
- // }
- // });
-
- // //测试2
- // var clicked2 = function(e) {
- // console.log("clicked2", e.target.dataset.value)
- // }
- // new MyDropdown({
- // el: ".my-dropdown-btn2",
- // items: [
- // {
- // name: 'Home2',
- // value: 'home2',
- // icon: '',
- // fn: clicked2
- // },
- // {
- // name: 'About2',
- // value: 'about2',
- // icon: '',
- // selected: false,
- // fn: clicked2
- // },
- // {
- // name: 'Contact2',
- // value: 'contact2',
- // icon: '',
- // fn: clicked2
- // }
- // ],
- // created: function(menu) {
- // console.log('After created callback');
- // },
- // shown: function(menu) {
- // console.log('After shown callback');
- // },
- // hidden: function(menu) {
- // console.log('After hidden callback');
- // }
- // });