element-ui 实战各种小技巧(长期更新)

资料

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

image.png

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

官网地址

  • 源码和相应部分页面截图,当前页面有三个上传组件
image.png

image.png
  • 解决思路:

给【选取文件】这个按钮绑了个点击事件 ,多用了个变量 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 图
Animation49.gif

3. form 表单验证规则

官网地址

  • 效果 gif 图
Animation50.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
Animation51.gif
  • 优化将 frontPic reversePic handPic 这三个字段用一个数组包着, sign 就不用在搞那么多的判断了,这样的话就是 0 1 2,下面是三个代码片段
// 三个上传字段写个数组方便下面使用,就不用一个一个的判断 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()
image.png

image.png

3. 使用 vue-cli3.x 时,引用 element-uicss 文件报错

  • 报错截图
image.png
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 部分就展示不出来了,后来试了试,发现是没加这个的原因,下面是可以正常显示的代码
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 实现点击下拉子菜单更改数据的需求

  • 效果 Gif 图
Dropdown Menu使用效果图.gif
<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>

7. 当使用 v-if v-else 进行两个 el-table 数据判断,数据切换时会报错

  • 报错信息如下
Error in render: "TypeError: _self.$scopedSlots.default is not a function"
  • 原因

是由于两个 el-table 组件使用了相同的数据导致

  • 解决方法

给两个 el-table 组价分别增加一个不同的 key 属性值

8. 当使用 pug 模板进行布局时,table 的排序 sortable 功能无法使用

  1. 这个问题真的是很怪异,翻阅了 github 的 Issues 列表幸好查到了相关的问题文章

issues 链接:[Bug Report] el-table can not sort with Pug template language used. #11531
上述人员提供的成功在线 demo

  1. 主要就是写法和官网的有些差异
代码截图
sortable 写成 :sortable='true' 即可

9. 引用 element-ui 中的 Tree 组件时,在 IE 浏览器中会报错

  1. 错误重现
  • 浏览器版本 IE11
  • 报错截图
    报错截图
  • 示例源码
    <el-tree ref="treeDOM" :data="treeData" show-checkbox
                             node-key="id" default-expand-all
                             :expand-on-click-node="false">
            <span class="custom-tree-node" slot-scope="{ node, data }">{{ data.name }} ({{ data.roleName }})
            </span>
                    </el-tree>
    
  1. 百度之后找到可参考的文章

vue在IE浏览器下报错Failed to generate render function:SyntaxError: 缺少标识符 in

  1. 解决思路

看到这个错误提示的时候,其实我没想到会是 Tree 组件的问题,主要是参考上面的文章,测试之后发现确实是这个组件的写法导致的错误;
主要的原因是 slot-scope="{ node, data }" 这个是 es6 的对象解构赋值,很显然 IE 是不支持的,具体的纠错方法是将 slot-scope 属性的值写成 scope 这个对象,然后后面使用 scope.node 或者 scope.data 的写法去调用子属性即可。

  • 示例源码
    <el-tree ref="treeDOM" :data="treeData" show-checkbox
                             node-key="id" default-expand-all
                             :expand-on-click-node="false">
            <span class="custom-tree-node" slot-scope="scope">{{ scope.data.name }} ({{ scope.data.roleName }})
            </span>
                    </el-tree>
    

10. el-table -> el-table-columnrender-header 属性使用示例

  • 需求:表头需要定制为换行的风格
  • 实现:使用 render-header 属性,下面是相应的 htmljavascript 代码片段
el-table-column(prop="" label="第一行的文本,第二行的文本" show-overflow-tooltip :render-header="renderHeaderHtml")
    renderHeaderHtml(h, { column, $index }){
      const stringArray = column.label.split(',')
      return h('p', [
        h('span', stringArray[0]),
        h('br'),
        h('span', stringArray[1])
     ])
    }

11. el-cascader ,封装一个公用的组件

  • 组件的完整源码,这个组件是
<template lang="pug">
//- 基于 el-cascader 组件,自定义一个角色结构树组件
.identity-tree
  //- 是否保留清空方法待定 clearable
  el-cascader(ref="identityTree" v-model="selectedOptions" :props="{ checkStrictly: true,lazy: true,lazyLoad: loadHandleNode,leaf: 'isLeaf', label: 'orgnName', value: 'orgnId'}" :show-all-levels="false" @change="cascaderHandleChange" filterable placeholder="请选择" size="mini")
</template>

<script>
// api
import { getSysOrgnInfo } from "@/api/common";

