基于 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 Store
const 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 加入
老街坊,小弄堂,是属于那年代白墙黑瓦的淡淡的忧伤。
评论