<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題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關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

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

        來源:懂視網 責編:小采 時間:2020-11-27 22:31:35
        文檔

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

        Vue實現typeahead組件功能(非常靠譜): 前言 之前那個typeahead寫的太早,不滿足當前的業務需求。 而且有些瑕疵,還有也不方便傳入數據和響應數據.. 于是就推倒了重來,寫了個V2的版本 看圖,多了一些細節的考慮;精簡了實現的邏輯代碼 效果圖 實現的功能 1: 鼠標點擊下拉框之外的區域關閉下拉框 2:
        推薦度:
        導讀Vue實現typeahead組件功能(非常靠譜): 前言 之前那個typeahead寫的太早,不滿足當前的業務需求。 而且有些瑕疵,還有也不方便傳入數據和響應數據.. 于是就推倒了重來,寫了個V2的版本 看圖,多了一些細節的考慮;精簡了實現的邏輯代碼 效果圖 實現的功能 1: 鼠標點擊下拉框之外的區域關閉下拉框 2:

         前言

        之前那個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>
      1. asyncData:響應的數據,也就是選中的..回來是一個對象
      2. mapData : 搜索的列表數據,肯定是外部傳入了…
      3. mapData : 列表值映射
      4. 代碼

        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組件功能(非常靠譜),希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網站的支持!

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

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

        Vue實現typeahead組件功能(非常靠譜): 前言 之前那個typeahead寫的太早,不滿足當前的業務需求。 而且有些瑕疵,還有也不方便傳入數據和響應數據.. 于是就推倒了重來,寫了個V2的版本 看圖,多了一些細節的考慮;精簡了實現的邏輯代碼 效果圖 實現的功能 1: 鼠標點擊下拉框之外的區域關閉下拉框 2:
        推薦度:
        標簽: VUE 靠譜 非常
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 国产无遮挡裸体免费视频| 99免费在线观看视频| 亚洲精品美女视频| 亚洲精品在线视频观看| 国产精品无码永久免费888| 18禁无遮挡无码网站免费| 亚洲日韩乱码中文无码蜜桃| 久久国产精品免费| 亚洲成a人在线看天堂无码| 亚洲AV无码乱码在线观看富二代| 免费人成又黄又爽的视频在线电影| 大地资源网高清在线观看免费 | 免费观看激色视频网站(性色)| 国产h视频在线观看免费| 亚洲视频小说图片| 69视频免费观看l| 337p欧洲亚洲大胆艺术| 免费国产黄网站在线观看可以下载 | 最近最新高清免费中文字幕 | 日本免费高清视频| 亚洲区小说区图片区QVOD| 中国国产高清免费av片| 亚洲精品国产成人片| 免费国产黄网站在线观看视频| 2022年亚洲午夜一区二区福利 | 久久WWW免费人成—看片| 国产成人精品日本亚洲专区61| 亚洲一级毛片视频| 男女免费观看在线爽爽爽视频| 亚洲国产综合无码一区| a级毛片无码免费真人久久| 亚洲成AV人片在| 99久久国产热无码精品免费| 国产精品亚洲一区二区麻豆| 美女被cao网站免费看在线看| 啊v在线免费观看| 中国videos性高清免费| 亚洲福利视频网址| 日本成人免费在线| 久久国产精品成人免费| 亚洲a级片在线观看|