1. 在main.js同级创建directive.js文件
directive.js:
import Vue from 'vue'
Vue.directive('loadMore', {
bind(el, binding) {
// 如果有method由调用方实现,没有则在这里实现加载和远程搜索的功能
if (binding.modifiers.method) { // 方法一
// 节流
let timer
// 滚动监听
el.querySelector('.el-select-dropdown .el-select-dropdown__wrap').addEventListener('scroll', function() {
const condition = this.scrollHeight - this.scrollTop <= this.clientHeight + 100
if (!timer && condition) {
// 滚动加载(调用自定义的加载方法)
binding.value()
timer = setTimeout(() => {
clearTimeout(timer)
timer = null
}, 500)
}
})
} else { // 方法二
// 传入的对象
let value = binding.value
// 节流
let timer
// 无搜索内容变量
let pageNo = 1
let pages = 1
// 远程搜索内容变量
let searchPageNo = 1
let searchPages = 1
// 每次加载的条数
let pageSize = isNaN(value.pageSize) ? 10 : parseInt(value.pageSize)
// 远程搜索变量
let searchField = value.searchField
// 搜索固定内容
let searchData = value.searchData
// 接口地址
let url = value.url
// 下拉数组,这个options在本方法中必须永远指向value.options,否则整个功能都将失效
let options = value.options
// 无搜索拷贝数组,此处是为了在加载的基础上加一些默认的下拉项
let optionsCopy = JSON.parse(JSON.stringify(value.options))
// 远程搜索拷贝数组
let optionsSearch = []
// 远程搜索内容
let searchValue = ''
// 加载逻辑
const loadOptions = (searchField, search, searchData) => {
let params = {
pageSize: pageSize
}
if (searchData) {
Object.assign(params, searchData)
}
// 这里不能改变options的指向,否则会使整个功能失效(不能用options = [])
options.length = 0
// 判断是否为远程搜索,true-是
if (searchField && search) {
// 当到最大页数时不再查询
if (searchPages >= searchPageNo) {
params.pageNo = searchPageNo++
params[searchField] = search
api[url](params).then(res => {
if (res) {
searchPages = Math.ceil(res.data.total / pageSize)
optionsSearch = optionsSearch.concat(res.data.data)
dataProcessing(optionsSearch)
}
})
}
} else {
// 当到最大页数时不再查询
if (pages >= pageNo) {
params.pageNo = pageNo++
api[url](params).then(res => {
if (res) {
pages = Math.ceil(res.data.total / pageSize)
optionsCopy = optionsCopy.concat(res.data.data)
dataProcessing(optionsCopy)
}
})
}
}
}
// 返回数据处理
let dataProcessing = (optionsCopy) => {
// 这里不能改变options的指向,否则会使整个功能失效
optionsCopy.forEach(item => {
let check = options.find(t => {
return t[value.modelField] === item[value.modelField]
})
if (!check) {
options.push(item)
}
})
}
// 首次加载
loadOptions(undefined, undefined, searchData)
// 判断是否需要回显
if (value.model && value.modelField) {
// 回显方法
let echo = (model, modelField, searchData) => {
let params = {}
params[modelField] = model
if (searchData) {
Object.assign(params, searchData)
}
api[url](params).then(res => {
if (res) {
optionsCopy = optionsCopy.concat(res.data.data)
dataProcessing(optionsCopy)
}
})
}
if (optionsCopy.length > 0) {
let check = optionsCopy.find((item) => {
return item[value.modelField] === value.model
})
if (!check) {
echo(value.model, value.modelField, searchData)
}
} else {
echo(value.model, value.modelField, searchData)
}
}
// 滚动监听(无限滚动)
el.querySelector('.el-select-dropdown .el-select-dropdown__wrap').addEventListener('scroll', function() {
const condition = this.scrollHeight - this.scrollTop <= this.clientHeight + 100
if (!timer && condition) {
// 滚动加载
loadOptions(searchField, searchValue, searchData)
timer = setTimeout(() => {
clearTimeout(timer)
timer = null
}, 200)
}
})
// 输入监听(远程搜索)
if (searchField) {
const elInput = el.getElementsByTagName('input')[0]
// 输入搜索
elInput.addEventListener('input', function() {
if (this.value) {
searchPageNo = 1
searchPages = 1
optionsSearch = []
searchValue = this.value
loadOptions(searchField, searchValue, searchData)
} else {
searchValue = ''
dataProcessing(optionsCopy)
}
})
// 失去焦点时清除输入内容
elInput.addEventListener('blur', function() {
searchValue = ''
dataProcessing(optionsCopy)
})
}
}
}
})
2. 在main中注册
import directives from './directives' Vue.use(directives)
3.使用方法 (我是有很多地方使用到,所以封装成组件)
3.1 方法一
data() { return { loading: false, // 本来是想直接使用collectorId的,但是使用后报错,不允许我直接使用父传过来的,只好重新取一个 collectorIdValue: '', options: [], params: { pageSize: 15, pageNum: 1, pageTotal: 0, }, } }, created() { this.remoteMethod() }, props: { // 父传子的绑定数据 collectorId: { default: null, type: [Number, String] }, }, watch: { // 监听绑定数据是否存在,存在则传递给父组件对应的数据 'collectorIdValue': { handler(newVal) { if (newVal) { this.$parent.model.collectorId = newVal; } else { this.$parent.model.collectorId = '' } }, immediate: true } },
methods: { // 初始加载数据 remoteMethod(query) { this.loading = true; this.collectorIdValue = query || '' this.params.pageNum = 1 const params = { pageSize: this.params.pageSize, pageNum: this.params.pageNum, collectorId: this.collectorIdValue } // 调用接口 listCollector(params).then(response => { this.options = response.rows.map(el => { el.value = el.collectorId el.label = el.collectorId + '-(' + el.meterCount + ')只' + `${el.description? '-' + el.description : ''}` return el }) this.params.pageTotal = response.total; this.loading = false; }); }, // 滚动到底部,加载数据 loadMore(){ if (this.options.length >= this.params.pageTotal) return this.params.pageNum++ this.loading = true; const params = { pageSize: this.params.pageSize, pageNum: this.params.pageNum, collectorId: this.collectorIdValue } listCollector(params).then(response => { this.$nextTick(() => { this.options = this.options.concat(response.rows.map(el => { el.value = el.collectorId el.label = el.collectorId + '--(' + el.meterCount + ')只' return el })) }) this.params.pageTotal = response.total; this.loading = false; }); } }
效果图:
3.2 方法二
:filter-method="()=>{}"
v-load-more="{
url:'url',
options: options,
model: id,
modelField: 'id',
searchField: 'name'}"
>
:key="item.id"
:label="item.name"
:value="item.id">
data() {
return {
options:[],
id: ''
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)