element-ui 中文官网
element-ui 官网组件使用指南

1. 项目中安装并引用 element-ui

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

  • 安装

    1. npm i element-ui -S
  • 项目中 main.js 文件中引用

    1. import Vue from 'vue'
    2. import ElementUI from 'element-ui'
    3. import 'element-ui/lib/theme-chalk/index.css'
    4. Vue.use(ElementUI)
    5. /* eslint-disable no-new */
    6. new Vue({
    7. el: '#app',
    8. render: h => h(App)
    9. })

    资料 - 图1

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

官网地址

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

    资料 - 图2 资料 - 图3

  • 解决思路:

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

  • 实现的源码

    1. <template>
    2. <div>
    3. <el-form>
    4. <el-form-item label="身份证正面">
    5. <el-row :gutter="30">
    6. <el-col :span="8">
    7. <div class="grid-content">
    8. <el-upload
    9. class="upload-demo"
    10. ref="frontPic"
    11. accept="image/png, image/jpeg"
    12. name="imgPath"
    13. :action="imgUploadAPI"
    14. :before-upload="beforeAvatarUpload"
    15. :on-success="handleSuccess"
    16. :limit="1"
    17. :on-exceed="handleExceed"
    18. list-type="picture">
    19. <el-button size="small" type="primary" @click="uploadSign=1">选取文件</el-button>
    20. <div slot="tip" class="el-upload__tip">只能上传jpg/png文件</div>
    21. </el-upload>
    22. </div>
    23. </el-col>
    24. <el-col :span="8">
    25. <div class="grid-content">
    26. <img class="show-img" src="@/assets/img/frontPic.png" alt="样图" />
    27. </div>
    28. </el-col>
    29. </el-row>
    30. </el-form-item>
    31. <el-form-item label="身份证背面">
    32. <el-row :gutter="30">
    33. <el-col :span="8">
    34. <div class="grid-content">
    35. <el-upload
    36. class="upload-demo"
    37. ref="reversePic"
    38. accept="image/png, image/jpeg"
    39. name="imgPath"
    40. :action="imgUploadAPI"
    41. :before-upload="beforeAvatarUpload"
    42. :on-success="handleSuccess"
    43. :limit="1"
    44. :on-exceed="handleExceed"
    45. list-type="picture">
    46. <el-button size="small" type="primary" @click="uploadSign=2">选取文件</el-button>
    47. <div slot="tip" class="el-upload__tip">只能上传jpg/png文件</div>
    48. </el-upload>
    49. </div>
    50. </el-col>
    51. <el-col :span="8">
    52. <div class="grid-content">
    53. <img class="show-img" src="@/assets/img/reversePic.png" alt="样图" />
    54. </div>
    55. </el-col>
    56. </el-row>
    57. </el-form-item>
    58. <el-form-item label="身份证SIM卡手持">
    59. <el-row :gutter="30">
    60. <el-col :span="8">
    61. <div class="grid-content">
    62. <el-upload
    63. class="upload-demo"
    64. ref="handPic"
    65. accept="image/png, image/jpeg"
    66. name="imgPath"
    67. :action="imgUploadAPI"
    68. :before-upload="beforeAvatarUpload"
    69. :on-success="handleSuccess"
    70. :limit="1"
    71. :on-exceed="handleExceed"
    72. list-type="picture">
    73. <el-button size="small" type="primary" @click="uploadSign=3">选取文件</el-button>
    74. <div slot="tip" class="el-upload__tip">只能上传jpg/png文件</div>
    75. </el-upload>
    76. </div>
    77. </el-col>
    78. <el-col :span="8">
    79. <div class="grid-content">
    80. <img class="show-img" src="@/assets/img/handPic.png" alt="样图" />
    81. </div>
    82. </el-col>
    83. </el-row>
    84. </el-form-item>
    85. </el-form>
    86. </div>
    87. </template>
    88. <script>
    89. import qs from 'qs' // 解决 axios 数据提交格式与后台不一致的问题 -> name=hehe&age=10
    90. import { Loading } from 'element-ui'
    91. export default {
    92. name: 'App',
    93. data() {
    94. return {
    95. // 多个上传组件标记 1 身份证正面;2 身份证背面;3 省份证SIM卡手持
    96. uploadSign: null,
    97. // 图片上传接口
    98. imgUploadAPI: '/jjhServerApi/ab/imgPath',
    99. // 信息提交接口
    100. postAPI: '/jjhServerApi/ab/insertposn',
    101. // 信息提交数据
    102. postData: {
    103. /**
    104. * name 姓名
    105. * department 部门
    106. * phoneNumber 手机号码
    107. * position 职位
    108. * certCode 证件号 身份证号
    109. * companyId 公司Id
    110. * frontPic 身份证正面
    111. * reversePic 身份证反面
    112. * handPic 手持身份证
    113. * lastOperation 该记录最后操作 A:添加操作,D:设置为离职操作
    114. */
    115. name: '',
    116. phoneNumber: '',
    117. department: '',
    118. position: '',
    119. certCode: '',
    120. companyId: '1', // 先写一个假数据
    121. frontPic: '',
    122. reversePic: '',
    123. handPic: '',
    124. lastOperation: 'A'
    125. }
    126. },
    127. methods: {
    128. // 上传文件之前的钩子,参数为上传的文件,若返回 false 或者返回 Promise 且被 reject,则停止上传。
    129. // 判断上传文件类型
    130. beforeAvatarUpload: function(file) {
    131. const me = this
    132. const isJPG = file.type === 'image/jpeg'
    133. const isPNG = file.type === 'image/png'
    134. if (!(isJPG || isPNG)) {
    135. me.$message.error('上传的文件只能是 JPG 或者是 PNG 格式的')
    136. }
    137. },
    138. // 文件超出个数限制时的钩子
    139. handleExceed(file, fileList) {
    140. const me = this
    141. me.$message.warning('只能上传一个文件')
    142. },
    143. // 文件上传成功时的钩子
    144. handleSuccess(res, file) {
    145. const me = this
    146. const sign = me.uploadSign
    147. // 判断 code 是否为 0 0 代表成功
    148. if (res.code === 0) {
    149. // 通过 sign 判断给相应的字段赋值
    150. if (sign === 1) {
    151. // 正面
    152. me.postData.frontPic = JSON.parse(res.result).url
    153. } else if (sign === 2) {
    154. // 背面
    155. me.postData.reversePic = JSON.parse(res.result).url
    156. } else if (sign === 3) {
    157. // 手持
    158. me.postData.handPic = JSON.parse(res.result).url
    159. }
    160. } else {
    161. // 失败回调
    162. me.$message.error(`${res.info}`)
    163. // 通过 sign 判断清空相应的列表 因为默认会显示出图片其实是失败了,容易造成用户误解
    164. if (sign === 1) {
    165. // 正面
    166. me.$refs.frontPic.clearFiles()
    167. } else if (sign === 2) {
    168. // 背面
    169. me.$refs.reversePic.clearFiles()
    170. } else if (sign === 3) {
    171. // 手持
    172. me.$refs.handPic.clearFiles()
    173. }
    174. }
    175. // 清空标记
    176. me.uploadSign = null
    177. }
    178. }
    179. }
    180. </script>
  • 效果 gif 图

    资料 - 图4

3. form 表单验证规则

官网地址

  • 效果 gif 图

    资料 - 图5

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

    1. <template>
    2. <div class="container">
    3. <el-form ref="dataForm" :model="postData" :rules="rules" label-width="180px">
    4. <el-form-item label="员工姓名" prop="name">
    5. <el-input v-model="postData.name" type="text" placeholder="请输入员工姓名" autofocus=""></el-input>
    6. </el-form-item>
    7. <el-form-item label="手机号码" prop="phoneNumber">
    8. <el-input v-model="postData.phoneNumber" type="text" placeholder="请输入手机号码"></el-input>
    9. </el-form-item>
    10. <el-form-item label="部门" prop="department">
    11. <el-select v-model="postData.department" placeholder="请选择部门">
    12. <el-option label="管理层" value="管理层"></el-option>
    13. <el-option label="研发部" value="研发部"></el-option>
    14. <el-option label="市场部" value="市场部"></el-option>
    15. <el-option label="行政部" value="行政部"></el-option>
    16. </el-select>
    17. </el-form-item>
    18. <el-form-item label="职位" prop="position">
    19. <el-input v-model="postData.position" type="text" placeholder="请输入职位"></el-input>
    20. </el-form-item>
    21. <el-form-item label="身份证号" prop="certCode">
    22. <el-input v-model="postData.certCode" type="text" placeholder="请输入身份证号"></el-input>
    23. </el-form-item>
    24. <el-form-item label="身份证正面">
    25. <el-row :gutter="30">
    26. <el-col :span="11">
    27. <div class="grid-content">
    28. <el-upload
    29. class="upload-demo"
    30. ref="frontPic"
    31. accept="image/png, image/jpeg"
    32. name="imgPath"
    33. :action="imgUploadAPI"
    34. :before-upload="beforeAvatarUpload"
    35. :on-success="handleSuccess"
    36. :before-remove="beforeRemove"
    37. :on-remove="handleRemoveFront"
    38. :limit="1"
    39. :on-exceed="handleExceed"
    40. list-type="picture">
    41. <el-button size="small" type="primary" @click="uploadSign=1">选取文件</el-button>
    42. <div slot="tip" class="el-upload__tip">只能上传jpg/png文件</div>
    43. </el-upload>
    44. </div>
    45. </el-col>
    46. <el-col :span="12">
    47. <div class="grid-content">
    48. <img class="show-img" src="@/assets/img/frontPic.png" alt="样图" />
    49. </div>
    50. </el-col>
    51. </el-row>
    52. </el-form-item>
    53. <el-form-item label="身份证背面">
    54. <el-row :gutter="30">
    55. <el-col :span="11">
    56. <div class="grid-content">
    57. <el-upload
    58. class="upload-demo"
    59. ref="reversePic"
    60. accept="image/png, image/jpeg"
    61. name="imgPath"
    62. :action="imgUploadAPI"
    63. :before-upload="beforeAvatarUpload"
    64. :on-success="handleSuccess"
    65. :before-remove="beforeRemove"
    66. :on-remove="handleRemoveReverse"
    67. :limit="1"
    68. :on-exceed="handleExceed"
    69. list-type="picture">
    70. <el-button size="small" type="primary" @click="uploadSign=2">选取文件</el-button>
    71. <div slot="tip" class="el-upload__tip">只能上传jpg/png文件</div>
    72. </el-upload>
    73. </div>
    74. </el-col>
    75. <el-col :span="12">
    76. <div class="grid-content">
    77. <img class="show-img" src="@/assets/img/reversePic.png" alt="样图" />
    78. </div>
    79. </el-col>
    80. </el-row>
    81. </el-form-item>
    82. <el-form-item label="身份证SIM卡手持">
    83. <el-row :gutter="30">
    84. <el-col :span="11">
    85. <div class="grid-content">
    86. <el-upload
    87. class="upload-demo"
    88. ref="handPic"
    89. accept="image/png, image/jpeg"
    90. name="imgPath"
    91. :action="imgUploadAPI"
    92. :before-upload="beforeAvatarUpload"
    93. :on-success="handleSuccess"
    94. :before-remove="beforeRemove"
    95. :on-remove="handleRemoveHand"
    96. :limit="1"
    97. :on-exceed="handleExceed"
    98. list-type="picture">
    99. <el-button size="small" type="primary" @click="uploadSign=3">选取文件</el-button>
    100. <div slot="tip" class="el-upload__tip">只能上传jpg/png文件</div>
    101. </el-upload>
    102. </div>
    103. </el-col>
    104. <el-col :span="12">
    105. <div class="grid-content">
    106. <img class="show-img" src="@/assets/img/handPic.png" alt="样图" />
    107. </div>
    108. </el-col>
    109. </el-row>
    110. </el-form-item>
    111. <el-form-item>
    112. <el-button type="primary" @click="submitForm('dataForm')">立即提交</el-button>
    113. <el-button @click="resetForm('dataForm')">重置</el-button>
    114. </el-form-item>
    115. </el-form>
    116. </div>
    117. </template>
    118. <script>
    119. import qs from 'qs' // 解决 axios 数据提交格式与后台不一致的问题 -> name=hehe&age=10
    120. import { Loading } from 'element-ui'
    121. export default {
    122. name: 'App',
    123. data() {
    124. return {
    125. // 多个上传组件标记 1 身份证正面;2 身份证背面;3 省份证SIM卡手持
    126. uploadSign: null,
    127. // 图片上传接口
    128. imgUploadAPI: '/jjhServerApi/ab/imgPath',
    129. // 信息提交接口
    130. postAPI: '/jjhServerApi/ab/insertposn',
    131. // 信息提交数据
    132. postData: {
    133. /**
    134. * name 姓名
    135. * department 部门
    136. * phoneNumber 手机号码
    137. * position 职位
    138. * certCode 证件号 身份证号
    139. * companyId 公司Id
    140. * frontPic 身份证正面
    141. * reversePic 身份证反面
    142. * handPic 手持身份证
    143. * lastOperation 该记录最后操作 A:添加操作,D:设置为离职操作
    144. */
    145. name: '',
    146. phoneNumber: '',
    147. department: '',
    148. position: '',
    149. certCode: '',
    150. companyId: '1', // 先写一个假数据
    151. frontPic: '',
    152. reversePic: '',
    153. handPic: '',
    154. lastOperation: 'A'
    155. },
    156. // 表单定义验证规则 trigger 为触发条件 http://element-cn.eleme.io/#/zh-CN/component/form#biao-dan-yan-zheng 官网地址
    157. rules: {
    158. // 姓名
    159. name: [{ required: true, message: '请输入员工姓名', trigger: 'blur' }],
    160. // 手机号码
    161. phoneNumber: [
    162. { required: true, message: '请输入手机号码', trigger: 'blur' },
    163. {
    164. validator: function(rule, value, callback) {
    165. var MobileRegex = /^(13[0-9]|147|15[0-9]|17[0-9]|18[0-9])\d{8}$/
    166. if (!MobileRegex.test(value)) {
    167. callback(new Error('手机号码格式不正确!'))
    168. } else {
    169. callback()
    170. }
    171. },
    172. trigger: 'blur'
    173. }
    174. ],
    175. // 选择部门
    176. department: [
    177. {
    178. required: true,
    179. message: '请选择您的部门',
    180. trigger: 'change'
    181. }
    182. ],
    183. // 职位
    184. position: [{ required: true, message: '请输入职位', trigger: 'blur' }],
    185. // 身份证号
    186. certCode: [
    187. { required: true, message: '请输入身份证号', trigger: 'blur' },
    188. {
    189. validator: function(rule, value, callback) {
    190. var MobileRegex = /(^\d{18}$)|(^\d{17}(\d|X|x)$)/
    191. if (!MobileRegex.test(value)) {
    192. callback(new Error('身份证号格式不正确!'))
    193. } else {
    194. callback()
    195. }
    196. },
    197. trigger: 'blur'
    198. }
    199. ]
    200. }
    201. }
    202. },
    203. methods: {
    204. // 上传文件之前的钩子,参数为上传的文件,若返回 false 或者返回 Promise 且被 reject,则停止上传。
    205. beforeAvatarUpload: function(file) {
    206. // 判断上传文件类型
    207. const me = this
    208. const isJPG = file.type === 'image/jpeg'
    209. const isPNG = file.type === 'image/png'
    210. if (!(isJPG || isPNG)) {
    211. me.$message.error('上传的文件只能是 JPG 或者是 PNG 格式的')
    212. }
    213. },
    214. // 文件超出个数限制时的钩子
    215. handleExceed(file, fileList) {
    216. const me = this
    217. me.$message.warning('只能上传一个文件')
    218. },
    219. // 文件上传成功时的钩子
    220. handleSuccess(res, file) {
    221. const me = this
    222. const sign = me.uploadSign
    223. // 判断接口返回的 code 是否为 0 0 代表成功
    224. if (res.code === 0) {
    225. // 通过 sign 判断给相应的字段赋值
    226. if (sign === 1) {
    227. // 正面
    228. me.postData.frontPic = JSON.parse(res.result).url
    229. } else if (sign === 2) {
    230. // 背面
    231. me.postData.reversePic = JSON.parse(res.result).url
    232. } else if (sign === 3) {
    233. // 手持
    234. me.postData.handPic = JSON.parse(res.result).url
    235. }
    236. } else {
    237. // 失败回调
    238. me.$message.error(`${res.info}`)
    239. // 通过 sign 判断清空相应的列表 因为默认会显示出图片其实是失败了,容易造成用户误解
    240. if (sign === 1) {
    241. // 正面
    242. me.$refs.frontPic.clearFiles()
    243. } else if (sign === 2) {
    244. // 背面
    245. me.$refs.reversePic.clearFiles()
    246. } else if (sign === 3) {
    247. // 手持
    248. me.$refs.handPic.clearFiles()
    249. }
    250. }
    251. // 清空标记
    252. me.uploadSign = null
    253. },
    254. // 删除文件之前的钩子,参数为上传的文件和文件列表,若返回 false 或者返回 Promise 且被 reject,则停止上传。
    255. beforeRemove(file, fileList) {
    256. // 增加一个询问框
    257. return this.$confirm(`确定移除 ${file.name}?`)
    258. },
    259. // 文件列表移除文件时的钩子 因为是三个组件所以便分开写了三个方法,写成一个带参数的试过了不行
    260. handleRemoveFront(file, fileList) {
    261. const me = this
    262. me.postData.frontPic = ''
    263. },
    264. handleRemoveReverse(file, fileList) {
    265. const me = this
    266. me.postData.reversePic = ''
    267. },
    268. handleRemoveHand(file, fileList) {
    269. const me = this
    270. me.postData.handPic = ''
    271. },
    272. // 提交数据
    273. submitForm(formName) {
    274. const me = this
    275. this.$refs[formName].validate(valid => {
    276. // 通过插件自定义全部规则已验证通过
    277. if (valid) {
    278. if (!me.postData.frontPic) {
    279. me.$message.error('请上传您的身份证正面图片')
    280. return false
    281. }
    282. if (!me.postData.reversePic) {
    283. me.$message.error('请上传您的身份证反面图片')
    284. return false
    285. }
    286. if (!me.postData.handPic) {
    287. me.$message.error('请上传您的身份证SIM卡手持图片')
    288. return false
    289. }
    290. let loading = Loading.service({
    291. fullscreen: true,
    292. text: '正在请求服务器'
    293. })
    294. me.axios
    295. .post(me.postAPI, qs.stringify(me.postData))
    296. .then(response => {
    297. loading.close()
    298. const getData = response.data
    299. // code 为 0 表示成功
    300. if (getData.code === 0) {
    301. me.$message.success(`${getData.info},即将自动跳转至列表页面`)
    302. // 新增成功跳转至 【通讯录管理】页面
    303. setTimeout(function() {
    304. location.href = 'addresslist.html'
    305. }, 2000)
    306. } else {
    307. me.$message.error(getData.info)
    308. }
    309. })
    310. .catch(error => {
    311. console.log(error)
    312. me.$message.error('请求服务器失败了,请稍后重试!')
    313. })
    314. } else {
    315. console.log('error submit!!')
    316. return false
    317. }
    318. })
    319. },
    320. // 重置表单
    321. resetForm(formName) {
    322. const me = this
    323. this.$refs[formName].resetFields()
    324. // 清空上传的文件
    325. // 正面
    326. me.$refs.frontPic.clearFiles()
    327. // 背面
    328. me.$refs.reversePic.clearFiles()
    329. // 手持
    330. me.$refs.handPic.clearFiles()
    331. me.postData.frontPic = ''
    332. me.postData.reversePic = ''
    333. me.postData.handPic = ''
    334. }
    335. }
    336. }
    337. </script>
    338. <style lang="less">
    339. body {
    340. .container {
    341. form {
    342. width: 700px;
    343. margin: 0 auto;
    344. .show-img {
    345. width: 300px;
    346. max-width: 100%;
    347. }
    348. }
    349. }
    350. }
    351. </style>
  • 主要演示下删除上传成功后的效果 gif

    资料 - 图6

  • 优化将 frontPic reversePic handPic 这三个字段用一个数组包着, sign 就不用在搞那么多的判断了,这样的话就是 0 1 2,下面是三个代码片段

    1. // 三个上传字段写个数组方便下面使用,就不用一个一个的判断 uploadSign 的值了,直接 me.postData[me.uploadSignString[me.uploadSign]] 即可
    2. uploadSignString: ['frontPic', 'reversePic', 'handPic'],
    3. // 通过 [me.uploadSignString[me.uploadSign]] 判断给相应的字段赋值
    4. me.postData[me.uploadSignString[me.uploadSign]] = JSON.parse(
    5. res.result
    6. ).url
    7. // 通过 sign 判断清空相应的列表 因为默认会显示出图片其实是失败了,容易造成用户误解
    8. me.$refs[me.uploadSignString[me.uploadSign]].clearFiles()

    资料 - 图7 资料 - 图8

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

  • 报错截图

    资料 - 图9

  1. These dependencies were not found:
  2. * 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
  3. * 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
  4. 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 模板)

    1. 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")
    2. span.el-pagination__total {{ cusCrmList.pages }}
  • 因为我不需要展示总页数,所以便没加 :total 属性,但是这样的话,分页的 pager 部分就展示不出来了,后来试了试,发现是没加这个的原因,下面是可以正常显示的代码

    1. 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")
    2. span.el-pagination__total {{ cusCrmList.pages }}

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

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

    1. .el-loading-mask {
    2. position: absolute;
    3. z-index: 2000;
    4. background-color: rgba(255, 255, 255, 0.9);
    5. margin: 0;
    6. top: 0;
    7. right: 0;
    8. bottom: 0;
    9. left: 0;
    10. -webkit-transition: opacity 0.3s;
    11. transition: opacity 0.3s;
    12. }

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

