提示:本章为了记录写过的项目功能,方便下次项目直接取用
公司的新项目,后台管理系统,框架用的Vue和elementUI,在实际项目开发中, elementUI可满足大多数需求,但仍有一些问题出现,主要因为特殊化需求或是后台返回数据格式的问题,这篇文章总结了一些,方便以后使用和学习提高
后台管理系统中,导航菜单和面包屑都是必不可少的,这里依据elementui的demo,结合后台返回数据,利用路由,实现具体功能
代码如下(示例):
<el-menu
:default-active="toPath"
exact
class="el-menu-vertical-demo"
background-color="#303244"
text-color="#fff"
active-text-color="#029051"
unique-opened
router
>
<el-submenu v-for="(item,index) in menuArrays.sFuncMsgsList" :index="index+''" :key="index">
<template slot="title">
<span class="mine_icon-title">span>
<span slot="title">{
{item.funcName}}span>
template>
<template v-for="child in item.sFuncMsgsList">
<el-menu-item :index="child.funcUrl" :key="child.id">
<span class="mine_icon-menu">span>
<span slot="title" class="mine_title-menu">{
{child.funcName}}span>
el-menu-item>
template>
el-submenu>
el-menu>
代码如下(示例):
{
path: '/d_accesstoken_infos',
component: layout, //继承layout
name: 'd_accesstoken_infos',
children: [
{
//异常信息审批
path: '/d_accesstoken_infos',
component: () => import('@V/d_accesstoken_infos'),
meta: {
title: '异常信息审批' },
},
]
},
<el-breadcrumb separator="I" class="title">
<el-breadcrumb-item v-for="(v,i) in list" :key="i">{
{v.meta.title}}el-breadcrumb-item>
el-breadcrumb>
data() {
return {
list: []
};
},
watch: {
$route(to, from) {
this.list = this.$route.matched;
}
},
created() {
this.list = this.$route.matched;
},
代码如下(示例):
el-table-column>
/* 格式化 开始 */
statusFormat(row, column,cellValue, index) {
if (row.status == "0") {
return "启用";
} else {
return "禁用";
}
}
/* 格式化 结束 */
最适用场景是:当表格里每一行都有一个删除按钮时,每次删除成功后,在页面上这一行就应该消失,比起重新调起接口、刷新页面,直接移除这条数据是最省事的方式
代码如下(示例):
rows.splice(index, 1);
以下代码是项目中用到的比较典型的一些规则,涉及到输入框,选择器,密码,手机号,身份证号,和自定义校验规则validator
代码如下(示例):
data() {
// 保证设备编码的唯一性
var validatePass = (rule, value, callback) => {
if (!value) {
return callback(new Error("请输入设备编码"));
} else {
// 查看数组里是否有某个元素,是就返回其坐标,不是,就返回 -1
const findThisNum = this.ucCodes.findIndex((x) => x === value);
if (findThisNum == -1) {
callback();
} else {
callback(new Error("该编码已经存在,请输入其他编码"));
}
}
};
return {
addRules: {
loginNo: [
{
required: true, message: "请输入登录账号", trigger: "blur" }
],
sRoleMsgsId: [
{
required: true, message: "请选择角色", trigger: "change" }
],
password: [
{
required: true, message: "请输入用户密码", trigger: "blur" },
{
min: 3,max: 10,message: "密码长度为3-10位",trigger: "blur"}
],
projectTelephone: [
{
required: true, message: "请输入负责人联系方式", trigger: "blur" },
{
pattern: /^1[3|4|5|7|8][0-9]\d{8}$/, message: "手机号格式不对", trigger: "blur"}
],
idCard: [
{
required: true, message: "请输入身份证编号", trigger: "blur" },
{
pattern: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/, message: "身份证编号格式不对",trigger: "blur" }
],
deviceUc: [
{
required: true, validator: validatePass, trigger: "blur" },
],
}
}
}
代码如下(示例):
<el-button type="primary" @click="onSubmit(loginForm)" native-type="submit">登录<el-button>
代码如下(示例):
<div v-for="(list,index) in roleArrays" :key="index">
<el-checkbox
v-model="roleids"
:label="list.roleMsgsWrapper.id"
:key="list.roleMsgsWrapper.id"
@change="handleCheckAllChange(index,list.roleMsgsWrapper.id,$event)"
>{
{list.roleMsgsWrapper.funcName}}el-checkbox
>
<div class="checkGroup">
<el-checkbox
v-for="(item,i) in list.roleMsgsWrapperList"
:label="item.id"
:key="item.id"
v-model="roleids"
@change="handleCheckedRolesChange(i,index,item.id,list.roleMsgsWrapper.id,$event)"
>{
{item.funcName}}el-checkbox
>
div>
div>
data() {
return {
roleArrays: [], //所有角色
roleids: [] //选中的角色id
};
},
methods: {
// 全选
// handleCheckAllChange 用的是是elementUI Checkbox的内置change事件
// 参数是更新后的值
handleCheckAllChange(i, id, check) {
var childrenArray = this.roleArrays[i].roleMsgsWrapperList;
if (childrenArray) {
for (var i = 0, len = childrenArray.length; i < len; i++) {
if (check == false) {
// 全不选时,从[]中删掉其下属的item的ID
this.removeByValue(this.roleids, childrenArray[i].id);
} else {
// 全选时,将其下属的item的ID,push进[]里
this.roleids.push(childrenArray[i].id);
}
}
}
},
//单选
handleCheckedRolesChange(index, fatherIndex, sonId, fatherId, check) {
var childrenArray = this.roleArrays[fatherIndex].roleMsgsWrapperList;
var len = childrenArray.length;
let child_ids = [];
for (var i = 0; i < len; i++) {
// 将childrenArray[i]的id,组成新数组
child_ids.push(childrenArray[i].id);
// 手动添加字段checked,没条件创造条件
// 这是重点,用来判断item有没有被check
childrenArray[index].checked = check;
if (childrenArray[i].checked) {
if (childrenArray[i].checked == true) {
// 这是选中的item个数,之所以放在声明之前,是因为,这里获取的是后台数据里返回的item个数
// 可用来进行check回显
tickCount++;
}
}
}
// 过滤两个数组,取重复值
// 过滤[]里的值
let bbb = this.roleids.filter(item => child_ids.indexOf(item) > -1);
var tickCount = bbb.length; // 选中数量,取数据返回的初始length
// 子级勾选,与全选联动
// 全不选时
if (tickCount == 0) {
this.removeByValue(this.roleids, fatherId);
} else {
// 有勾选时,fatherId不要重复添加
if (this.roleids.includes(fatherId)) {
} else {
this.roleids.push(fatherId);
}
}
},
/* 删除数组指定值 开始 */
removeByValue(arr, val) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] == val) {
arr.splice(i, 1);
break;
}
}
},
/* 删除数组指定值 结束 */
};
// 最终所需数据,数组拼接成字符串 [3,14,15] -> 3,14,15
this_.roleids.length > 0 ? this_.roleids.join() : "",
代码如下(示例):
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="searchForm.pageNum"
:page-sizes="[10, 20, 30, 40]"
:page-size="searchForm.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="totalNum"
:key="totalNum"
>el-pagination>
data() {
return {
loading: false, //懒加载
totalNum: 0, //总条数默认为0
currentPage: 1, //当前页数默认为1
searchForm: {
pageSize: 10,
pageNum: 1,
},
};
},
methods: {
//初始化请求数据
initData() {
this.loading = true;
var this_ = this;
this.$https
.get("/d_device_infos/getList", this_.searchForm)
.then((res) => {
if (res.data.retCode == 200) {
this_.userLists = res.data.datas.list;
this_.totalNum = res.data.datas.total;
}
this.loading = false;
});
},
/*每页条数变化*/
handleSizeChange(val) {
this.searchForm.pageSize = val;
this.initData();
},
/*当前页码改变*/
handleCurrentChange(val) {
this.searchForm.pageNum = val;
this.initData();
},
},
代码如下(示例):
<el-table-column type="index" label="序号" align="center" width="50" :index="indexMethod">el-table-column>
// 序号
// 根据数据的index和页码数和页码来算的
// 1-10
// 11-20
// ...
indexMethod(index) {
index = (index + 1) + (this.searchForm.pageNum - 1) * this.searchForm.pageSize
return index
},
代码如下(示例):
<el-form-item label="归属区域" prop="sAreaCodesId">
el-cascader>
el-form-item>
data() {
return {
reginArrays: [],
// elementui 默认需要value和label属性名,但是后台返回数据并不一定符合,所以利用内置属性props,修改属性名
optionProps: {
value: "id",
label: "areaName",
checkStrictly: true , // 可父子节点不互相关联
// emitPath: false, // 在选中节点改变时,是否返回由该节点所在的各级菜单的值所组成的数组,若设置 false,则只返回该节点的值
},
},
},
methods: {
getRegionsInfo() {
var this_ = this;
this.$https.get("/public/regionsInfo").then(res => {
if (res.data.retCode == 200) {
// 处理后台返回的数据
this_.reginArrays = this.getTreeData(res.data.datas);
}
});
},
// 处理数组数据,删掉最后一个children
getTreeData(data) {
for (var i = 0; i < data.length; i++) {
if (data[i].children.length < 1) {
delete data[i].children;
} else {
this.getTreeData(data[i].children);
}
}
return data;
},
// 用elementui内置方法,取ID数组里最后一个值
handleChange(value) {
console.log('value :>> ', value); // -> [17,19]
this.addForm.sAreaCodesId = value[value.length - 1]; // -> 19
// 或可借助optionProps的emitPath属性,直接获取该节点的值
// console.log('emitPathvalue :>> ', value); // -> 19
},
}
代码如下(示例):
<el-form-item label="考勤时间" prop="timeRange">
el-time-picker>
el-form-item>
// 后台需要数据是startTime和endTime,是HH:mm 的字符串
// 但是 elementui 用的是timeRange 的数组
// 所以为了回显编辑,数据需要拼接 和 拆分
const startTime = this_.dWorkTimeList.startTime; // -> 08:00
const endTime = this_.dWorkTimeList.endTime;
// 方法一:date对象回显
// 这里数据用的是HH:mm,先转化成yyyy-MM-dd HH:mm,再转成date对象
var date = new Date();
var mytime = date.toLocaleDateString(); //获取当前时间
startTime = mytime + " " + startTime; // -> 2020-12-12 08:00
endTime = mytime + " " + endTime;
var timeRanges = [];
timeRanges.push(new Date(startTime));
timeRanges.push(new Date(endTime));
console.log("object :>> ", timeRanges); // ⬆︎[xx.png]
// 方法二:字符串回显
var timeRanges = [];
timeRanges.push(startTime);
timeRanges.push(endTime);
console.log("object :>> ", timeRanges); // -> ["09:02", "13:02"]
// 获取到时间数组后,不能直接赋值给el-time-picker,会导致回显后不能编辑,所以用以下方法
// 这个方法是可用来在正常回显后,能正常切换change
// 网上找来的方法,思路是用vue的this.$set
// 只用el-time-picker 需要,其他时间选择器不用
this.$set(this_.dWorkTimeList, "timeRange", timeRanges);
代码如下(示例):
<el-form-item label="选择时间">
<el-date-picker
v-model="searchForm.data_time"
type="date"
placeholder="请选择日期"
value-format="yyyy-MM-dd"
:picker-options="pickerOptions" // 时间限制
></el-date-picker>
</el-form-item>
---
// 设置选择今天以及今天以前的日期
data() {
return {
pickerOptions: {
// disabledDate 是elementUI DatePicker的 Picker Options 的内置参数
// 设置禁用状态,参数为当前日期,要求返回 Boolean
disabledDate(time) {
return time.getTime() > Date.now() - 8.64e6
}
},
},
},
代码如下(示例):
<el-form-item label="选择时间">
<el-date-picker
v-model="timeRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
:picker-options="pickerOptions"
></el-date-picker>
</el-form-item>
---
data() {
return {
pickerMinDate: "",
pickerOptions: {
onPick: ({
maxDate, minDate }) => {
this.pickerMinDate = minDate.getTime();
if (maxDate) {
this.pickerMinDate = "";
}
},
disabledDate: (time) => {
if (this.pickerMinDate !== "") {
const day30 = (30 - 1) * 24 * 3600 * 1000;
let maxTime = this.pickerMinDate + day30;
if (maxTime > new Date()) {
maxTime = new Date();
}
return time.getTime() > maxTime;
}
return time.getTime() > Date.now();
},
},
},
},
Vue 中关闭 el-dialog 时如何销毁(参考链接)
其实并不需要把 el-dialog 完全销毁,只要把数据重置一下就可以了
代码如下(示例):
<el-dialog
:title="title"
v-if="centerDetailVisible"
:visible.sync="centerDetailVisible"
@close="handleClose"
center
>
handleClose(){
Object.assign(this.$data, this.$options.data())
},
提示:以上是一个项目的总结,以后如果有新的收获,会持续更新