做后台系统的时候,估计接触最多的就是表单 + 表格
,以此进行增删改查的操作。
本篇,努力将增删改查的通用逻辑分析清除,使用的时候,能通过简单的配置,就搞定一个复杂的页面。
可以的话,可以先看下准备篇:
本篇代码,涉及的文件比较多,想要看细节,可以参照github
TL;DR
- 基础的查询和表格显示
- 表格增加分页和排序
- 更改查询条件,进行查询需要重置页码和排序
- 重置查询条件
- 新加表格项
- 编辑表格项
1. 基础的查询和表格
第一步,先将表单显示出来,表格的数据通过请求拿到数据,也显示出来。
之前封装过表格和表单插件。
一个页面,先看下,查询的条件,将其变成一个表单的model
,表格就更简单,将列进行配置化。
当然查询条件,除了表单,还外加下分页和排序数据,pageIndex pageSize sortBy isAsc
。
第一版展示效果:
第一版核心代码,详细代码见文末:
github上可以切换c1分支
2. 排序和分页
排序的话:
- 不分页,直接配置
colConfig
的sortable:true
,就在该列的表头显示排序符号
了 - 分页,需要请求数据的话,配置
colConfig
的sortable:custom
,在组件上写上@sort-change="sortChange"
,点击排序符号的时候,就会触发sort-change
事件。
页码变化的话: 分页组件有事件current-change
,相应的设置pageIndex
监测pageIndex sortBy isAsc
发生变化的时候,请求表格数据
github上可以切换c2分支
3. 修改查询条件
点击查询的时候,按照查询条件,请求数据。
!!!注意,当前页数需要重置为1。
github上可以切换c3分支
4. 重置
重置其实有三个方面:
- 重置查询表单:将所有字段值重置为初始值并移除校验结果
- 重置当前页:设置为1
- 重置排序:将排序重置为默认排序
!!!注意,排序的设置,除了data里的isAsc和sortBy,还需要将表格里的排序图标保持正确。
设置排序的图标,有两个方法:
- clearSort:用于清空排序条件,数据会恢复成未排序的状态
- sort:手动对 Table 进行排序。参数prop属性指定排序列,order指定排序顺序。
所以,需要watch下data里的isAsc和sortBy,发生变化的时候,显示相应的排序图标。
为了监测方便,将isAsc和sortBy放在一个对象里,这样只需要监听一次
clickResetBtn() {
// 重置查询表单,将所有字段值重置为初始值并移除校验结果
this.$refs.queryForm.resetFields();
// 重置页数
this.pageIndex = 1;
// 重置排序
this.sortConfig = { ...this.sortConfigDefault };
},
效果图: 代码:
github上可以切换c4分支
5. 新建
新建功能一般会弹框显示,填完表单,确定之后,会在列表上显示。
用代码表达:
DOM
提前准备好弹框和表单,但不显示- 点击新建之后,显示弹框
- 弹框里点击提交,有错提示错误,没错请求新建的接口
- 此时看需求,但是多数需要,重置页面,再次请求列表数据,以显示刚刚创建的信息
- 细节:考虑到第二次点击新建的时候,同一个表单可能会有残留的验证提示,所以需要重置弹框表单
效果图:
代码:
DOM的核心代码:
el-dialog(:title="dialogFormTitle" :visible.sync="isShowDialogForm" center width="340px")
enhanced-el-form(ref="dialogForm" :model="dialogFormModel" :schema="dialogFormSchema" label-width="70px" label-position= "right")
template(#footer)
el-form-item
el-button.btn(type='primary', @click='clickCancelOfDialogForm') 取消
el-button.btn(plain, @click='clickConfirmOfDialogForm') 确定
github上可以切换c5分支
6. 编辑
编辑功能通常和新建用的同一个表单框。 但是和新建不一样的是,编辑表单是有数据的。
用代码表达:
DOM
提前准备好弹框和表单,但不显示- 表格配置加上编辑
- 点击编辑之后,填充表单数据,显示弹框
- 弹框里点击提交,有错提示错误,没错请求编辑的接口
- 此时看需求,但是多数需要,将当前行的数据及时更新
效果图:
代码:
colConfigs.js
增加操作列:
{ prop: "score", label: "分数", sortable: "custom" },
{ slotName: "action", label: "操作" }
github上可以切换c6分支
7. 待续
时间原因,先写到这里。
后期追加下 删除、导出
终极目标:封装成组件,高效使用~
代码
代码:1. 显示查询的表单和表格
这边使用vue create
创建了项目。
整体的代码略微复杂,加了mock数据、加了请求、全局用$api。
相应的文件有很多:但是除了App.vue
文件,其余文件后期不动。
目录结构这样,红框的文件就是需要动的文件
App.vue
App.vue
<template lang="pug">
div#app
//- 表单区域
enhanced-el-form(ref="queryForm" :model="model" :schema="schema" :inline="true" label-width="100px" label-position= "right")
template(#footer)
el-form-item.app-btns-box
el-button.btn(type='primary', @click='clickSearchBtn') 查询
//- 表格区域
enhanced-el-table(:data='tableData', :col-configs='colConfigs')
template(#name="colConfig")
el-table-column(v-bind="colConfig")
template(#default="{row}")
a.link(href="javascript:;" @click="clickName(row)") {{row.name}}
//- 分页
.pagination-box
el-pagination(@current-change='changeTablePage', :current-page.sync='pageIndex', :page-size='pageSize', layout='prev, pager, next, jumper', :total='dataCount')
</template>
<script>
import EnhancedElTable from "@/components/EnhancedElTable";
import EnhancedElForm from "@/components/EnhancedElForm";
import schema from "./schema";
import colConfigs from "./colConfigs";
export default {
name: "app",
components: { EnhancedElTable, EnhancedElForm },
data() {
return {
model: {},
// 表单配置
schema,
// 表格配置
colConfigs,
// 表格请求的原始数据
tableData: [],
// 有数据就意味着可能分页
pageIndex: 0,
pageSize: 10,
isAsc: "",
sortBy: "",
// 数据总长度,基本只给分页组件用的
dataCount: 0
};
},
mounted() {
this.getTableData();
},
methods: {
async getTableData() {
const { pageIndex, pageSize, sortBy, isAsc } = this;
let params = { ...this.model, pageIndex, pageSize, sortBy, isAsc };
const res = await this.$api.ApiGetList(params);
this.tableData = res.data;
this.dataCount = res.dataCount;
},
clickName() {},
clickSearchBtn() {},
changeTablePage(curPageIndex) {
this.pageIndex = curPageIndex;
}
}
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
}
.el-table {
border: 1px solid #e8e8e8;
width: 90%;
margin: auto;
}
.pagination-box {
margin-top: 20px;
text-align: center;
}
</style>
表单和表格的配置:colConfig.js、 schema.js
colConfig.js
export default [
{ prop: "orderNumber", label: "序号" },
{
slotName: "name",
label: "姓名"
},
{
prop: "year",
label: "年份"
},
{
prop: "quarter",
label: "季度"
},
{ prop: "score", label: "分数", sortable: "custom" }
];
schema.js
export default [
{
modelKey: "year",
label: "年份",
type: "date-picker",
props: {
type: "year",
format: "yyyy",
valueFormat: "yyyy",
style: { width: "150px" }
}
},
{
modelKey: "quarter",
label: "季度",
type: "select",
props: {
options: [
{ value: "春", label: "春" },
{ value: "夏", label: "夏" },
{ value: "秋", label: "秋" },
{ value: "冬", label: "冬" }
],
style: { width: "150px" }
}
},
{ modelKey: "name", label: "姓名", type: "input", style: { width: "150px" } }
];
两个组件:EnhancedElTable.vue和EnhancedElForm.vue
EnhancedElTable.vue
<template lang="pug">
el-table(ref="elTable" :data="data" v-bind="$attrs" v-on="$listeners")
template(v-for="colConfig in colConfigs")
slot(v-if="colConfig.slotName" :name="colConfig.slotName" v-bind="colConfig")
el-table-column(v-else v-bind="colConfig" :key="colConfig.prop")
</template>
<script>
export default {
name: "enhanced-el-table",
props: {
data: {
type: Array,
default() {
return [];
}
},
colConfigs: {
type: Array,
default() {
return [];
}
}
},
mounted() {
console.log(444, this.tableData);
const methods = [
"clearSelection",
"toggleRowSelection",
"toggleAllSelection",
"toggleRowExpansion",
"setCurrentRow",
"clearSort",
"clearFilter",
"doLayout",
"sort"
];
methods.forEach(method => (this[method] = this.$refs.elTable[method]));
}
};
</script>
EnhancedElForm.vue
<template lang="pug">
el-form(ref="elForm" :model="model" :rules="rules" v-bind="$attrs" v-on="$listeners")
slot(name="header")
template(v-for="config in schema" )
slot(v-if="config.slotName" :name="config.slotName" v-bind="config")
el-form-item(v-else :label="config.label" :prop="config.modelKey" :key="config.modelKey")
el-radio-group(v-if="config.type==='radio-group'" v-model="model[config.modelKey]" v-bind="config.props")
el-radio(v-for="(item,index) in config.props.options" :key="index" :label="typeof item==='object'?item.value:item") {{ typeof item==='object'?item.label:item }}
el-checkbox-group(v-else-if="config.type==='checkbox-group'" v-model="model[config.modelKey]" v-bind="config.props")
el-checkbox(v-for="(item,index) in config.props.options" :key="index" :label="typeof item==='object'?item.value:item") {{ typeof item==='object'?item.label:item }}
el-select(v-else-if="config.type==='select'" v-model="model[config.modelKey]" v-bind="config.props")
el-option(v-for="(item,index) in config.props.options" :key="index" :value="typeof item==='object'?item.value:item" :label="typeof item==='object'?item.label:item")
component(v-else :is="'el-'+config.type" v-model="model[config.modelKey]" v-bind="config.props") {{config.text}}
slot(name="footer")
</template>
<script>
export default {
name: "enhanced-el-form",
props: {
model: {
type: Object,
default() {
return {};
}
},
schema: {
type: Array,
default() {
return {};
}
}
},
computed: {
rules() {
return this.schema.reduce((acc, cur) => {
acc[cur.modelKey] = cur.rules;
// 日期组件可能有children
const hasChildren = cur.children && cur.children.length;
hasChildren &&
cur.children.forEach(child => (acc[child.modelKey] = child.rules));
return acc;
}, {});
}
},
mounted() {
// el-form上面的方法继承过来
const methods = [
"validate",
"validateField",
"resetFields",
"clearValidate"
];
methods.forEach(method => (this[method] = this.$refs.elForm[method]));
}
};
</script>
mock数据部分:.env.mock、mock.js、vue.config.js
.env.mock
NODE_ENV = 'mock'
mock.js
module.exports = Array.from({ length: 28 }, (v, i) => ({
orderNumber: i + 1,
year: "199" + i - 0 + 1 + "",
quarter: i % 4 === 1 ? "春" : i % 4 === 2 ? "夏" : i % 4 === 3 ? "秋" : "冬",
name: `李三${i + 1}`,
score: `8${i}`
}));
vue.config.js
const nativeData = require("./mock");
module.exports = {
devServer: {
before(app) {
app.get("/api/list", (req, res) => {
console.log(req.query);
const { pageIndex, pageSize, sortBy, isAsc, year, quarter, name } = req.query;
let data = [...nativeData];
// 拿到查询条件
const conditions = { year, quarter, name };
// 看查询条件有没有值
const keysOfHasValue = Object.keys(conditions).filter(
key => conditions[key]
);
const isHasCondition = keysOfHasValue.length > 0;
// 如果有查询条件的话就过滤下
if (isHasCondition) {
data = data.filter(item =>
keysOfHasValue.every(key => item[key] === conditions[key])
);
}
// 如果有排序的话
if (sortBy && isAsc) {
isAsc === "true"
? data.sort((x, y) => x[sortBy] - y[sortBy])
: data.sort((x, y) => y[sortBy] - x[sortBy]);
}
// 如果有分页的话
if (pageSize) {
data = data.slice((pageIndex - 1) * pageSize, pageSize * pageIndex);
}
return res.json({
state: 1,
data,
dataCount: data.length
});
});
}
}
};
加了请求:api/index.js
api/index.js
import axios from "axios";
// 所有请求统一配置
const instance = axios.create({ timeout: 5000 });
// 请求拦截器,统一加些appid、sign之类的
instance.interceptors.request.use(
config => {
config.method === "get" && (config.params.appid = "颜酱");
return config;
},
error => Promise.error(error)
);
// 响应拦截器,错误的统一处理
instance.interceptors.response.use(
// 请求成功
res => {
// 200的状态就是请求成功了
const isSuccess = res.status === 200;
if (!isSuccess) {
Promise.reject(res);
return;
}
return Promise.resolve(res.data);
},
// 请求失败
error => {
console.log(error);
if (!window.navigator.onLine) {
this.$message.error("网不好");
return;
}
const { response } = error;
if (response) {
this.$message.error(response.message);
}
}
);
export const ApiGetList = ({ pageIndex, pageSize, sortBy, isAsc, year, quarter, name }) =>
instance.get("/api/list", {
params: { pageIndex, pageSize, sortBy, isAsc, year, quarter, name }
});
全局api:main.js
main.js
import Vue from "vue";
import ElementUI from "element-ui";
import "element-ui/lib/theme-chalk/index.css";
import App from "./App.vue";
import * as api from "@/api";
// 让全局方便访问api
Vue.prototype.$api = api;
Vue.use(ElementUI);
new Vue({
el: "#app",
render: h => h(App)
});
代码:2. 增加排序和页码变化
App.vue
<template lang="pug">
div#app
//- 表单区域
enhanced-el-form(:model="model" :schema="schema" :inline="true" label-width="100px" label-position= "right")
template(#footer)
el-form-item.app-btns-box
el-button.btn(type='primary', @click='clickSearchBtn') 查询
//- 表格区域
enhanced-el-table(@sort-change="sortChange" :data='tableData', :col-configs='colConfigs')
template(#name="colConfig")
el-table-column(v-bind="colConfig")
template(#default="{row}")
a.link(href="javascript:;" @click="clickName(row)") {{row.name}}
//- 分页
.pagination-box
el-pagination(@current-change='changeCurrentPage', :current-page.sync='pageIndex', :page-size='pageSize', layout='prev, pager, next, jumper', :total='dataCount')
</template>
<script>
import EnhancedElTable from "@/components/EnhancedElTable";
import EnhancedElForm from "@/components/EnhancedElForm";
import schema from "./schema";
import colConfigs from "./colConfigs";
export default {
name: "app",
components: { EnhancedElTable, EnhancedElForm },
data() {
return {
// 表单数据
model: {},
// 表单配置
schema,
// 表格配置
colConfigs,
// 表格请求的原始数据
tableData: [],
// 有数据就意味着可能分页
pageIndex: 0,
pageSize: 10,
isAsc: "",
sortBy: "",
// 数据总长度,基本只给分页组件用的
dataCount: 0
};
},
mounted() {
this.getTableData();
},
watch: {
isAsc() {
this.getTableData();
},
sortBy() {
this.getTableData();
},
pageIndex() {
this.getTableData();
}
},
methods: {
changeCurrentPage(curPageIndex) {
this.pageIndex = curPageIndex;
},
async getTableData() {
const { pageIndex, pageSize, sortBy, isAsc } = this;
let params = { ...this.model, pageIndex, pageSize, sortBy, isAsc };
const res = await this.$api.ApiGetList(params);
this.tableData = res.data;
this.dataCount = res.dataCount;
},
sortChange({ column, prop, order }) {
console.log(column, prop, order);
this.isAsc = order === "ascending";
this.sortBy = prop;
},
clickName() {},
clickSearchBtn() {}
}
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
}
.el-table {
border: 1px solid #e8e8e8;
width: 90%;
margin: auto;
}
.pagination-box {
margin-top: 20px;
text-align: center;
}
</style>
代码:3. 增加查询条件变化
App.vue
<template lang="pug">
div#app
//- 表单区域
enhanced-el-form(:model="model" :schema="schema" :inline="true" label-width="70px" label-position= "right")
template(#footer)
el-form-item.app-btns-box
el-button.btn(type='primary', @click='clickSearchBtn') 查询
//- 表格区域
enhanced-el-table(@sort-change="sortChange" :data='tableData', :col-configs='colConfigs')
template(#name="colConfig")
el-table-column(v-bind="colConfig")
template(#default="{row}")
a.link(href="javascript:;" @click="clickName(row)") {{row.name}}
//- 分页
.pagination-box
el-pagination(@current-change='changeCurrentPage', :current-page.sync='pageIndex', :page-size='pageSize', layout='prev, pager, next, jumper', :total='dataCount')
</template>
<script>
import EnhancedElTable from "@/components/EnhancedElTable";
import EnhancedElForm from "@/components/EnhancedElForm";
import schema from "./schema";
import colConfigs from "./colConfigs";
export default {
name: "app",
components: { EnhancedElTable, EnhancedElForm },
data() {
return {
// 表单数据
model: {},
// 表单配置
schema,
// 表格配置
colConfigs,
// 表格请求的原始数据
tableData: [],
// 有数据就意味着可能分页
pageIndex: 0,
pageSize: 10,
isAsc: "",
sortBy: "",
// 数据总长度,基本只给分页组件用的
dataCount: 0
};
},
mounted() {
this.sortConditionDefault = { isAsc: this.isAsc, sortBy: this.sortBy };
this.getTableData();
},
watch: {
isAsc() {
this.getTableData();
},
sortBy() {
this.getTableData();
},
pageIndex() {
this.getTableData();
}
},
methods: {
clickSearchBtn() {
this.pageIndex = 1;
this.sortBy = this.sortConditionDefault.sortBy;
this.isAsc = this.sortConditionDefault.isAsc;
this.getTableData();
},
changeCurrentPage(curPageIndex) {
this.pageIndex = curPageIndex;
},
async getTableData() {
const { pageIndex, pageSize, sortBy, isAsc } = this;
let params = { ...this.model, pageIndex, pageSize, sortBy, isAsc };
const res = await this.$api.ApiGetList(params);
this.tableData = res.data;
this.dataCount = res.dataCount;
},
sortChange({ column, prop, order }) {
console.log(column, prop, order);
this.isAsc = order === "ascending";
this.sortBy = prop;
},
clickName() {}
}
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
}
.el-table {
border: 1px solid #e8e8e8;
width: 90%;
margin: auto;
}
.pagination-box {
margin-top: 20px;
text-align: center;
}
</style>
代码:4. 增加重置
App.vue
<template lang="pug">
div#app
//- 表单区域
enhanced-el-form(ref="queryForm" :model="model" :schema="schema" :inline="true" label-width="70px" label-position= "right")
template(#footer)
el-form-item.app-btns-box
el-button.btn(type='primary', @click='clickSearchBtn') 查询
el-button.btn(plain, @click='clickResetBtn') 重置
//- 表格区域
enhanced-el-table(ref="mainTable" @sort-change="sortChange" :data='tableData', :col-configs='colConfigs')
template(#name="colConfig")
el-table-column(v-bind="colConfig")
template(#default="{row}")
a.link(href="javascript:;" @click="clickName(row)") {{row.name}}
//- 分页
.pagination-box
el-pagination(@current-change='changeCurrentPage', :current-page.sync='pageIndex', :page-size='pageSize', layout='prev, pager, next, jumper', :total='dataCount')
</template>
<script>
import EnhancedElTable from "@/components/EnhancedElTable";
import EnhancedElForm from "@/components/EnhancedElForm";
import schema from "./schema";
import colConfigs from "./colConfigs";
export default {
name: "app",
components: { EnhancedElTable, EnhancedElForm },
data() {
return {
// 表单数据
model: { quarter: "" },
// 表单配置
schema,
// 表格配置
colConfigs,
// 表格请求的原始数据
tableData: [],
// 有数据就意味着可能分页
pageIndex: 0,
pageSize: 10,
sortConfig: { isAsc: "", sortBy: "" },
// 数据总长度,基本只给分页组件用的
dataCount: 0
};
},
mounted() {
// 存下默认,这里需要复制,引用类型你懂的
this.sortConfigDefault = { ...this.sortConfig };
this.getTableData();
},
watch: {
sortConfig: {
handler(newValue) {
console.log(newValue);
const order =
newValue.isAsc === ""
? null
: newValue.isAsc === false
? "descending"
: "ascending";
const hasOrder = order !== null;
const mainTable = this.$refs.mainTable;
// 有排序的时候,需要设置,没有排序的时候直接清除掉
hasOrder
? mainTable.sort(newValue.sortBy, order)
: mainTable.clearSort();
this.getTableData();
},
deep: true
},
pageIndex() {
this.getTableData();
}
},
methods: {
clickResetBtn() {
// 重置查询表单,将所有字段值重置为初始值并移除校验结果
this.$refs.queryForm.resetFields();
// 重置页数
this.pageIndex = 1;
// 重置排序
this.sortConfig = { ...this.sortConfigDefault };
},
clickSearchBtn() {
this.pageIndex = 1;
this.getTableData();
},
changeCurrentPage(curPageIndex) {
this.pageIndex = curPageIndex;
},
async getTableData() {
const { pageIndex, pageSize } = this;
let params = { ...this.model, ...this.sortConfig, pageIndex, pageSize };
const res = await this.$api.ApiGetList(params);
this.tableData = res.data;
this.dataCount = res.dataCount;
},
sortChange({ column, prop, order }) {
console.log(1, column, prop, order);
this.sortConfig.isAsc = order === null ? "" : order === "ascending";
this.sortConfig.sortBy = prop;
},
clickName() {}
}
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
}
.el-table {
border: 1px solid #e8e8e8;
width: 90%;
margin: auto;
}
.pagination-box {
margin-top: 20px;
text-align: center;
}
</style>
5.代码:新建
App.vue
<template lang="pug">
div#app
//- 表单区域
enhanced-el-form(ref="queryForm" :model="model" :schema="schema" :inline="true" label-width="70px" label-position= "right")
template(#footer)
el-form-item.app-btns-box
el-button.btn(type='primary', @click='clickSearchBtn') 查询
el-button.btn(plain, @click='clickResetBtn') 重置
el-button.btn(plain, @click='clickCreateBtn') 新建
//- 表格区域
enhanced-el-table(ref="mainTable" @sort-change="sortChange" :data='tableData', :col-configs='colConfigs')
template(#name="colConfig")
el-table-column(v-bind="colConfig")
template(#default="{row}")
a.link(href="javascript:;" @click="clickName(row)") {{row.name}}
//- 分页
.pagination-box
el-pagination(@current-change='changeCurrentPage', :current-page.sync='pageIndex', :page-size='pageSize', layout='prev, pager, next, jumper', :total='dataCount')
el-dialog(:title="dialogFormTitle" :visible.sync="isShowDialogForm" center width="340px")
enhanced-el-form(ref="dialogForm" :model="dialogFormModel" :schema="dialogFormSchema" label-width="70px" label-position= "right")
template(#footer)
el-form-item
el-button.btn(type='primary', @click='clickCancelOfDialogForm') 取消
el-button.btn(plain, @click='clickConfirmOfDialogForm') 确定
</template>
<script>
import EnhancedElTable from "@/components/EnhancedElTable";
import EnhancedElForm from "@/components/EnhancedElForm";
import schema from "./schema";
import colConfigs from "./colConfigs";
export default {
name: "app",
components: { EnhancedElTable, EnhancedElForm },
data() {
return {
// 表单数据
model: {},
// 表单配置
schema,
// 表格配置
colConfigs,
// 表格请求的原始数据
tableData: [],
// 有数据就意味着可能分页
pageIndex: 0,
pageSize: 10,
sortConfig: { isAsc: "", sortBy: "" },
// 数据总长度,基本只给分页组件用的
dataCount: 0,
// 弹框 新建的各种参数
isShowDialogForm: false,
dialogFormTitle: "新建学生",
dialogFormModel: {},
dialogFormSchema: schema.map(item => {
let res = { ...item };
res.rules = [{ required: true, trigger: "blur", message: "不能为空" }];
return res;
})
};
},
mounted() {
// 存下默认,这里需要复制,引用类型你懂的
this.sortConfigDefault = { ...this.sortConfig };
this.getTableData();
},
watch: {
sortConfig: {
handler(newValue) {
const order =
newValue.isAsc === ""
? null
: newValue.isAsc === false
? "descending"
: "ascending";
const hasOrder = order !== null;
const mainTable = this.$refs.mainTable;
// 有排序的时候,需要设置,没有排序的时候直接清除掉
hasOrder
? mainTable.sort(newValue.sortBy, order)
: mainTable.clearSort();
this.getTableData();
},
deep: true
},
pageIndex() {
this.getTableData();
}
},
methods: {
clickCreateBtn() {
this.$refs.dialogForm && this.$refs.dialogForm.resetFields();
this.isShowDialogForm = true;
},
clickCancelOfDialogForm() {
this.isShowDialogForm = false;
},
async clickConfirmOfDialogForm() {
const isValid = await this.$refs.dialogForm.validate();
if (!isValid) {
return;
}
// 鉴于时间不多,不在多写接口,表达意思就行
// await this.$api.createData(this.dialogFormModel)
// this.$message.success('新建成功~')
this.isShowDialogForm = false;
// 重置查询条件和排序
this.resetQueryAndSort();
},
resetQueryAndSort() {
// 重置查询表单,将所有字段值重置为初始值并移除校验结果
this.$refs.queryForm.resetFields();
// 重置页数
this.pageIndex = 1;
// 重置排序
this.sortConfig = { ...this.sortConfigDefault };
},
clickResetBtn() {
this.resetQueryAndSort();
},
clickSearchBtn() {
this.pageIndex = 1;
this.getTableData();
},
changeCurrentPage(curPageIndex) {
this.pageIndex = curPageIndex;
},
async getTableData() {
const { pageIndex, pageSize } = this;
let params = { ...this.model, ...this.sortConfig, pageIndex, pageSize };
const res = await this.$api.ApiGetList(params);
this.tableData = res.data;
this.dataCount = res.dataCount;
},
sortChange({ column, prop, order }) {
console.log(1, column, prop, order);
this.sortConfig.isAsc = order === null ? "" : order === "ascending";
this.sortConfig.sortBy = prop;
},
clickName() {}
}
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
}
.el-table {
border: 1px solid #e8e8e8;
width: 90%;
margin: auto;
}
.pagination-box {
margin-top: 20px;
text-align: center;
}
</style>
6.代码:编辑
App.vue
<template lang="pug">
div#app
//- 表单区域
enhanced-el-form(ref="queryForm" :model="model" :schema="schema" :inline="true" label-width="70px" label-position= "right")
template(#footer)
el-form-item.app-btns-box
el-button.btn(type='primary', @click='clickSearchBtn') 查询
el-button.btn(plain, @click='clickResetBtn') 重置
el-button.btn(plain, @click='clickCreateBtn') 新建
//- 表格区域
enhanced-el-table(ref="mainTable" @sort-change="sortChange" :data='tableData', :col-configs='colConfigs')
template(#name="colConfig")
el-table-column(v-bind="colConfig")
template(#default="{row}")
a.link(href="javascript:;" @click="clickName(row)") {{row.name}}
template(#action="colConfig")
el-table-column(v-bind="colConfig")
template(#default="{row}")
div(style="color:#409eff;cursor:pointer" @click="clickEdit(row)") 编辑
//- 分页
.pagination-box
el-pagination(@current-change='changeCurrentPage', :current-page.sync='pageIndex', :page-size='pageSize', layout='prev, pager, next, jumper', :total='dataCount')
el-dialog(:title="dialogFormTitle" :visible.sync="isShowDialogForm" center width="340px")
enhanced-el-form(ref="dialogForm" :model="dialogFormModel" :schema="dialogFormSchema" label-width="70px" label-position= "right")
template(#footer)
el-form-item
el-button.btn( plain,@click='clickCancelOfDialogForm') 取消
el-button.btn(type='primary', @click='clickConfirmOfDialogForm') 确定
</template>
<script>
import EnhancedElTable from "@/components/EnhancedElTable";
import EnhancedElForm from "@/components/EnhancedElForm";
import schema from "./schema";
import colConfigs from "./colConfigs";
export default {
name: "app",
components: { EnhancedElTable, EnhancedElForm },
data() {
return {
// 表单数据
model: {},
// 表单配置
schema,
// 表格配置
colConfigs,
// 表格请求的原始数据
tableData: [],
// 有数据就意味着可能分页
pageIndex: 0,
pageSize: 10,
sortConfig: { isAsc: "", sortBy: "" },
// 数据总长度,基本只给分页组件用的
dataCount: 0,
// 弹框 新建的各种参数
isShowDialogForm: false,
dialogFormTitle: "新建学生",
dialogFormModel: {},
dialogFormSchema: schema.map(item => {
let res = { ...item };
res.rules = [{ required: true, trigger: "blur", message: "不能为空" }];
return res;
})
};
},
mounted() {
// 存下默认,这里需要复制,引用类型你懂的
this.sortConfigDefault = { ...this.sortConfig };
this.getTableData();
},
watch: {
sortConfig: {
handler(newValue) {
const order =
newValue.isAsc === ""
? null
: newValue.isAsc === false
? "descending"
: "ascending";
const hasOrder = order !== null;
const mainTable = this.$refs.mainTable;
// 有排序的时候,需要设置,没有排序的时候直接清除掉
hasOrder
? mainTable.sort(newValue.sortBy, order)
: mainTable.clearSort();
this.getTableData();
},
deep: true
},
pageIndex() {
this.getTableData();
}
},
methods: {
clickEdit(row) {
// 这里后期确定是编辑还是添加,以此做一些不同的操作
this.isEdit = true;
// 注意这里必须是这行在下行的前面,为了后期的resetFields因为页面首次点击编辑的话,表单初始值是空的。如果下面那行在上面的话,页面先点击编辑后点击新建的话,resetFields就会失效。nextTick也是保证这个功能
this.isShowDialogForm = true;
this.$nextTick(() => {
this.dialogFormModel = { ...row };
});
// 保留当前行的信息,修改成功之后,将更新的信息赋值
this.curRow = row;
// 可能需要修改标题
this.dialogFormTitle = "修改";
},
async clickConfirmOfDialogForm() {
const isValid = await this.$refs.dialogForm.validate();
if (!isValid) {
return;
}
// 鉴于时间不多,不在多写接口,表达意思就行
if (this.isEdit) {
// await this.$api.editData(this.dialogFormModel)
this.$message.success("修改成功~");
// 这里需要用遍历的办法更新当前row的信息,必须等接口成功
Object.keys(this.dialogFormModel).forEach(key => {
this.curRow[key] = this.dialogFormModel[key];
});
} else {
// await this.$api.createData(this.dialogFormModel)
this.$message.success("新建成功~");
// 重置查询条件和排序
this.resetQueryAndSort();
}
this.isShowDialogForm = false;
},
clickCreateBtn() {
// 这里后期确定是编辑还是添加,以此做一些不同的操作
this.isEdit = false;
this.dialogFormTitle = "新建";
this.$refs.dialogForm && this.$refs.dialogForm.resetFields();
this.isShowDialogForm = true;
},
clickCancelOfDialogForm() {
this.isShowDialogForm = false;
},
resetQueryAndSort() {
// 重置查询表单,将所有字段值重置为初始值并移除校验结果
this.$refs.queryForm.resetFields();
// 重置页数
this.pageIndex = 1;
// 重置排序
this.sortConfig = { ...this.sortConfigDefault };
},
clickResetBtn() {
this.resetQueryAndSort();
},
clickSearchBtn() {
this.pageIndex = 1;
this.getTableData();
},
changeCurrentPage(curPageIndex) {
this.pageIndex = curPageIndex;
},
async getTableData() {
const { pageIndex, pageSize } = this;
let params = { ...this.model, ...this.sortConfig, pageIndex, pageSize };
const res = await this.$api.ApiGetList(params);
this.tableData = res.data;
this.dataCount = res.dataCount;
},
sortChange({ column, prop, order }) {
console.log(1, column, prop, order);
this.sortConfig.isAsc = order === null ? "" : order === "ascending";
this.sortConfig.sortBy = prop;
},
clickName() {}
}
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
}
.el-table {
border: 1px solid #e8e8e8;
width: 90%;
margin: auto;
}
.pagination-box {
margin-top: 20px;
text-align: center;
}
</style>