当前位置:   article > 正文

【web系列十二】element plus的一些实用技巧_element-plus

element-plus

目录

写在前面

menu+router

基本功能实现

 手动设置菜单激活状态

el-table:span-method

el-table树状表格递归显示数据及双击单元格修改功能

树状表格递归显示数据

双击单元格修改

el-upload

el-tabs

记录当前tab页

一些小技巧或坑

date-picker

table

form

参考资料


写在前面

        element-plus的官网上已经把各种组件的实用说明写的比较清楚了,并且由于element-plus功能很强大,属性、组件都很多,不可能全部整理下来,也没有必要,大家有需要的可以直接去官网查看。因此这篇文章主要记录一下element-plus组件的一些实用技巧和注意事项,同时会提供对应的代码示例。

        这里插上官网地址:

一个 Vue 3 UI 框架 | Element Plus (gitee.io)

基本功能实现

        这里使用el-menu组件和vue-router实现菜单栏以及页面的跳转。

         官网上说设置了router属性后就可以使用vue-router实现跳转了,咱们来试一试。

  1. <template>
  2. <el-menu
  3. router
  4. class="el-menu-demo"
  5. mode="horizontal"
  6. background-color="#545c64"
  7. text-color="#fff"
  8. active-text-color="#ffd04b"
  9. >
  10. <el-menu-item index="'/home/' + /">首页</el-menu-item>
  11. <el-menu-item index="'/home/' + /page1">页面1</el-menu-item>
  12. <el-menu-item index="'/home/' + /page2">页面2</el-menu-item>
  13. <el-menu-item index="'/home/' + /page3">页面3</el-menu-item>
  14. </el-menu>
  15. <router-view />
  16. </template>
  17. <script></script>
  18. <style></style>

        这里要注意,index的路径要用字符串拼接的形式

index="'/home/' + url"

        同时要记得先配置好vue-route,router/index.ts

  1. import { createRouter, createWebHistory } from 'vue-router'
  2. import Home from '../views/Home.vue'
  3. const routes = [
  4. {
  5. path: '/',
  6. name: 'Home',
  7. component: Home
  8. },
  9. {
  10. path: '/page1',
  11. name: 'Page1'
  12. component: () => import(/* webpackChunkName: "about" */ '../views/Page1.vue')
  13. },
  14. {
  15. path: '/page2',
  16. name: 'Page2'
  17. component: () => import('../views/Page2.vue')
  18. },
  19. {
  20. path: '/page3',
  21. name: 'Page3'
  22. component: () => import('../views/Page3.vue')
  23. }
  24. ]
  25. const router = createRouter({
  26. history: createWebHistory(process.env.BASE_URL),
  27. routes
  28. })
  29. export default router

        实际效果如下:

 手动设置菜单激活状态

         el-menu有一个属性是default-active,用来设置默认激活的菜单。咱们可以把他设置成一个ref变量,变量的内容是菜单的index,也就是下面el-menu-item的index属性内容。这样当变量改变时,对应的菜单就会显示成激活状态了。

  1. <template>
  2. <el-menu
  3. :default-active="activeIndex"
  4. mode="horizontal"
  5. >
  6. <el-menu-item index="1">Processing Center</el-menu-item>
  7. <el-sub-menu index="2">
  8. <template #title>Workspace</template>
  9. <el-menu-item index="2-1">item one</el-menu-item>
  10. <el-menu-item index="2-2">item two</el-menu-item>
  11. <el-menu-item index="2-3">item three</el-menu-item>
  12. <el-sub-menu index="2-4">
  13. <template #title>item four</template>
  14. <el-menu-item index="2-4-1">item one</el-menu-item>
  15. <el-menu-item index="2-4-2">item two</el-menu-item>
  16. <el-menu-item index="2-4-3">item three</el-menu-item>
  17. </el-sub-menu>
  18. </el-sub-menu>
  19. <el-menu-item index="3" disabled>Info</el-menu-item>
  20. <el-menu-item index="4">Orders</el-menu-item>
  21. </el-menu>
  22. </template>
  23. <script lang="ts" setup>
  24. import { ref } from 'vue'
  25. const activeIndex = ref('1')
  26. </script>