export default {
  name: "IdentityTree",
  data() {
    return {
      selectedOptions: [],
      // 储存转换后的当前用户信息
      currentUserInfo: {}
    };
  },
  methods: {
    /**
     * 查询部门下拉树结构
     * id 如果有传 id 值,表示这里请求的是子级的数据,返回一个 peomise,否则表示是一级数据直接返回
     */
    getSysOrgnInfo(orgnId) {
      // 判断如果传的是 "" 值,表示这里是需要初始化最初的用户身份,否则正常请求接口
      if (orgnId) {
        // 获取下级的列表数据
        return new Promise(resolve => {
          getSysOrgnInfo({
            orgnSumId: orgnId
          }).then(res => {
            let saveData = res.data.data;
            console.log(saveData);
            // 手动将 isLeaf 字段转换成 Boolean 值
            saveData.forEach(element => {
              element.isLeaf = !!element.isLeaf;
            });
            resolve(saveData);
          });
        });
      } else {
        // 获取当前用户身份的数据
        return new Promise(resolve => {
          let { currentManagerTm } = JSON.parse(
            JSON.stringify(this.$store.getters.getUserInfo)
          );
          currentManagerTm.orgnName = currentManagerTm.areaName;
          currentManagerTm.orgnId = currentManagerTm.areaId;

          // resolve([currentManagerTm]);
          // 直接传递当前用户信息
          // this.$emit("update-component-data", this.currentUserInfo);

          getSysOrgnInfo({
            sessionOrgnSumId: currentManagerTm.orgnId
          }).then(res => {
            let saveData = res.data.data;
            // 手动将 isLeaf 字段转换成 Boolean 值
            saveData.forEach(element => {
              element.isLeaf = !!element.isLeaf;
            });
            resolve(saveData);
            this.currentUserInfo = saveData[0];
            // 默认选中当前用户身份,并触发页面加载数据
            this.selectedOptions = [currentManagerTm.orgnId];
            this.$emit("update-component-data", saveData[0]);
          });
        });

        /*
        return new Promise(resolve => {
          let { currentManagerTm } = JSON.parse(
            JSON.stringify(this.$store.getters.getUserInfo)
          );
          getSysOrgnInfo({
            sessionOrgnSumId: currentManagerTm.areaId
          }).then(res => {
            let saveData = res.data.data;
            console.log(saveData);
            // 手动将 isLeaf 字段转换成 Boolean 值
            saveData.forEach(element => {
              element.isLeaf = !!element.isLeaf;
            });
            resolve(saveData);
            this.$emit("update-component-data", saveData);
          });
        });
        */
      }
    },
    /**
     * 部门节点加载函数
     */
    async loadHandleNode(node, resolve) {
      console.log(node.level);
      const data = await this.getSysOrgnInfo(
        node.level === 0 ? "" : node.data.orgnId
      );
      resolve(data);
    },
    /**
     * 选中弹窗内部的部门节点加载函数
     */
    cascaderHandleChange(value) {
      let $identityTree = this.$refs.identityTree;
      // 由于组件没有单选关闭悬浮窗的回调,所以需要手动关闭
      $identityTree.toggleDropDownVisible(false);
      if (value) {
        // 调用父组件方法,传递当前单选选中的身份对象
        const checkedNodes = $identityTree.getCheckedNodes();
        // 判断如果单选无选中值时,传递当前用户信息
        this.$emit(
          "update-component-data",
          checkedNodes.length ? checkedNodes[0].data : this.currentUserInfo
        );
      }
    }
  }
};
</script>

12. Uncaught ReferenceError: _MessageBox is not defined 浏览器控制台报错,错误导致应用无法正常显示

  • 这个错误之前从未遇到过,我什么都没改过,也不知道抽什么风 0.0
  • 参考文章:

https://github.com/ElementUI/babel-plugin-component/issues/31

  • 解决方法:

https://github.com/ElementUI/babel-plugin-component/issues/31#issuecomment-530874578

const msgbox = MessageBox
const { alert, confirm, prompt } = msgbox

Vue.prototype.$msgbox = msgbox
Vue.prototype.$alert = alert
Vue.prototype.$confirm = confirm
Vue.prototype.$prompt = prompt

13. el-form-item 自动验证的 Bug

  • 问题描述

首先页面是两个大的模块,由 if else 驱动其显示隐藏,,第二个模块中的一个表单元素在每次判断其显示时,会自动验证一下,而且提示还不是我自定义的文本

image.png

  • 参考资料

在dialog弹框里放一个form,form里面的一组checkbox加了change验证后,在第二次打开弹框及以后,每次打开dialog弹框,什么都没做,它就自动验证了 #3240
文章给出的解决方法是 this.$refs.baseForm.resetFields(); ,但是场景和我的有些差异。

  • 解决方法

将这个表单元素自身判断使用的 v-if ,放到作为其自动响应式布局的父级 el-row 即可。

