基于 Vue3 的列设置(拖动排序、显示隐藏)
作者:青柚1943
- 2022 年 9 月 01 日 湖南
本文字数:2983 字
阅读完需:约 10 分钟
最近新项目要写了一个列设置的组件(拖动排序、显示隐藏),这里简单整理一下(基于 TypeScript、Vue3、Element-Plus-UI、Pinia、Sortablejs)
设计思路:将 column(列表头)抽象成一个数组, 每个 column 是一个元素。
通过属性 show(true/false)来控制列的显示隐藏;
通过拖动来控制数组元素顺序,以此来改变列渲染的顺序。
//数组元素(列的抽象,后期甚至可以扩展更多关于列的设置interface ColumnSettings { prop: string //列头 label:string //列名 show:boolean //显隐}复制代码
基本效果图如下:
列设置
下面是列设置组件 ColumnsSetting.vue,这边用的 Sortablejs,整体拖拽的效果还是很好,无明显抖动,很丝滑。
<template> <div style="display: auto; align-items: center" title="列设置"> <el-popover placement="bottom-start" :width="360" trigger="click" title="列设置"> <el-divider /> <template #reference> <el-icon> <Setting /> </el-icon> </template> <el-table class="wrap-box" ref="table" :data="columns" row-key="prop" style="width: 100%" border> <el-table-column prop="" label="排序" width="60"> <el-tag class="move" style="cursor: move;"> <el-icon style="cursor: move;"> <Sort /> </el-icon> </el-tag> </el-table-column> <el-table-column prop="label" label="列名"> <template #default="scope"> <el-tag round :effect="scope.row.show?'dark':'light'">{{ scope.row.label }}</el-tag> </template> </el-table-column> <el-table-column prop="hide" label="显示" width="60"> <template #default="scope"> <el-switch v-model="scope.row.show" size="small" :active-value="true" :inactive-value="false" /> </template> </el-table-column> </el-table> </el-popover> </div></template>
<script lang="ts" setup>import Sortable from 'sortablejs'import { Setting,Sort } from '@element-plus/icons-vue'import { inject, onMounted, ref } from '@vue/runtime-core';
const columns=inject("columns") as ColumnSettings[] const rowDrop = () => { const tbody = document.querySelector('.wrap-box .el-table__body-wrapper tbody') as HTMLElement | null if (tbody) { Sortable.create(tbody, { handle: ".move", animation: 200, ghostClass: "ghost", onEnd(event: any) { const { oldIndex, newIndex } = event //删除并获取当前行 const currRow = columns.splice(oldIndex, 1)[0] //再拖动结束位置插入当前行 columns.splice(newIndex, 0, currRow) } }) }}
onMounted(() => { rowDrop()})</script>
复制代码
这里为了方便展示,我把 Pinia 的 store 层代码处理了一下(和生产稍微有点不一样),并移到了 index.vue 中。
<template> <div class="app-container"> <el-card> <div class="mb-10px"> <el-row> <el-col :span="12"> <el-button type="primary" @click="addUser">新增</el-button> <el-button type="danger" @click="deleteUser">删除 </el-button> </el-col> <el-col :span="12"> <ColumnSetting @settingChange="settingChange" /> </el-col>
</el-row> </div> </el-card> <el-table :data="userList" style="width: 100%"> <el-table-column v-for="(column, index) in showColumns" :key="index" :prop="column.prop" :label="column.label"> <opts v-if="column.label === 'Operations'" /> <template #default="scope" v-if="column.label === 'WfStatusName'"> <el-tag :type="scope.row.wfStatusName === '启用' ? 'success' : ''" disable-transitions>{{ scope.row.wfStatusName }} </el-tag> </template> </el-table-column> </el-table> </div></template>
<script lang="ts" setup>import opts from './opts.vue'import { computed } from 'vue'import { defineStore, storeToRefs } from 'pinia'import { reactive, ref } from '@vue/reactivity'import { onMounted, provide } from '@vue/runtime-core'import { getUserApi } from '../../../api/frontend/user/index'import ColumnSetting from './columnSetting.vue'
//#region Pinia Storeconst columnsDefault = reactive({ "userColumns": [ { prop: 'id', label: 'ID', show: true }, { prop: 'name', label: 'Name', show: true }, { prop: 'displayName', label: 'DisplayName', show: true }, { prop: 'isExternal', label: 'IsExternal', show: true }, { prop: 'mfaPhoneNumber', label: 'MfaPhoneNumber', show: true }, { prop: 'wfStatusName', label: 'WfStatusName', show: true }, { prop: 'createTime', label: 'CreateTime', show: true }, { prop: '', label: 'Operations', show: true } ]})
const testStore = defineStore('TestStore', { state: () => { return columnsDefault }, persist: { key: 'TestStoreConfig' },})
//用Pinia的storeToRefs响应式解构const { userColumns } = storeToRefs(testStore())const columns = userColumns.value as ColumnSettings[]//#endregion
provide('columns', columns)
//通过计算属性过滤”show=false”的的列const showColumns = computed(() => columns.filter(col => col.show))
const userList = ref([]);onMounted(async () => { const res = await getUserApi() userList.value = res.data.list})</script>复制代码
这里的 Axios 封装就不展示了
import { useAxios } from '/@/utils/axios'const request = useAxios()//后端用户列表接口export const getUserApi = async (): Promise<ApiResponse> => { return await request.get({ url: '/api/user/userList' }) }复制代码
划线
评论
复制
发布于: 刚刚阅读数: 4
版权声明: 本文为 InfoQ 作者【青柚1943】的原创文章。
原文链接:【http://xie.infoq.cn/article/8cd93e69f3e138a4e24eed633】。文章转载请联系作者。
青柚1943
关注
生命不息,代码不止。 2020.08.04 加入
老街坊,小弄堂,是属于那年代白墙黑瓦的淡淡的忧伤。









评论