el-table:span-method

        使用span-method方法可以合并行或列,官网上的说明不是很详细,这边直接拿官网的示例解释一下,比如我们想实现以下效果,将id奇偶行合并。

         我们先给el-table添加一个span-method属性

  1. <el-table
  2. :data="tableData"
  3. :span-method="objectSpanMethod"
  4. border
  5. style="width: 100%; margin-top: 20px"
  6. >
  7. </el-table>

         然后我们定义一个接口,这个其实不定义也是可以的。

  • User是表格数据的接口,请根据实际修改
  • row表示表格每一行的数据
  • column表示表格每一列的数据
  • rowIndex表示表格的行索引,不包括表头,从0开始
  • columnIndex表示表格的列索引,从0开始

         要注意这里的变量除了User,名称都不能修改!

  1. interface SpanMethodProps {
  2. row: User
  3. column: TableColumnCtx<User>
  4. rowIndex: number
  5. columnIndex: number
  6. }

        最后我们定义一下合并规则

        判断条件还是比较好理解的就不说了,主要是返回值,先说第二个return,两个0代表是空值,也就是被合并的格给他设成空值就行了;第一个return,rowspan表示合并的行数,colspan表示合并的列数。这里的合并规则就是当列索引时0时,也就是从第一列开始每两行每一列合并成一个格子,且被合并的单元格置空。

  1. const objectSpanMethod = ({
  2. row,
  3. column,
  4. rowIndex,
  5. columnIndex,
  6. }: SpanMethodProps) => {
  7. if (columnIndex === 0) {
  8. if (rowIndex % 2 === 0) {
  9. return {
  10. rowspan: 2,
  11. colspan: 1,
  12. }
  13. } else {
  14. return {
  15. rowspan: 0,
  16. colspan: 0,
  17. }
  18. }
  19. }
  20. }

el-table树状表格递归显示数据及双击单元格修改功能

树状表格递归显示数据

         先来看看效果,这个是我们的数据,假设是一个描述图书馆藏书情况的多层嵌套yaml文件。

  1. '历史':
  2. '中国':
  3. '清朝': ['2本', 'A1-2']
  4. '明朝': ['3本', 'A3-5']
  5. '外国':
  6. '法国': ['2本', 'B1-2']
  7. '美国':
  8. '独立战争': ['1本', 'B3']
  9. '音乐':
  10. '钢琴': ['5本', 'C1-5']
  11. '古典': ['1本', 'C6']

        显示出来效果如下

        可以看到表格中的格式与我们的数据格式一致的,废话不多说,直接上代码:

  1. <template>
  2. <div>
  3. <el-table
  4. :data="tableData"
  5. style="width: 100%; margin-bottom: 20px"
  6. row-key="id"
  7. max-height="800"
  8. border
  9. default-expand-all
  10. > <!--max-height随便用来控制表格高度,用height不好使-->
  11. <el-table-column fixed prop="class" label="分类" sortable width="250" />
  12. <el-table-column prop="num" label="数量" sortable width="250" />
  13. <el-table-column prop="position" label="位置" sortable min-width="300" />
  14. </el-table>
  15. </div>
  16. </template>
  17. <script lang="ts" setup>
  18. import axios from 'axios';
  19. import { ref, onBeforeMount } from 'vue';
  20. interface Books {
  21. id: number;
  22. class: string;
  23. num?: string;
  24. position?: string;
  25. children?: Books[];
  26. }
  27. onBeforeMount(() => {
  28. getMessage();
  29. });
  30. let table_data = ref<Books[]>([]);
  31. function getMessage(): void {
  32. axios.get('/getMessage').then((response) => {
  33. let idx: number = 0; // 保证递归时的idx是全局的
  34. table_data.value.splice(0, table_data.value.length);
  35. display(response.data['message'], idx, table_data.value);
  36. })
  37. }
  38. function display(data: any, idx: number, idArr: Books[] = []): number {
  39. for(let key in data) {
  40. let value: any = data[key];
  41. let type: string = getType(value);
  42. if(type === "dict") {
  43. let child_books: Books[] = [];
  44. idArr.push({
  45. id: idx++,
  46. class: key,
  47. children: child_books
  48. });
  49. idx = display(value, idx, child_books);
  50. }
  51. else {
  52. idArr.push({
  53. id: idx++,
  54. class: key,
  55. index: -1,
  56. num: <string>(<unknown>value[0]),
  57. position: <string>(<unknown>value[1])
  58. });
  59. }
  60. }
  61. return idx;
  62. }
  63. function getType(data: any): string {
  64. let type = Object.prototype.toString.call(data);
  65. if(type === "[object Object]") return "dict";
  66. else {
  67. if(type === "[object Array]") return "list";
  68. else return "other";
  69. }
  70. }
  71. </script>