14. el-select 绑定值为对象时使用 value-key 的示例

codepen 在线 demo
官方参考文档

<template>
  <el-select v-model="value" value-key="code" placeholder="请选择">
    <el-option-group
      v-for="group in options"
      :key="group.label"
      :label="group.label">
      <el-option
        v-for="item in group.child"
        :key="item.code"
        :label="item.label"
        :value="item">
      </el-option>
    </el-option-group>
  </el-select>
</template>

export default {
  data() {
      return {
        options:[
    {
        "code": "01",
        "label": "用户属性",
        "child": [
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01001001",
                "label": "用户邮箱",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01001002",
                "label": "用户名称",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01001003",
                "label": "用户ID",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01001004",
                "label": "用户归属省份",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01001005",
                "label": "用户归属地市",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01001006",
                "label": "用户归属区县",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01001007",
                "label": "用户归属渠道",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01001008",
                "label": "客户手机号",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01001009",
                "label": "客户ID",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01001010",
                "label": "客户名称",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "1",
                "inputFlag": "1",
                "code": "A01001011",
                "label": "注册时间",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01001012",
                "label": "注册渠道",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01001013",
                "label": "个人/企业",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01001015",
                "label": "所属行业",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "3",
                "inputFlag": "0",
                "code": "A01001016",
                "label": "是否实名",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01001017",
                "label": "实名认证类型",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "1",
                "inputFlag": "0",
                "code": "A01001018",
                "label": "实名认证时间",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01001019",
                "label": "性别",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01001020",
                "label": "年龄",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01001021",
                "label": "生日",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01001022",
                "label": "客户经理",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01001023",
                "label": "一人一码客户经理",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01001024",
                "label": "一人一码客户经理手机号",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "3",
                "inputFlag": "0",
                "code": "A01001026",
                "label": "是否一人一码注册用户(云大使注册)",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01001027",
                "label": "一人一码(云大使)二维码ID",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01001028",
                "label": "一人一码归属省",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01001029",
                "label": "一人一码归属地市",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01001030",
                "label": "一人一码归属区县",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01001031",
                "label": "运营商",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "3",
                "inputFlag": "0",
                "code": "A01002002",
                "label": "是否资源在用用户",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "3",
                "inputFlag": "0",
                "code": "A01002003",
                "label": "是否测试用户",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01002005",
                "label": "到期产品",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "1",
                "inputFlag": "0",
                "code": "A01002006",
                "label": "到期时间",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "3",
                "inputFlag": "0",
                "code": "A01002008",
                "label": "是否首次到期",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01002010",
                "label": "在网时长",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01003001",
                "label": "账户余额",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01003002",
                "label": "欠费金额",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "2",
                "code": "A01003003",
                "label": "欠费次数",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01003004",
                "label": "总出账金额",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01003005",
                "label": "近3月出账金额",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01003006",
                "label": "分产品出账金额",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01003010",
                "label": "充值金额",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01003013",
                "label": "充值方式",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01003015",
                "label": "累计充值次数",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01003016",
                "label": "累计充值金额",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01003017",
                "label": "累计欠费次数",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01003018",
                "label": "累计提现次数",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01003019",
                "label": "日均按需费用",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01004016",
                "label": "近30天充值次数",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "2",
                "code": "A01004017",
                "label": "近30天充值金额",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01004018",
                "label": "累计订单标准价",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01004019",
                "label": "累计订单降配实际价格",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01004020",
                "label": "累计订单实际价格",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01004021",
                "label": "累计订单现金金额",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01004022",
                "label": "累计降配次数",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01004023",
                "label": "累计降配订单标准价",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01004024",
                "label": "累计降配订单现金",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01004025",
                "label": "累计退订次数",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01004026",
                "label": "累计退订金额",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01004027",
                "label": "累计优惠券/代金券使用金额",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01005001",
                "label": "产品名称",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01005002",
                "label": "产品类型",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "1",
                "inputFlag": "0",
                "code": "A01005011",
                "label": "订单失效时间",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01005012",
                "label": "订单按需或包周期",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01005013",
                "label": "付费类型",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "3",
                "inputFlag": "0",
                "code": "A01005021",
                "label": "是否一人一码订单",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01006010",
                "label": "资源个数",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01006011",
                "label": "资源类型",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01006012",
                "label": "资源使用时长",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "1",
                "inputFlag": "0",
                "code": "A01006013",
                "label": "资源最晚到期时间",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01008001",
                "label": "优惠券/满折优惠券活动名称",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01008002",
                "label": "优惠券号",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01008003",
                "label": "优惠券名称",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "1",
                "inputFlag": "0",
                "code": "A01008004",
                "label": "优惠券领取时间",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01008005",
                "label": "优惠券金额",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "1",
                "inputFlag": "0",
                "code": "A01008007",
                "label": "优惠券到期时间",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01008009",
                "label": "优惠券使用金额",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01008013",
                "label": "优惠券使用条件",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01008014",
                "label": "优惠券发放目的",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01008016",
                "label": "满减折扣类型",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01008017",
                "label": "代金券号码",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "1",
                "inputFlag": "0",
                "code": "A01008019",
                "label": "代金券领取时间",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01008020",
                "label": "代金券金额",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "1",
                "inputFlag": "0",
                "code": "A01008022",
                "label": "代金券到期时间",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01008031",
                "label": "满折优惠券名称",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01008032",
                "label": "满折优惠券券号",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "1",
                "inputFlag": "0",
                "code": "A01008033",
                "label": "满折优惠券领取时间",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01008034",
                "label": "满折优惠券金额",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "1",
                "inputFlag": "0",
                "code": "A01008036",
                "label": "满折优惠券到期时间",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A01008038",
                "label": "满折优惠券使用金额",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01008042",
                "label": "满折优惠券使用条件",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01008054",
                "label": "折扣券发放目的",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009001",
                "label": "track",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009002",
                "label": "推广单元",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009003",
                "label": "推广关键词",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009004",
                "label": "推广渠道",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009005",
                "label": "引导登录页面名称",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009006",
                "label": "引导登录页面模块",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009007",
                "label": "引导登录注册模块",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009008",
                "label": "引导页面登录URL",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009009",
                "label": "引导页面注册URL",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009010",
                "label": "引导注册页面名称",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009011",
                "label": "注册访问来源(referer)",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009012",
                "label": "注册track",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009013",
                "label": "注册推广单元",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009014",
                "label": "注册推广计划",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009015",
                "label": "注册推广关键词",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009016",
                "label": "注册推广渠道",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009017",
                "label": "实名渠道",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009018",
                "label": "实名track",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009019",
                "label": "实名推广单元",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009020",
                "label": "实名推广计划",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009021",
                "label": "实名推广关键词",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009022",
                "label": "订单渠道",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009023",
                "label": "订单track",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009024",
                "label": "订单推广单元",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009025",
                "label": "订单推广计划",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01009026",
                "label": "订单推广关键词",
                "firstLevelCode": "01"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A01010002",
                "label": "实名认证状态",
                "firstLevelCode": "01"
            }
        ]
    },
    {
        "code": "02",
        "label": "用户行为",
        "child": [
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A02001016",
                "label": "访问来源(referer)",
                "firstLevelCode": "02"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A02001017",
                "label": "访问终端类型",
                "firstLevelCode": "02"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A02002001",
                "label": "近30天浏览页面名称",
                "firstLevelCode": "02"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A02003005",
                "label": "CPU使用率",
                "firstLevelCode": "02"
            },
            {
                "calculateFlag": "2",
                "inputFlag": "1",
                "code": "A02003006",
                "label": "内存使用率",
                "firstLevelCode": "02"
            },
            {
                "calculateFlag": "1",
                "inputFlag": "0",
                "code": "A02008001",
                "label": "最近登录时间",
                "firstLevelCode": "02"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A02009001",
                "label": "故障产品名称",
                "firstLevelCode": "02"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A02009002",
                "label": "故障解决满意度",
                "firstLevelCode": "02"
            },
            {
                "calculateFlag": "0",
                "inputFlag": "2",
                "code": "A02009004",
                "label": "故障原因",
                "firstLevelCode": "02"
            }
        ]
    }
],
        value: ''
      }
    }
}

