element-ui 实战各种小技巧

element-ui 实战各种小技巧(长期更新)
96 sunxiaochuan
0.2 2018.06.04 17:35* 字数 1038 阅读 14141评论 1喜欢 9
资料

element-ui 中文官网
element-ui 官网组件使用指南
1. 项目中安装并引用 element-ui

官网安装地址
官网引入地址
因为是初次使用,所以我这里先全部引用,并没有使用官网下面介绍的按需引用的方法

安装

npm i element-ui -S

项目中 main.js 文件中引用

import Vue from 'vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'

Vue.use(ElementUI)

/* eslint-disable no-new */
new Vue({
  el: '#app',
  render: h => h(App)
})

在这里插入图片描述

2. 解决一个页面多个 Upload 组件,出现 “上传成功之后无法判断是哪个组件” 的问题

官网地址

源码和相应部分页面截图,当前页面有三个上传组件
在这里插入图片描述在这里插入图片描述

解决思路:

给【选取文件】这个按钮绑了个点击事件 ,多用了个变量 uploadSign 做标记 成功的时候判断标记 uploadSign 相应的值就好了

实现的源码

<template>
  <div>
    <el-form>
      <el-form-item label="身份证正面">
        <el-row :gutter="30">
          <el-col :span="8">
            <div class="grid-content">
              <el-upload
                class="upload-demo"
                ref="frontPic"
                accept="image/png, image/jpeg"
                name="imgPath"
                :action="imgUploadAPI"
                :before-upload="beforeAvatarUpload"
                :on-success="handleSuccess"
                :limit="1"
                :on-exceed="handleExceed"
                list-type="picture">
                <el-button size="small" type="primary" @click="uploadSign=1">选取文件</el-button>
                <div slot="tip" class="el-upload__tip">只能上传jpg/png文件</div>
              </el-upload>
            </div>
          </el-col>
          <el-col :span="8">
            <div class="grid-content">
              <img class="show-img" src="@/assets/img/frontPic.png" alt="样图" />
            </div>
          </el-col>
        </el-row>
      </el-form-item>
      <el-form-item label="身份证背面">
        <el-row :gutter="30">
          <el-col :span="8">
            <div class="grid-content">
              <el-upload
                class="upload-demo"
                ref="reversePic"
                accept="image/png, image/jpeg"
                name="imgPath"
                :action="imgUploadAPI"
                :before-upload="beforeAvatarUpload"
                :on-success="handleSuccess"
                :limit="1"
                :on-exceed="handleExceed"
                list-type="picture">
                <el-button size="small" type="primary" @click="uploadSign=2">选取文件</el-button>
                <div slot="tip" class="el-upload__tip">只能上传jpg/png文件</div>
              </el-upload>
            </div>
          </el-col>
          <el-col :span="8">
            <div class="grid-content">
              <img class="show-img" src="@/assets/img/reversePic.png" alt="样图" />
            </div>
          </el-col>
        </el-row>
      </el-form-item>
      <el-form-item label="身份证SIM卡手持">
        <el-row :gutter="30">
          <el-col :span="8">
            <div class="grid-content">
              <el-upload
                class="upload-demo"
                ref="handPic"
                accept="image/png, image/jpeg"
                name="imgPath"
                :action="imgUploadAPI"
                :before-upload="beforeAvatarUpload"
                :on-success="handleSuccess"
                :limit="1"
                :on-exceed="handleExceed"
                list-type="picture">
                <el-button size="small" type="primary" @click="uploadSign=3">选取文件</el-button>
                <div slot="tip" class="el-upload__tip">只能上传jpg/png文件</div>
              </el-upload>
            </div>
          </el-col>
          <el-col :span="8">
            <div class="grid-content">
              <img class="show-img" src="@/assets/img/handPic.png" alt="样图" />
            </div>
          </el-col>
        </el-row>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
import qs from 'qs' // 解决 axios 数据提交格式与后台不一致的问题  -> name=hehe&age=10
import { Loading } from 'element-ui'