6. 使用 dropdown、dropdown-menu、dropdown-item 实现点击下拉子菜单更改数据的需求

  • 效果 Gif 图

    资料 - 图10

  • 官方实例参考地址

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

    1. <template lang="pug">
    2. el-dropdown(:show-timeout="0" @command="filtersStateHandle")
    3. span(class="filter-state-title") 状态
    4. i(class="el-icon-arrow-down el-icon--right")
    5. el-dropdown-menu(slot="dropdown")
    6. 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 }}
    7. template(slot-scope="scope")
    8. span {{ scope.row.GET_SERV_STATE }}
    9. </template>
    10. <script>
    11. export default {
    12. data() {
    13. return {
    14. // 【状态】字段下来使用的数据
    15. filtersStateData: [
    16. { text: "全部", value: "ALL" },
    17. { text: "正常", value: "F0A" },
    18. { text: "主动停机", value: "F0I" },
    19. { text: "欠费双向停机", value: "F0K" },
    20. { text: "拆机", value: "F1X" }
    21. ],
    22. }
    23. },
    24. methods:{
    25. /**
    26. * 右侧 header 【状态】 下拉筛选子列表点击回调
    27. * @param {object} command 当前点击的元素 key 为 command 的对象值
    28. */
    29. filtersStateHandle(command) {
    30. // console.log(command);
    31. const me = this;
    32. // 数据变化
    33. me.signFilterData.getServState = command.value;
    34. me.getProductDyList();
    35. },
    36. }
    37. }
    38. <script>
    39. <style lang="stylus" scoped>
    40. .el-dropdown-menu
    41. .filter-state-active
    42. background-color #ecf3ff
    43. color #659bfe
    44. </style>

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

  • 报错信息如下

    1. 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

  2. 主要就是写法和官网的有些差异

    资料 - 图11

  1. sortable 写成 :sortable='true' 即可

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

  1. 错误重现
  • 浏览器版本 IE11
  • 报错截图

    资料 - 图12

  • 示例源码

    1. <el-tree ref="treeDOM" :data="treeData" show-checkbox
    2. node-key="id" default-expand-all
    3. :expand-on-click-node="false">
    4. <span class="custom-tree-node" slot-scope="{ node, data }">{{ data.name }} ({{ data.roleName }})
    5. </span>
    6. </el-tree>
  1. 百度之后找到可参考的文章

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

  2. 解决思路

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

  • 示例源码

    1. <el-tree ref="treeDOM" :data="treeData" show-checkbox
    2. node-key="id" default-expand-all
    3. :expand-on-click-node="false">
    4. <span class="custom-tree-node" slot-scope="scope">{{ scope.data.name }} ({{ scope.data.roleName }})
    5. </span>
    6. </el-tree>

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

  • 需求:表头需要定制为换行的风格

  • 实现:使用 render-header 属性,下面是相应的 htmljavascript 代码片段

    1. el-table-column(prop="" label="第一行的文本,第二行的文本" show-overflow-tooltip :render-header="renderHeaderHtml")
    1. renderHeaderHtml(h, { column, $index }){
    2. const stringArray = column.label.split(',')
    3. return h('p', [
    4. h('span', stringArray[0]),
    5. h('br'),
    6. h('span', stringArray[1])
    7. ])
    8. }

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

  • 组件的完整源码,这个组件是

    1. <template lang="pug">
    2. //- 基于 el-cascader 组件,自定义一个角色结构树组件
    3. .identity-tree
    4. //- 是否保留清空方法待定 clearable
    5. 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")
    6. </template>
    7. <script>
    8. // api
    9. import { getSysOrgnInfo } from "@/api/common";
    10. export default {
    11. name: "IdentityTree",
    12. data() {
    13. return {
    14. selectedOptions: [],
    15. // 储存转换后的当前用户信息
    16. currentUserInfo: {}
    17. };
    18. },
    19. methods: {
    20. /**
    21. * 查询部门下拉树结构
    22. * id 如果有传 id 值,表示这里请求的是子级的数据,返回一个 peomise,否则表示是一级数据直接返回
    23. */
    24. getSysOrgnInfo(orgnId) {
    25. // 判断如果传的是 "" 值,表示这里是需要初始化最初的用户身份,否则正常请求接口
    26. if (orgnId) {
    27. // 获取下级的列表数据
    28. return new Promise(resolve => {
    29. getSysOrgnInfo({
    30. orgnSumId: orgnId
    31. }).then(res => {
    32. let saveData = res.data.data;
    33. console.log(saveData);
    34. // 手动将 isLeaf 字段转换成 Boolean 值
    35. saveData.forEach(element => {
    36. element.isLeaf = !!element.isLeaf;
    37. });
    38. resolve(saveData);
    39. });
    40. });
    41. } else {
    42. // 获取当前用户身份的数据
    43. return new Promise(resolve => {
    44. let { currentManagerTm } = JSON.parse(
    45. JSON.stringify(this.$store.getters.getUserInfo)
    46. );
    47. currentManagerTm.orgnName = currentManagerTm.areaName;
    48. currentManagerTm.orgnId = currentManagerTm.areaId;
    49. // resolve([currentManagerTm]);
    50. // 直接传递当前用户信息
    51. // this.$emit("update-component-data", this.currentUserInfo);
    52. getSysOrgnInfo({
    53. sessionOrgnSumId: currentManagerTm.orgnId
    54. }).then(res => {
    55. let saveData = res.data.data;
    56. // 手动将 isLeaf 字段转换成 Boolean 值
    57. saveData.forEach(element => {
    58. element.isLeaf = !!element.isLeaf;
    59. });
    60. resolve(saveData);
    61. this.currentUserInfo = saveData[0];
    62. // 默认选中当前用户身份,并触发页面加载数据
    63. this.selectedOptions = [currentManagerTm.orgnId];
    64. this.$emit("update-component-data", saveData[0]);
    65. });
    66. });
    67. /*
    68. return new Promise(resolve => {
    69. let { currentManagerTm } = JSON.parse(
    70. JSON.stringify(this.$store.getters.getUserInfo)
    71. );
    72. getSysOrgnInfo({
    73. sessionOrgnSumId: currentManagerTm.areaId
    74. }).then(res => {
    75. let saveData = res.data.data;
    76. console.log(saveData);
    77. // 手动将 isLeaf 字段转换成 Boolean 值
    78. saveData.forEach(element => {
    79. element.isLeaf = !!element.isLeaf;
    80. });
    81. resolve(saveData);
    82. this.$emit("update-component-data", saveData);
    83. });
    84. });
    85. */
    86. }
    87. },
    88. /**
    89. * 部门节点加载函数
    90. */
    91. async loadHandleNode(node, resolve) {
    92. console.log(node.level);
    93. const data = await this.getSysOrgnInfo(
    94. node.level === 0 ? "" : node.data.orgnId
    95. );
    96. resolve(data);
    97. },
    98. /**
    99. * 选中弹窗内部的部门节点加载函数
    100. */
    101. cascaderHandleChange(value) {
    102. let $identityTree = this.$refs.identityTree;
    103. // 由于组件没有单选关闭悬浮窗的回调,所以需要手动关闭
    104. $identityTree.toggleDropDownVisible(false);
    105. if (value) {
    106. // 调用父组件方法,传递当前单选选中的身份对象
    107. const checkedNodes = $identityTree.getCheckedNodes();
    108. // 判断如果单选无选中值时,传递当前用户信息
    109. this.$emit(
    110. "update-component-data",
    111. checkedNodes.length ? checkedNodes[0].data : this.currentUserInfo
    112. );
    113. }
    114. }
    115. }
    116. };
    117. </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

  1. const msgbox = MessageBox
  2. const { alert, confirm, prompt } = msgbox
  3. Vue.prototype.$msgbox = msgbox
  4. Vue.prototype.$alert = alert
  5. Vue.prototype.$confirm = confirm
  6. Vue.prototype.$prompt = prompt

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

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