15. el-cascader 在内部的 tags 单个标签删除时,getCheckedNodes 还是可以正常获取到删除之前的所有节点,导致处理数据时出现 bug

  • 解决方式

这里我将 watch 中的同步代码,改为异步,之后就能正常读取到,删除之后的所有标签了

  • 源码
// template => html
<el-cascader
            v-else-if="item.type === 'cascader'"
            v-model="basicInfo[item.name]"
            :ref="`${item.name}Cascader`"
            placeholder="全部"
            :options="commonData[item.selectKey]"
            :props="{
              multiple: true,
              checkStrictly: true,
              label: 'activityName',
              children: 'child',
              value: 'activityName'
            }"
            filterable
            collapse-tags
            clearable
          ></el-cascader>

// js => watch
    /**
     * 监测活动字段,手动赋值
     */
    'basicInfo.activeName': {
      handler(val) {
        // 同步会有 bug(tags 删除时,getCheckedNodes 还是可以正常获取到),所以做成异步的
        this.$nextTick(() => {
          if (
            this.$refs['activeNameCascader'] &&
            this.$refs['activeNameCascader'][0]
          ) {
            // 因为组件是在一个 `v-for`循环中生成的,所以需要使用 [0]
            const activeCascader = this.$refs['activeNameCascader'][0]
            const selectedData = this.$refs[
              'activeNameCascader'
            ][0].getCheckedNodes()

            // 初始化值时有两种情况:
            // 1 表头需要动态展示的 也就是 activityName 和 eventTypeName 设置为 null
            // 2 表头需要固定展示的
            let activityType = '',
              activityName = null,
              eventTypeName = null
            const { dataDetailShow, pageNavValue } = this
            if (
              dataDetailShow ||
              ['RelevanceBuyStatistics'].includes(pageNavValue)
            ) {
              activityName = eventTypeName = ''
            }

            // 有选中值才进行操作
            if (selectedData.length) {
              const levelOne = selectedData.filter((o) => {
                const { level, checked } = o
                return level === 1 && checked
              })
              if (levelOne.length) {
                activityType = levelOne
                  .map((element) => {
                    return element.value
                  })
                  .join(',')
              }

              const levelTwo = selectedData.filter((o) => {
                const { level, checked } = o
                return level === 2 && checked
              })
              if (levelTwo.length) {
                activityName = levelTwo
                  .map((element) => {
                    return element.value
                  })
                  .join(',')
              }

              const levelThree = selectedData.filter((o) => {
                const { level, checked } = o
                return level === 3 && checked
              })
              // levelThree 需要截取下划线之后的名称
              if (levelThree.length) {
                let resultFirstName = []
                levelThree.forEach((element) => {
                  const { value } = element
                  const index = value.indexOf('_')
                  if (index !== -1) {
                    resultFirstName.push(value.substring(index + 1))
                  }
                })
                eventTypeName = resultFirstName.join(',')
              }
            }
            // 赋值
            this.$set(this.basicInfo, 'activityType', activityType)
            this.$set(this.basicInfo, 'activityName', activityName)

            // 活动用户关联购买统计 字段名不同
            if (!['RelevanceBuyStatistics'].includes(pageNavValue)) {
              this.$set(this.basicInfo, 'eventTypeName', eventTypeName)
            } else {
              this.$set(this.basicInfo, 'activityFirstName', eventTypeName)
            }
          }
        })
      }
    }