export default {
  name: 'App',
  data() {
    return {
      // 多个上传组件标记  1 身份证正面;2 身份证背面;3 省份证SIM卡手持
      uploadSign: null,
      // 图片上传接口
      imgUploadAPI: '/jjhServerApi/ab/imgPath',
      // 信息提交接口
      postAPI: '/jjhServerApi/ab/insertposn',
      // 信息提交数据
      postData: {
        /**
         * name 姓名
         * department 部门
         * phoneNumber 手机号码
         * position 职位
         * certCode 证件号  身份证号
         * companyId 公司Id
         * frontPic 身份证正面
         * reversePic 身份证反面
         * handPic 手持身份证
         * lastOperation 该记录最后操作   A:添加操作,D:设置为离职操作
         */
        name: '',
        phoneNumber: '',
        department: '',
        position: '',
        certCode: '',
        companyId: '1', // 先写一个假数据
        frontPic: '',
        reversePic: '',
        handPic: '',
        lastOperation: 'A'
      }
  },
  methods: {
    // 上传文件之前的钩子,参数为上传的文件,若返回 false 或者返回 Promise 且被 reject,则停止上传。
    // 判断上传文件类型
    beforeAvatarUpload: function(file) {
      const me = this
      const isJPG = file.type === 'image/jpeg'
      const isPNG = file.type === 'image/png'
      if (!(isJPG || isPNG)) {
        me.$message.error('上传的文件只能是 JPG 或者是 PNG 格式的')
      }
    },
    // 文件超出个数限制时的钩子
    handleExceed(file, fileList) {
      const me = this
      me.$message.warning('只能上传一个文件')
    },
    // 文件上传成功时的钩子
    handleSuccess(res, file) {
      const me = this
      const sign = me.uploadSign
      // 判断 code 是否为  0    0 代表成功
      if (res.code === 0) {
        // 通过 sign 判断给相应的字段赋值
        if (sign === 1) {
          // 正面
          me.postData.frontPic = JSON.parse(res.result).url
        } else if (sign === 2) {
          // 背面
          me.postData.reversePic = JSON.parse(res.result).url
        } else if (sign === 3) {
          // 手持
          me.postData.handPic = JSON.parse(res.result).url
        }
      } else {
        // 失败回调
        me.$message.error(`${res.info}`)
        // 通过 sign 判断清空相应的列表 因为默认会显示出图片其实是失败了,容易造成用户误解
        if (sign === 1) {
          // 正面
          me.$refs.frontPic.clearFiles()
        } else if (sign === 2) {
          // 背面
          me.$refs.reversePic.clearFiles()
        } else if (sign === 3) {
          // 手持
          me.$refs.handPic.clearFiles()
        }
      }
      // 清空标记
      me.uploadSign = null
    }
  }
}
</script>

效果 gif 图

在这里插入图片描述

3.加粗样式 form 表单验证规则

官网地址

效果 gif 图
在这里插入图片描述

直接上源码了,除了正则表达式大多都是官网示例的东西,还有就是 upload 上传插件是我手写的规则验证的;
因为 upload 上传成功后的删除图标是后面生成的,且 :on-remove 给的方法如果自定义参数的话,就不能正常使用了,所以使用了三个不同的方法来定义删除成功后的钩子

<template>
  <div class="container">
    <el-form ref="dataForm" :model="postData" :rules="rules" label-width="180px">
      <el-form-item label="员工姓名" prop="name">
        <el-input v-model="postData.name" type="text" placeholder="请输入员工姓名" autofocus=""></el-input>
      </el-form-item>
      <el-form-item label="手机号码" prop="phoneNumber">
        <el-input v-model="postData.phoneNumber" type="text" placeholder="请输入手机号码"></el-input>
      </el-form-item>
      <el-form-item label="部门" prop="department">
        <el-select v-model="postData.department" placeholder="请选择部门">
          <el-option label="管理层" value="管理层"></el-option>
          <el-option label="研发部" value="研发部"></el-option>
          <el-option label="市场部" value="市场部"></el-option>
          <el-option label="行政部" value="行政部"></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="职位" prop="position">
        <el-input v-model="postData.position" type="text" placeholder="请输入职位"></el-input>
      </el-form-item>
      <el-form-item label="身份证号" prop="certCode">
        <el-input v-model="postData.certCode" type="text" placeholder="请输入身份证号"></el-input>
      </el-form-item>
      <el-form-item label="身份证正面">
        <el-row :gutter="30">
          <el-col :span="11">
            <div class="grid-content">
              <el-upload
                class="upload-demo"
                ref="frontPic"
                accept="image/png, image/jpeg"
                name="imgPath"
                :action="imgUploadAPI"
                :before-upload="beforeAvatarUpload"
                :on-success="handleSuccess"
                :before-remove="beforeRemove"
                :on-remove="handleRemoveFront"
                :limit="1"
                :on-exceed="handleExceed"
                list-type="picture">
                <el-button size="small" type="primary" @click="uploadSign=1">选取文件</el-button>
                <div slot="tip" class="el-upload__tip">只能上传jpg/png文件</div>
              </el-upload>
            </div>
          </el-col>
          <el-col :span="12">
            <div class="grid-content">
              <img class="show-img" src="@/assets/img/frontPic.png" alt="样图" />
            </div>
          </el-col>
        </el-row>
      </el-form-item>
      <el-form-item label="身份证背面">
        <el-row :gutter="30">
          <el-col :span="11">
            <div class="grid-content">
              <el-upload
                class="upload-demo"
                ref="reversePic"
                accept="image/png, image/jpeg"
                name="imgPath"
                :action="imgUploadAPI"
                :before-upload="beforeAvatarUpload"
                :on-success="handleSuccess"
                :before-remove="beforeRemove"
                :on-remove="handleRemoveReverse"
                :limit="1"
                :on-exceed="handleExceed"
                list-type="picture">
                <el-button size="small" type="primary" @click="uploadSign=2">选取文件</el-button>
                <div slot="tip" class="el-upload__tip">只能上传jpg/png文件</div>
              </el-upload>
            </div>
          </el-col>
          <el-col :span="12">
            <div class="grid-content">
              <img class="show-img" src="@/assets/img/reversePic.png" alt="样图" />
            </div>
          </el-col>
        </el-row>
      </el-form-item>
      <el-form-item label="身份证SIM卡手持">
        <el-row :gutter="30">
          <el-col :span="11">
            <div class="grid-content">
              <el-upload
                class="upload-demo"
                ref="handPic"
                accept="image/png, image/jpeg"
                name="imgPath"
                :action="imgUploadAPI"
                :before-upload="beforeAvatarUpload"
                :on-success="handleSuccess"
                :before-remove="beforeRemove"
                :on-remove="handleRemoveHand"
                :limit="1"
                :on-exceed="handleExceed"
                list-type="picture">
                <el-button size="small" type="primary" @click="uploadSign=3">选取文件</el-button>
                <div slot="tip" class="el-upload__tip">只能上传jpg/png文件</div>
              </el-upload>
            </div>
          </el-col>
          <el-col :span="12">
            <div class="grid-content">
              <img class="show-img" src="@/assets/img/handPic.png" alt="样图" />
            </div>
          </el-col>
        </el-row>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="submitForm('dataForm')">立即提交</el-button>
    <el-button @click="resetForm('dataForm')">重置</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
import qs from 'qs' // 解决 axios 数据提交格式与后台不一致的问题  -> name=hehe&age=10
import { Loading } from 'element-ui'

export default {
  name: 'App',
  data() {
    return {
      // 多个上传组件标记  1 身份证正面;2 身份证背面;3 省份证SIM卡手持
      uploadSign: null,
      // 图片上传接口
      imgUploadAPI: '/jjhServerApi/ab/imgPath',
      // 信息提交接口
      postAPI: '/jjhServerApi/ab/insertposn',
      // 信息提交数据
      postData: {
        /**
         * name 姓名
         * department 部门
         * phoneNumber 手机号码
         * position 职位
         * certCode 证件号  身份证号
         * companyId 公司Id
         * frontPic 身份证正面
         * reversePic 身份证反面
         * handPic 手持身份证
         * lastOperation 该记录最后操作   A:添加操作,D:设置为离职操作
         */
        name: '',
        phoneNumber: '',
        department: '',
        position: '',
        certCode: '',
        companyId: '1', // 先写一个假数据
        frontPic: '',
        reversePic: '',
        handPic: '',
        lastOperation: 'A'
      },
      // 表单定义验证规则   trigger 为触发条件 http://element-cn.eleme.io/#/zh-CN/component/form#biao-dan-yan-zheng   官网地址
      rules: {
        // 姓名
        name: [{ required: true, message: '请输入员工姓名', trigger: 'blur' }],
        // 手机号码
        phoneNumber: [
          { required: true, message: '请输入手机号码', trigger: 'blur' },
          {
            validator: function(rule, value, callback) {
              var MobileRegex = /^(13[0-9]|147|15[0-9]|17[0-9]|18[0-9])\d{8}$/
              if (!MobileRegex.test(value)) {
                callback(new Error('手机号码格式不正确!'))
              } else {
                callback()
              }
            },
            trigger: 'blur'
          }
        ],
        // 选择部门
        department: [
          {
            required: true,
            message: '请选择您的部门',
            trigger: 'change'
          }
        ],
        // 职位
        position: [{ required: true, message: '请输入职位', trigger: 'blur' }],
        // 身份证号
        certCode: [
          { required: true, message: '请输入身份证号', trigger: 'blur' },
          {
            validator: function(rule, value, callback) {
              var MobileRegex = /(^\d{18}$)|(^\d{17}(\d|X|x)$)/
              if (!MobileRegex.test(value)) {
                callback(new Error('身份证号格式不正确!'))
              } else {
                callback()
              }
            },
            trigger: 'blur'
          }
        ]
      }
    }
  },
  methods: {
    // 上传文件之前的钩子,参数为上传的文件,若返回 false 或者返回 Promise 且被 reject,则停止上传。
    beforeAvatarUpload: function(file) {
      // 判断上传文件类型
      const me = this
      const isJPG = file.type === 'image/jpeg'
      const isPNG = file.type === 'image/png'
      if (!(isJPG || isPNG)) {
        me.$message.error('上传的文件只能是 JPG 或者是 PNG 格式的')
      }
    },
    // 文件超出个数限制时的钩子
    handleExceed(file, fileList) {
      const me = this
      me.$message.warning('只能上传一个文件')
    },
    // 文件上传成功时的钩子
    handleSuccess(res, file) {
      const me = this
      const sign = me.uploadSign
      // 判断接口返回的 code 是否为  0    0 代表成功
      if (res.code === 0) {
        // 通过 sign 判断给相应的字段赋值
        if (sign === 1) {
          // 正面
          me.postData.frontPic = JSON.parse(res.result).url
        } else if (sign === 2) {
          // 背面
          me.postData.reversePic = JSON.parse(res.result).url
        } else if (sign === 3) {
          // 手持
          me.postData.handPic = JSON.parse(res.result).url
        }
      } else {
        // 失败回调
        me.$message.error(`${res.info}`)
        // 通过 sign 判断清空相应的列表 因为默认会显示出图片其实是失败了,容易造成用户误解
        if (sign === 1) {
          // 正面
          me.$refs.frontPic.clearFiles()
        } else if (sign === 2) {
          // 背面
          me.$refs.reversePic.clearFiles()
        } else if (sign === 3) {
          // 手持
          me.$refs.handPic.clearFiles()
        }
      }
      // 清空标记
      me.uploadSign = null
    },
    // 删除文件之前的钩子,参数为上传的文件和文件列表,若返回 false 或者返回 Promise 且被 reject,则停止上传。
    beforeRemove(file, fileList) {
      // 增加一个询问框
      return this.$confirm(`确定移除 ${file.name}?`)
    },
    // 文件列表移除文件时的钩子 因为是三个组件所以便分开写了三个方法,写成一个带参数的试过了不行
    handleRemoveFront(file, fileList) {
      const me = this
      me.postData.frontPic = ''
    },
    handleRemoveReverse(file, fileList) {
      const me = this
      me.postData.reversePic = ''
    },
    handleRemoveHand(file, fileList) {
      const me = this
      me.postData.handPic = ''
    },
    // 提交数据
    submitForm(formName) {
      const me = this
      this.$refs[formName].validate(valid => {
        // 通过插件自定义全部规则已验证通过
        if (valid) {
          if (!me.postData.frontPic) {
            me.$message.error('请上传您的身份证正面图片')
            return false
          }
          if (!me.postData.reversePic) {
            me.$message.error('请上传您的身份证反面图片')
            return false
          }
          if (!me.postData.handPic) {
            me.$message.error('请上传您的身份证SIM卡手持图片')
            return false
          }
          let loading = Loading.service({
            fullscreen: true,
            text: '正在请求服务器'
          })
          me.axios
            .post(me.postAPI, qs.stringify(me.postData))
            .then(response => {
              loading.close()
              const getData = response.data
              // code 为 0 表示成功
              if (getData.code === 0) {
                me.$message.success(`${getData.info},即将自动跳转至列表页面`)
                // 新增成功跳转至 【通讯录管理】页面
                setTimeout(function() {
                  location.href = 'addresslist.html'
                }, 2000)
              } else {
                me.$message.error(getData.info)
              }
            })
            .catch(error => {
              console.log(error)
              me.$message.error('请求服务器失败了,请稍后重试!')
            })
        } else {
          console.log('error submit!!')
          return false
        }
      })
    },
    // 重置表单
    resetForm(formName) {
      const me = this
      this.$refs[formName].resetFields()
      // 清空上传的文件
      // 正面
      me.$refs.frontPic.clearFiles()
      // 背面
      me.$refs.reversePic.clearFiles()
      // 手持
      me.$refs.handPic.clearFiles()
      me.postData.frontPic = ''
      me.postData.reversePic = ''
      me.postData.handPic = ''
    }
  }
}
</script>

<style lang="less">
body {
  .container {
    form {
      width: 700px;
      margin: 0 auto;
      .show-img {
        width: 300px;
        max-width: 100%;
      }
    }
  }
}
</style>

    主要演示下删除上传成功后的效果 gif

   ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190328092329506.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQyNDU1NzEw,size_16,color_FFFFFF,t_70)

    优化将 frontPic reversePic handPic 这三个字段用一个数组包着, sign 就不用在搞那么多的判断了,这样的话就是 0 1 2,下面是三个代码片段
