最近在写一个后台管理页面
一开始我并没有什么好的想法或者所谓的设计,直接开始看需求文档开始一路开鲁
现在已经搞了两个分类下的页面,大概有20多个了,我感觉特别的累,存在好多必要的不能省略的重复代码 o(╥﹏╥)o。
我觉得有必要去理一理思路了。
====================分割线============================
后台管理界面使用的是一个用vue实现的名为iviewUi的框架
vuex+vue-router+自带的脚手架(框架自带的不是vue-cli)
页面大概如下(图后面再补):
主题结构:
左测页面菜单栏
右侧:
---顶部:面包屑,已经打开过的页面tag(后面省略为tag)
---主题内容:搜索(一个或多个条件),表格,表格分页
====================分割线============================
一开始我是直接把弹窗,表格,表格分页,搜索都是写在一个页面的(我感觉脑子一片混乱,这对于一个有2年多的vue开发者,我感觉特别的不舒适。)
第一个个页面出来后,我花费了一天的时间去整理我的思路以及代码。
目录:
-index.vue
-compoments
- change.vue
- add.vue
- exportExcel.vue
_ .....
至于可以公共使用的组件则丢在公共组件目录里面。
我考虑过是否要用vuex来做数据通讯,思考之后还是放弃,vuex虽然优雅但是代码量多的让人受不了。同时,当前项目并不涉及子组件和子组件之间的通讯。
最终采用props加子组件触发事件,父组件标签监听的形式
到这里,我已经解决了部分让我很不爽的东西,至少让主页面的代码减少同时逻辑清晰了好多,长嘘一口气。。。
====================分割线============================
路由是采用后端接口提供,请求接口后再push进去的(这点让我有点新奇,虽然技术上并没啥难点)
右侧顶部“tag”点击的时候需要缓存页面,而左侧菜单栏则不需要,这个让我尝试了一把keeplive的好处。处理方法就是:
<!-- 区分左侧菜单和顶部tag跳转-->
<keep-alive >
<router-view v-if="$route.query.keepalivekeepalive"></router-view>
</keep-alive>
<router-view v-if="!$route.query.keepalivekeepalive"></router-view>
其中query.keepalivekeepalive 实在点击“tag”的时候通过事件触发对应的函数并且手动push的时候手动追加query
使用UI框架:https://www.iviewui.com/cli
================父组件==================
主页面标签:
<login-log-list-search v-on:update:searchName="handleSubmit($event)"/>
<rolelist-change-model :rowForServer="rowForServer" v-on:reloadbyChange:tableData1="triggerByAddModel"/>
============必要的不可少的代码,这是导入我不断的拷贝和修改的原因,头大[=============
import platformService from "./../../../service/member.js"; //对应分类下的数据请求列表
import loginLogListSearch from "./components/search.vue"; //对应的搜索组件
import exportExcel from "../../my-components/exportTable/index.vue"; //对应的导出数据组件
import rolelistChangeModel from "./components/change.vue"; //对应的修改弹窗组件
components: {
loginLogListSearch,
// exportExcel,
rolelistChangeModel
},
data(){
return {
tableData1: [],//表格列表
tableColumns1: [] //表格列
searchName: "", //搜索用户
searchDepartment: "", //描述职位
searchTime: "", //搜索时间
searchAccount: "", //搜索时间
searchType: 0, //类型
//page分页
page: {
currents: 1,
totals: 1,
limits: 4,
size: [1, 2, 3, 4] //可选显示条数
},
//发送给后端的修改
rowForServer: {
account: "",
name: "",
position: "",
department: "",
role: "",
ip: "",
position: "",
time: "",
id: ""
},
}
}
//避免给后台发送一些不必要的数据,需要在computed里面动态生成新的数据
//computed里面依赖对应的数据,如果依赖数据不动,会读取上一次的缓存
computed: {
forServerParams() {
// searchName: "", //搜索用户
// searchDepartment: "", //描述职位
// searchTime:"",//搜索时间
let name = this.searchName ? { name: this.searchName } : {};
let department = this.searchDepartment
? { text: this.searchDepartment }
: {};
let time = this.searchTime ? { time: this.searchTime } : {};
let Account = this.searchAccount ? { Account: this.searchAccount } : {};
let type = this.searchType ? { type: this.searchType } : { type: 0 };
return {
limits: this.page.limits,
page: this.page.currents,
...name,
...department,
...time,
...Account,
...type
};
}
},
menthods:{
resetRow//重置选中行
triggerByAddModel //新增弹窗的触发函数
async getRoleList //获取所有列表//获取单独列表(如果有形参的情况)
handleChange //table行选中回调
handleSubmit //查询组件触发
changePage //翻页回调
changeSize //页数修改回调
}
============必要的不可少的代码,这是导入我不断的拷贝和修改的原因,头大】=============
-----------子组件在父级上的耦合-----------
*login-log-list-search:
核心标签:包含按钮和弹窗
主动触发事件:”update:searchName”父组件接收后处理回调
props:不需要
data:
需要提交给后端的数据
时间格式化处理后的数据
Select关联的数组列表
menthods:
提交函数-》触发事件和传递查询参数给“父级组件去查询”
*rolelist-change-model:
核心标签:包含按钮和弹窗
和父组件的table数据有耦合,需要接受选中的row
Props:和父级选中行数据保存一致,由于接受的是一个对象,如果不想在重置弹窗表单的时候影响到父级的数据,需要如下操作
data(){
return {
row:Object.asign({},this.propsRow)
}
}
Watch:{
propsRow(newV,oldV){
//清空子组件表单
this.$refs["formValidate"].resetFields();
//再赋值
this.row=Object.asign(this.row,this.propsRow)
}
}
表单校验规则:
data(){
return {
ruleValidate: {
Status: [
{
required: true,
message: "Status cannot be empty"
}
],
account: [
{
required: true,
message: "account cannot be empty"
}
],
disabled: [
{
required: true,
message: "disabled cannot be empty"
}
]
},
}
}
其他必要的menthods:{
async changeModel
/*
点击按钮触发
1.点击按钮,
2.显示弹窗和弹窗蒙层async
3.判断是否有选中父级表格行
4.触发单个列表数据的请求,并更新弹窗数据,修改会在新的数据前提下修改,不会触发父组件相关数据的修改
*/
cancel
/*
弹窗取消按钮的回调
1.关闭弹窗
*/
validForm
/*
表单校验
异步校验
用promise包装返回promise
*/
async okValidForChange
/*
表单校验函数调用以及校验成功后的处理
*/
async modelbyChange
/*
提交更新
1.关闭弹窗和提交loading
2.请求所有列表数据
3. this.$emit("reloadbyChange:tableData1");告诉父级更新分页
*/
}
一开始我并没有什么好的想法或者所谓的设计,直接开始看需求文档开始一路开鲁
现在已经搞了两个分类下的页面,大概有20多个了,我感觉特别的累,存在好多必要的不能省略的重复代码 o(╥﹏╥)o。
我觉得有必要去理一理思路了。
====================分割线============================
后台管理界面使用的是一个用vue实现的名为iviewUi的框架
vuex+vue-router+自带的脚手架(框架自带的不是vue-cli)
页面大概如下(图后面再补):
主题结构:
左测页面菜单栏
右侧:
---顶部:面包屑,已经打开过的页面tag(后面省略为tag)
---主题内容:搜索(一个或多个条件),表格,表格分页
====================分割线============================
一开始我是直接把弹窗,表格,表格分页,搜索都是写在一个页面的(我感觉脑子一片混乱,这对于一个有2年多的vue开发者,我感觉特别的不舒适。)
第一个个页面出来后,我花费了一天的时间去整理我的思路以及代码。
目录:
-index.vue
-compoments
- change.vue
- add.vue
- exportExcel.vue
_ .....
至于可以公共使用的组件则丢在公共组件目录里面。
我考虑过是否要用vuex来做数据通讯,思考之后还是放弃,vuex虽然优雅但是代码量多的让人受不了。同时,当前项目并不涉及子组件和子组件之间的通讯。
最终采用props加子组件触发事件,父组件标签监听的形式
到这里,我已经解决了部分让我很不爽的东西,至少让主页面的代码减少同时逻辑清晰了好多,长嘘一口气。。。
====================分割线============================
路由是采用后端接口提供,请求接口后再push进去的(这点让我有点新奇,虽然技术上并没啥难点)
右侧顶部“tag”点击的时候需要缓存页面,而左侧菜单栏则不需要,这个让我尝试了一把keeplive的好处。处理方法就是:
<!-- 区分左侧菜单和顶部tag跳转-->
<keep-alive >
<router-view v-if="$route.query.keepalivekeepalive"></router-view>
</keep-alive>
<router-view v-if="!$route.query.keepalivekeepalive"></router-view>
其中query.keepalivekeepalive 实在点击“tag”的时候通过事件触发对应的函数并且手动push的时候手动追加query
使用UI框架:https://www.iviewui.com/cli
================父组件==================
主页面标签:
<login-log-list-search v-on:update:searchName="handleSubmit($event)"/>
<rolelist-change-model :rowForServer="rowForServer" v-on:reloadbyChange:tableData1="triggerByAddModel"/>
============必要的不可少的代码,这是导入我不断的拷贝和修改的原因,头大[=============
import platformService from "./../../../service/member.js"; //对应分类下的数据请求列表
import loginLogListSearch from "./components/search.vue"; //对应的搜索组件
import exportExcel from "../../my-components/exportTable/index.vue"; //对应的导出数据组件
import rolelistChangeModel from "./components/change.vue"; //对应的修改弹窗组件
components: {
loginLogListSearch,
// exportExcel,
rolelistChangeModel
},
data(){
return {
tableData1: [],//表格列表
tableColumns1: [] //表格列
searchName: "", //搜索用户
searchDepartment: "", //描述职位
searchTime: "", //搜索时间
searchAccount: "", //搜索时间
searchType: 0, //类型
//page分页
page: {
currents: 1,
totals: 1,
limits: 4,
size: [1, 2, 3, 4] //可选显示条数
},
//发送给后端的修改
rowForServer: {
account: "",
name: "",
position: "",
department: "",
role: "",
ip: "",
position: "",
time: "",
id: ""
},
}
}
//避免给后台发送一些不必要的数据,需要在computed里面动态生成新的数据
//computed里面依赖对应的数据,如果依赖数据不动,会读取上一次的缓存
computed: {
forServerParams() {
// searchName: "", //搜索用户
// searchDepartment: "", //描述职位
// searchTime:"",//搜索时间
let name = this.searchName ? { name: this.searchName } : {};
let department = this.searchDepartment
? { text: this.searchDepartment }
: {};
let time = this.searchTime ? { time: this.searchTime } : {};
let Account = this.searchAccount ? { Account: this.searchAccount } : {};
let type = this.searchType ? { type: this.searchType } : { type: 0 };
return {
limits: this.page.limits,
page: this.page.currents,
...name,
...department,
...time,
...Account,
...type
};
}
},
menthods:{
resetRow//重置选中行
triggerByAddModel //新增弹窗的触发函数
async getRoleList //获取所有列表//获取单独列表(如果有形参的情况)
handleChange //table行选中回调
handleSubmit //查询组件触发
changePage //翻页回调
changeSize //页数修改回调
}
============必要的不可少的代码,这是导入我不断的拷贝和修改的原因,头大】=============
-----------子组件在父级上的耦合-----------
*login-log-list-search:
核心标签:包含按钮和弹窗
主动触发事件:”update:searchName”父组件接收后处理回调
props:不需要
data:
需要提交给后端的数据
时间格式化处理后的数据
Select关联的数组列表
menthods:
提交函数-》触发事件和传递查询参数给“父级组件去查询”
*rolelist-change-model:
核心标签:包含按钮和弹窗
和父组件的table数据有耦合,需要接受选中的row
Props:和父级选中行数据保存一致,由于接受的是一个对象,如果不想在重置弹窗表单的时候影响到父级的数据,需要如下操作
data(){
return {
row:Object.asign({},this.propsRow)
}
}
Watch:{
propsRow(newV,oldV){
//清空子组件表单
this.$refs["formValidate"].resetFields();
//再赋值
this.row=Object.asign(this.row,this.propsRow)
}
}
表单校验规则:
data(){
return {
ruleValidate: {
Status: [
{
required: true,
message: "Status cannot be empty"
}
],
account: [
{
required: true,
message: "account cannot be empty"
}
],
disabled: [
{
required: true,
message: "disabled cannot be empty"
}
]
},
}
}
其他必要的menthods:{
async changeModel
/*
点击按钮触发
1.点击按钮,
2.显示弹窗和弹窗蒙层async
3.判断是否有选中父级表格行
4.触发单个列表数据的请求,并更新弹窗数据,修改会在新的数据前提下修改,不会触发父组件相关数据的修改
*/
cancel
/*
弹窗取消按钮的回调
1.关闭弹窗
*/
validForm
/*
表单校验
异步校验
用promise包装返回promise
*/
async okValidForChange
/*
表单校验函数调用以及校验成功后的处理
*/
async modelbyChange
/*
提交更新
1.关闭弹窗和提交loading
2.请求所有列表数据
3. this.$emit("reloadbyChange:tableData1");告诉父级更新分页
*/
}
我这个项目可能存在几十个类似的新增、修改弹窗,然后copy,paste,edit something,这酸爽。。。。。。。