16. el-table 自定义表头列表中某个单元格的样式

codepen 在线示例:element table 表头某个单元格样式自定义

  • 源码:
<template>
  <el-table
    :data="tableData"
    style="width: 100%"
  :header-cell-style="headerCellStyle">
    <el-table-column
      prop="date"
      label="各省"
      width="150">
    </el-table-column>
    <el-table-column label="宽带">
      <el-table-column
        prop="name"
        label="姓名"
        width="120">
      </el-table-column>
      <el-table-column label="移动">
        <el-table-column
          prop="province"
          label="省份"
          width="120">
        </el-table-column>
        <el-table-column
          prop="city"
          label="市区"
          width="120">
        </el-table-column>
        <el-table-column
          prop="address"
          label="地址"
          width="300">
        </el-table-column>
        <el-table-column
          prop="zip"
          label="邮编"
          width="120">
        </el-table-column>
      </el-table-column>
    </el-table-column>
  </el-table>
</template>

<script>
export default {
  data() {
    return {
      tableData: [
        {
          date: "2016-05-03",
          name: "王小虎",
          province: "上海",
          city: "普陀区",
          address: "上海市普陀区金沙江路 1518 弄",
          zip: 200333
        },
        {
          date: "2016-05-02",
          name: "王小虎",
          province: "上海",
          city: "普陀区",
          address: "上海市普陀区金沙江路 1518 弄",
          zip: 200333
        },
        {
          date: "2016-05-04",
          name: "王小虎",
          province: "上海",
          city: "普陀区",
          address: "上海市普陀区金沙江路 1518 弄",
          zip: 200333
        },
        {
          date: "2016-05-01",
          name: "王小虎",
          province: "上海",
          city: "普陀区",
          address: "上海市普陀区金沙江路 1518 弄",
          zip: 200333
        },
        {
          date: "2016-05-08",
          name: "王小虎",
          province: "上海",
          city: "普陀区",
          address: "上海市普陀区金沙江路 1518 弄",
          zip: 200333
        },
        {
          date: "2016-05-06",
          name: "王小虎",
          province: "上海",
          city: "普陀区",
          address: "上海市普陀区金沙江路 1518 弄",
          zip: 200333
        },
        {
          date: "2016-05-07",
          name: "王小虎",
          province: "上海",
          city: "普陀区",
          address: "上海市普陀区金沙江路 1518 弄",
          zip: 200333
        }
      ]
    };
  },
  methods: {
    /**
     * 自定义表头列表中某个单元格的样式
     */
    headerCellStyle({ column }) {
      const whitelist = ['各省', '宽带', '移动', '5G']
      if (!whitelist.includes(column.label)) {
        return {
          backgroundColor: 'red',
          color: '#333'
        }
      } else {
        return {}
      }
    }
  }
}
</script>