双击单元格修改

        也先来看看效果,双击某个单元格,可以编辑,但是不能编辑原本就不应该存在数据的单元格。

         在原来的代码上修改

  1. <template>
  2. <div>
  3. <el-table
  4. :data="tableData"
  5. style="width: 100%; margin-bottom: 20px"
  6. row-key="id"
  7. max-height="800"
  8. border
  9. default-expand-all
  10. @cell-dblclick="editData"
  11. :cell-class-name="setCellClassName"
  12. >
  13. <!--用cell-dblclick绑定一个鼠标双击事件editData-->
  14. <!--用cell-class-name给每个单元格绑定位置信息-->
  15. <el-table-column fixed prop="class" label="分类" sortable width="250">
  16. <template #default='scope'>
  17. <el-input
  18. class="el-input"
  19. size="default"
  20. v-model="scope.row.class"
  21. v-if="scope.row.index+','+scope.column.index == current_cell"
  22. autofocus="true"
  23. @blur="hideInput"
  24. />
  25. <!--给一个class,为了让el-input尺寸小一些,避免换行-->
  26. <!--v-model绑定该单元格的数据-->
  27. <!--v-if和v-else成对使用,根据当前单元格位置信息切换显示状态-->
  28. <!--autofocus,显示的时候自动聚焦-->
  29. <!--blur,失去焦点时执行的函数-->
  30. <span v-else>{{ scope.row.class }}</span>
  31. </template>
  32. </el-table-column>
  33. <el-table-column prop="num" label="数量" sortable width="250">
  34. <template #default='scope'>
  35. <el-input
  36. class="el-input"
  37. size="default"
  38. v-model="scope.row.num"
  39. v-if="scope.row.index+','+scope.column.index == current_cell"
  40. autofocus="true"
  41. @blur="hideInput"
  42. />
  43. <span v-else>{{ scope.row.num }}</span>
  44. </template>
  45. </el-table-column>
  46. <el-table-column prop="position" label="位置" sortable min-width="300">
  47. <template #default='scope'>
  48. <el-input
  49. class="el-input"
  50. size="default"
  51. v-model="scope.row.position"
  52. v-if="scope.row.index+','+scope.column.index == current_cell"
  53. autofocus="true"
  54. @blur="hideInput"
  55. />
  56. <span v-else>{{ scope.row.position }}</span>
  57. </template>
  58. </el-table-column>
  59. </el-table>
  60. </div>
  61. </template>
  62. <script lang="ts" setup>
  63. import axios from 'axios';
  64. import { ref, onBeforeMount } from 'vue';
  65. import { toRaw } from '@/vue/reactivity';
  66. interface Books {
  67. id: number;
  68. class: string;
  69. num?: string;
  70. position?: string;
  71. index?: number; //增加一个index用于当前的row位置信息
  72. children?: Books[];
  73. }
  74. onBeforeMount(() => {
  75. getMessage();
  76. });
  77. let table_data = ref<Books[]>([]);
  78. let current_cell = ref<string | null>(null); // 记录双击选中的单元格位置信息
  79. function getMessage(): void {
  80. axios.get('/getMessage').then((response) => {
  81. let idx: number = 0; // 保证递归时的idx是全局的
  82. table_data.value.splice(0, table_data.value.length);
  83. display(response.data['message'], idx, table_data.value);
  84. })
  85. }
  86. function display(data: any, idx: number, idArr: Books[] = []): number {
  87. for(let key in data) {
  88. let value: any = data[key];
  89. let type: string = getType(value);
  90. if(type === "dict") {
  91. let child_books: Books[] = [];
  92. idArr.push({
  93. id: idx++,
  94. class: key,
  95. children: child_books
  96. });
  97. idx = display(value, idx, child_books);
  98. }
  99. else {
  100. idArr.push({
  101. id: idx++,
  102. class: key,
  103. index: -1,
  104. num: <string>(<unknown>value[0]),
  105. position: <string>(<unknown>value[1])
  106. });
  107. }
  108. }
  109. return idx;
  110. }
  111. function getType(data: any): string {
  112. let type = Object.prototype.toString.call(data);
  113. if(type === "[object Object]") return "dict";
  114. else {
  115. if(type === "[object Array]") return "list";
  116. else return "other";
  117. }
  118. }
  119. // 在初始化表格的时候就给每个单元格赋予位置信息
  120. function setCellClassName({ row, column, rowIndex, columnIndex }): void {
  121. row.index = rowIndex;
  122. column.index = columnIndex;
  123. }
  124. // 双击后先判断当前单元格是否可能存在数据,可能的话,把current_cell置为当前单元格的位置
  125. function editData(row, colunm): void {
  126. if(row.children != undefined &&column.index != 0) {}
  127. else {
  128. current_cell.value = row.index + ',' + column.index;
  129. }
  130. }
  131. // 失去焦点后,把current_cell置为null
  132. function hideInput(row): void {
  133. current_cell.value = null;
  134. }
  135. </script>
  136. <style scope>
  137. .el-input {
  138. width: 80%;
  139. }
  140. </style>

