国产99久久精品_欧美日本韩国一区二区_激情小说综合网_欧美一级二级视频_午夜av电影_日本久久精品视频

最新文章專題視頻專題問(wèn)答1問(wèn)答10問(wèn)答100問(wèn)答1000問(wèn)答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專題關(guān)鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問(wèn)答文章1 問(wèn)答文章501 問(wèn)答文章1001 問(wèn)答文章1501 問(wèn)答文章2001 問(wèn)答文章2501 問(wèn)答文章3001 問(wèn)答文章3501 問(wèn)答文章4001 問(wèn)答文章4501 問(wèn)答文章5001 問(wèn)答文章5501 問(wèn)答文章6001 問(wèn)答文章6501 問(wèn)答文章7001 問(wèn)答文章7501 問(wèn)答文章8001 問(wèn)答文章8501 問(wèn)答文章9001 問(wèn)答文章9501
當(dāng)前位置: 首頁(yè) - 科技 - 知識(shí)百科 - 正文

Vue實(shí)現(xiàn)typeahead組件功能(非常靠譜)

來(lái)源:懂視網(wǎng) 責(zé)編:小采 時(shí)間:2020-11-27 22:31:35
文檔

Vue實(shí)現(xiàn)typeahead組件功能(非??孔V)

Vue實(shí)現(xiàn)typeahead組件功能(非??孔V): 前言 之前那個(gè)typeahead寫的太早,不滿足當(dāng)前的業(yè)務(wù)需求。 而且有些瑕疵,還有也不方便傳入數(shù)據(jù)和響應(yīng)數(shù)據(jù).. 于是就推倒了重來(lái),寫了個(gè)V2的版本 看圖,多了一些細(xì)節(jié)的考慮;精簡(jiǎn)了實(shí)現(xiàn)的邏輯代碼 效果圖 實(shí)現(xiàn)的功能 1: 鼠標(biāo)點(diǎn)擊下拉框之外的區(qū)域關(guān)閉下拉框 2:
推薦度:
導(dǎo)讀Vue實(shí)現(xiàn)typeahead組件功能(非常靠譜): 前言 之前那個(gè)typeahead寫的太早,不滿足當(dāng)前的業(yè)務(wù)需求。 而且有些瑕疵,還有也不方便傳入數(shù)據(jù)和響應(yīng)數(shù)據(jù).. 于是就推倒了重來(lái),寫了個(gè)V2的版本 看圖,多了一些細(xì)節(jié)的考慮;精簡(jiǎn)了實(shí)現(xiàn)的邏輯代碼 效果圖 實(shí)現(xiàn)的功能 1: 鼠標(biāo)點(diǎn)擊下拉框之外的區(qū)域關(guān)閉下拉框 2:

 前言

之前那個(gè)typeahead寫的太早,不滿足當(dāng)前的業(yè)務(wù)需求。

而且有些瑕疵,還有也不方便傳入數(shù)據(jù)和響應(yīng)數(shù)據(jù)..

于是就推倒了重來(lái),寫了個(gè)V2的版本

看圖,多了一些細(xì)節(jié)的考慮;精簡(jiǎn)了實(shí)現(xiàn)的邏輯代碼

效果圖

這里寫圖片描述

實(shí)現(xiàn)的功能

1: 鼠標(biāo)點(diǎn)擊下拉框之外的區(qū)域關(guān)閉下拉框

2: 支持鍵盤上下鍵選擇,支持鼠標(biāo)選擇

3: 支持列表過(guò)濾搜索

4: 支持外部傳入列表JSON格式的映射

5: 支持placeholder的傳入

6: 選中對(duì)象的響應(yīng)(.sync vue2.3的組件通訊的語(yǔ)法糖)

7: 箭頭icon的映射,感覺(jué)作用不大,移除了

用法