17. el-table 多列合并单元格,可以指定某列

codepen 在线示例:element table 多列合并单元格,可以指定某列

  • 源码:

<template>
  <div>
<!--   指定 count 取默认属性   -->
    <el-table
      :data="tableData"
      :span-method="arraySpanMethod"
      border
      style="width: 100%">
      <el-table-column
        prop="id"
        label="ID"
        width="180">
      </el-table-column>
      <el-table-column
        prop="name"
        label="姓名">
      </el-table-column>
      <el-table-column
        prop="amount1"
        sortable
        label="数值 1">
      </el-table-column>
      <el-table-column
        prop="amount2"
        sortable
        label="数值 2">
      </el-table-column>
      <el-table-column
        prop="amount3"
        sortable
        label="数值 3">
      </el-table-column>
    </el-table>
<hr />
<!--   指定 props   -->
    <el-table
      :data="tableData"
      :span-method="arraySpanMethod2"
      border
      style="width: 100%">
      <el-table-column
        prop="id"
        label="ID"
        width="180">
      </el-table-column>
      <el-table-column
        prop="name"
        label="姓名">
      </el-table-column>
      <el-table-column
        prop="amount1"
        sortable
        label="数值 1">
      </el-table-column>
      <el-table-column
        prop="amount2"
        sortable
        label="数值 2">
      </el-table-column>
      <el-table-column
        prop="amount3"
        sortable
        label="数值 3">
      </el-table-column>
    </el-table>

  </div>
</template>


<script>
export default {
  data() {
    return {
      tableData: [
        {
          id: "12987122",
          name: "王小1虎",
          amount1: "234",
          amount2: "3.2",
          amount3: 10
        },
        {
          id: "12987121",
          name: "王小虎",
          amount1: "324",
          amount2: "4.43",
          amount3: 12
        },
        {
          id: "12987125",
          name: "王小虎",
          amount1: "621",
          amount2: "1.9",
          amount3: 9
        },
        {
          id: "12987125",
          name: "王小21虎",
          amount1: "621",
          amount2: "2.2",
          amount3: 17
        },
        {
          id: "12987126",
          name: "王小2虎",
          amount1: "539",
          amount2: "2.2",
          amount3: 15
        }
      ],
      mergeResult: [],
      mergeResult2: [],
      props: ["name", "amount2"]
    };
  },
  created() {
    // 指定 count 取默认属性
    this.mergeResult = this.mergeColumnCells(this.tableData, 2);
    // 指定 props
    this.mergeResult2 = this.mergeColumnCells(this.tableData, 0, this.props);

    console.log(this.mergeResult);
    console.log(this.mergeResult2);
  },
  methods: {
    /**
     * 多列合并单元格,可以指定某列,下面的 count 和 props 参数,虽然都是非必须的,但是至少得保证有一个
     * @param {Array} data 需要处理的数据
     * @param {Number} count 非必须参数:需要合并单元格的列的总数量(满足从初始第一列至连续的 count 列的条件)
     * @param {Array} props 非必须参数:需要合并单元格的数据列对应的属性列表,示例:['id','name']
     * @returns {Array} 储存嵌套的每一列需要合并单元格的合并的格数,示例:[[1,1,2,0,1],[1,2,0,1,1]]
     * 两种不同方式的调用示例:
     * 指定 count 取默认属性:this.mergeResult = this.mergeColumnCells(this.tableData, 2);
     * 指定 props:this.mergeResult = this.mergeColumnCells(this.tableData, 0, this.props);
     * 完整的在线示例地址 [element table 多列合并单元格,可以指定某列](https://codepen.io/sunxiaochuan/pen/wvoOXzG)
     */
    mergeColumnCells(data, count, props) {
      if (data && data.length && (count || props)) {
        // 先获取到需要合并的属性列表
        props = props || [];
        // 不存在的话就依照 count 字段开始取默认名称
        if (!props.length) {
          for (const key in data[0]) {
            if (data[0].hasOwnProperty(key)) {
              props.push(key);
            }
            if (props.length === count) {
              break;
            }
          }
        }

        let saveData = [];
        for (let index = 0; index < props.length; index++) {
          const prop = props[index];
          // 设置初始化值
          saveData[index] = [];
          let dataList = saveData[index];
          // 标记属性值重复的位置
          let position;

          // 数据计算
          for (let i = 0; i < data.length; i++) {
            const element = data[i];
            // 逻辑:默认的第一条 i === 0 数据将初始化单元格数量为 1,并将标记位置初始为 0;从第二条 i === 1 数据开始与上一条数据做属性比较:一致的话被标记位置的单元格 += 1,相应的当前单元格需要置为 0;否则当前单元格为 1,并重新将当前的索引设置为初始标记位置
            if (i === 0) {
              dataList.push(1);
              position = 0;
            } else {
              // 判断与上一条数据对应的属性值是否一致,一致的话被标记位置的单元格 += 1,并设置当前的单元格为 0;否则当前单元格为 1,并重新将当前的索引设置为初始标记位置
              const prev = data[i - 1];
              if (element[prop] === prev[prop]) {
                dataList[position] += 1;
                dataList.push(0);
              } else {
                dataList.push(1);
                position = i;
              }
            }
          }
        }

        return saveData;
      } else {
        return [];
      }
    },
    arraySpanMethod({ row, column, rowIndex, columnIndex }) {
      if (columnIndex < 2) {
        const _row = this.mergeResult[columnIndex][rowIndex];
        return [_row, 1];
      }
    },
    //         指定 props
    arraySpanMethod2({ row, column, rowIndex, columnIndex }) {
      const index = this.props.indexOf(column.property);
      if (index != -1) {
        const _row = this.mergeResult2[index][rowIndex];
        return [_row, 1];
      }
    }
  }
}
</script>

