最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用Vue自定義指令實(shí)現(xiàn)Select組件

 更新時(shí)間:2018年05月24日 13:27:08   作者:limingru  
這篇文章主要介紹了使用Vue自定義指令實(shí)現(xiàn)Select組件,如果哪位朋友對(duì)vue自定義指令不是多了解的話,此篇文章會(huì)對(duì)你有所幫助的,需要的朋友可以參考下

本篇文章教大家寫一個(gè)非常簡(jiǎn)單的Select組件,想必很多人都寫過Select,畢竟它太常用了,但是本篇文章的示例使用到了Vue的自定義指令,如果你對(duì)Vue自定義指令不怎么熟悉的話,本篇文章或許會(huì)讓您有所收獲!

完成的效果圖如下:

 

一、首先,我們簡(jiǎn)單布局一下:

<template>
 <div class="select">
  <div class="inner">
   <div class="inputWrapper">
    <input type="text" readonly placeholder="請(qǐng)選擇菜品">
    <span class="iconfont icon-zhankaishangxia"></span>
   </div>
   <ul class="options">
    <li v-for="(item, index) in options" :key="index">{{item.value}}</li>
   </ul>
  </div>
 </div>
</template> 
......
data() {
  return {
    options: [
      {
       value: '西紅柿雞蛋'
      },
      {
       value: '青椒抱雞蛋'
      },
      {
       value: '回鍋肉'
      },
      {
       value: '宮保雞丁'
      },
      {
       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就好。

<div class="inputWrapper" @click="showOptions = !showOptions">
  <input type="text" readonly placeholder="請(qǐng)選擇菜品">
  <span class="iconfont icon-zhankaishangxia"></span>
</div>
<ul class="options" v-show="showOptions" v-show="showOptions"> //添加v-show
  <li v-for="(item, index) in options" :key="index">{{item.value}}</li>
</ul>
......
data() {
  showOptions: false
}

如上所示,在選項(xiàng)里添加 v-show="showOptions" 并將 showOptions 初始化為 false 。同時(shí),在包裹 input 的 div 上添加 click 事件來回切換 showOptions 的布爾值。

效果如下:

 

第二個(gè),點(diǎn)擊下面的選項(xiàng),將被選擇的展示到input里,同時(shí)讓options消失,也不難。

<div class="inputWrapper" @click="showOptions = !showOptions">
  <input type="text" readonly placeholder="請(qǐng)選擇菜品" :value="selected"> //這里用value綁定一個(gè)data值selected
  <span class="iconfont icon-zhankaishangxia"></span>
</div>
<ul class="options" v-show="showOptions">
  <li v-for="(item, index) in options" :key="index" @click="choose(item.value)">{{item.value}}</li>
</ul>
......
data() {
  return {
    ......
    showOptions: false
    selected: ''
  }
},
methods: {
  choose(value) {
    this.showOptions = false
    if (value !== this.selected) {
      this.selected = value
    }
  }
}

邏輯很簡(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

<div class="inputWrapper" @click.stop="showOptions = !showOptions"> //注意這里的stop修飾器
  <input type="text" readonly placeholder="請(qǐng)選擇菜品" :value="selected">
  <span class="iconfont icon-zhankaishangxia"></span>
</div>
<ul class="options" v-show="showOptions">
  <li v-for="(item, index) in options" :key="index" @click.stop="choose(item.value)">{{item.value}}</li> //還有這里的stop修飾器
</ul>
...
data() {
  return {
    ......
    showOptions: false
  }
}
mounted() {
  let that = this
  document.addEventListener('click', function() {
    that.showOptions = false
  })
}

上面的代碼有兩點(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è)自定義指令。

<ul class="options" v-show="showOptions" v-clickOut="test"> //這里使用了下面的自定義指令,并將一個(gè)test方法傳遞進(jìn)去了
  <li v-for="(item, index) in options" :key="index" @click.stop="choose(item.value)">{{item.value}}</li>
</ul>
...
methods: {
  ......
  test() {       //test函數(shù),它作為參數(shù)傳遞給了指令
    console.log('這是一個(gè)測(cè)試函數(shù)')
  }
}, 
directives: {       //這里是自定義指令
  clickOut: {       // 這里是自定義的v-clickOut指令
    bind: function(el, binding) {    // bind鉤子函數(shù),當(dāng)它與元素綁定的時(shí)候就會(huì)執(zhí)行
      console.log('el===>', el)
      console.log('binding.name===>', binding.name)
      console.log('binding.expression===>', binding.expression)
      console.log('binding.value===>', binding.value)
    }
  }
}

上面的代碼都有清楚的注釋說明,我們自定義了一個(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è)指令。

<ul class="options" v-show="showOptions" v-clickOut="test">
  <li v-for="(item, index) in options" :key="index" @click.stop="choose(item.value)">{{item.value}}</li>
</ul>
...
methods: {
  test() {
    this.showOptions = false  
  }
},
directives: {
  clickOut: {
   bind: function(el, binding) {
    document.addEventListener('click', function(e) {
     if (el.contains(e.target)) return false
     if (binding.expression) {
      binding.value()
     }
    })
   }
  }

看下上面改寫過的代碼做了些啥? 說下邏輯:當(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)
    }    
  }
}

代碼如上,效果如下:

 

簡(jiǎn)單總結(jié)一下:這是一個(gè)非常簡(jiǎn)單的小例子,因?yàn)樾枰僮鱀OM,所以我們選擇使用自定義來完成,當(dāng)然我們也可以使用其它方法。只是,在我們用Vue的時(shí)候,如果遇到需要操作DOM的時(shí)候,那么可以想想可不可以通過自定義指令來實(shí)現(xiàn)呢!

相關(guān)文章

  • 使用Vue.js和Flask來構(gòu)建一個(gè)單頁(yè)的App的示例

    使用Vue.js和Flask來構(gòu)建一個(gè)單頁(yè)的App的示例

    本篇文章主要介紹了使用Vue.js和Flask來構(gòu)建一個(gè)單頁(yè)的App的示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-03-03
  • VUE+ElementUI下載文件的幾種方式(小結(jié))

    VUE+ElementUI下載文件的幾種方式(小結(jié))

    本文主要介紹了VUE+ElementUI下載文件的幾種方式(小結(jié)),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01
  • Vue項(xiàng)目中new?Vue()和export?default{}的區(qū)別說明

    Vue項(xiàng)目中new?Vue()和export?default{}的區(qū)別說明

    這篇文章主要介紹了Vue項(xiàng)目中new?Vue()和export?default{}的區(qū)別說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • vue實(shí)現(xiàn)日歷備忘錄功能

    vue實(shí)現(xiàn)日歷備忘錄功能

    這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)日歷備忘錄功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-06-06
  • vue-cli打包后本地運(yùn)行dist文件中的index.html操作

    vue-cli打包后本地運(yùn)行dist文件中的index.html操作

    這篇文章主要介紹了vue-cli打包后本地運(yùn)行dist文件中的index.html操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • 在axios中使用params傳參的時(shí)候傳入數(shù)組的方法

    在axios中使用params傳參的時(shí)候傳入數(shù)組的方法

    今天小編就為大家分享一篇在axios中使用params傳參的時(shí)候傳入數(shù)組的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-09-09
  • 淺談vue?腳手架文件結(jié)構(gòu)及加載過程

    淺談vue?腳手架文件結(jié)構(gòu)及加載過程

    這篇文章主要介紹了vue腳手架文件結(jié)構(gòu)及加載過程淺談,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-08-08
  • vite build vue3項(xiàng)目配置開啟sourcemap方式

    vite build vue3項(xiàng)目配置開啟sourcemap方式

    這篇文章主要介紹了vite build vue3項(xiàng)目配置開啟sourcemap方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • 前端vue3打印功能實(shí)現(xiàn)(多頁(yè)打印、不使用插件)

    前端vue3打印功能實(shí)現(xiàn)(多頁(yè)打印、不使用插件)

    在Vue項(xiàng)目中實(shí)現(xiàn)打印功能是前端開發(fā)中常見需求之一,這篇文章主要介紹了前端vue3打印功能實(shí)現(xiàn)的全部過程,文中介紹的方法實(shí)現(xiàn)了多頁(yè)打印并且不使用插件,需要的朋友可以參考下
    2024-09-09
  • vue打包后,用后端接口報(bào)錯(cuò)304、404問題

    vue打包后,用后端接口報(bào)錯(cuò)304、404問題

    這篇文章主要介紹了vue打包后,用后端接口報(bào)錯(cuò)304、404問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-05-05

最新評(píng)論

慈溪市| 喀喇沁旗| 化德县| 句容市| 青田县| 溆浦县| 三都| 九台市| 花垣县| 会宁县| 东海县| 锦州市| 徐汇区| 乌拉特前旗| 山西省| 修文县| 怀远县| 伊吾县| 张家口市| 姚安县| 罗源县| 瓮安县| 富裕县| 法库县| 义马市| 望江县| 凤阳县| 乌鲁木齐市| 礼泉县| 太康县| 舟山市| 搜索| 延安市| 邻水| 岳西县| 新宁县| 清涧县| 博爱县| 延庆县| 乌苏市| 清流县|