写点什么

基于 Vue3 的列设置(拖动排序、显示隐藏)

作者:青柚1943
  • 2022 年 9 月 01 日
    湖南
  • 本文字数:2983 字

    阅读完需:约 10 分钟

最近新项目要写了一个列设置的组件(拖动排序、显示隐藏),这里简单整理一下(基于 TypeScript、Vue3、Element-Plus-UI、Pinia、Sortablejs)

设计思路:将 column(列表头)抽象成一个数组, 每个 column 是一个元素。

  1. 通过属性 show(true/false)来控制列的显示隐藏;

  2. 通过拖动来控制数组元素顺序,以此来改变列渲染的顺序。

//数组元素(列的抽象,后期甚至可以扩展更多关于列的设置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
用户头像

青柚1943

关注

生命不息,代码不止。 2020.08.04 加入

老街坊,小弄堂,是属于那年代白墙黑瓦的淡淡的忧伤。

评论

发布
暂无评论
基于Vue3的列设置(拖动排序、显示隐藏)_typescript_青柚1943_InfoQ写作社区