```python
// 三个上传字段写个数组方便下面使用,就不用一个一个的判断 uploadSign 的值了,直接 me.postData[me.uploadSignString[me.uploadSign]] 即可
      uploadSignString: ['frontPic', 'reversePic', 'handPic'],

// 通过 [me.uploadSignString[me.uploadSign]] 判断给相应的字段赋值
        me.postData[me.uploadSignString[me.uploadSign]] = JSON.parse(
          res.result
        ).url

// 通过 sign 判断清空相应的列表 因为默认会显示出图片其实是失败了,容易造成用户误解
        me.$refs[me.uploadSignString[me.uploadSign]].clearFiles()

在这里插入图片描述
在这里插入图片描述

  1. 使用 vue-cli3.x 时,引用 element-ui 的 css 文件报错

    报错截图
    在这里插入图片描述

These dependencies were not found:

* fonts/element-icons.ttf in ./node_modules/css-loader??ref--6-oneOf-3-1!./node_modules/postcss-loader/src??ref--6-oneOf-3-2!./node_modules/element-ui/lib/theme-chalk/index.css
* fonts/element-icons.woff in ./node_modules/css-loader??ref--6-oneOf-3-1!./node_modules/postcss-loader/src??ref--6-oneOf-3-2!./node_modules/element-ui/lib/theme-chalk/index.css

To install them, you can run: npm install --save fonts/element-icons.ttf fonts/element-icons.woff

解决错误

问题 github 参考链接
出现错误的主要原因是在 vue.config.js 配置文件中设置了 css.modules = true,这个默认的值为 false ,只要把这个设置去掉问题即可得到解决

4. 使用分页 el-pagination 时,如果没加 :total 属性的话,即使用了 pager 这个 list 也显示不出来

出现问题的代码(我的 html 代码使用的是 pug 模板)

el-pagination(v-if="cusCrmList.total > 11" @current-change="clientPaginationHandle" :page-size="cusCrmList.size" layout="prev, pager, next, slot, jumper" :current-page.sync="cusCrmList.current" background small prev-text="上一页" next-text="下一页" align="right")
        span.el-pagination__total 共 {{ cusCrmList.pages }} 页```

    因为我不需要展示总页数,所以便没加 :total 属性,但是这样的话,分页的 pager 部分就展示不出来了,后来试了试,发现是没加这个的原因,下面是可以正常显示的代码