<select-search 
style="max-width:195px" 
placeholder="請(qǐng)選擇廣告主" 
:asyncData.sync="adHostData" 
:mapData="adHostDataList" 
:mapDataFormat="{label:'userName',value:'userId'}">
</select-search>
  • asyncData:響應(yīng)的數(shù)據(jù),也就是選中的..回來(lái)是一個(gè)對(duì)象
  • mapData : 搜索的列表數(shù)據(jù),肯定是外部傳入了…
  • mapData : 列表值映射
  • 代碼

    selectSearch.vue

    <template>
     <div class="select-search" v-if="typeaheadData" ref="selectSearch" @click.native="showHideMenu($event)">
     <div class="select-header">
     <input type="text" autocomplete="off" readonly :placeholder="placeholder" :value="placeholderValue" @keydown.down.prevent="selectChildWidthArrowDown" @keydown.up.prevent="selectChildWidthArrowUp" @keydown.enter="selectChildWidthEnter">
     <i class="fzicon " :class="isExpand?'fz-ad-jiantou1':'fz-ad-jiantou'"></i>
     </div>
     <div class="select-body" v-if="isExpand && typeaheadData">
     <input type="text" placeholder="關(guān)鍵字" v-model="searchVal" autocomplete="off" @keydown.esc="resetDefaultStatus" @keydown.down.prevent="selectChildWidthArrowDown" @keydown.up.prevent="selectChildWidthArrowUp" @keydown.enter="selectChildWidthEnter">
     <transition name="el-fade-in-linear" mode="out-in">
     <div class="typeahead-filter">
     <transition-group tag="ul" name="el-fade-in-linear" v-show="typeaheadData.length>0">
     <li v-for="(item,index) in typeaheadData" :key="index" :class="item.active ? 'active':''" @mouseenter="setActiveClass(index)" @mouseleave="setActiveClass(index)" @click="selectChild(index)">
     <a href="javascript:;" rel="external nofollow" >
     {{item[mapDataFormat.label]}}
     </a>
     </li>
     </transition-group>
     <p class="noFound" v-show="typeaheadData && typeaheadData.length === 0">未能查詢到,請(qǐng)重新輸入!</p>
     </div>
     </transition>
     </div>
     </div>
    </template>
    <script>
     export default {
     name: 'selectSearch',
     data: function () {
     return {
     placeholderValue: '',// 給看到選擇內(nèi)容的
     isExpand: false,
     searchVal: '', // 搜索關(guān)鍵字
     resultVal: '', // 保存搜索到的值
     searchList: [], //保存過(guò)濾的結(jié)果集
     currentIndex: -1, // 當(dāng)前默認(rèn)選中的index,
     }
     },
     computed: {
     mapFormatData () { // 外部有傳入格式的時(shí)候映射mapData
     return this.mapData.map(item => {
     item[this.mapDataFormat.value] = item[this.mapDataFormat.value];
     return item;
     });
     },
     typeaheadData () {
     let temp = [];
     if (this.searchVal && this.searchVal === '') {
     return this.mapFormatData;
     } else {
     this.currentIndex = -1; // 重置特殊情況下的索引
     this.mapFormatData.map(item => {
     if (item[this.mapDataFormat.label].indexOf(this.searchVal.toLowerCase().trim()) !== -1) {
     temp.push(item)
     }
     return item;
     })
     return temp;
     }
     }
     },
     props: {
     placeholder: {
     type: String,
     default: '--請(qǐng)選擇--'
     },
     emptyText: {
     type: String,
     default: '暫無(wú)數(shù)據(jù)'
     },
     mapData: { // 外部傳入的列表數(shù)據(jù)
     type: Array,
     default: function () {
     return []
     }
     },
     mapDataFormat: { // 映射傳入數(shù)據(jù)的格式
     type: Object,
     default: function () {
     return {
     label: 'text',
     value: 'value',
     extraText: 'extraText'
     }
     }
     },
     asyncData: { // 實(shí)時(shí)響應(yīng)的值
     type: [Object, String],
     default: function () {
     return {}
     }
     }
     },
     methods: {
     showHideMenu (e) { // 點(diǎn)擊其他區(qū)域關(guān)閉下拉列表
     if (e) {
     if (this.$refs.selectSearch && this.$refs.selectSearch.contains(e.target)) {
     this.isExpand = true;
     } else {
     this.isExpand = false;
     }
     }
     },
     resetDefaultStatus () { // 清除所有選中狀態(tài)
     this.searchVal = '';
     this.currentIndex = -1;
     this.typeaheadData.map(item => {
     this.$delete(item, 'active');
     })
     },
     setActiveClass (index) { // 設(shè)置樣式活動(dòng)類
     this.typeaheadData.map((item, innerIndex) => {
     if (index === innerIndex) {
     this.$set(item, 'active', true);
     this.currentIndex = index; // 這句話是用來(lái)修正index,就是鍵盤上下鍵的索引,不然會(huì)跳位
     } else {
     this.$set(item, 'active', false)
     }
     })
     },
     selectChildWidthArrowDown () {
     // 判斷index選中子項(xiàng)
     if (this.currentIndex < this.typeaheadData.length) {
     this.currentIndex++;
     this.typeaheadData.map((item, index) => {
     this.currentIndex === index ? this.$set(item, 'active', true) : this.$set(item, 'active', false);
     })
     }
     },
     selectChildWidthArrowUp () {
     // 判斷index選中子項(xiàng)
     if (this.currentIndex > 0) {
     this.currentIndex--;
     this.typeaheadData.map((item, index) => {
     this.currentIndex === index ? this.$set(item, 'active', true) : this.$set(item, 'active', false);
     })
     }
     },
     selectChildWidthEnter () {
     // 若是結(jié)果集只有一個(gè),則默認(rèn)選中
     if (this.typeaheadData.length === 1) {
     this.$emit('update:asyncData', this.typeaheadData[0]); // emit響應(yīng)的值
     this.placeholderValue = this.typeaheadData[0][this.mapDataFormat.label];
     } else {
     // 若是搜索的內(nèi)容完全匹配到項(xiàng)內(nèi)的內(nèi)容,則默認(rèn)選中
     this.typeaheadData.map(item => {
     if (this.searchVal === item[this.mapDataFormat.label] || item.active === true) {
     this.$emit('update:asyncData', item); // emit響應(yīng)的值
     this.placeholderValue = item[this.mapDataFormat.label];
     }
     })
     }
     this.isExpand = false;
     },
     selectChild (index) {
     // 鼠標(biāo)點(diǎn)擊選擇子項(xiàng)
     this.typeaheadData.map((item, innerIndex) => {
     if (index === innerIndex || item.active) {
     this.placeholderValue = item[this.mapDataFormat.label];
     this.$emit('update:asyncData', item); // emit響應(yīng)的值
     }
     });
     this.isExpand = false;
     },
     },
     mounted () {
     window.addEventListener('click', this.showHideMenu);
     },
     beforeDestroy () {
     window.removeEventListener('click', this.showHideMenu);
     },
     watch: {
     'isExpand' (newValue) {
     if (newValue === false) {
     this.resetDefaultStatus();
     }
     }
     }
     }
    </script>
    <style scoped lang="scss">
     .el-fade-in-linear-enter-active,
     .el-fade-in-linear-leave-active,
     .fade-in-linear-enter-active,
     .fade-in-linear-leave-active {
     transition: opacity .2s linear;
     }
     .el-fade-in-enter,
     .el-fade-in-leave-active,
     .el-fade-in-linear-enter,
     .el-fade-in-linear-leave,
     .el-fade-in-linear-leave-active,
     .fade-in-linear-enter,
     .fade-in-linear-leave,
     .fade-in-linear-leave-active {
     opacity: 0;
     }
     .noFound {
     text-align: center;
     }
     .select-search {
     position: relative;
     z-index: 1000;
     a {
     color: #333;
     text-decoration: none;
     padding: 5px;
     }
     ul {
     list-style: none;
     padding: 6px 0;
     margin: 0;
     max-height: 200px;
     overflow-x: hidden;
     overflow-y: auto;
     li {
     display: block;
     width: 100%;
     padding: 5px;
     font-size: 14px;
     padding: 8px 10px;
     position: relative;
     white-space: nowrap;
     overflow: hidden;
     text-overflow: ellipsis;
     color: #48576a;
     height: 36px;
     line-height: 1.5;
     box-sizing: border-box;
     cursor: pointer;
     &.active {
     background-color: #20a0ff;
     a {
     color: #fff;
     }
     }
     }
     }
     .select-header {
     position: relative;
     border-radius: 4px;
     border: 1px solid #bfcbd9;
     outline: 0;
     padding: 0 8px;
     >input {
     border: none;
     -webkit-appearance: none;
     -moz-appearance: none;
     appearance: none;
     width: 100%;
     outline: 0;
     box-sizing: border-box;
     color: #1f2d3d;
     font-size: inherit;
     height: 36px;
     line-height: 1;
     }
     >i {
     transition: all .3s linear;
     display: inline-block;
     position: absolute;
     right: 3%;
     top: 50%;
     transform: translateY(-50%);
     }
     }
     .select-body {
     position: absolute;
     border-radius: 2px;
     background-color: #fff;
     box-sizing: border-box;
     margin: 5px 0;
     padding: 8px;
     width: 100%;
     box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);
     >input {
     -webkit-appearance: none;
     -moz-appearance: none;
     appearance: none;
     background-color: #fff;
     background-image: none;
     border-radius: 4px;
     border: 1px solid #bfcbd9;
     box-sizing: border-box;
     color: #1f2d3d;
     font-size: inherit;
     height: 36px;
     line-height: 1;
     outline: 0;
     padding: 3px 10px;
     transition: border-color .2s cubic-bezier(.645, .045, .355, 1);
     width: 100%;
     display: inline-block;
     &:focus {
     outline: 0;
     border-color: #20a0ff;
     }
     }
     }
     }
    </style>

    總結(jié)

    以上所述是小編給大家介紹的Vue實(shí)現(xiàn)typeahead組件功能(非??孔V),希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

    聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

    文檔

    Vue實(shí)現(xiàn)typeahead組件功能(非常靠譜)

    Vue實(shí)現(xiàn)typeahead組件功能(非常靠譜): 前言 之前那個(gè)typeahead寫的太早,不滿足當(dāng)前的業(yè)務(wù)需求。 而且有些瑕疵,還有也不方便傳入數(shù)據(jù)和響應(yīng)數(shù)據(jù).. 于是就推倒了重來(lái),寫了個(gè)V2的版本 看圖,多了一些細(xì)節(jié)的考慮;精簡(jiǎn)了實(shí)現(xiàn)的邏輯代碼 效果圖 實(shí)現(xiàn)的功能 1: 鼠標(biāo)點(diǎn)擊下拉框之外的區(qū)域關(guān)閉下拉框 2:
    推薦度:
    標(biāo)簽: VUE 靠譜 非常
    • 熱門焦點(diǎn)

    最新推薦

    猜你喜歡

    熱門推薦

    專題
    Top
    主站蜘蛛池模板: 久久91精品国产99久久yfo | 成人精品一级毛片 | 亚洲国产精久久久久久久 | 国产喷水在线观看 | 国产精品亚洲一区二区三区 | a国产成人免费视频 | 久久久久久久亚洲精品 | 自拍亚洲 | 国产精品系列在线一区 | 国产在线视频不卡 | 91频道 | 一本色道久久88综合亚洲精品高清 | 国产精品自在欧美一区 | 亚洲日韩精品欧美一区二区 | 日韩另类 | 国产日韩视频一区 | 另类区 | 国产精品久久亚洲一区二区 | 精品日韩欧美国产一区二区 | 日韩精品一区二区三区 在线观看 | 国产精品美女流白浆视频 | 国产欧美一区二区精品性色 | 最新国产精品精品视频 | 偷拍第一页 | 91精品久久久 | 国产成人久久精品激情91 | 国产日韩一区 | 中文亚洲欧美日韩无线码 | 国产在线视频资源 | 亚欧日韩| 五月天婷婷在线视频 | 国产短视频精品一区二区三区 | 欧美日韩一区二区在线 | 成人在线一区二区 | 日韩一区二区三区在线视频 | 日韩专区一区 | 亚洲精品国产字幕久久vr | 日韩精品欧美高清区 | 国产精品久久久久久久y | 黄色在线免费观看网址 | 午夜视频免费观看 |