vue中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)需求分析
1. 輸入框?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
}
},2. 緩存上一次已查詢的數(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
},3.滾動(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
)
}
}
}4. 分頁加載
- 請(qǐng)求前展示加載圈
- 加載至最后一頁時(shí)不再進(jìn)行請(qǐng)求并提示暫無更多數(shù)據(jù)
- 關(guān)閉loading加載圈
- 把數(shù)據(jù)追加至已展示的數(shù)據(jù)列表中
4.0 獲取數(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>4.1 關(guān)閉加載圈
// 關(guān)閉加載圈
closeLoading() {
loadingInstance && loadingInstance.close && loadingInstance.close()
loadingInstance = null
},4.2 分頁加載事件
// 滾動(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)
},4.3 清空輸入框,重置上次記錄的數(shù)據(jù)
// 清空搜索項(xiàng)
handleClear() {
this.blurTxt = ''
this.blurArr = []
this.$refs['autocomplete'].$data.suggestions = []
},4.4 選中時(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>總結(jié)
到此這篇關(guān)于vue中el-autocomplete支持分頁上拉加載功能的文章就介紹到這了,更多相關(guān)el-autocomplete分頁上拉加載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue 實(shí)例中使用$refs的注意事項(xiàng)
這篇文章主要介紹了Vue 實(shí)例中使用$refs的注意事項(xiàng),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-01-01
vue-router實(shí)現(xiàn)webApp切換頁面動(dòng)畫效果代碼
本篇文章主要介紹了vue實(shí)現(xiàn)app頁面切換效果實(shí)例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-05-05
在vue項(xiàng)目中引入highcharts圖表的方法(詳解)
下面小編就為大家分享一篇在vue項(xiàng)目中引入highcharts圖表的方法(詳解),具有很好的參考價(jià)值,希望對(duì)大家有所幫助2018-03-03
vue-cli創(chuàng)建項(xiàng)目ERROR?in?Conflict:?Multiple?assets?emit?dif
最近vue/cli創(chuàng)建項(xiàng)目后出現(xiàn)了錯(cuò)誤,下面這篇文章主要給大家介紹了關(guān)于vue-cli創(chuàng)建項(xiàng)目ERROR?in?Conflict:?Multiple?assets?emit?different?content?to?the?same?filename?index.html問題的解決辦法,需要的朋友可以參考下2023-02-02
關(guān)于Nuxt的五種渲染模式的差異和使用場(chǎng)景全解析
這篇文章主要介紹了關(guān)于Nuxt的五種渲染模式的差異和使用場(chǎng)景全解析,在過去傳統(tǒng)開發(fā)中,頁面渲染任務(wù)是由服務(wù)端完成的,那么Nuxt是如何渲染的呢,需要的朋友可以參考下2023-04-04
vue實(shí)現(xiàn)codemirror代碼編輯器中的SQL代碼格式化功能
這篇文章主要介紹了vue實(shí)現(xiàn)codemirror代碼編輯器中的SQL代碼格式化功能,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-08-08

