国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

Vue實現typeahead組件功能(非常靠譜)

2019-11-19 15:39:44
字體:
來源:轉載
供稿:網友

 前言

之前那個typeahead寫的太早,不滿足當前的業務需求。

而且有些瑕疵,還有也不方便傳入數據和響應數據..

于是就推倒了重來,寫了個V2的版本

看圖,多了一些細節的考慮;精簡了實現的邏輯代碼

效果圖

這里寫圖片描述

實現的功能

1: 鼠標點擊下拉框之外的區域關閉下拉框

2: 支持鍵盤上下鍵選擇,支持鼠標選擇

3: 支持列表過濾搜索

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

5: 支持placeholder的傳入

6: 選中對象的響應(.sync vue2.3的組件通訊的語法糖)

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

用法

<select-search style="max-width:195px" placeholder="請選擇廣告主" :asyncData.sync="adHostData" :mapData="adHostDataList" :mapDataFormat="{label:'userName',value:'userId'}"></select-search>
  • asyncData:響應的數據,也就是選中的..回來是一個對象
  • mapData : 搜索的列表數據,肯定是外部傳入了…
  • 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="關鍵字" 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">未能查詢到,請重新輸入!</p>    </div>   </transition>  </div> </div></template><script> export default {  name: 'selectSearch',  data: function () {   return {    placeholderValue: '',// 給看到選擇內容的    isExpand: false,    searchVal: '', // 搜索關鍵字    resultVal: '', // 保存搜索到的值    searchList: [], //保存過濾的結果集    currentIndex: -1, // 當前默認選中的index,   }  },  computed: {   mapFormatData () { // 外部有傳入格式的時候映射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: '--請選擇--'   },   emptyText: {    type: String,    default: '暫無數據'   },   mapData: { // 外部傳入的列表數據    type: Array,    default: function () {     return []    }   },   mapDataFormat: { // 映射傳入數據的格式    type: Object,    default: function () {     return {      label: 'text',      value: 'value',      extraText: 'extraText'     }    }   },   asyncData: { // 實時響應的值    type: [Object, String],    default: function () {     return {}    }   }  },  methods: {   showHideMenu (e) { // 點擊其他區域關閉下拉列表    if (e) {     if (this.$refs.selectSearch && this.$refs.selectSearch.contains(e.target)) {      this.isExpand = true;     } else {      this.isExpand = false;     }    }   },   resetDefaultStatus () { // 清除所有選中狀態    this.searchVal = '';    this.currentIndex = -1;    this.typeaheadData.map(item => {     this.$delete(item, 'active');    })   },   setActiveClass (index) { // 設置樣式活動類    this.typeaheadData.map((item, innerIndex) => {     if (index === innerIndex) {      this.$set(item, 'active', true);      this.currentIndex = index; // 這句話是用來修正index,就是鍵盤上下鍵的索引,不然會跳位     } else {      this.$set(item, 'active', false)     }    })   },   selectChildWidthArrowDown () {    // 判斷index選中子項    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選中子項    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 () {    // 若是結果集只有一個,則默認選中    if (this.typeaheadData.length === 1) {     this.$emit('update:asyncData', this.typeaheadData[0]); // emit響應的值     this.placeholderValue = this.typeaheadData[0][this.mapDataFormat.label];    } else {     // 若是搜索的內容完全匹配到項內的內容,則默認選中     this.typeaheadData.map(item => {      if (this.searchVal === item[this.mapDataFormat.label] || item.active === true) {       this.$emit('update:asyncData', item); // emit響應的值       this.placeholderValue = item[this.mapDataFormat.label];      }     })    }    this.isExpand = false;   },   selectChild (index) {    // 鼠標點擊選擇子項    this.typeaheadData.map((item, innerIndex) => {     if (index === innerIndex || item.active) {      this.placeholderValue = item[this.mapDataFormat.label];      this.$emit('update:asyncData', item); // emit響應的值     }    });    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>

總結

以上所述是小編給大家介紹的Vue實現typeahead組件功能(非常靠譜),希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對武林網網站的支持!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 涟水县| 江安县| 广南县| 乐安县| 喜德县| 从化市| 汶上县| 关岭| 时尚| 株洲市| 崇阳县| 正阳县| 曲松县| 于田县| 灵寿县| 汝州市| 广元市| 高青县| 洪雅县| 潼南县| 宜丰县| 浮梁县| 裕民县| 旺苍县| 丰台区| 泸州市| 昭通市| 彩票| 普兰店市| 旬阳县| 盘山县| 新邵县| 盐津县| 贞丰县| 泾源县| 安新县| 烟台市| 理塘县| 察哈| 尉氏县| 湘阴县|