el-upload

        这个组件用于文件上传,先上一些参考文章

vue+element upload上传带参数的方法 - 开发技术 - 亿速云 (yisu.com)

ElementUI upload 文件自定义上传 和 文件自定义分块上传 - 简书 (jianshu.com)

(2条消息) vue中,Upload上传组件el-upload的使用-zip格式,大小不超过10M & store中获取和保存token_viceen的博客-CSDN博客

        这边列一个示例

  1. <template>
  2. <div class="algo">
  3. <el-upload
  4. ref="upload"
  5. :action="action" <!--上传请求的服务器url建议设成变量-->
  6. :data="upload_data" <!--请求时发送额外参数,建议设成变量-->
  7. :limit="1" <!--限制上传文件的数量-->
  8. :on-exceed="handleExceed" <!--当超出限制时,执行的钩子函数,在这里就是当触发了limit后执行-->
  9. :on-success="handleSuccess" <!--请求成功后执行的函数,相当于axios的then-->
  10. :on-error="handleError" <!--请求失败后执行的函数,相当于axios的catch-->
  11. :beforeUpload="handleBeforeUpload" <!--发送请求前执行的函数,在这里可以做一些条件判断,配置参数等-->
  12. :auto-upload="false" <!--不自动上传-->
  13. >
  14. <template #trigger>
  15. <el-button type="primary">选择文件</el-button>
  16. </template>
  17. <el-button type="success" @click="submitUpload">上传</el-button>
  18. </el-upload>
  19. </div>
  20. </template>
  21. <script lang="ts" setup>
  22. import axois from "axios";
  23. import { reactive } from 'vue';
  24. import { genFileId } from 'element-plus';
  25. import type { UploadInstance, UploadProps, UploadRawFile } from 'element-plus';
  26. let action = ref<string>(axios.defaults.baseURL + '/upload'); // 这样就可以像发送其他axios请求一样,用axios的默认baseURL,而不用输一遍服务器地址,当然这个默认值需要提前配置的
  27. let upload_data = reactive<string>({}); // 直接设置成对象,方便后面添加内容
  28. const upload = ref<UploadInstance>(); // 这时上传对象的实例
  29. // 点击后会发送提交请求,但是在发送请求前会先调用handleBeforeUpload函数
  30. function submitUpload(): void {
  31. upload.value!.submit();
  32. }
  33. // 这个函数必须返回boolean参数,当返回false时,会自动停止发送上传请求
  34. function handleBeforeUpload(file: UploadRawFile): boolean {
  35. const type = file.name.split('.')[file.name.split('.').length - 1]; // 注意这里不能像python一样写-1
  36. if(type !== 'zip') { // 要求上传的时zip
  37. alert("必须上传zip格式的文件!");
  38. return false;
  39. }
  40. upload_data['a'] = '111'; // 在这里配置参数
  41. return true;
  42. }
  43. // 移除之前上传的内容,并用新的内容替代
  44. function handleExceed: UploadProps['onExceed'] = (files) => {
  45. upload.value!.clearFiles();
  46. const file = files[0] as UploadRawFile;
  47. file.uid = genFileId();
  48. upload.value!.handleStart(file);
  49. }
  50. function handleSuccess(response: any):void {
  51. console.log(response);
  52. }
  53. function handleError(error: Error):void {
  54. alert(error);
  55. }
  56. </script>

         这里有一个坑要注意,如果BeforeUpload中用到了异步函数,或者BeforeUpload本身就是异步函数的话,会导致BeforeUpload异步函数中的返回值无法控制submit,这个也有解决方案,但是并不好用,我建议直接把异步的函数包在调用submit接口的外面,这样可以很好的规避这个问题。

