用deepseek封装一个 vue2+elementui 表单搜索组件和表格组件
·
用deepseek封装一个 vue2+elementui 表单搜索组件和表格组件
主要是自己保存使用,有错误欢迎提出!
表单搜索代码
<!-- SearchForm.vue -->
<template>
<div class="search-container">
<el-form
ref="searchForm"
:model="formData"
:inline="inline"
:label-width="labelWidth"
size="small"
@submit.native.prevent
>
<el-row :gutter="gutter">
<!-- 可见表单项 -->
<el-col
v-for="(item, index) in visibleConfig"
:key="index"
:span="item.span || defaultSpan"
:offset="item.offset || 0"
>
<form-item :config="item" :form-data="formData" />
</el-col>
</el-row>
<!-- 展开收起按钮 -->
<el-row type="flex" justify="center">
<el-col :span="btnSpan" class="operation-col">
<el-form-item>
<el-button
type="primary"
icon="el-icon-search"
@click="handleSearch"
>
搜索
</el-button>
<el-button icon="el-icon-refresh-right" @click="handleReset">
重置
</el-button>
<el-button
v-if="showCollapse"
type="text"
@click="isCollapsed = !isCollapsed"
>
{{ isCollapsed ? "展开" : "收起" }}
<i
:class="isCollapsed ? 'el-icon-arrow-down' : 'el-icon-arrow-up'"
/>
</el-button>
<slot name="extra-buttons" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</template>
<script>
import FormItem from "./FormItem.vue";
export default {
name: "SearchForm",
components: { FormItem },
props: {
config: {
type: Array,
required: true,
},
// 传入的查询参数
value: {
type: Object,
required: true,
},
inline: {
type: Boolean,
default: true,
},
labelWidth: {
type: String,
default: "90px",
},
gutter: {
type: Number,
default: 16,
},
defaultSpan: {
type: Number,
default: 6,
},
btnSpan: {
type: Number,
default: 6,
},
// 显示折叠按钮的阈值
collapseThreshold: {
type: Number,
default: 3,
},
},
data() {
return {
formData: { ...this.value },
isCollapsed: true,
};
},
computed: {
// 判断是否显示展开收起
showCollapse() {
return this.config.length > this.collapseThreshold;
},
visibleConfig() {
return this.showCollapse && this.isCollapsed
? this.config.slice(0, this.collapseThreshold)
: this.config;
},
},
watch: {
value: {
handler(newVal) {
this.formData = { ...newVal };
},
deep: true,
},
},
methods: {
handleSearch() {
this.$emit("search", this.formData);
},
// 重置表单
handleReset() {
this.$refs.searchForm.resetFields();
this.$emit("reset");
this.$emit("input", this.formData);
},
},
};
</script>
<style scoped>
.search-container {
padding: 16px;
background: #fff;
border-radius: 4px;
border: 1px solid #dcdfe6;
}
.operation-col {
text-align: center;
display: flex;
justify-content: center;
align-items: center;
margin-top: 10px;
}
.el-form-item {
margin-bottom: 16px;
}
.el-button--text {
padding: 9px 5px;
}
</style>
搜索表单项组件
<!-- FormItem.vue -->
<template>
<el-form-item :label="config.label" :prop="config.prop">
<!-- 输入框 -->
<el-input
v-if="config.type === 'input'"
v-model="formData[config.prop]"
:placeholder="config.placeholder || '请输入'"
clearable
size="small"
/>
<!-- 下拉选择 -->
<el-select
v-else-if="config.type === 'select'"
v-model="formData[config.prop]"
:placeholder="config.placeholder || '请选择'"
clearable
size="small"
>
<el-option
v-for="opt in config.options"
:key="opt.value"
:label="opt.label"
:value="opt.value"
/>
</el-select>
<!-- 日期选择 -->
<el-date-picker
v-else-if="config.type === 'date'"
v-model="formData[config.prop]"
:type="config.dateType || 'date'"
:placeholder="config.placeholder || '选择日期'"
value-format="yyyy-MM-dd"
size="small"
/>
<!-- 自定义插槽 -->
<slot
v-else-if="config.type === 'slot'"
:name="config.slotName"
:scope="formData"
/>
</el-form-item>
</template>
<script>
export default {
name: "FormItem",
props: {
config: {
type: Object,
required: true,
},
formData: {
type: Object,
required: true,
},
},
};
</script>
表单配置文件
// formConfig.js
export const SEARCH_CONFIG = [
{
type: "input",
label: "订单",
prop: "aaa",
span: 8,
},
{
type: "input",
label: "订单编号",
prop: "orderNo",
span: 8,
},
{
type: "input",
label: "订单编号",
prop: "orderNo",
span: 8,
},
{
type: "select",
label: "订单状态",
prop: "status",
options: [
{ label: "待支付", value: 1 },
{ label: "已发货", value: 2 },
],
span: 8,
},
// {
// type: "date",
// label: "创建时间",
// prop: "createTime",
// dateType: "daterange",
// span: 8,
// },
// 更多配置项...
];
表格组件
<!-- SmartTable.vue -->
<template>
<div class="smart-table-container">
<!-- 顶部工具栏插槽 -->
<div v-if="$slots.toolbar" class="table-toolbar">
<slot name="toolbar"></slot>
</div>
<el-table
ref="elTable"
v-loading="loading"
:data="tableData"
:border="border"
:stripe="stripe"
:row-key="rowKey"
:height="height"
@selection-change="handleSelectionChange"
@row-click="handleRowClick"
>
<!-- 选择列 -->
<el-table-column
v-if="showSelection"
type="selection"
width="55"
align="center"
/>
<!-- 序号列 -->
<el-table-column
v-if="showIndex"
label="序号"
type="index"
width="80"
align="center"
>
<template slot-scope="scope">
{{ (pagination.page - 1) * pagination.pageSize + scope.$index + 1 }}
</template>
</el-table-column>
<!-- 动态列渲染 -->
<el-table-column
v-for="column in columns"
:key="column.prop"
v-bind="column"
:align="column.align || 'center'"
:show-overflow-tooltip="column.tooltip !== false"
>
<template slot-scope="scope">
<!-- 自定义插槽 -->
<slot v-if="column.slot" :name="column.slot" :row="scope.row" />
<!-- 标签类型 -->
<el-tag
v-else-if="column.type === 'tag'"
:type="column.tagType || getTagType(scope.row[column.prop], column)"
>
{{ getColumnText(scope.row, column) }}
</el-tag>
<!-- 按钮类型 -->
<el-button
v-else-if="column.type === 'button'"
v-bind="column.buttonProps"
@click="handleColumnButton(scope.row, column)"
>
{{ getColumnText(scope.row, column) }}
</el-button>
<!-- 图片类型 -->
<el-image
v-else-if="column.type === 'image'"
:src="scope.row[column.prop]"
:preview-src-list="[scope.row[column.prop]]"
fit="cover"
style="width: 60px; height: 60px"
/>
<!-- 默认文本 -->
<span v-else>{{ getColumnText(scope.row, column) }}</span>
</template>
</el-table-column>
<!-- 操作列 -->
<el-table-column
v-if="actions.length"
label="操作"
align="center"
:width="actionsWidth"
fixed="right"
>
<template slot-scope="scope">
<template v-for="(action, index) in actions">
<el-button
v-if="showAction(action, scope.row)"
:key="index"
v-bind="action.props"
@click="handleAction(action, scope.row)"
>
<i v-if="action.icon" :class="action.icon"></i>
{{ action.label }}
</el-button>
</template>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div v-if="showPagination" class="pagination-container">
<el-pagination
:current-page="pagination.page"
:page-sizes="pagination.sizes"
:page-size="pagination.pageSize"
:layout="pagination.layout"
:total="pagination.total"
@size-change="handleSizeChange"
@current-change="handlePageChange"
/>
</div>
</div>
</template>
<script>
export default {
name: "SmartTable",
props: {
columns: {
type: Array,
required: true,
},
data: {
type: Array,
default: () => [],
},
loading: Boolean,
rowKey: String,
height: [String, Number],
border: {
type: Boolean,
default: true,
},
stripe: {
type: Boolean,
default: true,
},
showIndex: Boolean,
showSelection: Boolean,
actions: {
type: Array,
default: () => [],
},
actionsWidth: {
type: [String, Number],
default: "240",
},
pagination: {
type: Object,
default: () => ({
page: 1,
pageSize: 10,
sizes: [10, 20, 50, 100],
total: 0,
layout: "total, sizes, prev, pager, next, jumper",
}),
},
},
data() {
return {
tableData: [...this.data],
selectedRows: [],
};
},
computed: {
showPagination() {
return this.pagination && this.pagination.total > 0;
},
},
watch: {
data: {
handler(newVal) {
this.tableData = [...newVal];
},
deep: true,
},
},
methods: {
// 获取单元格显示内容
getColumnText(row, column) {
if (column.formatter) {
return column.formatter(row);
}
return column.prop ? row[column.prop] : "";
},
// 获取标签类型
getTagType(value, column) {
if (column.tagMap) {
return column.tagMap[value] || "";
}
return "";
},
// 处理操作按钮
handleAction(action, row) {
if (action.handler) {
action.handler(row);
} else {
this.$emit("action", { action: action.name, row });
}
},
// 处理列按钮点击
handleColumnButton(row, column) {
this.$emit("column-action", { column, row });
},
// 显示操作按钮条件
showAction(action, row) {
return typeof action.show === "function"
? action.show(row)
: action.show !== false;
},
// 分页事件
handleSizeChange(size) {
this.pagination.pageSize = size;
this.$emit("pagination-change", { ...this.pagination });
},
handlePageChange(page) {
this.pagination.page = page;
this.$emit("pagination-change", { ...this.pagination });
},
// 选择变化
handleSelectionChange(selection) {
this.selectedRows = selection;
this.$emit("selection-change", selection);
},
// 行点击事件
handleRowClick(row) {
this.$emit("row-click", row);
},
// 暴露Element Table方法
clearSelection() {
this.$refs.elTable.clearSelection();
},
},
};
</script>
<style scoped>
.smart-table-container {
background: #fff;
padding: 16px;
border-radius: 4px;
}
.table-toolbar {
margin-bottom: 16px;
}
.pagination-container {
margin-top: 16px;
text-align: right;
}
.el-button + .el-button {
margin-left: 8px;
}
</style>
表格配置文件
export const TABLE_COLUMNS = [
{
prop: "name",
label: "姓名",
width: 120,
searchable: true,
},
{
prop: "avatar",
label: "头像",
type: "image",
},
{
prop: "status",
label: "状态",
type: "tag",
tagMap: {
1: "success",
0: "danger",
},
formatter: (row) => (row.status === 1 ? "启用" : "停用"),
},
{
prop: "phone",
label: "联系电话",
slot: "phone", // 使用插槽
},
];
export const TABLE_ACTIONS = [
{
label: "编辑",
name: "edit",
icon: "el-icon-edit",
props: {
type: "text",
},
},
{
label: "删除",
name: "delete",
icon: "el-icon-delete",
props: {
type: "text",
style: { color: "#f56c6c" },
},
show: (row) => row.status === 1, // 条件显示
},
];
// 配置说明
/*
// 列配置
{
prop: '字段名', // 必需
label: '列名', // 必需
type: 'text/tag/button/image', // 类型
width: 120, // 列宽
align: 'left/center/right',
slot: 'slot-name', // 自定义插槽名称
tagMap: { // 标签类型颜色映射
value: 'el-tag-type'
},
formatter: row => {} // 数据格式化函数
}
// 操作按钮配置
{
label: '按钮文字', // 必需
name: 'action-name', // 操作标识
icon: 'el-icon-name',// 图标类名
props: { // el-button的props
type: 'primary',
size: 'small'
},
show: row => true // 显示条件
}
*/
使用案例
<template>
<div class="app-container">
<search-form
:config="formConfig"
:value="queryParams"
@search="handleSearch"
@reset="handleReset"
:collapse-threshold="3"
>
<!-- 自定义插槽 -->
<template #custom-slot="{ scope }">
<el-input v-model="scope.customField" placeholder="自定义内容" />
</template>
</search-form>
<smart-table
:columns="columns"
:data="tableData"
:actions="actions"
:pagination="pagination"
:loading="loading"
@pagination-change="handlePagination"
@action="handleTableAction"
>
<!-- 顶部工具栏 -->
<template #toolbar>
<el-button type="primary" size="small" @click="handleAdd"
>新增</el-button
>
</template>
</smart-table>
</div>
</template>
<script>
import { SEARCH_CONFIG } from "./formConfig";
import { TABLE_COLUMNS, TABLE_ACTIONS } from "./tableConfig";
import SearchForm from "./components/SearchForm.vue";
import SmartTable from "./components/SmartTable.vue";
export default {
components: {
SearchForm,
SmartTable,
},
data() {
return {
queryParams: {
/* ... */
},
formConfig: SEARCH_CONFIG,
columns: TABLE_COLUMNS,
actions: TABLE_ACTIONS,
tableData: [],
pagination: {
page: 1,
pageSize: 10,
total: 0,
},
loading: false,
};
},
methods: {
// 表单搜索相关
handleSearch(v) {
console.log(v);
},
handleReset() {},
// 表格相关
handlePagination(pagination) {
this.fetchData(pagination);
},
handleTableAction({ action, row }) {
if (action === "edit") {
this.handleEdit(row);
} else if (action === "delete") {
this.handleDelete(row);
}
},
async fetchData(pagination) {
this.loading = true;
// 调用API获取数据...
this.loading = false;
},
// 表格操作
handleAdd(){
}
},
};
</script>
如果这篇文章能帮助到你的话,希望点赞留下一个小星星吧!你的鼓励是我最大的动力!!!
更多推荐


所有评论(0)