需求
实现产品列表筛选条件排序,记得element-plus中的el-table-column实现了对表格数据排序的效果,不过俺现在做的是移动端页面,用的vant,vant没有类似的组件,于是打算手写一个。
思路
v-for遍历显示从父组件传来配置数据信息,flex一行进行显示,当点击上三角按钮时为升序,下三角为降序,再次点击时取消排序,当三角按钮被点击时,触发自定义事件sortOptionsChange,传递给父组件对应的prop(哪一栏)和state(升序、降序、不排序)信息,父组件接收到子组件传来的信息进行对应的后端请求
代码
子组件 table-column-sort.vue
<template>
<div class="zc-table-column-sort">
<div
class="sort-option"
v-for="(option, index) in sortOptionsOriginData"
:key="option.name"
>
<!-- 排序条件名称 -->
<span class="label">{{ option.label }}</span>
<!-- 上三角 下三角 -->
<span class="caret-wrapper">
<i
:class="{ 'ascending-active': option.state === SortType.ASCENDING }"
class="ascending"
@click="handleSortBtnClick(option.prop, index, SortType.ASCENDING)"
></i>
<i
:class="{ 'descending-active': option.state === SortType.DESCENDING }"
class="descending"
@click="handleSortBtnClick(option.prop, index, SortType.DESCENDING)"
></i>
</span>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue"
export default defineComponent({
props: {
// 排序条件配置信息
sortOptions: {
type: Array,
default: () => []
}
},
emits: ["sortOptionsChange"], // 通知父组件排序配置改变
setup(props, { emit }) {
// 为了不违反单向数据流 新建一个排序配置数据
const sortOptionsOriginData = ref(
JSON.parse(JSON.stringify(props.sortOptions))
)
// 排序类型
enum SortType {
UNSORTED = 0,
ASCENDING = 1,
DESCENDING = 2
}
// 初始化 置state为0
const originOptions = () => {
sortOptionsOriginData.value.forEach((option: any) => {
option["state"] = SortType.UNSORTED
})
}
originOptions()
// 排序按钮点击
const handleSortBtnClick = (prop: string, index: number, state: number) => {
// 再次点击则取消
if (sortOptionsOriginData.value[index].state === state) {
sortOptionsOriginData.value[index].state = SortType.UNSORTED
emit("sortOptionsChange", prop, SortType.UNSORTED)
return
}
originOptions()
sortOptionsOriginData.value[index].state = state
emit("sortOptionsChange", prop, state)
}
return {
SortType,
sortOptionsOriginData,
handleSortBtnClick
}
}
})
</script>
<style lang="less" scoped>
.zc-table-column-sort {
display: flex;
.sort-option {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
.label {
font-size: 0.3077rem;
color: #b8b8b8;
padding-right: 0.1282rem;
}
.caret-wrapper {
display: flex;
flex-direction: column;
align-items: center;
// 升序上三角
.ascending {
border: 0.1282rem solid transparent;
border-bottom-color: #a8abb2;
margin-bottom: 0.0256rem;
}
// 降序下三角
.descending {
border: 0.1282rem solid transparent;
border-top-color: #a8abb2;
margin-top: 0.0256rem;
}
// 升序上三角点击样式
.ascending-active {
border-bottom-color: #91bef4;
}
// 降序下三角点击样式
.descending-active {
border-top-color: #91bef4;
}
}
}
}
</style>
父组件 product-list.vue
<template>
<div class="product-list">
<zc-table-column-sort
@sortOptionsChange="sortOptionsChange"
:sortOptions="sortOptions"
/>
</div>
</template>
<script lang="ts">
import { defineComponent, computed, ref } from "vue"
import { useStore } from "vuex"
import ZcTableColumnSort from "@/base-ui/table-column-sort"
import { sortOptions } from "./config/sort.config"
export default defineComponent({
components: {
NavTitle,
ZcTableColumnSort
},
setup() {
const store = useStore()
// 搜索产品列表的初始化条件
const payload = ref({
keyWords: "",
initialAmount: -1,
deadLine: -1,
riskRating: "",
selectType: "", // 排序字段名称
state: 0, // 排序类型 0不排序 1升序 2降序
curPage: 1,
pageSize: 5
})
const sortOptionsChange = (prop: string, state: number) => {
payload.value.selectType = prop
payload.value.state = state
}
store.dispatch("product/getProductListAction", payload.value)
const productList = computed(() => store.state.product.productList)
return {
productList,
sortOptions,
sortOptionsChange
}
}
})
</script>
<style lang="less" scoped></style>
排序条件配置信息 sort.config.ts
export const sortOptions = [
{
prop: "rateOfReturn",
label: "七日年化%"
},
{
prop: "rateOfComparative",
label: "业绩比较%"
},
{
prop: "initialAmount",
label: "起购金额"
},
{
prop: "deadLine",
label: "有效期限"
}
]