Cat-Table-Select 基于Vue+Element的表格选择器

Cat-Table-Select是一个基于Vue 2.x和Element的组件,提供单选、多选、分页及自定义列等功能。用户可以通过复制仓库、安装依赖并预览Demo来体验这个表格选择器。它还包括了Api文档,详细说明了TableSelect的Attributes、Columns、Props、Events和V-Slot。

Cat-Table-Select 基于Vue+Element的表格选择器

基于 Element 的Vue 组件(Vue.js 2.x)

cat-table-select Github 地址

前言

之前自己动手做了个基于Element树选择器 cat-tree-selec ,于是就照着之前的思路又封装了个表格选择器。目前已经实现了单选,多选,分页,自定义列,可搜索等功能。

效果预览

在这里插入图片描述
在这里插入图片描述

Demo 安装

复制仓库

git clone git@github.com:scuxiatian/cat-table-select.git

安装依赖

npm install

demo预览

npm run serve

实例

单选表格

<cat-table-select 
	v-model="value" 
	:data="data" 
	:columns="columns" 
	:props="props">
</cat-table-select>
export default {  
	data () {   
		return { 
			value: '',
			columns: [
				{ key: 'name',  label: '姓名', width: 100}, 
				{ key: 'address', label: '地址'  }
			],
			props: { key: 'id', label: 'name' },
			data: [
				{ id: '1', name: '王小虎1', address: '上海市普陀区金沙江路 1518 弄' }, 
				{ id: '2', name: '王小虎2', address: '上海市普陀区金沙江路 1517 弄' },
				{ id: '3', name: '王小虎3', address: '上海市普陀区金沙江路 1519 弄' },
				{ id: '4', name: '王小虎4', address: '上海市普陀区金沙江路 1516 弄'  }
			] 
		}
	}
}

可分页

<cat-table-select 
	v-model="value" 
	:data="data" 
	:columns="columns" 
	:props="p
