el?autocomplete支持分頁上拉加載使用詳解
el-autocomplete使用
- 效果圖
template
<template> <el-autocomplete :clearable="true" //支持清空 :title="searchStr" // 鼠標(biāo)移上去提示文案 :trigger-on-focus="true" // 聚焦時(shí)是否觸發(fā)下拉列表展示 :fetch-suggestions="querySearchAsync" // 篩選符合條件的數(shù)據(jù) :placeholder="placeholder" // 占位符提示信息 v-scrollLoad="load" // 自定義上拉加載指令 v-model="searchStr" // 搜索關(guān)鍵字 popper-class="diy-autocomplete" // 下拉框自定義class控制樣式 class="el-autocomplete-component" // 給當(dāng)前組件定義專屬類名 size="small" // 組件顯示尺寸 ref="autocomplete" // 用于后期獲取dom元素 @select="handleSelect" // 選中時(shí)觸發(fā)事件 @blur="handleBlur" // 失去焦點(diǎn)時(shí)觸發(fā) @clear="handleClear" // 清空數(shù)據(jù)時(shí)觸發(fā) ></el-autocomplete> </template>
實(shí)現(xiàn)需求分析
輸入框?yàn)榭諘r(shí)聚焦或失焦后又重新聚焦不會(huì)觸發(fā)請(qǐng)求數(shù)據(jù)接口
// blurTxt: 記錄上次失焦時(shí) 和 選中時(shí)的篩選字段 // blurArr: 記錄上次失焦時(shí) 和 選中時(shí)已經(jīng)查詢到的數(shù)據(jù) async querySearchAsync(queryString, cb) { if (this.blurTxt === queryString || !queryString) { cb(this.blurArr) return } },
緩存上一次已查詢的數(shù)據(jù)&搜索條件:blurArr、blurTxt
// 失焦事件 handleBlur() { this.blurTxt = this.searchStr || '' this.blurArr = this.$refs['autocomplete'].$data.suggestions }, // 過濾數(shù)據(jù)時(shí)及時(shí)更新篩選字段 async querySearchAsync(queryString, cb) { this.blurTxt = searchVal },
滾動(dòng)加載指令(監(jiān)聽容器的scroll事件并進(jìn)行防抖處理)
- 防抖函數(shù)
/** * @param {Function} func * @param {number} wait * @param {boolean} immediate * @return {*} */ export function debounce(func, wait, immediate) { let timeout, args, context, timestamp, result const later = function() { // 據(jù)上一次觸發(fā)時(shí)間間隔 const last = +new Date() - timestamp // 上次被包裝函數(shù)被調(diào)用時(shí)間間隔 last 小于設(shè)定時(shí)間間隔 wait if (last < wait && last > 0) { timeout = setTimeout(later, wait - last) } else { timeout = null // 如果設(shè)定為immediate===true,因?yàn)殚_始邊界已經(jīng)調(diào)用過了此處無需調(diào)用 if (!immediate) { result = func.apply(context, args) if (!timeout) context = args = null } } } return function(...args) { context = this timestamp = +new Date() const callNow = immediate && !timeout // 如果延時(shí)不存在,重新設(shè)定延時(shí) if (!timeout) timeout = setTimeout(later, wait) if (callNow) { result = func.apply(context, args) context = args = null } return result } }
- 滾動(dòng)加載指令
directives: { scrollLoad: { bind(el, binding, vnode) { let wrapDom = el.querySelector('.el-autocomplete-suggestion__wrap') let listDom = el.querySelector('.el-autocomplete-suggestion__wrap .el-autocomplete-suggestion__list') // 滾動(dòng)事件做防抖處理 wrapDom.addEventListener( 'scroll', debounce(e => { let condition = wrapDom.offsetHeight + wrapDom.scrollTop + 50 - listDom.offsetHeight if (condition > 0 && !vnode.context.loading) { binding.value() } }, 300), false ) } } }
分頁加載
- 請(qǐng)求前展示加載圈
- 加載至最后一頁時(shí)不再進(jìn)行請(qǐng)求并提示暫無更多數(shù)據(jù)
- 關(guān)閉loading加載圈
- 把數(shù)據(jù)追加至已展示的數(shù)據(jù)列表中
獲取數(shù)據(jù),并進(jìn)行格式化
第一種方式: 在組件上設(shè)置valueKey為你要展示的字段名稱,默認(rèn)值為value
<el-autocomplete valueKey="nickName"></el-autocomplete>
第二種方式:拿到數(shù)據(jù)后遍歷數(shù)據(jù)為每一項(xiàng)增添value屬性,值為自己組合想展示的方式
// 獲取用戶列表 async getList(queryString) { let result = await searchUserList({ pageNum: this.pageNum, pageSize: this.pageSize, searchValue: decodeURI(queryString) }) this.total = result.total // 調(diào)用 callback 返回建議列表的數(shù)據(jù) result.rows && result.rows.forEach(element => { // 學(xué)生展示 姓名+班級(jí) if (element.classList[0] && element.roleId === 101) { element.value = element.nickName + '-' + element.classList[0].className } else { // 非學(xué)生或者學(xué)生沒有主班級(jí)展示 姓名+身份 element.value = element.nickName + '-' + (element.roleName || '暫無角色I(xiàn)D') } }) return result.rows },
第三種方式:在組件對(duì)應(yīng)的插槽slot中自定義展示內(nèi)容
<el-autocomplete > <!-- 輸入框小圖標(biāo)插槽 --> <i class="el-icon-edit el-input__icon" slot="suffix"> </i> <!-- 搜索列表每一項(xiàng)展示 --> <template slot-scope="{ item }"> <div class="name">{{ item.nickName }} - {{item.className}}</div> </template> </el-autocomplete>
關(guān)閉加載圈
// 關(guān)閉加載圈 closeLoading() { loadingInstance && loadingInstance.close && loadingInstance.close() loadingInstance = null },
分頁加載事件
// 滾動(dòng)加載 async load() { this.closeLoading() // 加載到最后一頁停止加載 if (this.pageNum * this.pageSize > this.total) { return } this.pageNum++ loadingInstance = Loading.service({ target: document.querySelector('.el-autocomplete-suggestion'), fullscreen: false, spinner: 'el-icon-loading', lock: true, text: '加載中...' }) let results = await this.getList(this.searchStr) this.closeLoading() this.pageNum * this.pageSize >= this.total ? results.push({ value: '暫無更多數(shù)據(jù)' }) : '' // 將數(shù)據(jù)添加到下拉列表 this.$refs['autocomplete'].$data.suggestions = this.$refs['autocomplete'].$data.suggestions.concat(results) },
清空輸入框,重置上次記錄的數(shù)據(jù)
// 清空搜索項(xiàng) handleClear() { this.blurTxt = '' this.blurArr = [] this.$refs['autocomplete'].$data.suggestions = [] },
選中時(shí)記錄相關(guān)數(shù)據(jù)
// 選中用戶跳轉(zhuǎn)至對(duì)應(yīng)的頁面 handleSelect(item) { this.$refs['autocomplete'].$data.suggestions = this.blurArr = [item] this.blurTxt = this.searchStr || '' this.pageNum = 1 this.total = 0 ... //下拉選中的值 // console.log(item) }
數(shù)據(jù)展示不穩(wěn)定問題
例如姓名模糊搜索過程中,也許我們會(huì)先輸入姓為第一個(gè)關(guān)鍵詞,接著在輸入第二個(gè)關(guān)鍵詞名字,只輸入姓的時(shí)候肯定要比姓名要查詢的數(shù)據(jù)多,當(dāng)在大量數(shù)據(jù)中查詢時(shí)會(huì)面臨著第二個(gè)請(qǐng)求(搜索條件:輸入姓名的)先返回?cái)?shù)據(jù),然后第一個(gè)請(qǐng)求(搜索條件:輸入姓的)才會(huì)返回?cái)?shù)據(jù)的情況,而此時(shí)篩選列表中展示的肯定是最后請(qǐng)求出來的結(jié)果(搜索框中展示的是完整姓名:張三,而展示列表中卻展示出了:張一、張二、張三...),此時(shí)的解決方案是相同接口取消上一次的接口。
- 請(qǐng)求攔截中限制重復(fù)請(qǐng)求某個(gè)接口
import axios from 'axios' let pending = []; //聲明一個(gè)數(shù)組用于存儲(chǔ)每個(gè)ajax請(qǐng)求的取消函數(shù)和ajax標(biāo)識(shí) let cancelToken = axios.CancelToken; let removePending = (ever) => { for (let p in pending) { if (pending[p].u === ever.url + '&' + ever.method) { //當(dāng)當(dāng)前請(qǐng)求在數(shù)組中存在時(shí)執(zhí)行函數(shù)體 pending[p].f(); //執(zhí)行取消操作 pending.splice(p, 1); //把這條記錄從數(shù)組中移除 } } } var errorFlag = false; var erFlag = false; // 創(chuàng)建axios實(shí)例 const service = axios.create({ // axios中請(qǐng)求配置有baseURL選項(xiàng),表示請(qǐng)求URL公共部分 baseURL: process.env.VUE_APP_BASE_API, // 超時(shí) timeout: 90000 }) // request攔截器 service.interceptors.request.use( config => { // 如果你是在老項(xiàng)目中開發(fā)就加一個(gè)限制,避免影響到原有的功能 // if(config.url.indexOf('system/user/newsearch_list')!==-1){ config && removePending(config); //在一個(gè)ajax發(fā)送前執(zhí)行一下取消操作 config.cancelToken = new cancelToken((c) => { // 這里的ajax標(biāo)識(shí)我是用請(qǐng)求地址&請(qǐng)求方式拼接的字符串,當(dāng)然你可以選擇其他的一些方式 pending.push({ u: config.url + '&' + config.method, f: c }); }); // } return config }, error => { console.log(error) Promise.reject(error) } )
- 相應(yīng)攔截中對(duì)取消請(qǐng)求這個(gè)操作單獨(dú)處理,不展示錯(cuò)誤消息提示彈窗
// 響應(yīng)攔截器 service.interceptors.response.use(res => { const code = res.data.code if (code === 401) { ... } else if (code !== 200) { if(!errorFlag){ ... return Promise.reject(res.data || {}) } } else { return res.data } }, error => { // 單獨(dú)處理取消請(qǐng)求導(dǎo)致的錯(cuò)誤 if(error.__CANCEL__){ return false } if(!erFlag){ Message({ message: error.message, type: 'error', duration: 3 * 1000 }) return Promise.reject(error) } } )
完整的 scss 文件
.el-autocomplete-component { max-width: 230px; vertical-align: text-bottom; height: 50px; padding-top: 1px; cursor: pointer; /deep/ .el-input__inner { cursor: pointer; padding-left: 5px; padding-right: 8px; background: transparent; border: none; color: #fff; font-size: 14px; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; &::placeholder { color: #bfbfbf; font-size: 12px; } } } .diy-autocomplete { .name { max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; height: 34px; } }
完整的 js 文件
<script> import { searchUserList } from '@/api/system/user' // 請(qǐng)求用戶列表的接口 import { debounce } from '@/utils/index' // 防抖函數(shù) import { Loading } from 'element-ui' // 下拉加載時(shí)的過渡loading let loadingInstance = null export default { data() { return { showAutocomplete: false, searchStr: '', //輸入關(guān)鍵詞的值 pageNum: 1, pageSize: 20, total: 0, //篩選數(shù)據(jù)的總值 placeholder: '請(qǐng)輸入用戶名/手機(jī)號(hào)/QQ', blurTxt: '', //記錄失焦時(shí)搜索框中的文字,避免聚焦時(shí)重新篩選數(shù)據(jù) blurArr: [] //記錄失焦時(shí)已經(jīng)搜索出來的列表 } }, methods: { // 失焦事件 handleBlur() { this.blurTxt = this.searchStr || '' this.blurArr = this.$refs['autocomplete'].$data.suggestions }, // 清空搜索項(xiàng) handleClear() { this.blurTxt = '' this.blurArr = [] this.$refs['autocomplete'].$data.suggestions = [] }, // 關(guān)閉加載圈 closeLoading() { loadingInstance && loadingInstance.close && loadingInstance.close() loadingInstance = null }, // 條件查詢 async querySearchAsync(queryString, cb) { this.$refs['autocomplete'].$data.suggestions = [] if (this.blurTxt === queryString || !queryString) { cb(this.blurArr) return } this.handleClear() let searchVal = queryString // 后面所拼接的班級(jí)名稱和角色不參與篩選字段中 queryString.indexOf('-') !== -1 ? (searchVal = queryString.split('-')[0]) : '' this.pageNum = 1 this.blurTxt = searchVal let results = await this.getList(searchVal) cb(results || []) }, // 獲取用戶列表 async getList(queryString) { let result = await searchUserList({ pageNum: this.pageNum, pageSize: this.pageSize, searchValue: decodeURI(queryString) }) this.total = result.total // 調(diào)用 callback 返回建議列表的數(shù)據(jù) result.rows && result.rows.forEach(element => { // 學(xué)生展示 姓名+班級(jí) if (element.classList[0] && element.roleId === 101) { element.value = element.nickName + '-' + element.classList[0].className } else { // 非學(xué)生或者學(xué)生沒有主班級(jí)展示 姓名+身份 element.value = element.nickName + '-' + (element.roleName || '暫無角色I(xiàn)D') } }) return result.rows }, // 滾動(dòng)加載 async load() { this.closeLoading() // 加載到最后一頁停止加載 if (this.pageNum * this.pageSize > this.total) { return } this.pageNum++ loadingInstance = Loading.service({ target: document.querySelector('.el-autocomplete-suggestion'), fullscreen: false, spinner: 'el-icon-loading', lock: true, text: '加載中...' }) let results = await this.getList(this.searchStr) this.closeLoading() this.pageNum * this.pageSize >= this.total ? results.push({ value: '暫無更多數(shù)據(jù)' }) : '' // 將數(shù)據(jù)添加到下拉列表 this.$refs['autocomplete'].$data.suggestions = this.$refs['autocomplete'].$data.suggestions.concat(results) }, // 選中用戶跳轉(zhuǎn)至對(duì)應(yīng)的頁面 handleSelect(item) { this.$refs['autocomplete'].$data.suggestions = this.blurArr = [item] this.blurTxt = this.searchStr || '' this.pageNum = 1 this.total = 0 let routeData = {} if (item.roleId === 101) { // 學(xué)生 routeData = this.$router.resolve({ path: '/personInf/student', query: { userId: item.userId } }) } else { // 非學(xué)生 routeData = this.$router.resolve({ path: '/userManagement/user', query: { userInfo: item.nickName ,roleId: item.roleId||''} }) } window.open(routeData.href, '_blank') //下拉選中的值 // console.log(item) } }, directives: { scrollLoad: { bind(el, binding, vnode) { let wrapDom = el.querySelector('.el-autocomplete-suggestion__wrap') let listDom = el.querySelector('.el-autocomplete-suggestion__wrap .el-autocomplete-suggestion__list') // 滾動(dòng)事件做防抖處理 wrapDom.addEventListener( 'scroll', debounce(e => { let condition = wrapDom.offsetHeight + wrapDom.scrollTop + 50 - listDom.offsetHeight if (condition > 0 && !vnode.context.loading) { binding.value() } }, 300), false ) } } } } </script>
以上就是el autocomplete支持分頁上拉加載使用詳解的詳細(xì)內(nèi)容,更多關(guān)于el autocomplete分頁上拉加載的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue實(shí)現(xiàn)商城上貨組件簡(jiǎn)易版
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)商城上貨組件簡(jiǎn)易版,50行js代碼實(shí)現(xiàn)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11vue.js內(nèi)置組件之keep-alive組件使用
keep-alive是Vue.js的一個(gè)內(nèi)置組件。這篇文章主要介紹了vue.js內(nèi)置組件之keep-alive組件使用,需要的朋友可以參考下2018-07-07vue+quasar使用遞歸實(shí)現(xiàn)動(dòng)態(tài)多級(jí)菜單
這篇文章主要為大家詳細(xì)介紹了vue+quasar使用遞歸實(shí)現(xiàn)動(dòng)態(tài)多級(jí)菜單,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07Vue 列表頁帶參數(shù)進(jìn)詳情頁的操作(router-link)
這篇文章主要介紹了Vue 列表頁帶參數(shù)進(jìn)詳情頁的操作(router-link),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-11-11vue watch如何深度監(jiān)聽數(shù)組每一項(xiàng)的變化
這篇文章主要介紹了vue watch如何深度監(jiān)聽數(shù)組每一項(xiàng)的變化問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07vue實(shí)現(xiàn)動(dòng)態(tài)綁定行內(nèi)樣式style的backgroundImage
這篇文章主要介紹了vue實(shí)現(xiàn)動(dòng)態(tài)綁定行內(nèi)樣式style的backgroundImage方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07vue的rules驗(yàn)證部分可以部分又失效的原因及解決方案
vue的rules驗(yàn)證失效,部分可以部分又失效,很多百度都有,但是我這里遇到了一個(gè)特別的,那就是prop沒有寫全,導(dǎo)致驗(yàn)證某一個(gè)失效,接下來就跟小編一起來看看這個(gè)失效的原因和解決方案吧2023-11-11