怎么在Vue中通過自定義指令實(shí)現(xiàn)一個(gè)Select組件?針對(duì)這個(gè)問題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡(jiǎn)單易行的方法。
在成都網(wǎng)站設(shè)計(jì)、網(wǎng)站制作過程中,需要針對(duì)客戶的行業(yè)特點(diǎn)、產(chǎn)品特性、目標(biāo)受眾和市場(chǎng)情況進(jìn)行定位分析,以確定網(wǎng)站的風(fēng)格、色彩、版式、交互等方面的設(shè)計(jì)方向。創(chuàng)新互聯(lián)建站還需要根據(jù)客戶的需求進(jìn)行功能模塊的開發(fā)和設(shè)計(jì),包括內(nèi)容管理、前臺(tái)展示、用戶權(quán)限管理、數(shù)據(jù)統(tǒng)計(jì)和安全保護(hù)等功能。
一、首先,我們簡(jiǎn)單布局一下:
...... data() { return { options: [ { value: '西紅柿雞蛋' }, { value: '青椒抱雞蛋' }, { value: '回鍋肉' }, { value: '宮保雞丁' }, { value: '地三鮮' } ], } }
- {{item.value}}
效果是這樣:
下面可供選擇的options用的是絕對(duì)定位;同時(shí)input設(shè)置了readonly,使input變的不可輸入,整體布局很簡(jiǎn)單。
二、開始添加功能
接下來,我們要添加兩個(gè)功能:
點(diǎn)擊上面的input框,可以切換顯示下面的options
選擇options里的某個(gè)選項(xiàng)后讓它展示在input里,同時(shí)讓選項(xiàng)部分消失
這兩項(xiàng)目功能都挺簡(jiǎn)單,先來完成第一個(gè),點(diǎn)擊input框切換顯示options,借助v-show就好。
如上所示,在選項(xiàng)里添加 v-show="showOptions"
并將 showOptions 初始化為 false 。同時(shí),在包裹 input 的 div 上添加 click 事件來回切換 showOptions 的布爾值。
效果如下:
第二個(gè),點(diǎn)擊下面的選項(xiàng),將被選擇的展示到input里,同時(shí)讓options消失,也不難。
//這里用value綁定一個(gè)data值selected
邏輯很簡(jiǎn)單,在input里用value綁定一個(gè)data值,點(diǎn)擊選擇某個(gè)選項(xiàng)后,將選項(xiàng)的內(nèi)容賦給這個(gè)data值即可,同時(shí),隱藏整個(gè)選項(xiàng)內(nèi)容。
效果如下:
從上面的效果圖中可以看到,已經(jīng)可以正常選擇了,但是有一個(gè)問題,就是它選項(xiàng)內(nèi)容展示的時(shí)候,我們希望點(diǎn)擊其它空白的地方也可以讓選擇內(nèi)容隱藏,但是上面的代碼并沒有解決這個(gè)問題,接下來我們來用兩種辦法來解決它。
3、常規(guī)的DOM操作 VS Vue自定義指令
其實(shí),實(shí)現(xiàn)這個(gè)功能并不難,只是要想解決它就需要操作DOM
//注意這里的stop修飾器
上面的代碼有兩點(diǎn):一個(gè)是在mounted后面給整個(gè)document添加了點(diǎn)擊事件,這樣在點(diǎn)擊時(shí)候就可以將options隱藏,但是,我們?cè)邳c(diǎn)擊輸入框部分和選項(xiàng)內(nèi)容時(shí),我們不希望它觸發(fā),而是讓它走我們之前寫好的邏輯,所以給兩個(gè) click 事件都添加了 stop 修飾器來阻止冒泡,這樣,點(diǎn)擊到它們的時(shí)候就不會(huì)冒泡到 document 上面了。效果如下:
到這里基本功能都寫完了,可以通過添加 $emit 和 props 來進(jìn)行數(shù)據(jù)傳遞,讓它更加通用些。但是最后關(guān)于點(diǎn)擊其它地方讓選項(xiàng)部分消失的功能,我們還可以再完善下,可以考慮使用Vue指令的方式實(shí)現(xiàn)。
關(guān)于Vue指令,官方文檔里有比較清楚的說明,如果不是特別明白可以點(diǎn)擊這里先看看!
關(guān)于Vue自定義指令,在這個(gè)例子中需要明白以下基本知識(shí)點(diǎn):
它是用來操作DOM的,所以所有Vue指令都會(huì)掛在 template 里的某個(gè)元素上
它有4個(gè)鉤子函數(shù),一是 bind ,它在指令第一次綁定到元素上調(diào)用而且只調(diào)用一次,這個(gè)鉤子很重要,我們?cè)谶@個(gè)例子里會(huì)用到;第二個(gè)是 inserted ,它在元素插入到父元素的時(shí)候調(diào)用,官方文檔里給了一個(gè) v-focus 的例子就用到了它;第三個(gè)和第四個(gè)分別是 update 和 componentUpdated ,前者是在 vNode 更新時(shí)調(diào)用,后者是在更新完成后調(diào)用;最后是 unbind ,在指令和元素解綁時(shí)調(diào)用。
這4個(gè)鉤子函數(shù)可以 都至少可以傳3個(gè)參數(shù) ,第一是 el 就是被綁定指令的元素,第二個(gè) binding , 它是個(gè)對(duì)象 ,而且 它的一些屬性特別有用 ,它的屬性包括 name , expression 和 value 等,當(dāng)然不只這三個(gè),但是我們這個(gè)例子要用。舉個(gè)例子: 假如我寫一個(gè)自定義指令 v-example="test" ,而這個(gè) test 是我在 methods 里寫的一個(gè)方法,那么就可以通過 binding.name 拿到 example 字符串,可以通過 binding.value 拿到 test 函數(shù)本身并且執(zhí)行。如果這里不明白沒關(guān)系接下來我們會(huì)說到。
如果仔細(xì)觀察,它們非常像 Vue 本身的生命周期鉤子函數(shù),只是它們是作用在指令上與元素的上的。從 bind 最開始綁定到最后 unbind 解綁完成了一個(gè)完整的周期。
好了,我們把之前 mounted 寫的DOM操作相關(guān)的東西都刪掉,開始動(dòng)手寫一個(gè)自定義指令。
上面的代碼都有清楚的注釋說明,我們自定義了一個(gè) clickOut 的指令,并且把它掛到了一個(gè)元素上,而且給它傳了一個(gè) test 方法,我們來看看 console.log 出的東西都是些啥。
從上面的圖片可以看出當(dāng)指令和元素綁定的時(shí)候即 bind 的時(shí)候,它會(huì)執(zhí)行bind函數(shù)獲得很多有用的東西,上面我們講了 bind 函數(shù)里有幾個(gè)重要的參數(shù),從打印出的結(jié)果里我們非常清楚地看到,el就是指令綁定的元素本身,binding是一個(gè)對(duì)象,它獲得了很多有用的東西,包括傳遞進(jìn)來的函數(shù)。
明白了它的基本構(gòu)造,我們就來繼續(xù)完善這個(gè)指令。
看下上面改寫過的代碼做了些啥? 說下邏輯:當(dāng)我們自定的 v-clickOut 與選項(xiàng)部分的ul元素綁定的時(shí)候,我們監(jiān)聽document的click事件,如果點(diǎn)擊的元素是被指令綁定的元素的子元素或是被綁定元素本身,那就什么都不做;如果不是,那就執(zhí)行傳遞進(jìn)來的test函數(shù)。而test函數(shù)執(zhí)行的結(jié)果就是把選項(xiàng)部分隱藏。
邏輯很清楚。
當(dāng)然我們可以繼續(xù)完善它。我們給 document.addEventListener
了,也可以在 合適的時(shí)候 removeEventListener
,這個(gè)合適的時(shí)候就是 unbind 鉤子函數(shù)。
所以我們可以完善下:
...... directives : { clickOut: { bind: function(el, binding) { function handler(e) { if (el.contains(el.target)) return false if (binding.expression) { binding.value() } } el.handler = handler document.addEventListener('click', el.handler) }, unbind: function(el) { document.removeEventListener('click', el.handler) } } }
關(guān)于怎么在Vue中通過自定義指令實(shí)現(xiàn)一個(gè)Select組件問題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識(shí)。