codepen 在线 demo 官方参考文档

  1. <template>
  2. <el-select v-model="value" value-key="code" placeholder="请选择">
  3. <el-option-group
  4. v-for="group in options"
  5. :key="group.label"
  6. :label="group.label">
  7. <el-option
  8. v-for="item in group.child"
  9. :key="item.code"
  10. :label="item.label"
  11. :value="item">
  12. </el-option>
  13. </el-option-group>
  14. </el-select>
  15. </template>
  1. export default {
  2. data() {
  3. return {
  4. options:[
  5. {
  6. "code": "01",
  7. "label": "用户属性",
  8. "child": [
  9. {
  10. "calculateFlag": "0",
  11. "inputFlag": "2",
  12. "code": "A01001001",
  13. "label": "用户邮箱",
  14. "firstLevelCode": "01"
  15. },
  16. {
  17. "calculateFlag": "0",
  18. "inputFlag": "2",
  19. "code": "A01001002",
  20. "label": "用户名称",
  21. "firstLevelCode": "01"
  22. },
  23. {
  24. "calculateFlag": "0",
  25. "inputFlag": "2",
  26. "code": "A01001003",
  27. "label": "用户ID",
  28. "firstLevelCode": "01"
  29. },
  30. {
  31. "calculateFlag": "0",
  32. "inputFlag": "2",
  33. "code": "A01001004",
  34. "label": "用户归属省份",
  35. "firstLevelCode": "01"
  36. },
  37. {
  38. "calculateFlag": "0",
  39. "inputFlag": "2",
  40. "code": "A01001005",
  41. "label": "用户归属地市",
  42. "firstLevelCode": "01"
  43. },
  44. {
  45. "calculateFlag": "0",
  46. "inputFlag": "2",
  47. "code": "A01001006",
  48. "label": "用户归属区县",
  49. "firstLevelCode": "01"
  50. },
  51. {
  52. "calculateFlag": "0",
  53. "inputFlag": "2",
  54. "code": "A01001007",
  55. "label": "用户归属渠道",
  56. "firstLevelCode": "01"
  57. },
  58. {
  59. "calculateFlag": "0",
  60. "inputFlag": "2",
  61. "code": "A01001008",
  62. "label": "客户手机号",
  63. "firstLevelCode": "01"
  64. },
  65. {
  66. "calculateFlag": "0",
  67. "inputFlag": "2",
  68. "code": "A01001009",
  69. "label": "客户ID",
  70. "firstLevelCode": "01"
  71. },
  72. {
  73. "calculateFlag": "0",
  74. "inputFlag": "2",
  75. "code": "A01001010",
  76. "label": "客户名称",
  77. "firstLevelCode": "01"
  78. },
  79. {
  80. "calculateFlag": "1",
  81. "inputFlag": "1",
  82. "code": "A01001011",
  83. "label": "注册时间",
  84. "firstLevelCode": "01"
  85. },
  86. {
  87. "calculateFlag": "0",
  88. "inputFlag": "2",
  89. "code": "A01001012",
  90. "label": "注册渠道",
  91. "firstLevelCode": "01"
  92. },
  93. {
  94. "calculateFlag": "0",
  95. "inputFlag": "2",
  96. "code": "A01001013",
  97. "label": "个人/企业",
  98. "firstLevelCode": "01"
  99. },
  100. {
  101. "calculateFlag": "0",
  102. "inputFlag": "2",
  103. "code": "A01001015",
  104. "label": "所属行业",
  105. "firstLevelCode": "01"
  106. },
  107. {
  108. "calculateFlag": "3",
  109. "inputFlag": "0",
  110. "code": "A01001016",
  111. "label": "是否实名",
  112. "firstLevelCode": "01"
  113. },
  114. {
  115. "calculateFlag": "0",
  116. "inputFlag": "2",
  117. "code": "A01001017",
  118. "label": "实名认证类型",
  119. "firstLevelCode": "01"
  120. },
  121. {
  122. "calculateFlag": "1",
  123. "inputFlag": "0",
  124. "code": "A01001018",
  125. "label": "实名认证时间",
  126. "firstLevelCode": "01"
  127. },
  128. {
  129. "calculateFlag": "0",
  130. "inputFlag": "2",
  131. "code": "A01001019",
  132. "label": "性别",
  133. "firstLevelCode": "01"
  134. },
  135. {
  136. "calculateFlag": "0",
  137. "inputFlag": "2",
  138. "code": "A01001020",
  139. "label": "年龄",
  140. "firstLevelCode": "01"
  141. },
  142. {
  143. "calculateFlag": "0",
  144. "inputFlag": "2",
  145. "code": "A01001021",
  146. "label": "生日",
  147. "firstLevelCode": "01"
  148. },
  149. {
  150. "calculateFlag": "0",
  151. "inputFlag": "2",
  152. "code": "A01001022",
  153. "label": "客户经理",
  154. "firstLevelCode": "01"
  155. },
  156. {
  157. "calculateFlag": "0",
  158. "inputFlag": "2",
  159. "code": "A01001023",
  160. "label": "一人一码客户经理",
  161. "firstLevelCode": "01"
  162. },
  163. {
  164. "calculateFlag": "0",
  165. "inputFlag": "2",
  166. "code": "A01001024",
  167. "label": "一人一码客户经理手机号",
  168. "firstLevelCode": "01"
  169. },
  170. {
  171. "calculateFlag": "3",
  172. "inputFlag": "0",
  173. "code": "A01001026",
  174. "label": "是否一人一码注册用户(云大使注册)",
  175. "firstLevelCode": "01"
  176. },
  177. {
  178. "calculateFlag": "0",
  179. "inputFlag": "2",
  180. "code": "A01001027",
  181. "label": "一人一码(云大使)二维码ID",
  182. "firstLevelCode": "01"
  183. },
  184. {
  185. "calculateFlag": "0",
  186. "inputFlag": "2",
  187. "code": "A01001028",
  188. "label": "一人一码归属省",
  189. "firstLevelCode": "01"
  190. },
  191. {
  192. "calculateFlag": "0",
  193. "inputFlag": "2",
  194. "code": "A01001029",
  195. "label": "一人一码归属地市",
  196. "firstLevelCode": "01"
  197. },
  198. {
  199. "calculateFlag": "0",
  200. "inputFlag": "2",
  201. "code": "A01001030",
  202. "label": "一人一码归属区县",
  203. "firstLevelCode": "01"
  204. },
  205. {
  206. "calculateFlag": "0",
  207. "inputFlag": "2",
  208. "code": "A01001031",
  209. "label": "运营商",
  210. "firstLevelCode": "01"
  211. },
  212. {
  213. "calculateFlag": "3",
  214. "inputFlag": "0",
  215. "code": "A01002002",
  216. "label": "是否资源在用用户",
  217. "firstLevelCode": "01"
  218. },
  219. {
  220. "calculateFlag": "3",
  221. "inputFlag": "0",
  222. "code": "A01002003",
  223. "label": "是否测试用户",
  224. "firstLevelCode": "01"
  225. },
  226. {
  227. "calculateFlag": "0",
  228. "inputFlag": "2",
  229. "code": "A01002005",
  230. "label": "到期产品",
  231. "firstLevelCode": "01"
  232. },
  233. {
  234. "calculateFlag": "1",
  235. "inputFlag": "0",
  236. "code": "A01002006",
  237. "label": "到期时间",
  238. "firstLevelCode": "01"
  239. },
  240. {
  241. "calculateFlag": "3",
  242. "inputFlag": "0",
  243. "code": "A01002008",
  244. "label": "是否首次到期",
  245. "firstLevelCode": "01"
  246. },
  247. {
  248. "calculateFlag": "2",
  249. "inputFlag": "1",
  250. "code": "A01002010",
  251. "label": "在网时长",
  252. "firstLevelCode": "01"
  253. },
  254. {
  255. "calculateFlag": "2",
  256. "inputFlag": "1",
  257. "code": "A01003001",
  258. "label": "账户余额",
  259. "firstLevelCode": "01"
  260. },
  261. {
  262. "calculateFlag": "2",
  263. "inputFlag": "1",
  264. "code": "A01003002",
  265. "label": "欠费金额",
  266. "firstLevelCode": "01"
  267. },
  268. {
  269. "calculateFlag": "2",
  270. "inputFlag": "2",
  271. "code": "A01003003",
  272. "label": "欠费次数",
  273. "firstLevelCode": "01"
  274. },
  275. {
  276. "calculateFlag": "2",
  277. "inputFlag": "1",
  278. "code": "A01003004",
  279. "label": "总出账金额",
  280. "firstLevelCode": "01"
  281. },
  282. {
  283. "calculateFlag": "2",
  284. "inputFlag": "1",
  285. "code": "A01003005",
  286. "label": "近3月出账金额",
  287. "firstLevelCode": "01"
  288. },
  289. {
  290. "calculateFlag": "2",
  291. "inputFlag": "1",
  292. "code": "A01003006",
  293. "label": "分产品出账金额",
  294. "firstLevelCode": "01"
  295. },
  296. {
  297. "calculateFlag": "2",
  298. "inputFlag": "1",
  299. "code": "A01003010",
  300. "label": "充值金额",
  301. "firstLevelCode": "01"
  302. },
  303. {
  304. "calculateFlag": "0",
  305. "inputFlag": "2",
  306. "code": "A01003013",
  307. "label": "充值方式",
  308. "firstLevelCode": "01"
  309. },
  310. {
  311. "calculateFlag": "2",
  312. "inputFlag": "1",
  313. "code": "A01003015",
  314. "label": "累计充值次数",
  315. "firstLevelCode": "01"
  316. },
  317. {
  318. "calculateFlag": "2",
  319. "inputFlag": "1",
  320. "code": "A01003016",
  321. "label": "累计充值金额",
  322. "firstLevelCode": "01"
  323. },
  324. {
  325. "calculateFlag": "2",
  326. "inputFlag": "1",
  327. "code": "A01003017",
  328. "label": "累计欠费次数",
  329. "firstLevelCode": "01"
  330. },
  331. {
  332. "calculateFlag": "2",
  333. "inputFlag": "1",
  334. "code": "A01003018",
  335. "label": "累计提现次数",
  336. "firstLevelCode": "01"
  337. },
  338. {
  339. "calculateFlag": "2",
  340. "inputFlag": "1",
  341. "code": "A01003019",
  342. "label": "日均按需费用",
  343. "firstLevelCode": "01"
  344. },
  345. {
  346. "calculateFlag": "2",
  347. "inputFlag": "1",
  348. "code": "A01004016",
  349. "label": "近30天充值次数",
  350. "firstLevelCode": "01"
  351. },
  352. {
  353. "calculateFlag": "2",
  354. "inputFlag": "2",
  355. "code": "A01004017",
  356. "label": "近30天充值金额",
  357. "firstLevelCode": "01"
  358. },
  359. {
  360. "calculateFlag": "2",
  361. "inputFlag": "1",
  362. "code": "A01004018",
  363. "label": "累计订单标准价",
  364. "firstLevelCode": "01"
  365. },
  366. {
  367. "calculateFlag": "2",
  368. "inputFlag": "1",
  369. "code": "A01004019",
  370. "label": "累计订单降配实际价格",
  371. "firstLevelCode": "01"
  372. },
  373. {
  374. "calculateFlag": "2",
  375. "inputFlag": "1",
  376. "code": "A01004020",
  377. "label": "累计订单实际价格",
  378. "firstLevelCode": "01"
  379. },
  380. {
  381. "calculateFlag": "2",
  382. "inputFlag": "1",
  383. "code": "A01004021",
  384. "label": "累计订单现金金额",
  385. "firstLevelCode": "01"
  386. },
  387. {
  388. "calculateFlag": "2",
  389. "inputFlag": "1",
  390. "code": "A01004022",
  391. "label": "累计降配次数",
  392. "firstLevelCode": "01"
  393. },
  394. {
  395. "calculateFlag": "2",
  396. "inputFlag": "1",
  397. "code": "A01004023",
  398. "label": "累计降配订单标准价",
  399. "firstLevelCode": "01"
  400. },
  401. {
  402. "calculateFlag": "2",
  403. "inputFlag": "1",
  404. "code": "A01004024",
  405. "label": "累计降配订单现金",
  406. "firstLevelCode": "01"
  407. },
  408. {
  409. "calculateFlag": "2",
  410. "inputFlag": "1",
  411. "code": "A01004025",
  412. "label": "累计退订次数",
  413. "firstLevelCode": "01"
  414. },
  415. {
  416. "calculateFlag": "2",
  417. "inputFlag": "1",
  418. "code": "A01004026",
  419. "label": "累计退订金额",
  420. "firstLevelCode": "01"
  421. },
  422. {
  423. "calculateFlag": "2",
  424. "inputFlag": "1",
  425. "code": "A01004027",
  426. "label": "累计优惠券/代金券使用金额",
  427. "firstLevelCode": "01"
  428. },
  429. {
  430. "calculateFlag": "0",
  431. "inputFlag": "2",
  432. "code": "A01005001",
  433. "label": "产品名称",
  434. "firstLevelCode": "01"
  435. },
  436. {
  437. "calculateFlag": "0",
  438. "inputFlag": "2",
  439. "code": "A01005002",
  440. "label": "产品类型",
  441. "firstLevelCode": "01"
  442. },
  443. {
  444. "calculateFlag": "1",
  445. "inputFlag": "0",
  446. "code": "A01005011",
  447. "label": "订单失效时间",
  448. "firstLevelCode": "01"
  449. },
  450. {
  451. "calculateFlag": "0",
  452. "inputFlag": "2",
  453. "code": "A01005012",
  454. "label": "订单按需或包周期",
  455. "firstLevelCode": "01"
  456. },
  457. {
  458. "calculateFlag": "0",
  459. "inputFlag": "2",
  460. "code": "A01005013",
  461. "label": "付费类型",
  462. "firstLevelCode": "01"
  463. },
  464. {
  465. "calculateFlag": "3",
  466. "inputFlag": "0",
  467. "code": "A01005021",
  468. "label": "是否一人一码订单",
  469. "firstLevelCode": "01"
  470. },
  471. {
  472. "calculateFlag": "2",
  473. "inputFlag": "1",
  474. "code": "A01006010",
  475. "label": "资源个数",
  476. "firstLevelCode": "01"
  477. },
  478. {
  479. "calculateFlag": "0",
  480. "inputFlag": "2",
  481. "code": "A01006011",
  482. "label": "资源类型",
  483. "firstLevelCode": "01"
  484. },
  485. {
  486. "calculateFlag": "2",
  487. "inputFlag": "1",
  488. "code": "A01006012",
  489. "label": "资源使用时长",
  490. "firstLevelCode": "01"
  491. },
  492. {
  493. "calculateFlag": "1",
  494. "inputFlag": "0",
  495. "code": "A01006013",
  496. "label": "资源最晚到期时间",
  497. "firstLevelCode": "01"
  498. },
  499. {
  500. "calculateFlag": "0",
  501. "inputFlag": "2",
  502. "code": "A01008001",
  503. "label": "优惠券/满折优惠券活动名称",
  504. "firstLevelCode": "01"
  505. },
  506. {
  507. "calculateFlag": "0",
  508. "inputFlag": "2",
  509. "code": "A01008002",
  510. "label": "优惠券号",
  511. "firstLevelCode": "01"
  512. },
  513. {
  514. "calculateFlag": "0",
  515. "inputFlag": "2",
  516. "code": "A01008003",
  517. "label": "优惠券名称",
  518. "firstLevelCode": "01"
  519. },
  520. {
  521. "calculateFlag": "1",
  522. "inputFlag": "0",
  523. "code": "A01008004",
  524. "label": "优惠券领取时间",
  525. "firstLevelCode": "01"
  526. },
  527. {
  528. "calculateFlag": "2",
  529. "inputFlag": "1",
  530. "code": "A01008005",
  531. "label": "优惠券金额",
  532. "firstLevelCode": "01"
  533. },
  534. {
  535. "calculateFlag": "1",
  536. "inputFlag": "0",
  537. "code": "A01008007",
  538. "label": "优惠券到期时间",
  539. "firstLevelCode": "01"
  540. },
  541. {
  542. "calculateFlag": "2",
  543. "inputFlag": "1",
  544. "code": "A01008009",
  545. "label": "优惠券使用金额",
  546. "firstLevelCode": "01"
  547. },
  548. {
  549. "calculateFlag": "0",
  550. "inputFlag": "2",
  551. "code": "A01008013",
  552. "label": "优惠券使用条件",
  553. "firstLevelCode": "01"
  554. },
  555. {
  556. "calculateFlag": "0",
  557. "inputFlag": "2",
  558. "code": "A01008014",
  559. "label": "优惠券发放目的",
  560. "firstLevelCode": "01"
  561. },
  562. {
  563. "calculateFlag": "0",
  564. "inputFlag": "2",
  565. "code": "A01008016",
  566. "label": "满减折扣类型",
  567. "firstLevelCode": "01"
  568. },
  569. {
  570. "calculateFlag": "0",
  571. "inputFlag": "2",
  572. "code": "A01008017",
  573. "label": "代金券号码",
  574. "firstLevelCode": "01"
  575. },
  576. {
  577. "calculateFlag": "1",
  578. "inputFlag": "0",
  579. "code": "A01008019",
  580. "label": "代金券领取时间",
  581. "firstLevelCode": "01"
  582. },
  583. {
  584. "calculateFlag": "2",
  585. "inputFlag": "1",
  586. "code": "A01008020",
  587. "label": "代金券金额",
  588. "firstLevelCode": "01"
  589. },
  590. {
  591. "calculateFlag": "1",
  592. "inputFlag": "0",
  593. "code": "A01008022",
  594. "label": "代金券到期时间",
  595. "firstLevelCode": "01"
  596. },
  597. {
  598. "calculateFlag": "0",
  599. "inputFlag": "2",
  600. "code": "A01008031",
  601. "label": "满折优惠券名称",
  602. "firstLevelCode": "01"
  603. },
  604. {
  605. "calculateFlag": "0",
  606. "inputFlag": "2",
  607. "code": "A01008032",
  608. "label": "满折优惠券券号",
  609. "firstLevelCode": "01"
  610. },
  611. {
  612. "calculateFlag": "1",
  613. "inputFlag": "0",
  614. "code": "A01008033",
  615. "label": "满折优惠券领取时间",
  616. "firstLevelCode": "01"
  617. },
  618. {
  619. "calculateFlag": "2",
  620. "inputFlag": "1",
  621. "code": "A01008034",
  622. "label": "满折优惠券金额",
  623. "firstLevelCode": "01"
  624. },
  625. {
  626. "calculateFlag": "1",
  627. "inputFlag": "0",
  628. "code": "A01008036",
  629. "label": "满折优惠券到期时间",
  630. "firstLevelCode": "01"
  631. },
  632. {
  633. "calculateFlag": "2",
  634. "inputFlag": "1",
  635. "code": "A01008038",
  636. "label": "满折优惠券使用金额",
  637. "firstLevelCode": "01"
  638. },
  639. {
  640. "calculateFlag": "0",
  641. "inputFlag": "2",
  642. "code": "A01008042",
  643. "label": "满折优惠券使用条件",
  644. "firstLevelCode": "01"
  645. },
  646. {
  647. "calculateFlag": "0",
  648. "inputFlag": "2",
  649. "code": "A01008054",
  650. "label": "折扣券发放目的",
  651. "firstLevelCode": "01"
  652. },
  653. {
  654. "calculateFlag": "0",
  655. "inputFlag": "2",
  656. "code": "A01009001",
  657. "label": "track",
  658. "firstLevelCode": "01"
  659. },
  660. {
  661. "calculateFlag": "0",
  662. "inputFlag": "2",
  663. "code": "A01009002",
  664. "label": "推广单元",
  665. "firstLevelCode": "01"
  666. },
  667. {
  668. "calculateFlag": "0",
  669. "inputFlag": "2",
  670. "code": "A01009003",
  671. "label": "推广关键词",
  672. "firstLevelCode": "01"
  673. },
  674. {
  675. "calculateFlag": "0",
  676. "inputFlag": "2",
  677. "code": "A01009004",
  678. "label": "推广渠道",
  679. "firstLevelCode": "01"
  680. },
  681. {
  682. "calculateFlag": "0",
  683. "inputFlag": "2",
  684. "code": "A01009005",
  685. "label": "引导登录页面名称",
  686. "firstLevelCode": "01"
  687. },
  688. {
  689. "calculateFlag": "0",
  690. "inputFlag": "2",
  691. "code": "A01009006",
  692. "label": "引导登录页面模块",
  693. "firstLevelCode": "01"
  694. },
  695. {
  696. "calculateFlag": "0",
  697. "inputFlag": "2",
  698. "code": "A01009007",
  699. "label": "引导登录注册模块",
  700. "firstLevelCode": "01"
  701. },
  702. {
  703. "calculateFlag": "0",
  704. "inputFlag": "2",
  705. "code": "A01009008",
  706. "label": "引导页面登录URL",
  707. "firstLevelCode": "01"
  708. },
  709. {
  710. "calculateFlag": "0",
  711. "inputFlag": "2",
  712. "code": "A01009009",
  713. "label": "引导页面注册URL",
  714. "firstLevelCode": "01"
  715. },
  716. {
  717. "calculateFlag": "0",
  718. "inputFlag": "2",
  719. "code": "A01009010",
  720. "label": "引导注册页面名称",
  721. "firstLevelCode": "01"
  722. },
  723. {
  724. "calculateFlag": "0",
  725. "inputFlag": "2",
  726. "code": "A01009011",
  727. "label": "注册访问来源(referer)",
  728. "firstLevelCode": "01"
  729. },
  730. {
  731. "calculateFlag": "0",
  732. "inputFlag": "2",
  733. "code": "A01009012",
  734. "label": "注册track",
  735. "firstLevelCode": "01"
  736. },
  737. {
  738. "calculateFlag": "0",
  739. "inputFlag": "2",
  740. "code": "A01009013",
  741. "label": "注册推广单元",
  742. "firstLevelCode": "01"
  743. },
  744. {
  745. "calculateFlag": "0",
  746. "inputFlag": "2",
  747. "code": "A01009014",
  748. "label": "注册推广计划",
  749. "firstLevelCode": "01"
  750. },
  751. {
  752. "calculateFlag": "0",
  753. "inputFlag": "2",
  754. "code": "A01009015",
  755. "label": "注册推广关键词",
  756. "firstLevelCode": "01"
  757. },
  758. {
  759. "calculateFlag": "0",
  760. "inputFlag": "2",
  761. "code": "A01009016",
  762. "label": "注册推广渠道",
  763. "firstLevelCode": "01"
  764. },
  765. {
  766. "calculateFlag": "0",
  767. "inputFlag": "2",
  768. "code": "A01009017",
  769. "label": "实名渠道",
  770. "firstLevelCode": "01"
  771. },
  772. {
  773. "calculateFlag": "0",
  774. "inputFlag": "2",
  775. "code": "A01009018",
  776. "label": "实名track",
  777. "firstLevelCode": "01"
  778. },
  779. {
  780. "calculateFlag": "0",
  781. "inputFlag": "2",
  782. "code": "A01009019",
  783. "label": "实名推广单元",
  784. "firstLevelCode": "01"
  785. },
  786. {
  787. "calculateFlag": "0",
  788. "inputFlag": "2",
  789. "code": "A01009020",
  790. "label": "实名推广计划",
  791. "firstLevelCode": "01"
  792. },
  793. {
  794. "calculateFlag": "0",
  795. "inputFlag": "2",
  796. "code": "A01009021",
  797. "label": "实名推广关键词",
  798. "firstLevelCode": "01"
  799. },
  800. {
  801. "calculateFlag": "0",
  802. "inputFlag": "2",
  803. "code": "A01009022",
  804. "label": "订单渠道",
  805. "firstLevelCode": "01"
  806. },
  807. {
  808. "calculateFlag": "0",
  809. "inputFlag": "2",
  810. "code": "A01009023",
  811. "label": "订单track",
  812. "firstLevelCode": "01"
  813. },
  814. {
  815. "calculateFlag": "0",
  816. "inputFlag": "2",
  817. "code": "A01009024",
  818. "label": "订单推广单元",
  819. "firstLevelCode": "01"
  820. },
  821. {
  822. "calculateFlag": "0",
  823. "inputFlag": "2",
  824. "code": "A01009025",
  825. "label": "订单推广计划",
  826. "firstLevelCode": "01"
  827. },
  828. {
  829. "calculateFlag": "0",
  830. "inputFlag": "2",
  831. "code": "A01009026",
  832. "label": "订单推广关键词",
  833. "firstLevelCode": "01"
  834. },
  835. {
  836. "calculateFlag": "0",
  837. "inputFlag": "2",
  838. "code": "A01010002",
  839. "label": "实名认证状态",
  840. "firstLevelCode": "01"
  841. }
  842. ]
  843. },
  844. {
  845. "code": "02",
  846. "label": "用户行为",
  847. "child": [
  848. {
  849. "calculateFlag": "0",
  850. "inputFlag": "2",
  851. "code": "A02001016",
  852. "label": "访问来源(referer)",
  853. "firstLevelCode": "02"
  854. },
  855. {
  856. "calculateFlag": "0",
  857. "inputFlag": "2",
  858. "code": "A02001017",
  859. "label": "访问终端类型",
  860. "firstLevelCode": "02"
  861. },
  862. {
  863. "calculateFlag": "0",
  864. "inputFlag": "2",
  865. "code": "A02002001",
  866. "label": "近30天浏览页面名称",
  867. "firstLevelCode": "02"
  868. },
  869. {
  870. "calculateFlag": "2",
  871. "inputFlag": "1",
  872. "code": "A02003005",
  873. "label": "CPU使用率",
  874. "firstLevelCode": "02"
  875. },
  876. {
  877. "calculateFlag": "2",
  878. "inputFlag": "1",
  879. "code": "A02003006",
  880. "label": "内存使用率",
  881. "firstLevelCode": "02"
  882. },
  883. {
  884. "calculateFlag": "1",
  885. "inputFlag": "0",
  886. "code": "A02008001",
  887. "label": "最近登录时间",
  888. "firstLevelCode": "02"
  889. },
  890. {
  891. "calculateFlag": "0",
  892. "inputFlag": "2",
  893. "code": "A02009001",
  894. "label": "故障产品名称",
  895. "firstLevelCode": "02"
  896. },
  897. {
  898. "calculateFlag": "0",
  899. "inputFlag": "2",
  900. "code": "A02009002",
  901. "label": "故障解决满意度",
  902. "firstLevelCode": "02"
  903. },
  904. {
  905. "calculateFlag": "0",
  906. "inputFlag": "2",
  907. "code": "A02009004",
  908. "label": "故障原因",
  909. "firstLevelCode": "02"
  910. }
  911. ]
  912. }
  913. ],
  914. value: ''
  915. }
  916. }
  917. }

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];
            // 数据计算
            for (let i = 0; i < data.length; i++) {
              const element = data[i];
              // 逻辑:默认的第一条 i === 0 数据将初始化单元格数量为 1,从第二条 i === 1 数据开始与上一条数据开始做属性比较,一致的话上一个单元格 += 1,相应的当前单元格需要置为 0,否则为默认值 1
              if (i === 0) {
                dataList.push(1);
              } else {
                // 判断与上一条数据对应的属性值是否一致,如果是的话上一个单元格需要自增 1,并设置当前的单元格为 0,否则为 1
                const prev = data[i - 1];
                if (element[prop] === prev[prop]) {
                  dataList[i - 1] += 1;
                  dataList.push(0);
                } else {
                  dataList.push(1);
                }
              }
            }
          }
          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>