1.组件实现
<template> <el-popover placement="bottom" popper-class="interBarControl-setPopover" :width="200" :visible="visible" trigger="click" @click.stop="" > <template #reference> <el-button size="small" type="primary" @click.stop="visible = true" >数据项</el-button > </template> <div class="popover-list" @click.stop=""> <div class="search-box"> <el-input placeholder="搜索" size="small" v-model="inputValue" @input="querySearch" clearable > <i class="el-icon-search el-input__icon" slot="prefix"></i> </el-input> </div> <div class="switch-box"> <el-tree :allow-drop="allowDrop" :allow-drag="allowDrag" :data="dragListColumn" draggable node-key="id" > <template #default="{ node, data }"> <div class="flex-row justify-content-between align-item-center drag-item" > <span> {{ node.label }}</span> <el-switch size="small" v-model="data.visible" :key="data.prop" ></el-switch> </div> </template> </el-tree> </div> <div class="btn-group flex-row justify-content-between"> <el-button size="small" type="primary" @click="_resetColumn" >重置</el-button > <div> <el-button size="small" type="primary" @click="_cancel" >取消</el-button > <el-button size="small" type="success" @click="_saveColumn" >保存</el-button > </div> </div> </div> </el-popover> </template> <script lang="ts" setup> import * as _ from 'lodash'; import { ref, defineProps, defineEmits, computed, watch, onMounted, onUnmounted, readonly, } from 'vue'; import type Node from 'element-plus/es/components/tree/src/model/node'; import type { DragEvents } from 'element-plus/es/components/tree/src/model/useDragNode'; import type { AllowDropType, NodeDropType, } from 'element-plus/es/components/tree/src/tree.type'; const $emit = defineEmits(['column-change']); const props = defineProps({ columns: { type: Array, default: () => [], }, }); const visible = ref(false); const inputValue = ref(''); const dragListColumn = ref([]); const originalColumn = ref([]); const lastColumn = ref({}); // 列表操作输入 const querySearch = queryString => { let tableColumn = props.columns; let results = queryString ? tableColumn.filter(createFilter(queryString)) : tableColumn; dragListColumn.value = _.cloneDeep([...results]); }; const createFilter = queryString => { return tableColumn => { return tableColumn.label.indexOf(queryString) === 0; }; }; const allowDrop = (draggingNode: Node, dropNode: Node, type: AllowDropType) => { if (draggingNode.data.level === dropNode.data.level) { if (draggingNode.data.parentId === dropNode.data.parentId) { return type === 'prev' || type === 'next'; } else { return false; } } else { // 不同级进行处理 return false; } }; const allowDrag = (draggingNode: Node) => { return true; }; // 重置 const _resetColumn = () => { dragListColumn.value = _.cloneDeep( originalColumn.value.filter(item => item.label !== '操作') ); }; // 取消 const _cancel = () => { closePopover(); }; // 保存 const _saveColumn = () => { closePopover(); $emit('column-change', dragListColumn.value.concat(lastColumn.value)); }; watch( () => props.columns, value => { if (value) { dragListColumn.value = _.cloneDeep( props.columns.filter(item => item.label !== '操作') ); lastColumn.value = props.columns.filter(item => item.label == '操作'); } } ); const closePopover = () => { visible.value = false; }; onMounted(() => { originalColumn.value = readonly(_.cloneDeep(props.columns)); // 不可修改 dragListColumn.value = _.cloneDeep( props.columns.filter(item => item.label !== '操作') ); lastColumn.value = props.columns.filter(item => item.label == '操作'); window.addEventListener('click', closePopover); }); onUnmounted(() => { window.removeEventListener('click', closePopover); }); </script> <style lang="scss" scoped> .popover-list { margin: -12px; padding: 8px 0 0; :deep(.el-switch--small) { width: 24px !important; height: 14px !important; .el-switch__core { width: 24px !important; height: 14px !important; .el-switch__action { width: 12px; height: 12px; margin-top: -1px; margin-left: -1px; } } &.is-checked { .el-switch__action { width: 12px; height: 12px; margin-top: -1px; margin-left: -12px; } } } :deep(.el-tree-node__content) { height: 30px; &:hover { color: var(--el-color-primary); background-color: var(--theme-select-dropdown-item-hover); } } } .search-box { padding: 0 8px; } .switch-box { margin-top: 4px; max-height: 189px; overflow-y: auto; } .btn-group { padding: 12px; .el-button + .el-button { margin-left: 8px; } } .drag-item { width: 100%; font-size: var(--el-font-size-base); padding: 0 12px 0 0; position: relative; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--el-text-color-regular); height: 30px; line-height: 30px; box-sizing: border-box; margin-left: -12px; cursor: pointer; &:hover { color: var(--el-color-primary); background-color: var(--theme-select-dropdown-item-hover); } } .interBarControl-setPopover { .el-checkbox__label { width: 142px; } .el-checkbox { margin-bottom: 20px; } .el-checkbox + .el-checkbox { margin-left: 0; } } </style>
2.组件调用
<r-table-data-item :columns="tableColumn" @column-change="handleColumnChange" ></r-table-data-item>
3.组件数据
const tableColumn = ref([ { prop: 'date', label: '日期', width: 200, visible: true, headerSlot: 'dateHeader', render: ({ column }) => h('span', proxy.$moment(column.date).format('yyyy-MM-DD')), }, { prop: 'name', label: '姓名', width: 200, visible: true }, { prop: 'num', label: '数量', width: 100, sortable: 'custom', visible: true }, { prop: 'type', label: '类型', width: 100, visible: true, headerSlot: 'typeHeader', }, { prop: 'address', label: '地址', width: 130, visible: true, headerRender: () => h(ElInput, { ...ElInput.$el, ...ElInput.$attrs, size: 'small', placeholder: '请输入内容', modelValue: search.value, 'onUpdate:modelValue': (value: any) => { return (search.value = value); }, }), }, { width: '180', label: '操作', visible: true, buttons: [ { name: '编辑', type: 'primary', size: 'small', command: 'edit', }, { name: '删除', type: 'primary', size: 'small', command: 'delete', }, { name: '审核', type: 'primary', size: 'small', command: 'check', }, { name: '保存', type: 'primary', size: 'small', command: 'save', }, { name: '设置', type: 'primary', size: 'small', command: 'set', }, ], }, ]); // 数据项 const handleColumnChange = val => { tableColumn.value = val; };
4.组件效果
- element-plus 顺序 位置 element pluselement-plus顺序 位置element element-plus quot element-plus elmessage element element-plus element plus element-plus element类型 文件 resizeobserver notifications element-plus undelivered element-plus组件element功能 39 quot element-plus elmessage element-plus实战element项目 element-plus一行element数据