vue+elementUI 项目相关总结

提示:本章为了记录写过的项目功能,方便下次项目直接取用

文章目录

  • 前言
  • 实现
    • 1.NavMenu 导航菜单
    • 2.Breadcrumb 面包屑
    • 3.Table 表格
      • 3.1 格式化内容
      • 3.2 移除数据代替刷新
    • 4.Form 表单
      • 4.1 表单验证规则
      • 4.2 回车键登录
    • 5.Checkbox 多选框
      • 5.1 全选单选
    • 6.Pagination 分页
      • 6.1 分页
      • 6.2 序号
    • 7. Cascader 级联选择器
    • 8.DateTimePicker 日期时间选择器
      • 8.1 时间回显
      • 8.2 添加日期限制
        • 8.2.1 只能选择今天及今天以前的日期
        • 8.2.2 日期选择范围限制 30 天,且不能超过当天
    • 9.Dialog 对话框
      • 9.1 关闭dialog 时销毁dom和数据
  • 总结


前言

公司的新项目,后台管理系统,框架用的Vue和elementUI,在实际项目开发中, elementUI可满足大多数需求,但仍有一些问题出现,主要因为特殊化需求或是后台返回数据格式的问题,这篇文章总结了一些,方便以后使用和学习提高


实现

1.NavMenu 导航菜单

后台管理系统中,导航菜单和面包屑都是必不可少的,这里依据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>


2.Breadcrumb 面包屑

  • 面包屑的路径数据,来自于 router 的自定义内容 meta
  • 这个 meta 要与导航栏的标题相一致

代码如下(示例):

{
     
	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;
},

3.Table 表格

3.1 格式化内容

  • :formatter=“statusFormat”
  • Function(row, column, cellValue, index)

代码如下(示例):


el-table-column>
/* 格式化 开始 */
statusFormat(row, column,cellValue, index) {
     
  if (row.status == "0") {
     
    return "启用";
  } else {
     
    return "禁用";
  }
}
/* 格式化 结束 */

3.2 移除数据代替刷新

最适用场景是:当表格里每一行都有一个删除按钮时,每次删除成功后,在页面上这一行就应该消失,比起重新调起接口、刷新页面,直接移除这条数据是最省事的方式

代码如下(示例):

rows.splice(index, 1);

4.Form 表单

4.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" },
      ],
    }
  }
}

4.2 回车键登录

  • 使用回车键 enter 来进行登录,在登录按钮上面添加 native-type=“submit”

代码如下(示例):

<el-button type="primary" @click="onSubmit(loginForm)" native-type="submit">登录<el-button>

5.Checkbox 多选框

5.1 全选单选

  • 整体是依照 elementUI checkbox 的 indeterminate 状态来做的
  • 用了其内置属性方法和数据格式
  • 但是后台返回数据没有 check 属性,与所需不符,所以要修改方法,
  • 最后只简单做到全选单选,没有做中间态
  • 具体功能是:整个页面有n组按钮,每组按钮,都有全选和单选。全选按钮影响 本组的全选/全不选 功能,一组里只要有单选按钮被选中,全选也会被选中,若是没有一个按钮被选中,全选也不被选中
  • 结果:要把所有选中的按钮拼成字符串提交,例 ‘1,2,3’

vue+elementUI 项目相关总结_第1张图片

vue+elementUI 项目相关总结_第2张图片

代码如下(示例):

<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() : "",

6.Pagination 分页

6.1 分页

代码如下(示例):

<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();
  },
},

6.2 序号

  • 序号要根据分页数据进行变化

代码如下(示例):

<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
},

7. Cascader 级联选择器

  • 因为后台返回数据里每一层级都有 children
  • 最后一层级没有数据时,children 为空,
  • 这会导致页面最后展示暂无数据页,影响用户选择
  • 所以,要对数据进行处理,去掉最后一个空 children

代码如下(示例):

 <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
    },
}

8.DateTimePicker 日期时间选择器

8.1 时间回显

vue+elementUI 项目相关总结_第3张图片

代码如下(示例):

<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);

8.2 添加日期限制

8.2.1 只能选择今天及今天以前的日期

  • 参考链接

代码如下(示例):

<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
        }
      },
  },
},

8.2.2 日期选择范围限制 30 天,且不能超过当天

代码如下(示例):

<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();
        },
      },
  },
},

9.Dialog 对话框

9.1 关闭dialog 时销毁dom和数据

  • 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())
},


总结

提示:以上是一个项目的总结,以后如果有新的收获,会持续更新

你可能感兴趣的:(项目总结,vue,elementui)