el-tabs

记录当前tab页

        使用el-tabs当切换页面是,其实是无法获取到当前处于哪一个页面的。我们可以给el-tabs添加一个点击触发的事件,在事件内由全局变量记录当前页面。但是这样会带来一个问题就是,el-tabs生成时不会激活任何页面,因此要给el-tabs绑定一个v-model,值就等于被激活页面的name属性的值。代码如下:

  1. <template>
  2. <div class="test">
  3. <el-tabs v-model="store.cur_tab" type="border-card" @tab-click="handleClick">
  4. <el-tab-pane label="first" name="first">
  5. <p>first</p>
  6. </el-tab-pane>
  7. <el-tab-pane label="second" name="second">
  8. <p>second</p>
  9. </el-tab-pane>
  10. </el-tabs>
  11. </div>
  12. </template>
  13. <script lang="ts" setup>
  14. import { mainStore } from '@/store';
  15. import { toRaw } from '@vue/reactivity';
  16. import type { TabsPaneContext } from 'element-plus';
  17. let store = mainStore();
  18. function handleClick(tab: TabsPaneContext, event: Event): void {
  19. store.cur_tab = toRaw(toRaw(tab).props).name;
  20. }
  21. </script>
  22. <style></style>

一些小技巧或坑

  1. element属性的值如果是函数或变量,则需要在属性前加上冒号
  2. element事件前要加上@

date-picker

  1. 默认的日期格式是Fri Jul  1 2022 00:00:00 GMT+0800(中国标准时间),增加value-format="YYYY-MM-DD HH:mm:ss"属性可以转换成2022-07-01 00:00:00格式
  2. 宽度控制:用css设置样式无法控制宽度,可以在元素中增加一个style属性
    1. <el-date-picker style="width:100%;"</el-date-picker>
    2. <el-date-picker style="width:250px;"</el-date-picker>

table

  1. 如果所有的el-table-column都设置了width,则可能出现无法占满整个屏幕的现象,这时只要把其中一个el-table-column的width改成min_width就可以了。
  2. fixed属性可以固定某个el-table-column,还可以通过赋值为'left' 或 'right'将某一列固定在左边或右边。
  3. 刷新table:给table添加key属性并绑定一个ref变量,当更新了data时,我们修改一下key对应的变量值,就可以触发table的重新渲染,将新的数据显示出来。
  4. 动态的嵌套表格vue+elementUI表格嵌套表单,包含联级下拉框、动态增加行_小佩丫的博客-CSDN博客_element表格嵌套表单理解element-ui中的slot-scope的理解_dongdongdongJL的博客-CSDN博客_element slot-scope

form

vue+element UI表单验证 - 走看看 (zoukankan.com)

未完待续。。。

参考资料

组件 | Element

 vue+elementUI表格嵌套表单,包含联级下拉框、动态增加行_小佩丫的博客-CSDN博客_element表格嵌套表单

 理解element-ui中的slot-scope的理解_dongdongdongJL的博客-CSDN博客_element slot-scope

 vue+element upload上传带参数的方法 - 开发技术 - 亿速云 (yisu.com)

 ElementUI upload 文件自定义上传 和 文件自定义分块上传 - 简书 (jianshu.com)

 vue中,Upload上传组件el-upload的使用-zip格式,大小不超过10M & store中获取和保存token_viceen的博客-CSDN博客

vue+element UI表单验证 - 走看看 (zoukankan.com)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/116828
推荐阅读
相关标签
  

闽ICP备14008679号