脚本宝典收集整理的这篇文章主要介绍了vue+element后台管理,table,form,pagination等二次分装,实现5到20行完成一个主页面列表,一天轻轻松松写20个页面,再也不用大量的Ctrl+c Ctrl+v了,脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
demo页面
最近看有小伙伴说后台管理系统,表格特别多,一个页面上百行代码,每天上班,大量的粘贴复制,一个个去改字段,特别累,问有没有简单高效的方法,答案是当然有,把一个页面封装成一个组件,需要什么传什么不就好了,所以本篇文章,只分享思路和简单的组件封装组合,不喜勿喷,先看效果,只需要传不同的值,就能定制自己想要的表格页面,像下面这样,短短几行
就能实现这样的列表 这样的最终的目录结构,crud/index.vue是我们的主体组件,search/index.vue是我们顶部条件筛选组件,table/index.vue是我们表格分页组件,page1.vue,page2.vue是demo页面,
以第一张列表为例,有一个页面名称,有普通的条件筛选,input,select,date,后面有查询,重置,导出下载等想要的操作,表格内容,有插槽固定列,操作列等,下面有分页等,下面我们一个个写(最后附上完整代码)
我们也先建一个公共组件,src/components/crud/index.vue,因为我们整个项目都要用,所以我们全局挂载,在main.js 里
import curd from '@/components/crud/index'
Vue.component('h-crud', curd)
要有个页面名称,XX管理,XX统计等,所以我们要传一个title过去
page1.vue <h-crud
:title="title"
</h-crud>
data() {
return {
// 页面标题
title: "复杂列表"
}
}
crud.vue
<div class="_title">{{ title }}</div>
props: {
title: {
type: String,
default: () => {
return "";
}
}
}
检索条件,有的页面有,有的页面没有,所以不需要必填
由图分析,里面有input,select,date,不同的筛选组件,所以我们用type字段区分一下,我们点击查询要知道input,select,date字段名和输入值,所以要有个value值,prop字段名。外面还要有一个表单的size组件的尺寸,labelWidth表单域标签的宽度,后面还有,查询,重置,必须的两个操作按钮,和其他操作按钮(导出,下载等),所以page1.vue
我们传过去一个对象searchOption,组件emit回来,search查询方法,reset重置方法,otherBtnsClick其他按钮方法
<h-crud
:search-option="searchOption"
@search="search"
@reset="reset"
@otherBtnsClick="otherBtnsClick"
>
</h-crud>
data() {
return {
// 顶部表单检索内容,非必填
searchOption: {
// 表单内组件的尺寸
size: "small",
// 表单域标签的宽度
labelWidth: "80px",
// 检索列表
searchList: [
/*
label 标签名,必填
type 表单类型,必填
value 绑定值,必填
prop 字段名,必填
placeholder 提示语,非必填,默认请输入/请选择
clearable 是否可清空,非必填,默认清空
optionData 下拉菜单数据,type为select时填
type为date时
format 显示在输入框中的格式
valueFormat 返回格式
*/
{ label: "审批人:", type: "input", value: "", prop: "user" },
{
label: "活动区域:",
type: "select",
value: "",
prop: "region",
optionData: [
{ value: "shanghai", label: "区域一" },
{ value: "beijing", label: "区域二", disabled: true }
]
},
{
label: "日期:",
type: "date",
value: "",
prop: "date",
placeholder: "选择日期",
format: "yyyy 年 MM 月 dd 日",
valueFormat: "yyyy-MM-dd"
}
],
// 其它操作按钮,默认已有查询重置,不必填,可不要
otherBtns: [
{ title: "导出", prop: "export", type: "danger" },
{ title: "下载", prop: "downLoad", type: "success" }
]
},
}
crud.vue
为了便于扩展,筛选内容比较多,我们在抽出一个Search组件出来,把对象searchOption传过去,组件emit回去,search查询方法,reset重置方法,otherBtnsClick其他按钮方法
<div class="_search_content">
<Search
:search-option="searchOption"
@search="
Obj => {
$emit('search', Obj);
}
"
@reset="handldReset"
@otherBtnsClick="
prop => {
$emit('otherBtnsClick', prop);
}
"
></Search>
</div>
//引入
import Search from "../Search/index";
//注册
components: { Search},
//接收
props: {
title: {
type: String,
default: () => {
return "";
}
},
searchOption: {
type: Object,
default: () => {
return {};
}
}
},
search/index.vue
//一个行内表单
<template>
<div class="_search">
<!-- 先判断searchOption存不存在,因为有的表格没有,
然后把表单的size,label-wdith,写上 -->
<el-form
v-if="searchOption && Object.keys(searchOption).length"
:inline="true"
:size="searchOption.size"
:label-width="searchOption.labelWidth"
>
<el-form-item
v-for="item in searchOption.searchList"
:key="item.label"
:label="item.label"
>
<!-- 判断type类型,输入框时 -->
<template v-if="item.type === 'input'">
<el-input
:clearable="item.clearable || true"
v-model="item.value"
:placeholder="item.placeholder || '请输入'"
></el-input>
</template>
<!-- 判断type类型,选择框时 -->
<template v-else-if="item.type === 'select'">
<el-select
v-model="item.value"
:placeholder="item.placeholder || '请选择'"
:clearable="item.clearable || true"
>
<el-option
v-for="option in item.optionData || []"
:key="option.value"
:label="option.label"
:value="option.value"
:disabled="option.disabled"
/>
</el-select>
</template>
<!-- 判断type类型,日期时 -->
<template v-else-if="item.type === 'date'">
<el-date-picker
v-model="item.value"
type="date"
:placeholder="item.placeholder || '请选择'"
:format="item.format || 'yyyy 年 MM 月 dd 日'"
:value-format="item.valueFormat || 'yyyy-MM-dd'"
>
</el-date-picker>
</template>
<!--
...
后续可根据自己的项目添加其他筛选组件,demo只写了input selece date
-->
</el-form-item>
<!-- 查询重置 -->
<el-form-item>
<el-button type="primary" :size="searchOption.size" @click="searchClick"
>查询</el-button
>
<el-button :size="searchOption.size" @click="resetClick"
>重置</el-button
>
<!-- 其它操作按钮,由于有的不需要,所以先判断有没有 -->
<template
v-if="searchOption.otherBtns && searchOption.otherBtns.length > 0"
>
<el-button
v-for="(btn, index) in searchOption.otherBtns"
:key="index"
:size="btn.size"
:type="btn.type"
@click="otherBtnsClick(btn)"
>{{ btn.title }}</el-button
>
</template>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: "search",
props: {
searchOption: {
type: Object,
default: () => {
return {};
}
}
},
data() {
return {};
},
methods: {
//遍历检索条件把值返回出去
searchClick() {
let Obj = {};
this.searchOption.searchList.forEach(item => {
if (item.value !== "") {
Obj[item.prop] = item.value;
}
});
this.$emit("search", Obj);
},
resetClick() {
this.$emit("reset");
},
//其他操作按钮
otherBtnsClick(btn) {
this.$emit("otherBtnsClick", btn.prop);
}
},
created() {
// console.log(this.searchOption);
}
};
</script>
<style lang="less" scoped></style>
表格主体,我们给拆成表格列,表格数据,分页数据,三个即可,由于我们有时需要操作处理列里面的数据,所以我们要有个具名插槽,哪个列需要操作写哪个,不需要不写,如下图,状态,数据是1,2,我们改成我们想要的内容,操作列也可以像普通列一样写成插槽,本demo,写成数据传过去在组件里写的
page1.vue传过去一个tableOption列表对象,接收columnClick操作列方法,handleSizeChange,handleCurrentChange,分页方法,不要操作列可不写, 分页数据也传过去
<h-crud
:table-option="tableOption"
@columnClick="columnClick"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
>
<!-- 普通列插槽 -->
<template slot="status" slot-scope="{ row }">
<span v-if="row.status && row.status === 1" style="color: #F53F3F;"
>错误,红的</span
>
<span v-else style="color:green">进行中,绿的</span>
</template>
</h-crud>
// 列表数据
tableOption: {
// 表格列,必填
tableColumn: [
{
prop: "name",
label: "姓名"
},
{
prop: "status",
label: "状态"
},
{
prop: "address",
label: "描述",
minWidth: "150"
},
{
prop: "date",
label: "日期",
minWidth: "200"
}
],
// 表格数据,必填
tableData: [
{
id: 1,
name: "张三",
status: 1,
address: "我是描述",
date: "2022-01-01"
},
{
id: 2,
name: "李四",
status: 2,
address: "我是描述2",
date: "2022-01-02"
}
],
// 表格操作按钮,非必填
operationColumn: {
// 是否fixed
fixed: "right",
// 最小宽度
minWidth: "250",
btns: [
{ title: "编辑", prop: "edit", type: "primary", size: "small" },
{ title: "删除", prop: "delete", type: "danger", size: "small" },
{ title: "查看", prop: "dtl", type: "info", size: "small" }
]
},
//分页数据
page: {
currentPage: 1,
pageSize: 10,
total: 20
}
}
crud.vue
//为了便于扩展,表格内容比较多,我们在抽出一个table组件出来
<div class="_table_content">
<Table
:table-option="tableOption"
@columnClick="
(prop, row) => {
$emit('columnClick', prop, row);
}
"
@size-change="
val => {
$emit('size-change', val);
}
"
@current-change="
val => {
$emit('current-change', val);
}
"
>
<template
v-for="item in tableOption.tableColumn"
:slot="item.prop"
slot-scope="{ row }"
>
<slot :name="item.prop" :row="row">
<template>
{{ row[item.prop] }}
</template>
</slot>
</template>
</Table>
</div>
Table/index.vue
<template>
<div class="_table">
<!-- <div class="_title">共 {{ tableOption.page.total }} 条记录</div> -->
<el-table
:data="tableOption.tableData"
stripe
border
:header-cell-style="{ backgroundColor: 'rgb(244, 244, 245)' }"
style="width: 100%"
>
<el-table-column
v-for="(item, index) in tableOption.tableColumn"
:key="index"
:label="item.label"
:min-width="item.minWidth"
>
<!-- 普通列插槽 -->
<template slot-scope="{ row }">
<slot :name="item.prop" :row="row">
<template>
{{ row[item.prop] }}
</template>
</slot>
</template>
</el-table-column>
<el-table-column
v-if="
tableOption.operationColumn &&
Object.keys(tableOption.operationColumn).length
"
:fixed="tableOption.operationColumn.fixed"
label="操作"
:min-width="tableOption.operationColumn.minWidth"
>
<template slot-scope="scope">
<el-button
v-for="(btn, index) in tableOption.operationColumn.btns"
:key="index"
:type="btn.type"
:size="btn.size || 'small'"
@click="
() => {
$emit('columnClick', btn.prop, scope.row);
}
"
>{{ btn.title }}</el-button
>
</template>
</el-table-column>
</el-table>
<!-- :hide-on-single-page="tableOption.page.total >= 0" -->
<el-pagination
background
style="padding:20px 0;text-align:right"
:current-page="tableOption.page.currentPage"
:page-sizes="[10, 20, 50]"
:page-size="tableOption.page.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="tableOption.page.total"
@size-change="
val => {
$emit('size-change', val);
}
"
@current-change="
val => {
$emit('current-change', val);
}
"
>
</el-pagination>
</div>
</template>
<script>
export default {
name: "Table",
props: {
tableOption: {
type: Object,
default: () => {
return {};
}
}
},
data() {
return {};
},
methods: {},
created() {}
};
</script>
<style lang="less" scoped>
._table {
border-top: 5px solid #f6f8fc;
padding: 16px;
._title {
font-weight: 600;
margin-bottom: 20px;
}
}
</style>
到此,封装结束 最终代码,
page1.vue
<template>
<h-crud
:title="title"
:search-option="searchOption"
:table-option="tableOption"
@search="search"
@reset="reset"
@otherBtnsClick="otherBtnsClick"
@columnClick="columnClick"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
>
<!-- 普通列插槽 -->
<template slot="status" slot-scope="{ row }">
<span v-if="row.status && row.status === 1" style="color: #F53F3F;"
>错误,红的</span
>
<span v-else style="color:green">进行中,绿的</span>
</template>
</h-crud>
</template>
<script>
export default {
data() {
return {
// 页面标题
title: "复杂列表",
// 顶部表单检索内容,非必填
searchOption: {
// 表单内组件的尺寸
size: "small",
// 表单域标签的宽度
labelWidth: "80px",
// 检索列表
searchList: [
/*
label 标签名,必填
type 表单类型,必填
value 绑定值,必填
prop 字段名,必填
placeholder 提示语,非必填,默认请输入/请选择
clearable 是否可清空,非必填,默认清空
optionData 下拉菜单数据,type为select时填
type为date时
format 显示在输入框中的格式
valueFormat 返回格式
*/
{ label: "审批人:", type: "input", value: "", prop: "user" },
{
label: "活动区域:",
type: "select",
value: "",
prop: "region",
optionData: [
{ value: "shanghai", label: "区域一" },
{ value: "beijing", label: "区域二", disabled: true }
]
},
{
label: "日期:",
type: "date",
value: "",
prop: "date",
placeholder: "选择日期",
format: "yyyy 年 MM 月 dd 日",
valueFormat: "yyyy-MM-dd"
}
],
// 其它操作按钮,默认已有查询重置,不必填,可不要
otherBtns: [
{ title: "导出", prop: "export", type: "danger" },
{ title: "下载", prop: "downLoad", type: "success" }
]
},
// 列表数据
tableOption: {
// 表格列,必填
tableColumn: [
{
prop: "name",
label: "姓名"
},
{
prop: "status",
label: "状态"
},
{
prop: "address",
label: "描述",
minWidth: "150"
},
{
prop: "date",
label: "日期",
minWidth: "200"
}
],
// 表格数据,必填
tableData: [
{
id: 1,
name: "张三",
status: 1,
address: "我是描述",
date: "2022-01-01"
},
{
id: 2,
name: "李四",
status: 2,
address: "我是描述2",
date: "2022-01-02"
}
],
// 表格操作按钮,非必填
operationColumn: {
// 是否fixed
fixed: "right",
// 最小宽度
minWidth: "250",
btns: [
{ title: "编辑", prop: "edit", type: "primary", size: "small" },
{ title: "删除", prop: "delete", type: "danger", size: "small" },
{ title: "查看", prop: "dtl", type: "info", size: "small" }
]
},
page: {
currentPage: 1,
pageSize: 10,
total: 20
}
}
};
},
methods: {
// 条件检索
search(obj) {
console.log(obj);
},
// 重置
reset() {
console.log("重置");
},
// 其他操作按钮
otherBtnsClick(prop) {
switch (prop) {
case "export":
console.log("我是导出");
break;
case "downLoad":
console.log("我是下载");
break;
default:
break;
}
},
// 表格列操作
columnClick(prop, row) {
switch (prop) {
case "edit":
console.log("编辑", row);
break;
case "delete":
this.$confirm("此操作将删除该数据,是否确认删除?", "删除", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$message({
type: "success",
message: "删除成功!"
});
})
.catch(() => {
this.$message({
type: "info",
message: "已取消删除"
});
});
break;
case "dtl":
console.log("查看")
break;
default:
break;
}
},
// 分页
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
},
handleCurrentChange(val) {
console.log(`当前页: ${val}`);
}
},
created() {}
};
</script>
<style lang="less" scoped></style>
crud/index.vue
<template>
<div class="_crud">
<div class="_title">{{ title }}</div>
<div class="_search_content">
<Search
:search-option="searchOption"
@search="
Obj => {
$emit('search', Obj);
}
"
@reset="handldReset"
@otherBtnsClick="
prop => {
$emit('otherBtnsClick', prop);
}
"
></Search>
</div>
<div class="_table_content">
<Table
:table-option="tableOption"
@columnClick="
(prop, row) => {
$emit('columnClick', prop, row);
}
"
@size-change="
val => {
$emit('size-change', val);
}
"
@current-change="
val => {
$emit('current-change', val);
}
"
>
<template
v-for="item in tableOption.tableColumn"
:slot="item.prop"
slot-scope="{ row }"
>
<slot :name="item.prop" :row="row">
<template>
{{ row[item.prop] }}
</template>
</slot>
</template>
</Table>
</div>
</div>
</template>
<script>
import Search from "../Search/index";
import Table from "../Table/index";
export default {
name: "crud",
components: { Search, Table },
props: {
title: {
type: String,
default: () => {
return "";
}
},
searchOption: {
type: Object,
default: () => {
return {};
}
},
tableOption: {
type: Object,
default: () => {
return {};
}
}
},
data() {
return {};
},
methods: {
// 重置
handldReset() {
this.searchOption.searchList.forEach(item => {
const value = item.value;
if (value instanceof Array) {
this.$set(item, "value", []);
} else if (value instanceof Object) {
this.$set(item, "value", {});
} else {
this.$set(item, "value", "");
}
});
this.$emit("reset");
}
},
created() {}
};
</script>
<style lang="less" scoped>
._crud {
._title {
font-size: 16px;
font-weight: 600;
padding: 16px;
}
._search_content {
padding: 0 16px;
border-radius: 10px;
}
}
</style>
Search/index.vue
<template>
<div class="_search">
<el-form
v-if="searchOption && Object.keys(searchOption).length"
:inline="true"
:size="searchOption.size"
:label-width="searchOption.labelWidth"
>
<el-form-item
v-for="item in searchOption.searchList"
:key="item.label"
:label="item.label"
>
<template v-if="item.type === 'input'">
<el-input
:clearable="item.clearable || true"
v-model="item.value"
:placeholder="item.placeholder || '请输入'"
></el-input>
</template>
<template v-else-if="item.type === 'select'">
<el-select
v-model="item.value"
:placeholder="item.placeholder || '请选择'"
:clearable="item.clearable || true"
>
<el-option
v-for="option in item.optionData || []"
:key="option.value"
:label="option.label"
:value="option.value"
:disabled="option.disabled"
/>
</el-select>
</template>
<template v-else-if="item.type === 'date'">
<el-date-picker
v-model="item.value"
type="date"
:placeholder="item.placeholder || '请选择'"
:format="item.format || 'yyyy 年 MM 月 dd 日'"
:value-format="item.valueFormat || 'yyyy-MM-dd'"
>
</el-date-picker>
</template>
<!--
...
后续可根据自己的项目添加其他筛选组件,demo只写了input selece date
-->
</el-form-item>
<el-form-item>
<el-button type="primary" :size="searchOption.size" @click="searchClick"
>查询</el-button
>
<el-button :size="searchOption.size" @click="resetClick"
>重置</el-button
>
<!-- 其它操作按钮 -->
<template
v-if="searchOption.otherBtns && searchOption.otherBtns.length > 0"
>
<el-button
v-for="(btn, index) in searchOption.otherBtns"
:key="index"
:size="btn.size"
:type="btn.type"
@click="otherBtnsClick(btn)"
>{{ btn.title }}</el-button
>
</template>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: "search",
props: {
searchOption: {
type: Object,
default: () => {
return {};
}
}
},
data() {
return {};
},
methods: {
searchClick() {
let Obj = {};
this.searchOption.searchList.forEach(item => {
if (item.value !== "") {
Obj[item.prop] = item.value;
}
});
this.$emit("search", Obj);
},
resetClick() {
this.$emit("reset");
},
otherBtnsClick(btn) {
this.$emit("otherBtnsClick", btn.prop);
}
},
created() {
// console.log(this.searchOption);
}
};
</script>
<style lang="less" scoped></style>
Table/index.vue
<template>
<div class="_table">
<!-- <div class="_title">共 {{ tableOption.page.total }} 条记录</div> -->
<el-table
:data="tableOption.tableData"
stripe
border
:header-cell-style="{ backgroundColor: 'rgb(244, 244, 245)' }"
style="width: 100%"
>
<el-table-column
v-for="(item, index) in tableOption.tableColumn"
:key="index"
:label="item.label"
:min-width="item.minWidth"
>
<!-- 普通列插槽 -->
<template slot-scope="{ row }">
<slot :name="item.prop" :row="row">
<template>
{{ row[item.prop] }}
</template>
</slot>
</template>
</el-table-column>
<el-table-column
v-if="
tableOption.operationColumn &&
Object.keys(tableOption.operationColumn).length
"
:fixed="tableOption.operationColumn.fixed"
label="操作"
:min-width="tableOption.operationColumn.minWidth"
>
<template slot-scope="scope">
<el-button
v-for="(btn, index) in tableOption.operationColumn.btns"
:key="index"
:type="btn.type"
:size="btn.size || 'small'"
@click="
() => {
$emit('columnClick', btn.prop, scope.row);
}
"
>{{ btn.title }}</el-button
>
</template>
</el-table-column>
</el-table>
<!-- :hide-on-single-page="tableOption.page.total >= 0" -->
<el-pagination
background
style="padding:20px 0;text-align:right"
:current-page="tableOption.page.currentPage"
:page-sizes="[10, 20, 50]"
:page-size="tableOption.page.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="tableOption.page.total"
@size-change="
val => {
$emit('size-change', val);
}
"
@current-change="
val => {
$emit('current-change', val);
}
"
>
</el-pagination>
</div>
</template>
<script>
export default {
name: "Table",
props: {
tableOption: {
type: Object,
default: () => {
return {};
}
}
},
data() {
return {};
},
methods: {},
created() {}
};
</script>
<style lang="less" scoped>
._table {
border-top: 5px solid #f6f8fc;
padding: 16px;
._title {
font-weight: 600;
margin-bottom: 20px;
}
}
</style>
配置简单的列表 page2.vue
<template>
<h-crud
:title="title"
:table-option="tableOption"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
>
</h-crud>
</template>
<script>
export default {
data() {
return {
// 页面标题
title: "简单的列表",
// 列表数据
tableOption: {
// 表格列,必填
tableColumn: [
{
prop: "name",
label: "姓名"
},
{
prop: "status",
label: "状态"
},
{
prop: "address",
label: "描述",
minWidth: "150"
},
{
prop: "date",
label: "日期",
minWidth: "200"
}
],
// 表格数据,必填
tableData: [
{
id: 1,
name: "张三",
status: 1,
address: "我是描述",
date: "2022-01-01"
},
{
id: 2,
name: "李四",
status: 2,
address: "我是描述2",
date: "2022-01-02"
}
],
page: {
currentPage: 1,
pageSize: 10,
total: 20
}
}
};
},
methods: {
// 分页
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
},
handleCurrentChange(val) {
console.log(`当前页: ${val}`);
}
},
created() {}
};
</script>
<style lang="less" scoped></style>
到此结束,后面在写页面,只需要在下面data里传自己想要的操作,想要的数据即可,一天写二十个页面,轻轻松松,具体效果,操作按钮可看demo页面,console打印值
然后,在对应方法里写自己的方法即可1、按照自己文件路径去写,粘贴复制时看着里面路径, 2、注释复制完了可以删了,或者看好别注释错了,出现低级的页面报错 3、本片文章,只分享封装思路,你可以在此基础上根据自己需求,继续扩展,封装详情页,各种其他组件 4、喜欢的话,收藏点个赞,哈哈哈,感谢
以上是脚本宝典为你收集整理的vue+element后台管理,table,form,pagination等二次分装,实现5到20行完成一个主页面列表,一天轻轻松松写20个页面,再也不用大量的Ctrl+c Ctrl+v了全部内容,希望文章能够帮你解决vue+element后台管理,table,form,pagination等二次分装,实现5到20行完成一个主页面列表,一天轻轻松松写20个页面,再也不用大量的Ctrl+c Ctrl+v了所遇到的问题。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。