18. el-table 多列排序

codepen 在线示例:element table 多列排序

  • 源码:
  <template>
    <el-table :data="tableData" style="width: 100%" :header-cell-class-name='handleHeadAddClass' @sort-change='tableSortChange'>
      <el-table-column prop="date" label="日期" sortable width="180">
      </el-table-column>
      <el-table-column prop="name" label="姓名" sortable width="180">
      </el-table-column>
      <el-table-column prop="address" label="地址">
      </el-table-column>
    </el-table>
  </template>

<script>
export default {
  data() {
    return {
      tableData: [
        {
          date: "2016-05-02",
          name: "李小虎",
          address: "上海市普陀区金沙江路 1518 弄"
        },
        {
          date: "2016-05-04",
          name: "王小虎",
          address: "上海市普陀区金沙江路 1517 弄"
        },
        {
          date: "2016-05-01",
          name: "安小虎",
          address: "上海市普陀区金沙江路 1519 弄"
        },
        {
          date: "2016-05-03",
          name: "王小虎",
          address: "上海市普陀区金沙江路 1516 弄"
        }
      ],
      sortPropList: {}
    };
  },
  methods: {
    /**
     * 报表所有表头都可以进行排序,1 升;2 降
     */
    tableSortChange({ column, prop, order }) {
      let sortType = undefined;
      switch (order) {
        case "ascending":
          sortType = "1";
          break;
        case "descending":
          sortType = "2";
          break;

        default:
          break;
      }
      this.sortPropList[prop] = order;
      // 获取数据
      // this.$set(sortProp, 'sortType', sortType)
      // this.submitFilterForm();
    },
    /**
     * 增加多列排序
     */
    handleHeadAddClass({ column }) {
      if (this.sortPropList[column.property]) {
        column.order = this.sortPropList[column.property];
      }
    }
  }
}
</script>

19. 自定义 el-pagination 组件中的的文本内容的方法

参考地址:[Feature Request] 分页栏的“前往___页”中的“前往”二字,应该改成“到第” #16030

  1. 新建一个 @/assets/locale/cn.js 文件,内容如下,具体参照 官方源码地址