```python
el-pagination(v-if="cusCrmList.total > 11" @current-change="clientPaginationHandle" :page-size="cusCrmList.size" layout="prev, pager, next, slot, jumper" :current-page.sync="cusCrmList.current" :total="cusCrmList.total" background small prev-text="上一页" next-text="下一页" align="right")
        span.el-pagination__total 共 {{ cusCrmList.pages }}

5. 使用 v-loading 时,需要给其父级增加相对定位 position: relative

偶然性 Bug 出现在 IE 上面(本地开发会出现,线上暂未见到),大致就是在某一次强制刷新页面的时候,由于 loading 的原因,遮住了部分的页面,页面会出现多个错位的 loading 导致布局看起来有些错乱,刷新也没有用,只能重新打开当前页面,后来发现使用 v-loading 自动生成的类名是 el-loading-mask 的标签样式如下

.el-loading-mask {
    position: absolute;
    z-index: 2000;
    background-color: rgba(255, 255, 255, 0.9);
    margin: 0;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    -webkit-transition: opacity 0.3s;
    transition: opacity 0.3s;
}

虽然正常情况是标签 display: none 了,但是这里的 Bug 就是在异常情况下(没有隐藏掉),样式如上所示为 绝对定位 ,但是由于父级没给 相对定位 ,所以这里是相对于 body 去决定定位的,所以这个 el-loading-mask 的位置是总在页面最顶部,给加 v-loading 标签的父级加上 相对定位 -> position: relative ,这样的话及时出现 loading 未隐藏的 Bug 也不会影响页面的正常布局

6. 使用 dropdown、dropdown-menu、dropdown-item 实现点击下拉子菜单更改数据的需求
在这里插入图片描述

官方实例参考地址
官网示例使用的 command=“a” 属性的值是 string,从下面的文档中可以看到这个指令支持 类型:string/number/object,我这里需要使用 object 类型的值
object 类型使用示例的主要源码:

<template lang="pug">
el-dropdown(:show-timeout="0" @command="filtersStateHandle")
                span(class="filter-state-title") 状态
                  i(class="el-icon-arrow-down el-icon--right")
                el-dropdown-menu(slot="dropdown")
                  el-dropdown-item(v-for="(item,index) in filtersStateData" :key="item.value" :command="{ value: item.value }" :class="{ 'filter-state-active': item.value === signFilterData.getServState }") {{ item.text }}
                template(slot-scope="scope")
                  span {{ scope.row.GET_SERV_STATE }}
</template>

<script>
export default {
  data() {
    return {
      // 【状态】字段下来使用的数据
      filtersStateData: [
        { text: "全部", value: "ALL" },
        { text: "正常", value: "F0A" },
        { text: "主动停机", value: "F0I" },
        { text: "欠费双向停机", value: "F0K" },
        { text: "拆机", value: "F1X" }
      ],
    }
  },
  methods:{
    /**
     * 右侧 header 【状态】 下拉筛选子列表点击回调
     * @param {object} command 当前点击的元素 key 为 command 的对象值
     */
    filtersStateHandle(command) {
      // console.log(command);
      const me = this;

      // 数据变化
      me.signFilterData.getServState = command.value;
      me.getProductDyList();
    },  
  } 
}
<script>

<style lang="stylus" scoped>
.el-dropdown-menu
  .filter-state-active
    background-color #ecf3ff
    color #659bfe
</style>

小礼物走一走,来简书关注我

猜你喜欢

转载自blog.csdn.net/qq_42455710/article/details/88862115