这篇文章将为大家详细讲解有关如何使用vue实现前台列表数据过滤搜索、分页效果,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。
vue实现列表数据过滤搜索、分页效果的具体代码如下
job.vue页面
<style lang="scss">
.job-wrapper {
padding-top: 50px;
}
.job-left {
float: left;
margin-right: 20px;
padding: 20px;
width: 310px;
background: #fff;
}
.job-serach-title {
margin: 8px 0 10px 0;
color: rgb(51, 51, 51);
font-size: 16px;
}
.job-search-input {
display: flex;
}
.job-keywords {
width: 400px;
}
.job-search-btn {
display: flex;
align-items: center;
justify-content: center;
margin-left: 10px;
width: 50px;
height: 40px;
border-radius: 4px;
background-color: rgb(254, 62, 98);
}
.line {
margin: 25px 0 0 0;
width: 100%;
height: 1px;
background: #dfdfdf;
}
.halogg {
margin-top: 30px;
color: rgb(102, 102, 102);
font-weight: 300;
font-size: 14px;
}
.job-right {
float: right;
width: 870px;
background: #fff;
}
</style>
<style lang="scss">
// 重置样式
#job-select-1,
#job-select-2 {
margin-top: 20px;
select {
width: 100%;
}
}
</style>
<template>
<article class="job">
<div class="job-content layout">
<div class="job-wrapper">
<div class="job-left">
<div class="job-serach-title">搜索更多职位</div>
<div class="job-search-input">
<input v-model.trim="formData.keywords" @change="searchData" placeholder="搜索更多职位" class="job-keywords" />
<div class="job-search-btn pointer" @click="searchData">
搜
</div>
</div>
<div class="line"></div>
<div class="job-select" id="job-select-1">
<select v-model="formData.address" @change="searchData">
<option v-for="item,index in regionArr" :key="index">{{item.name}}</option>
</select>
</div>
<div class="job-select" id="job-select-2">
<select v-model="formData.title" @change="searchData">
<option v-for="(item,index) in searchList" :key="index">{{item}}</option>
</select>
</div>
</div>
<div class="job-right">
<joblist></joblist>
</div>
</div>
</div>
</article>
</template>
<script>
import joblist from 'src/components/job/list';
import { mapGetters, mapActions, mapMutations } from 'vuex';
export default {
name: 'reportFormIndex',
data() {
return {
formData: {
title: '',
address: '',
keywords: '',
},
};
},
computed: {
...mapGetters(['searchList', 'regionArr', 'show']),
},
watch: {},
title() {
return '行业';
},
methods: {
...mapActions(['getData']),
// select 选中后的回调数据
searchData() {
const payload = {
formData: Object.assign({}, this.formData),
pageIndex: 0, // 每次搜索后, 显示搜索结果的第一页
};
this.$store.commit('setState', payload);
},
},
mounted() {
this.$nextTick(() => {
this.getData();
});
},
components: {
joblist,
},
};
</script>
组件list.vue
<style lang="scss">
.list-header {
position: relative;
display: flex;
padding: 25px 30px 20px 30px;
color: rgb(153, 153, 153);
font-size: 14px;
&:after {
position: absolute;
right: 0;
bottom: 0;
left: 0;
display: inline-block;
width: 100%;
height: 1px;
background-color: #dfdfdf;
content: '';
}
}
.l-header-item-1 {
padding-left: 20px;
width: 37.3%;
}
.l-header-item-2 {
padding-left: 10px;
width: 32.7%;
}
.l-header-item-3 {
padding-left: 10px;
width: 18.7%;
}
.l-header-item-4 {
display: flex;
width: 11.3%;
.open {
color: #3e8bf5;
text-decoration: underline;
font-size: 14px;
}
.arrow-open {
margin-top: 5px;
margin-left: 5px;
width: 11px;
height: 7px;
transition: all 0.5s linear;
}
}
.inner-item {
padding: 0 30px;
}
.inner-box {
position: relative;
display: flex;
padding: 25px 0;
color: rgb(51, 51, 51);
font-size: 16px;
transition: all 0.5s linear;
&:after {
position: absolute;
right: 0px;
bottom: 0;
left: 0px;
display: inline-block;
height: 1px;
background-color: #dfdfdf;
content: '';
}
}
//
.list-item {
&.active {
.list-show-detail {
visibility: visible;
padding: 0 50px;
max-height: 1000px;
transition: all 0.5s linear;
}
.inner-box {
background: #f2f2f2;
transition: all 0.5s linear;
&:after {
background-color: transparent;
}
}
.arrow-open {
transition: all 0.5s linear;
transform: rotate(-180deg);
}
}
}
.list-show-detail {
visibility: hidden;
max-height: 0;
transition: all 0.5s linear;
}
.list-task-title {
margin: 25px 0 15px 0;
color: rgb(51, 51, 51);
font-size: 14px;
}
.list-task-item {
color: rgb(102, 102, 102);
font-size: 14px;
line-height: 1.714;
}
.list-apply {
display: flex;
align-items: center;
justify-content: center;
margin: 25px 0 30px 0;
width: 140px;
height: 50px;
border-radius: 4px;
background-color: rgb(254, 62, 98);
color: rgb(255, 255, 255);
font-size: 16px;
}
/////pagination
.job-pagination {
padding: 50px 0;
.pagination-wrapper {
display: flex;
justify-content: center;
margin: 0 auto;
width: 100%;
.subscript {
display: flex;
align-items: center;
justify-content: center;
margin: 0 5px;
width: 28px;
height: 28px;
border: 1px solid rgb(223, 223, 223);
border-radius: 4px;
color: blue;
color: rgb(102, 102, 102);
text-align: center;
font-size: 14px;
&.active {
border: 1px solid rgb(254, 62, 98);
background-color: rgb(254, 62, 98);
color: #fff;
}
}
.pagination-page {
display: inline-block;
width: 7px;
height: 11px;
background-image: url('./images/arrow.png');
&.pagination-next {
transform: rotate(180deg);
}
}
}
}
////
.job-no-data {
padding: 100px 0;
.job-no-data-img {
margin: 0 auto;
width: 170px;
height: 170px;
background-image: url('./images/job@2x.png');
background-size: cover;
background-repeat: no-repeat;
}
.job-no-data-msg {
margin-top: 10px;
color: rgb(51, 51, 51);
text-align: center;
font-size: 18px;
line-height: 2.778;
}
}
@media only screen and (max-width: 1200px) {
.list-header {
padding: 25px 30px 20px 30px;
}
}
@media only screen and (max-width: 767px) {
.list-header {
padding: 20px 15px 15px 15px;
}
.inner-item {
padding: 0px 15px 0 15px;
&:after {
right: 15px;
left: 15px;
transform: scaleY(0.5);
}
}
.l-header-item-1 {
padding-left: 10px;
}
.l-header-item-2 {
padding-left: 10px;
width: 28.7%;
}
.l-header-item-3 {
padding-left: 10px;
width: 19.7%;
}
.l-header-item-4 {
width: 14.3%;
}
}
</style>
<template>
<article id="list">
<ul class="list-wrapper">
<li class="list-header">
<div class="l-header-item-1">职位名称</div>
<div class="l-header-item-2">职位分类</div>
<div class="l-header-item-3">所在地区</div>
<div class="l-header-item-4"></div>
</li>
<li class="list-item" v-for="(item,index) in curList" :key="index" :class="{'active':item.show}" v-show="curList.length">
<div class="inner-item">
<div class="inner-box">
<div class="list-position l-header-item-1">{{item.position}}</div>
<div class="list-title l-header-item-2">{{item.title}}</div>
<div class="list-address l-header-item-3">{{item.address}}</div>
<div class="list-action l-header-item-4 pointer" @click="showHandler(item.id)">
<span class="open">展开</span>
<img src="./images/arrow-open.png" alt="" class="arrow-open">
</div>
</div>
</div>
<transition name="el-zoom-in-top">
<div class="list-show-detail" v-show="item.show">
<div class="list-task-title">岗位职责:</div>
<div class="list-task-wrapper">
<div class="list-task-item" v-for="(item2,index2) in item.task" :key="index2">{{item2}}</div>
</div>
<div class="list-task-title">岗位要求:</div>
<div class="list-task-wrapper">
<div class="list-task-item" v-for="(item3,index3) in item.rule" :key="index3">{{item3}}</div>
</div>
</div>
</transition>
</li>
<li class="job-no-data" v-show="!curList.length">
<div class="job-no-data-img"></div>
<div class="job-no-data-msg">暂未合适的职位</div>
</li>
<li class="job-pagination" v-show="curList.length">
<div class="pagination-wrapper">
<span class="subscript pointer" @click="prev">
<span class="pagination-prev pagination-page"></span>
</span>
<span class="subscript pointer" @click="selectPageHandler(index - 1)" v-for="index in pageLength" :key="index" :class="{active: pageIndex === index - 1}">{{index}}</span>
<span class="subscript pointer" @click="next">
<span class="pagination-next pagination-page"></span>
</span>
</div>
</li>
</ul>
</article>
</template>
<script>
import { mapState, mapGetters, mapActions, mapMutations } from 'vuex';
const PER_PAGE = 8; // 每页显示多少个
export default {
name: 'list',
data() {
return {};
},
computed: {
...mapState({
// pageIndex: state => state.job.pageIndex,
}),
...mapGetters(['filterJobList', 'pageIndex']),
curList() {
const { filterJobList, pageIndex } = this;
const startIndex = pageIndex * PER_PAGE;
const endIndex = startIndex + PER_PAGE;
return filterJobList.slice(startIndex, endIndex);
},
pageLength() {
const { filterJobList } = this;
if (filterJobList.length) {
return Math.ceil(filterJobList.length / PER_PAGE);
}
return 0;
},
},
methods: {
...mapActions(['showAndHide']),
// 操作 展开 隐藏
showHandler(id) {
this.showAndHide(id);
},
selectPageHandler(pageIndex) {
this.$store.commit('setState', {
pageIndex,
});
//同时关闭已经打开的职位详情页
this.$store.commit('hideAllDetailMutations');
},
// 上一页
prev() {
this.$store.commit('prevMutations');
},
// 下一页
next() {
this.$store.commit('nextMutations', this.pageLength);
},
},
mounted() {},
components: {},
};
</script>
store/job.js
import { unique } from 'src/assets/script/util.js';
import jobData from 'src/views/job/data.js';
// 初始状态
const state = {
realData: [],
searchList: [],
regionArr: [{
name: '上海',
id: 1,
},
{
name: '武汉',
id: 2,
},
],
// 右侧搜索,用户输入
formData: {
title: '', // 职位分类
address: '', // 地区
keywords: '', // 搜索更多职位
},
pageIndex: 0, // 第 0 页
show: false, // 申请工作的 modal
ApplyJobPosition: '' // 申请工作的职位
};
// 读取数据
const getters = {
ApplyJobPosition: state => state.ApplyJobPosition,
show: state => state.show,
pageIndex: state => state.pageIndex,
regionArr: state => state.regionArr,
searchList: state => {
const cache = [];
state.realData.forEach(n => {
cache.push(n.title);
});
return unique(cache);
},
// 符合条件的职位
filterJobList({ realData, formData }) {
const { title, address, keywords } = formData;
return (
realData
// 职位筛选逻辑
.filter(item => {
let matchAddress = true; // 地区筛选
let matchPosition = true; // 职位筛选
let matchKeywrod = true; // 关键字 筛选
if (title) {
matchPosition = item.title === title;
}
if (address) {
matchAddress = item.address === address;
}
if (keywords) {
// 模糊搜索;
const keys = keywords
.toUpperCase() // 转大写
.replace(' ', '') // 删掉空格
.split(''); // 切割成 单个字
matchKeywrod = keys.every(key => item.position.toUpperCase().includes(key));
}
return matchAddress && matchPosition && matchKeywrod;
})
);
},
};
// 数据改变
const mutations = {
// 从json文件直接获取元数据
getDataMutations(state, jobData) {
state.realData = jobData;
},
// 职位详情 显示/隐藏
showAndHideMutations(state, id) {
state.realData.forEach((n, i) => {
if (id === n.id) {
n.show = !n.show;
}
});
},
// 职位详情 全部隐藏
hideAllDetailMutations(state) {
state.realData.forEach((n, i) => {
n.show = false;
});
},
setState(state, payload = {}) {
// console.log('payload', payload);
Object.entries(payload).forEach(([key, value]) => {
state[key] = value;
});
},
// prev
prevMutations(state, payload = {}) {
if (!state.pageIndex) {
return;
}
state.pageIndex--
},
// next
nextMutations(state, payload = {}) {
// console.info(state.pageIndex, payload)
if (state.pageIndex < payload - 1) {
state.pageIndex++
}
},
// open modal
openApplyJobModal(state, payload = {}) {
state.show = true
state.ApplyJobPosition = payload
},
//close modal
closeApplyJobModal(state) {
state.show = false
},
};
// 逻辑响应
const actions = {
getData({ commit }) {
commit('getDataMutations', jobData);
},
// 显示 隐藏
showAndHide({ commit }, id) {
commit('showAndHideMutations', id);
},
};
export default {
state,
getters,
actions,
mutations,
};
util.js
// 数组去重
export function unique(arr) {
var newArr = [arr[0]];
for (var i = 1; i < arr.length; i++) {
if (newArr.indexOf(arr[i]) == -1) { newArr.push(arr[i]); }
}
return newArr;
}
关于“如何使用vue实现前台列表数据过滤搜索、分页效果”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。