export default {
  el: {
    colorpicker: {
      confirm: '确定',
      clear: '清空'
    },
    datepicker: {
      now: '此刻',
      today: '今天',
      cancel: '取消',
      clear: '清空',
      confirm: '确定',
      selectDate: '选择日期',
      selectTime: '选择时间',
      startDate: '开始日期',
      startTime: '开始时间',
      endDate: '结束日期',
      endTime: '结束时间',
      prevYear: '前一年',
      nextYear: '后一年',
      prevMonth: '上个月',
      nextMonth: '下个月',
      year: '年',
      month1: '1 月',
      month2: '2 月',
      month3: '3 月',
      month4: '4 月',
      month5: '5 月',
      month6: '6 月',
      month7: '7 月',
      month8: '8 月',
      month9: '9 月',
      month10: '10 月',
      month11: '11 月',
      month12: '12 月',
      // week: '周次',
      weeks: {
        sun: '日',
        mon: '一',
        tue: '二',
        wed: '三',
        thu: '四',
        fri: '五',
        sat: '六'
      },
      months: {
        jan: '一月',
        feb: '二月',
        mar: '三月',
        apr: '四月',
        may: '五月',
        jun: '六月',
        jul: '七月',
        aug: '八月',
        sep: '九月',
        oct: '十月',
        nov: '十一月',
        dec: '十二月'
      }
    },
    select: {
      loading: '加载中',
      noMatch: '无匹配数据',
      noData: '无数据',
      placeholder: '请选择'
    },
    cascader: {
      noMatch: '无匹配数据',
      loading: '加载中',
      placeholder: '请选择',
      noData: '暂无数据'
    },
    pagination: {
      goto: '前往',
      pagesize: '个用户/页',
      total: '共 {total} 个用户',
      pageClassifier: '页'
    },
    messagebox: {
      title: '提示',
      confirm: '确定',
      cancel: '取消',
      error: '输入的数据不合法!'
    },
    upload: {
      deleteTip: '按 delete 键可删除',
      delete: '删除',
      preview: '查看图片',
      continue: '继续上传'
    },
    table: {
      emptyText: '暂无数据',
      confirmFilter: '筛选',
      resetFilter: '重置',
      clearFilter: '全部',
      sumText: '合计'
    },
    tree: {
      emptyText: '暂无数据'
    },
    transfer: {
      noMatch: '无匹配数据',
      noData: '无数据',
      titles: ['列表 1', '列表 2'],
      filterPlaceholder: '请输入搜索内容',
      noCheckedFormat: '共 {total} 项',
      hasCheckedFormat: '已选 {checked}/{total} 项'
    },
    image: {
      error: '加载失败'
    },
    pageHeader: {
      title: '返回'
    },
    popconfirm: {
      confirmButtonText: '确定',
      cancelButtonText: '取消'
    }
  }
};

  1. main.js 中引用即可,参考 官方文档地址
import locale from '@/assets/locale/cn.js'
Vue.use(ElementUI, { locale })
  • 我这里主要修改的是分页的文本,显示结果如下图所示
image.png

后续

  1. 上面是修改全局统一配置的方法,但是我这个需求并不适用,还是需要局部自定义来实现的。下面是主要的代码部分
el-pagination(
  v-show='total > 0',
  @size-change='handleSizeChange',
  @current-change='handleCurrentChange',
  :current-page='tableParams.pageNum',
  :page-sizes='[1, 2, 3, 4, 5, 10, 20, 50, 100]',
  :page-size='tableParams.pageSize',
  layout='slot, prev, pager, next, jumper',
  :total='total'
)
  span.el-pagination__total 共 {{ total }} 个用户
  el-select(
    v-model='tableParams.pageSize',
    @change='handleSizeChange(tableParams.pageSize)',
    size='mini',
    placeholder='请选择'
  )
    el-option(
      v-for='item in pageSizeList',
      :key='item.value',
      :label='item.name',
      :value='item.value'
    )



      pageSizeList: [
        {
          name: '1个用户/页',
          value: 1
        },
        {
          name: '2个用户/页',
          value: 2
        },
        {
          name: '3个用户/页',
          value: 3
        },
        {
          name: '4个用户/页',
          value: 4
        },
        {
          name: '5个用户/页',
          value: 5
        },
        {
          name: '10个用户/页',
          value: 10
        },
        {
          name: '20个用户/页',
          value: 20
        },
        {
          name: '50个用户/页',
          value: 50
        },
        {
          name: '100个用户/页',
          value: 100
        }
      ]

20. el-form 组件自定义规则时,需要注意的地方

image.png

一定要在最后执行 callback(),否则在 this.$refs.ruleForm.validate((valid) => {}) 检验的时候,无法执行
{} 中的内容。

ruleFormRules: {
  userGroupName: [
    {
      validator: (rule, value, callback) => {
        if (value === '') {
          callback(new Error('请输入人群名称'))
        } else if (value.includes('_')) {
          callback(new Error('不能包含_'))
        } else {
          callback()
        }
      },
      trigger: 'blur'
    }
  ],
  updateType: [
    { required: true, message: '请选择更新方式', trigger: 'change' }
  ]
},

21. el-date-picker 组件动态更新 type 属性时,时间选择弹窗会出现错位的问题

  • 解决方法:增加一个 key 属性,我是与 type 值保持一致了

                    <el-date-picker
                      v-model="item.fieldValue"
                      :type="
                        item.type === '1'
                          ? dateDictionary.type[item.dropDatas.code]
                          : dateDictionary.singleType[item.dropDatas.code]
                      "
                      :value-format="dateDictionary.value[item.dropDatas.code]"
                      :picker-options="pickerOptions"
                      :key="
                        item.type === '1'
                          ? dateDictionary.type[item.dropDatas.code]
                          : dateDictionary.singleType[item.dropDatas.code]
                      "
                    />
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容