摘要:指令中自定義的指令之一,顧名思義,就是當(dāng)鼠標(biāo)點(diǎn)擊了指令所綁定元素的外部時(shí),就會觸發(fā)綁定方法。在鼠標(biāo)放開觸發(fā)事件處理時(shí),通過獲取到他們的對象。使用示例原來的使用方式不受影響,只是添加了多個(gè)元素并集作為的功能。指令中的參數(shù)學(xué)習(xí)
都是個(gè)人理解,如果發(fā)現(xiàn)錯(cuò)誤,懇請大家批評指正,謝謝。還有我說的會比較啰嗦,因?yàn)槭且宰陨聿穗u水平的視角來記錄學(xué)習(xí)理解的過程,見諒。
1.前言產(chǎn)品使用vue+element作為前端框架。在功能開發(fā)過程中,難免遇到使用element的組件沒辦法滿足特殊的業(yè)務(wù)需要,需要對其進(jìn)行定制,例如要求選擇器的彈出框中,增加搜索過濾(跟目前element的輸入建議不太一樣)。于是想說說之前修改element組件,并定制為業(yè)務(wù)組件過程中遇到的問題。
ps:因?yàn)閷δ承┙M件改動很大,所以是直接拷貝了一份源碼,然后再進(jìn)行修改,但是這樣會遇到挺多問題,建議對于vue組件如果改動不大,只是簡單功能擴(kuò)展,就直接使用繼承的方式修改。2.clickoutside指令
element中自定義vue的指令之一,clickoutside顧名思義,就是當(dāng)鼠標(biāo)點(diǎn)擊了指令所綁定元素的外部時(shí),就會觸發(fā)綁定方法。用途就以el-select為例,當(dāng)選擇器的下拉框展示時(shí),監(jiān)聽鼠標(biāo)點(diǎn)擊事件,如果鼠標(biāo)位置在整個(gè)選擇器外部時(shí),進(jìn)行隱藏下拉框。
2.1使用方式引入Clickoutside.js
import Clickoutside from "element-ui/src/utils/clickoutside"
聲明指令使用
directives: { Clickoutside },
模板中正式使用
2.2實(shí)現(xiàn)介紹
簡要說明下原理,首先vue自定義指令本身(不了解可以點(diǎn)擊鏈接查看官網(wǎng)介紹)。主要就是利用vue指令的功能,獲取所綁定元素的dom對象dom_A以及傳遞過來的回調(diào)方法fun_A,然后監(jiān)聽瀏覽器的mousedown和mouseup事件(mousedown作為輔助信息,真正觸發(fā)傳遞的回調(diào)方法的是mouseup事件),當(dāng)前事件中鼠標(biāo)位置對應(yīng)的dom對象dom_B不屬于dom_A,則代表鼠標(biāo)點(diǎn)擊了dom_A外部,觸發(fā)clickoutside回調(diào)方法。
2.3擴(kuò)展介紹理論上clickoutside只能也只需要綁定一個(gè)元素作為inside,但是一些特殊的原因(可能是代碼不夠好),要求clickoutside可以選定多個(gè)元素作為inside,當(dāng)鼠標(biāo)點(diǎn)擊了這些元素所構(gòu)成的inside的外部時(shí),再觸發(fā)事件。
結(jié)合下圖,A與B兩個(gè)元素作為一個(gè)inside,當(dāng)鼠標(biāo)點(diǎn)擊在click1位置時(shí),觸發(fā)clickoutside,當(dāng)鼠標(biāo)點(diǎn)擊click2或者click3位置時(shí)都不觸發(fā)clickoutside。
要實(shí)現(xiàn)上述功能,就必須獲取到A和B的dom對象,然后在原先鼠標(biāo)事件的監(jiān)聽的基礎(chǔ)上,判斷鼠標(biāo)位置是否都不包含在A和B中,如果是的話再觸發(fā)clickoutside。
實(shí)現(xiàn)方式為,在A和B的父級parent元素上綁定v-clickoutside:yourClassName="handleClickOutside",在A和B元素上添加同一個(gè)class樣式,樣式名稱與指令冒號后面內(nèi)容一致class="yourClassName"。主要在處理指令綁定時(shí),通過binding.arg即可獲取到A和B共有的class,存放在dom變量中。在鼠標(biāo)放開觸發(fā)事件處理時(shí),通過class獲取到他們的dom對象。
clickoutside原來的使用方式不受影響,只是添加了多個(gè)元素并集作為inside的功能。
引入改為自己修改后的clickoutside.js,聲明不變,擴(kuò)展功能在模板中的使用方式
2.3.2代碼ParentAB
// 引入Vue用以判斷當(dāng)前運(yùn)行環(huán)境 import Vue from "vue" // element封裝的一些常用dom操作,這里on可以先當(dāng)做是addEventListener的封裝 import { on } from "element-ui/src/utils/dom" // 所有綁定了clickoutside指令的元素的dom對象數(shù)組 const nodeList = [] // 用來做存放于dom對象中clickoutside相關(guān)參數(shù)對象的key const ctx = "@@clickoutsideContext" let startClick let seed = 0 // 鼠標(biāo)按下時(shí),記錄此時(shí)事件信息 !Vue.prototype.$isServer && on(document, "mousedown", e => (startClick = e)) // 鼠標(biāo)松開時(shí)候,遍歷綁定clickoutside的節(jié)點(diǎn),進(jìn)行判斷是否在節(jié)點(diǎn)外部以觸發(fā)回調(diào) !Vue.prototype.$isServer && on(document, "mouseup", e => { nodeList.forEach(node => node[ctx].documentHandler(e, startClick)) }) // 是否在特殊限定范圍內(nèi) function ifInExact (exactElms, target1, taget2) { for (let i = 0; i < exactElms.length; i++) { let elm = exactElms[i] if (elm.contains(target1) || elm.contains(taget2) || elm === target1) return true } return false } // 是否有特殊限定范圍 function ifHasExact (el, exactArea) { if (!exactArea) return false return el.getElementsByClassName(exactArea) } function createDocumentHandler (el, binding, vnode) { return function (mouseup = {}, mousedown = {}) { if (!vnode || !vnode.context || !mouseup.target || !mousedown.target || (vnode.context.popperElm && (vnode.context.popperElm.contains(mouseup.target) || vnode.context.popperElm.contains(mousedown.target)))) return let exactElms = ifHasExact(el, el[ctx].exactArea) // 如果是有特殊限定范圍的,則進(jìn)行判斷當(dāng)前點(diǎn)擊是否在 限定范圍內(nèi) if (exactElms) { if (ifInExact(exactElms, mouseup.target, mousedown.target)) { return } // 無特殊限定范圍,則判斷點(diǎn)擊是否在默認(rèn)的指令所在范圍內(nèi) } else if (el.contains(mouseup.target) || el.contains(mousedown.target) || el === mouseup.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() } } } export default { bind (el, binding, vnode) { nodeList.push(el) const id = seed++ el[ctx] = { id, documentHandler: createDocumentHandler(el, binding, vnode), methodName: binding.expression, bindingFn: binding.value, // 特殊限定范圍的class,限定范圍為該class的所有元素的并集 exactArea: binding.arg } }, update (el, binding, vnode) { el[ctx].documentHandler = createDocumentHandler(el, binding, vnode) el[ctx].methodName = binding.expression el[ctx].bindingFn = binding.value // 附加 真正起作用部分 el[ctx].exactArea = binding.arg }, 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] } }3.最后
以上就是關(guān)于clickoutside的學(xué)習(xí)和擴(kuò)展。
1.引用element的popup注意事項(xiàng),如el-select-menu即el-select中的select-dropdown.vue。
2.使用cropperjs制作頭像裁剪。瀏覽器讀取本地圖片并展示,仿微博頭像排版,裁剪后上傳服務(wù)器。
3.vue指令中的參數(shù)vnode學(xué)習(xí)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/94012.html
摘要:前置知識既然要用的自定義指令,那么肯定要了解一下自定義指令的相關(guān)知識啦,關(guān)于這部分的內(nèi)容,看我之前寫過的自定義指令或者直接看官方文檔就可以啦,這里我就不再多講了。 前言 最近搞了畢設(shè),需要實(shí)現(xiàn)一個(gè)場景,點(diǎn)擊一塊區(qū)域,彈出一個(gè)編輯區(qū)域,點(diǎn)擊頁面的其他地方的時(shí)候,這個(gè)編輯區(qū)域就隱藏,本想想之前寫模態(tài)框一樣寫個(gè)方法的時(shí)候,突然showImg(https://segmentfault.com/...
摘要:使用場景代碼復(fù)用和抽象的主要形式是組件當(dāng)需要對普通元素進(jìn)行底層操作,此時(shí)就會用到自定義指令但是,對于大幅度的變動,還是應(yīng)該使用組件鉤子函數(shù)詳情查閱文檔示例輸入框自動聚焦注冊一個(gè)全局自定義指令當(dāng)被綁定的元素插入到中時(shí)聚焦元素下拉菜單點(diǎn)擊 1. 使用場景 代碼復(fù)用和抽象的主要形式是組件 當(dāng)需要對普通 DOM 元素進(jìn)行底層操作,此時(shí)就會用到自定義指令 但是,對于大幅度的 DOM 變動,...
摘要:從數(shù)組索引為開始刪除元素,直到對數(shù)組元素運(yùn)用指定方法為為止。對兩個(gè)數(shù)組的元素分別調(diào)用指定方法后,返回以運(yùn)行結(jié)果為判定基準(zhǔn)的并集,并集是原始數(shù)組元素的并集而不是運(yùn)行結(jié)果的并集。 原文地址:JavaScript30秒, 從入門到放棄之Array(六)博客地址:JavaScript30秒, 從入門到放棄之Array(六) 水平有限,歡迎批評指正 tail Returns all elem...
摘要:區(qū)別的是會周期性的把更新的數(shù)據(jù)寫入磁盤或者把修改操作寫入追加的記錄文件,并且在此基礎(chǔ)上實(shí)現(xiàn)了主從同步。存盤可以有意無意的對數(shù)據(jù)進(jìn)行寫操作。二的應(yīng)用場景緩存常常作為數(shù)據(jù)緩存。如果只用類型,就可以被看作加上持久化特性的。 一、Redis基本概念介紹和特性 1.1 Redis基本概念介紹 ????showImg(https://segmentfault.com/img/bVWpvd?w=50...
閱讀 892·2023-04-26 03:04
閱讀 2937·2021-11-15 18:10
閱讀 1269·2021-09-03 10:28
閱讀 1188·2019-08-30 15:53
閱讀 966·2019-08-30 12:45
閱讀 2020·2019-08-30 11:03
閱讀 2932·2019-08-29 14:01
閱讀 2987·2019-08-28 18:24