输入框滚动加载与搜索如何进行封装?
技术 vue2 项目 框架是 antdv 1.7.8
我项目中有很多表单,表单中有很多Select 选择器 选择器的内容是项目中的某一个列表,有很多这种下拉,在不同的界面。
我的问题是,单独的每一个下拉框都可以进行 远程搜索与滚动加载,但是接口是不同的,所以如何进行封住一下写一个,所有的下拉框都能用。
代码demo如此
<template> <div>
<div>
<a-select style="width: 500px;" v-model="queryParam.industry_id" show-search :filter-option="false"
:default-active-first-option="false" @search="handleSearch" @popupScroll="handlePopupScroll">
<a-select-option v-for="(item, index) in industryList" :key="index" :value="item.industry_id">
{{item.industry_name }}
</a-select-option>
</a-select>
</div>
<div>
<a-select style="width: 500px;" show-search :filter-option="false" :default-active-first-option="false"
@search="handleSearchEnt" v-model="queryParam.ent_id" @popupScroll="handlePopupScrollEnt">
<a-select-option v-for="(item, index) in industryEntList" :key="index" :value="item.ent_id">
{{ item.ent_name}}
</a-select-option>
</a-select>
</div>
</div>
</template>
<script>
import {
orgSelectAPI,
orgEntSelectAPI,
} from "@/api/enterprise.js";
import _ from "lodash";
export default {
data() {
return {
queryParam: {},
industryList: [], // 产业下拉数据
industryCount: 10, // 产业默认10个
industrySize: 0, // 总条数数据改变时候必须低于这个值
industrySearch: "", // 远程搜索值
industryEntList: [],
entCount: 10,
entSize: 0,
industryEntSearch: "",
};
},
created() {
this.getIndustryList();
this.getIndustryEntList();
},
methods: {
// 产业下拉加载
handlePopupScroll: _.debounce(function (e) {
const { target } = e;
const { scrollTop, scrollHeight, offsetHeight } = target;
if (
this.industryCount <= this.industrySize &&
scrollTop + 2 + offsetHeight >= scrollHeight
) {
this.industryCount = Math.min(
this.industryCount + 10,
this.industrySize
);
this.getIndustryList(this.industrySearch);
}
}, 500),
// 远程搜索
handleSearch: _.debounce(function (e) {
this.industrySearch = e;
this.getIndustryList(this.industrySearch);
}, 500),
// 获取产业数据
async getIndustryList(e) {
let res = await orgSelectAPI({
page: 1,
rows: e ? 0 : this.industryCount,
name: e,
});
this.industry_id = "";
this.industryList = [];
this.industrySize = res.data.total;
this.industryList = res.data.rows;
},
handleSearchEnt: _.debounce(function (e) {
this.industryEntSearch = e;
this.getIndustryEntList("", e);
}, 500),
handlePopupScrollEnt: _.debounce(function (e) {
const { target } = e;
const { scrollTop, scrollHeight, offsetHeight } = target;
if (
this.entCount <= this.entSize &&
scrollTop + 2 + offsetHeight >= scrollHeight
) {
this.entCount = Math.min(this.entCount + 10, this.entSize);
this.getIndustryEntList(this.industry_id, this.industryEntSearch);
}
}, 500),
// 获取企业数据
async getIndustryEntList(e, name) {
let res = await orgEntSelectAPI({
page: 1,
rows: this.entCount,
industry_id: e,
name,
});
this.industryEntList = []
this.industryEntList = res.data.rows;
this.entSize = res.data.total;
},
},
};
</script>
像这种数据我有很多,这种下拉出现一个我就得定义一个 count与 size 还有搜索与滚动的函数,写起来很麻烦,但是接口又不相同,我该如何进行封装一下,让这个东西写一次,后边的都能用
求大佬给个封装思路,接口与数据如何搞
经过大佬提示之后封装如下
<template> <a-select :placeholder='showPlaceHolder' v-model="selectedValue" style="width: 100%;" show-search :filter-option="false"
:default-active-first-option="false" @search="handleSearch" @popupScroll="handlePopupScroll">
<a-select-option v-for="(item, index) in showList" :key="index" :value="item[valueKey]">
{{ item[labelKey] }}
</a-select-option>
</a-select>
</template>
<script>
import _ from "lodash";
export default {
props: {
showPlaceHolder: '',
apiFunction: {
type: Function,
required: true,
},
queryParams: {
type: Object,
default: () => ({}),
},
valueKey: {
type: String,
default: 'id',
},
labelKey: {
type: String,
default: 'name',
},
initialCount: {
type: Number,
default: 10,
},
},
data() {
return {
selectedValue: undefined,
showList: [],
pageCount: this.initialCount, // 每页多少条
page: 1, // 当前第几页
allPage: 0, // 总共有多少页
pageTotal: 0, // 总共有多少条
itemSearch: "", // 搜索框搜索输入值
countNum: 0, // 计数器
};
},
watch: {
selectedValue(newV) {
this.$emit('getValue', newV)
this.itemSearch = undefined
this.getList();
},
queryParams: {
deep: true,
handler(newV, oldV) {
// 表单重置
if (oldV[this.valueKey] && !newV[this.valueKey]) {
this.selectedValue = null
}
}
}
},
created() {
if (this.queryParams && this.queryParams[this.valueKey]) {
// 有值就表示回显数据,回显只查当前条
this.selectedValue = this.queryParams[this.valueKey]
this.byIdGetList(this.queryParams)
} else {
this.getList();
}
},
/**
* 引用
* import popupScrollSelect from "@/views/common/components/popupScrollSelect.vue";
* <popupScrollSelect :showPlaceHolder="$t('pleaseSelect') + $t('facility_cn')" :query-params="{ facility_id: formRight.facility_id }" :api-function="emissionConfigFacilityAPI" value-key="facility_id" label-key="facility_cn" @getValue="e => formRight.facility_id = e"> </popupScrollSelect>
* 现在需要修改成分页请求数据,第一次请求 第1页,10条 第二次请求 2页,10条,将 第二页与第一页的数据拼接起来
* 设计思路,每页十条得到总页数,向上取整,页码每次加一,直到加到最大值,每次得到数据之后,push到原始展示数组中。
*
*/
methods: {
async getList(searchValue = "", page) {
const response = await this.apiFunction({
page: page ? page : 1,
rows: searchValue ? 0 : this.pageCount,
name: searchValue,
});
if (searchValue) {
this.showList = response.data.rows;
} else {
// 无法判断上次数据是搜索之后的 showList 还是下拉之后的数据,需要去重才能赋值
const mergedArray = [...this.showList.concat(response.data.rows)];
this.showList = _.uniqWith(mergedArray, _.isEqual)
}
// 总页数,总条数只需要计算一次
if (this.countNum == 0) {
this.pageTotal = response.data.total;
this.allPage = Math.ceil(this.pageTotal / this.pageCount) // 最多有多少页
this.countNum++
}
},
handleSearch: _.debounce(function (value) {
this.itemSearch = value;
this.getList(this.itemSearch);
}, 500),
handlePopupScroll: _.debounce(function (e) {
const { target } = e;
const { scrollTop, scrollHeight, offsetHeight } = target;
if (
this.page <= this.allPage &&
scrollTop + 2 + offsetHeight >= scrollHeight
) {
// this.pageCount = Math.min(this.pageCount + 10, this.pageTotal);
this.page = Math.min(this.page + 1, this.allPage);
this.getList(this.itemSearch, this.page);
}
}, 500),
async byIdGetList(queryParams) {
const response = await this.apiFunction(queryParams);
if (!this.showList.some(item => JSON.stringify(item) == JSON.stringify(response.data.rows[0]))) {
this.showList = [...this.showList, ...response.data.rows]
}
},
},
};
</script>
回答:
封装:
<template> <a-select :placeholder="placeholder" v-model="selectedValue" style="width: 100%;" show-search :filter-option="false"
:default-active-first-option="false" @search="handleSearch" @popupScroll="handlePopupScroll">
<a-select-option v-for="(item, index) in list" :key="index" :value="item[valueKey]">
{{ item[labelKey] }}
</a-select-option>
</a-select>
</template>
<script>
import _ from "lodash";
export default {
props: {
placeholder: String,
apiFunction: {
type: Function,
required: true,
},
queryParams: Object,
valueKey: {
type: String,
default: 'id',
},
labelKey: {
type: String,
default: 'name',
},
initialCount: {
type: Number,
default: 10,
},
},
data() {
return {
selectedValue: null,
list: [],
count: this.initialCount,
page: 1,
total: 0,
};
},
watch: {
selectedValue(value) {
this.$emit('input', value);
},
queryParams: {
deep: true,
handler() {
this.getList();
},
},
},
created() {
this.getList();
},
methods: {
async getList(searchValue = "", page = 1) {
try {
const response = await this.apiFunction({
page,
rows: searchValue ? 0 : this.count,
name: searchValue,
});
this.list = searchValue ? response.data.rows : [...this.list, ...response.data.rows];
this.total = response.data.total;
} catch (error) {
console.error(error);
}
},
handleSearch: _.debounce(function (value) {
this.getList(value);
}, 500),
handlePopupScroll: _.debounce(function (e) {
const { target } = e;
const { scrollTop, scrollHeight, offsetHeight } = target;
if (this.page * this.count < this.total && scrollTop + offsetHeight >= scrollHeight) {
this.page += 1;
this.getList("", this.page);
}
}, 500),
},
};
</script>
回答:
官方示例:
https://3x.ant.design/components/select-cn/
以上是 输入框滚动加载与搜索如何进行封装? 的全部内容, 来源链接: utcz.com/p/934942.html