vue 自定义指令心得
//各个快捷键对应的code const hotKeyList = { "S": 83, "O": 79, "Q": 81, "R": 82, 'ESC': 27, }; function bindEvent(e, el, arg) { if(!el || !arg){ return } if (el.displayFlag) { // console.log(el) 监听组合快捷键ctrl let keyCode = e.keyCode || e.which || e.charCode; let ctrlKey = e.ctrlKey || e.metaKey; if (arg === 'ESC' && keyCode === hotKeyList[arg]) { el.click() e.preventDefault(); e.returnValue = false; return false; } else { if (ctrlKey && keyCode === hotKeyList[arg]) { el.click() e.preventDefault(); e.returnValue = false; return false; } } } } // 递归检测触发的按钮是否会显示 function checkDisplay(el) { if (el.localName === "body") { return true } if (el.style.display === 'none') { return false } else { if (el.style.display === 'block') { return true } else { return checkDisplay(el.parentNode) //递归一定要加retur } } } export default { name: "shortcutKey", inserted() { console.log('inserted') //最好不要用bind,因为bind的el.parentNode是取不到的,用insert或是update都可以 }, update(el, binding) { // console.log('update') if (hotKeyList[binding.arg]) { setTimeout(() => { el.displayFlag = checkDisplay(el) if (!el.displayFlag) { window.removeEventListener('keydown', e => bindEvent(e, el, binding.arg)) } else { window.addEventListener('keydown', e => bindEvent(e, el, binding.arg)) } }, 300) } }, unbind() { //解绑事件,应该是有问题的,因为自定义指令定义的变量不是局部的,第二个指令会覆盖调之前定义的 window.removeEventListener('keydown', bindEvent) } };
import Vue from "vue"; const isServer = Vue.prototype.$isServer; const on = (function () { if (!isServer && document.addEventListener) { return function (element, event, handler) { if (element && event && handler) { element.addEventListener(event, handler, false); } }; } return function (element, event, handler) { if (element && event && handler) { element.attachEvent("on" + event, handler); } }; })(); const nodeList = []; const ctx = "@@clickoutsideContext"; let startClick; let seed = 0; !Vue.prototype.$isServer && on(document, "mousedown", e => (startClick = e)); !Vue.prototype.$isServer && on(document, "mouseup", e => { nodeList.forEach(node => node[ctx].documentHandler(e, startClick)); }); function createDocumentHandler(el, binding, vnode) { return function (mouseup = {}, mousedown = {}) { if ( !vnode || !vnode.context || !mouseup.target || !mousedown.target || el.contains(mouseup.target) || el.contains(mousedown.target) || el === mouseup.target || (vnode.context.popperElm && (vnode.context.popperElm.contains(mouseup.target) || vnode.context.popperElm.contains(mousedown.target))) ) return; if ( binding.expression && el[ctx].methodName && vnode.context[el[ctx].methodName] ) { vnode.context[el[ctx].methodName](); } else { el[ctx].bindingFn && el[ctx].bindingFn(); } }; } /** * v-clickoutside * @desc 点击元素外面才会触发的事件 * @example * ```vue * <div v-clickoutside="handleClose"> * ``` */ export default { name: "clickoutside", bind(el, binding, vnode) { nodeList.push(el); const id = seed++; el[ctx] = { id, documentHandler: createDocumentHandler(el, binding, vnode), methodName: binding.expression, bindingFn: binding.value }; }, update(el, binding, vnode) { el[ctx].documentHandler = createDocumentHandler(el, binding, vnode); el[ctx].methodName = binding.expression; el[ctx].bindingFn = binding.value; // 判断指令中是否绑定了函数 if (binding.expression) { // 如果绑定了函数 则调用那个函数,此处binding.value就是handleClose方法 binding.value(startClick); } }, unbind(el) { let len = nodeList.length; for (let i = 0; i < len; i++) { if (nodeList[i][ctx].id === el[ctx].id) { nodeList.splice(i, 1); break; } } delete el[ctx]; } };