<template> <div> <div class="flex justify-between items-center py-4 h-14 px-5"> <PageHeader :title="pageTitle" @back="handlegoback" /> <div class="flex gap-2.5"> <el-button type="default" @click="handlegoback">返回</el-button> <el-button type="primary" @click="handleSave">保存</el-button> </div> </div> <el-form :model="customForm" :rules="customRuleSet" ref="customFormRef" label-width="120px" class="flex gap-5 pt-5 border-t tlinter-border items-center pb-5" > <el-form-item label="规则集名称" prop="ruleSetName" class="m-0"> <el-input v-model="customForm.ruleSetName" placeholder="请输入1-20位规则集名称" show-word-limit class="w-60" /> </el-form-item> <el-text type="primary" class="mx-1 text-[#409eff] self-center" style="padding-bottom: 5px" > {{ usedRulesText }} </el-text> </el-form> <div class="flex gap-0 p-5 border-t tlinter-border"> <div class="flex flex-col gap-1 w-1/4 border-r tlinter-border pr-5 h-full"> <div class="w-full h-full"> <el-input v-model="searchQuery" placeholder="输入规则编号/描述查询" class="w-full" suffix-icon="Search" clearable /> </div> <div class="flex gap-4" label-width="0"> <el-checkbox v-model="isVHDLChecked">VHDL</el-checkbox> <el-checkbox v-model="isVerilogChecked">Verilog</el-checkbox> </div> <h1 class="font-inter text-base font-medium leading-[22px] tracking-0 tlinter-text-one pb-2">规则类别</h1> <div class="flex flex-col gap-3" label-width="0"> <el-checkbox v-for="(category, index) in ruleCategories" :key="index" v-model="category.checked" :label="category.name" class="block !mb-2 w-full" > {{ category.name }} </el-checkbox> </div> </div> <div class="flex-1 w-3/4 custom-form-item"> <el-table ref="ruleTableRef" :data="ruleTable" style="width: 100%" row-key="id" @selection-change="handleSelectionChange" > <el-table-column type="selection" width="55" reserve-selection /> <el-table-column width="400" prop="ruleNo" label="规则编号" > <template #header> <div class="flex items-center gap-2"> <span>规则编号</span> <el-select v-model="headerSelectValue" :placeholder="selectPlaceholder" style="width: 120px" @change="handleHeaderSelectChange" > <el-option label="启用" value="enableAll"></el-option> <el-option label="禁用" value="disableAll"></el-option> </el-select> </div> </template> <template #default="scope"> <el-text @click="openDrawer(scope.row)" class="hover:text-primary cursor-pointer" :class="activeRowId === scope.row.id ? 'el-text--primary' : ''" > {{ scope.row.ruleNo }} </el-text> </template> </el-table-column> <el-table-column prop="description" label="描述" width="420" /> <el-table-column prop="alarmType" label="告警类型(点击标签可切换)" > <template #default="scope"> <el-tag :type="getTagType(scope.row.alarmType)" @click="toggleAlarmType(scope.row)" :class="scope.row.alarmType === '错误' ? 'tag-pink' : 'tag-yellow'" > ● {{ scope.row.alarmType }} </el-tag> </template> </el-table-column> </el-table> </div> </div> <el-drawer v-model="drawerVisible" :title="drawerTitle" size="30%" :before-close="closeDrawer" > <RuleDetails :current-row="currentRow" /> </el-drawer> </div> </template> <script setup> import { ref, computed, reactive, watch, onMounted, nextTick } from 'vue' import { useRouter, useRoute } from 'vue-router' import { Search } from '@element-plus/icons-vue' import { ElMessage } from 'element-plus' import RuleDetails from './components/ruleDetails.vue' import PageHeader from "@/components/PageHeader.vue"; const router = useRouter() const route = useRoute() const ruleTableRef = ref(null) const customFormRef = ref(null) const headerSelectValue = ref('') // 搜索关键词 const searchQuery = ref('') const isVHDLChecked = ref(true) const isVerilogChecked = ref(false) // 抽屉相关 const drawerVisible = ref(false) const currentRow = ref(null) const drawerTitle = ref('') const activeRowId = ref(null) // 表格选中数据 const selectedRows = ref([]) // 页面标题 const pageTitle = computed(() => { return route.query.ruleSetName || '自定义规则集' }) // 表单数据(规则集名称) const customForm = reactive({ ruleSetName: route.query.ruleSetName || '' }) // 表单校验规则 const customRuleSet = reactive({ ruleSetName: [ { required: true, message: '请输入规则集名称', trigger: 'blur' }, { max: 20, message: '规则集名称不能超过20个字符', trigger: 'blur' } ] }) // 规则类别(左侧筛选) const ruleCategories = ref([ { name: 'VHDL编码规则', checked: true }, { name: 'VHDL同步设计规则', checked: true }, { name: 'VHDL标头规则', checked: false }, { name: '规则类别1', checked: false }, { name: '规则类别2', checked: false }, { name: '规则类别3', checked: false }, { name: '规则类别4', checked: false }, { name: '规则类别5', checked: false }, { name: '规则类别6', checked: false }, { name: '规则类别7', checked: false } ]) // 表格原始数据 const ruleData = ref([ { id: 1, ruleNo: 'TLR-030001V', description: 'VHDL源文件应包含头注释', alarmType: '错误', category: 'VHDL编码规则', enable: true }, { id: 2, ruleNo: 'TLR-030002V', description: '同步设计应遵循时钟域交叉原则', alarmType: '告警', category: 'VHDL同步设计规则', enable: true }, { id: 3, ruleNo: 'TLR-030003V', description: '标头应包含版本、作者等信息', alarmType: '告警', category: 'VHDL标头规则', enable: false }, { id: 4, ruleNo: 'TLR-030004V', description: '模块端口声明需指定方向(IN/OUT)', alarmType: '错误', category: 'VHDL编码规则', enable: true } ]) // 过滤后的表格数据 const ruleTable = computed(() => { if (!ruleData.value || !ruleCategories.value) return [] const selectedCategoryNames = ruleCategories.value .filter(cat => cat.checked) .map(cat => cat.name) if (selectedCategoryNames.length === 0) return [] let filteredData = ruleData.value.filter(item => selectedCategoryNames.includes(item.category) ) if (searchQuery.value.trim()) { const keyword = searchQuery.value.trim().toLowerCase() filteredData = filteredData.filter(item => item.ruleNo.toLowerCase().includes(keyword) || item.description.toLowerCase().includes(keyword) ) } return filteredData }) const isAllSelectedEnabled = computed(() => { if (selectedRows.value.length === 0) return false return selectedRows.value.every(row => row.enable === true) }) const selectPlaceholder = computed(() => { return isAllSelectedEnabled.value ? '已启用' : '启用状态' }) const usedRulesText = computed(() => { const enabledCount = ruleData.value.filter(rule => rule.enable === true).length return `已启用${enabledCount}条规则` }) const getTagType = computed(() => (alarmType) => { const typeMap = { '错误': 'danger', '告警': 'warning' } return typeMap[alarmType] || 'info' }) const handleTableSelection = (tableData) => { if (!ruleTableRef.value || !tableData || tableData.length === 0) { return } tableData.forEach(row => { ruleTableRef.value.toggleRowSelection(row, false) }) tableData.forEach(row => { if (row.enable) { ruleTableRef.value.toggleRowSelection(row, true) } }) } // 表格选中事件 const handleSelectionChange = (selection) => { selectedRows.value = selection } // 下拉框操作 const handleHeaderSelectChange = (value) => { switch (value) { case 'enableAll': handleBatchEnable() break case 'disableAll': handleBatchDisable() break } headerSelectValue.value = '' } // 批量启用 const handleBatchEnable = () => { if (selectedRows.value.length === 0) { ElMessage.warning('请先选择要启用的规则') return } ruleData.value.forEach(row => { row.enable = false }) selectedRows.value.forEach(selectedRow => { const targetRow = ruleData.value.find(row => row.id === selectedRow.id) if (targetRow) targetRow.enable = true }) handleTableSelection(ruleTable.value) // ElMessage.success(`成功启用${selectedRows.value.length}条规则`) } // 批量禁用 const handleBatchDisable = () => { if (selectedRows.value.length === 0) { ElMessage.warning('请先选择要禁用的规则') return } selectedRows.value.forEach(selectedRow => { const targetRow = ruleData.value.find(row => row.id === selectedRow.id) if (targetRow) targetRow.enable = false }) handleTableSelection(ruleTable.value) // ElMessage.success(`成功禁用${selectedRows.value.length}条规则`) } // 切换告警类型 const toggleAlarmType = (row) => { const types = ['错误', '告警'] const currentIdx = types.indexOf(row.alarmType) row.alarmType = types[(currentIdx + 1) % types.length] } // 打开规则详情抽屉 const openDrawer = (row) => { currentRow.value = row drawerTitle.value = row.ruleNo activeRowId.value = row.id drawerVisible.value = true } // 关闭抽屉 const closeDrawer = () => { currentRow.value = null drawerTitle.value = '' activeRowId.value = null drawerVisible.value = false } // 保存规则集 const handleSave = async () => { const valid = await customFormRef.value.validate() if (!valid) return const savedData = { name: customForm.ruleSetName, enabledRules: ruleData.value.filter(rule => rule.enable), totalEnabled: ruleData.value.filter(rule => rule.enable).length, updateTime: new Date().toLocaleString() } console.log('保存规则集数据:', savedData) ElMessage.success('规则集保存成功') handlegoback() } // 返回上一页 const handlegoback = () => { router.push("/rules") } // 监听表格数据变化 watch( () => ruleTable.value, (newTableData) => { handleTableSelection(newTableData) }, { immediate: true, deep: true } ) // 监听选中数据变化 watch( () => selectedRows.value, (newSelected) => { if (isAllSelectedEnabled.value) { headerSelectValue.value = 'enableAll' } else { const validActions = ['enableAll', 'disableAll'] if (!validActions.includes(headerSelectValue.value)) { headerSelectValue.value = '' } } }, { deep: true } ) // 组件挂载完成后,确保表格选中状态初始化 onMounted(async () => { await nextTick() handleTableSelection(ruleTable.value) }) </script> <style scoped lang="scss"> :deep(.custom-form-item .el-form-item__content) { margin-left: 20px !important; } // 抽屉样式调整 :deep(.el-drawer__header) { margin-bottom: 0px !important; padding: 16px 24px !important; border-bottom: 1px solid #eee; } </style>分析代码,修改代码文件,1.完成VHDL和Verilog改为单选框,并且选择VHDL时,规则类别下面的多选框只显示VHDL的规则类别,选择Verilog时,只显示Verilog的规则类别。2.完成规则类别下面的多选框,点击时表格里面数据只显示当前点击的规则类别里面的编号,点击另一个时,只显示另一个规则类别的规则编号,增加模拟数据完善此功能。并且给当前点击的规则类别增加背景色,选择框显示改为为如图图标,用unocss。编写完整代码显示出来
最新发布
10-23
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值