赞
踩
目录
element-plus的官网上已经把各种组件的实用说明写的比较清楚了,并且由于element-plus功能很强大,属性、组件都很多,不可能全部整理下来,也没有必要,大家有需要的可以直接去官网查看。因此这篇文章主要记录一下element-plus组件的一些实用技巧和注意事项,同时会提供对应的代码示例。
这里插上官网地址:
一个 Vue 3 UI 框架 | Element Plus (gitee.io)
这里使用el-menu组件和vue-router实现菜单栏以及页面的跳转。
官网上说设置了router属性后就可以使用vue-router实现跳转了,咱们来试一试。
- <template>
- <el-menu
- router
- class="el-menu-demo"
- mode="horizontal"
- background-color="#545c64"
- text-color="#fff"
- active-text-color="#ffd04b"
- >
- <el-menu-item index="'/home/' + /">首页</el-menu-item>
- <el-menu-item index="'/home/' + /page1">页面1</el-menu-item>
- <el-menu-item index="'/home/' + /page2">页面2</el-menu-item>
- <el-menu-item index="'/home/' + /page3">页面3</el-menu-item>
- </el-menu>
- <router-view />
- </template>
-
- <script></script>
- <style></style>
这里要注意,index的路径要用字符串拼接的形式
index="'/home/' + url"
同时要记得先配置好vue-route,router/index.ts
- import { createRouter, createWebHistory } from 'vue-router'
- import Home from '../views/Home.vue'
-
- const routes = [
- {
- path: '/',
- name: 'Home',
- component: Home
- },
- {
- path: '/page1',
- name: 'Page1',
- component: () => import(/* webpackChunkName: "about" */ '../views/Page1.vue')
- },
- {
- path: '/page2',
- name: 'Page2',
- component: () => import('../views/Page2.vue')
- },
- {
- path: '/page3',
- name: 'Page3',
- component: () => import('../views/Page3.vue')
- }
- ]
-
- const router = createRouter({
- history: createWebHistory(process.env.BASE_URL),
- routes
- })
-
- export default router
实际效果如下:
el-menu有一个属性是default-active,用来设置默认激活的菜单。咱们可以把他设置成一个ref变量,变量的内容是菜单的index,也就是下面el-menu-item的index属性内容。这样当变量改变时,对应的菜单就会显示成激活状态了。
- <template>
- <el-menu
- :default-active="activeIndex"
- mode="horizontal"
- >
- <el-menu-item index="1">Processing Center</el-menu-item>
- <el-sub-menu index="2">
- <template #title>Workspace</template>
- <el-menu-item index="2-1">item one</el-menu-item>
- <el-menu-item index="2-2">item two</el-menu-item>
- <el-menu-item index="2-3">item three</el-menu-item>
- <el-sub-menu index="2-4">
- <template #title>item four</template>
- <el-menu-item index="2-4-1">item one</el-menu-item>
- <el-menu-item index="2-4-2">item two</el-menu-item>
- <el-menu-item index="2-4-3">item three</el-menu-item>
- </el-sub-menu>
- </el-sub-menu>
- <el-menu-item index="3" disabled>Info</el-menu-item>
- <el-menu-item index="4">Orders</el-menu-item>
- </el-menu>
- </template>
-
- <script lang="ts" setup>
- import { ref } from 'vue'
-
- const activeIndex = ref('1')
- </script>
使用span-method方法可以合并行或列,官网上的说明不是很详细,这边直接拿官网的示例解释一下,比如我们想实现以下效果,将id奇偶行合并。
我们先给el-table添加一个span-method属性
- <el-table
- :data="tableData"
- :span-method="objectSpanMethod"
- border
- style="width: 100%; margin-top: 20px"
- >
- </el-table>
然后我们定义一个接口,这个其实不定义也是可以的。
要注意这里的变量除了User,名称都不能修改!
- interface SpanMethodProps {
- row: User
- column: TableColumnCtx<User>
- rowIndex: number
- columnIndex: number
- }
最后我们定义一下合并规则
判断条件还是比较好理解的就不说了,主要是返回值,先说第二个return,两个0代表是空值,也就是被合并的格给他设成空值就行了;第一个return,rowspan表示合并的行数,colspan表示合并的列数。这里的合并规则就是当列索引时0时,也就是从第一列开始每两行每一列合并成一个格子,且被合并的单元格置空。
const objectSpanMethod = ({ row, column, rowIndex, columnIndex, }: SpanMethodProps) => { if (columnIndex === 0) { if (rowIndex % 2 === 0) { return { rowspan: 2, colspan: 1, } } else { return { rowspan: 0, colspan: 0, } } } }
先来看看效果,这个是我们的数据,假设是一个描述图书馆藏书情况的多层嵌套yaml文件。
- '历史':
- '中国':
- '清朝': ['2本', 'A1-2']
- '明朝': ['3本', 'A3-5']
- '外国':
- '法国': ['2本', 'B1-2']
- '美国':
- '独立战争': ['1本', 'B3']
- '音乐':
- '钢琴': ['5本', 'C1-5']
- '古典': ['1本', 'C6']
显示出来效果如下
可以看到表格中的格式与我们的数据格式一致的,废话不多说,直接上代码:
- <template>
- <div>
- <el-table
- :data="tableData"
- style="width: 100%; margin-bottom: 20px"
- row-key="id"
- max-height="800"
- border
- default-expand-all
- > <!--max-height随便用来控制表格高度,用height不好使-->
- <el-table-column fixed prop="class" label="分类" sortable width="250" />
- <el-table-column prop="num" label="数量" sortable width="250" />
- <el-table-column prop="position" label="位置" sortable min-width="300" />
- </el-table>
- </div>
- </template>
-
- <script lang="ts" setup>
- import axios from 'axios';
- import { ref, onBeforeMount } from 'vue';
-
- interface Books {
- id: number;
- class: string;
- num?: string;
- position?: string;
- children?: Books[];
- }
-
- onBeforeMount(() => {
- getMessage();
- });
-
- let table_data = ref<Books[]>([]);
-
- function getMessage(): void {
- axios.get('/getMessage').then((response) => {
- let idx: number = 0; // 保证递归时的idx是全局的
- table_data.value.splice(0, table_data.value.length);
-
- display(response.data['message'], idx, table_data.value);
- })
- }
-
- function display(data: any, idx: number, idArr: Books[] = []): number {
- for(let key in data) {
- let value: any = data[key];
- let type: string = getType(value);
-
- if(type === "dict") {
- let child_books: Books[] = [];
- idArr.push({
- id: idx++,
- class: key,
- children: child_books
- });
- idx = display(value, idx, child_books);
- }
- else {
- idArr.push({
- id: idx++,
- class: key,
- index: -1,
- num: <string>(<unknown>value[0]),
- position: <string>(<unknown>value[1])
- });
- }
- }
- return idx;
- }
-
- function getType(data: any): string {
- let type = Object.prototype.toString.call(data);
-
- if(type === "[object Object]") return "dict";
- else {
- if(type === "[object Array]") return "list";
- else return "other";
- }
- }
- </script>
也先来看看效果,双击某个单元格,可以编辑,但是不能编辑原本就不应该存在数据的单元格。
在原来的代码上修改
- <template>
- <div>
- <el-table
- :data="tableData"
- style="width: 100%; margin-bottom: 20px"
- row-key="id"
- max-height="800"
- border
- default-expand-all
-
- @cell-dblclick="editData"
- :cell-class-name="setCellClassName"
- >
- <!--用cell-dblclick绑定一个鼠标双击事件editData-->
- <!--用cell-class-name给每个单元格绑定位置信息-->
- <el-table-column fixed prop="class" label="分类" sortable width="250">
- <template #default='scope'>
- <el-input
- class="el-input"
- size="default"
- v-model="scope.row.class"
- v-if="scope.row.index+','+scope.column.index == current_cell"
- autofocus="true"
- @blur="hideInput"
- />
- <!--给一个class,为了让el-input尺寸小一些,避免换行-->
- <!--v-model绑定该单元格的数据-->
- <!--v-if和v-else成对使用,根据当前单元格位置信息切换显示状态-->
- <!--autofocus,显示的时候自动聚焦-->
- <!--blur,失去焦点时执行的函数-->
- <span v-else>{{ scope.row.class }}</span>
- </template>
- </el-table-column>
- <el-table-column prop="num" label="数量" sortable width="250">
- <template #default='scope'>
- <el-input
- class="el-input"
- size="default"
- v-model="scope.row.num"
- v-if="scope.row.index+','+scope.column.index == current_cell"
- autofocus="true"
- @blur="hideInput"
- />
- <span v-else>{{ scope.row.num }}</span>
- </template>
- </el-table-column>
- <el-table-column prop="position" label="位置" sortable min-width="300">
- <template #default='scope'>
- <el-input
- class="el-input"
- size="default"
- v-model="scope.row.position"
- v-if="scope.row.index+','+scope.column.index == current_cell"
- autofocus="true"
- @blur="hideInput"
- />
- <span v-else>{{ scope.row.position }}</span>
- </template>
- </el-table-column>
- </el-table>
- </div>
- </template>
-
- <script lang="ts" setup>
- import axios from 'axios';
- import { ref, onBeforeMount } from 'vue';
- import { toRaw } from '@/vue/reactivity';
-
- interface Books {
- id: number;
- class: string;
- num?: string;
- position?: string;
- index?: number; //增加一个index用于当前的row位置信息
- children?: Books[];
- }
-
- onBeforeMount(() => {
- getMessage();
- });
-
- let table_data = ref<Books[]>([]);
- let current_cell = ref<string | null>(null); // 记录双击选中的单元格位置信息
-
- function getMessage(): void {
- axios.get('/getMessage').then((response) => {
- let idx: number = 0; // 保证递归时的idx是全局的
- table_data.value.splice(0, table_data.value.length);
-
- display(response.data['message'], idx, table_data.value);
- })
- }
-
- function display(data: any, idx: number, idArr: Books[] = []): number {
- for(let key in data) {
- let value: any = data[key];
- let type: string = getType(value);
-
- if(type === "dict") {
- let child_books: Books[] = [];
- idArr.push({
- id: idx++,
- class: key,
- children: child_books
- });
- idx = display(value, idx, child_books);
- }
- else {
- idArr.push({
- id: idx++,
- class: key,
- index: -1,
- num: <string>(<unknown>value[0]),
- position: <string>(<unknown>value[1])
- });
- }
- }
- return idx;
- }
-
- function getType(data: any): string {
- let type = Object.prototype.toString.call(data);
-
- if(type === "[object Object]") return "dict";
- else {
- if(type === "[object Array]") return "list";
- else return "other";
- }
- }
-
- // 在初始化表格的时候就给每个单元格赋予位置信息
- function setCellClassName({ row, column, rowIndex, columnIndex }): void {
- row.index = rowIndex;
- column.index = columnIndex;
- }
-
- // 双击后先判断当前单元格是否可能存在数据,可能的话,把current_cell置为当前单元格的位置
- function editData(row, colunm): void {
- if(row.children != undefined &&column.index != 0) {}
- else {
- current_cell.value = row.index + ',' + column.index;
- }
- }
-
- // 失去焦点后,把current_cell置为null
- function hideInput(row): void {
- current_cell.value = null;
- }
- </script>
-
- <style scope>
- .el-input {
- width: 80%;
- }
- </style>
这个组件用于文件上传,先上一些参考文章
vue+element upload上传带参数的方法 - 开发技术 - 亿速云 (yisu.com)
ElementUI upload 文件自定义上传 和 文件自定义分块上传 - 简书 (jianshu.com)
(2条消息) vue中,Upload上传组件el-upload的使用-zip格式,大小不超过10M & store中获取和保存token_viceen的博客-CSDN博客
这边列一个示例
- <template>
- <div class="algo">
- <el-upload
- ref="upload"
- :action="action" <!--上传请求的服务器url,建议设成变量-->
- :data="upload_data" <!--请求时发送额外参数,建议设成变量-->
- :limit="1" <!--限制上传文件的数量-->
- :on-exceed="handleExceed" <!--当超出限制时,执行的钩子函数,在这里就是当触发了limit后执行-->
- :on-success="handleSuccess" <!--请求成功后执行的函数,相当于axios的then-->
- :on-error="handleError" <!--请求失败后执行的函数,相当于axios的catch-->
- :beforeUpload="handleBeforeUpload" <!--发送请求前执行的函数,在这里可以做一些条件判断,配置参数等-->
- :auto-upload="false" <!--不自动上传-->
- >
- <template #trigger>
- <el-button type="primary">选择文件</el-button>
- </template>
- <el-button type="success" @click="submitUpload">上传</el-button>
- </el-upload>
- </div>
- </template>
-
- <script lang="ts" setup>
- import axois from "axios";
- import { reactive } from 'vue';
- import { genFileId } from 'element-plus';
- import type { UploadInstance, UploadProps, UploadRawFile } from 'element-plus';
-
- let action = ref<string>(axios.defaults.baseURL + '/upload'); // 这样就可以像发送其他axios请求一样,用axios的默认baseURL,而不用输一遍服务器地址,当然这个默认值需要提前配置的
- let upload_data = reactive<string>({}); // 直接设置成对象,方便后面添加内容
- const upload = ref<UploadInstance>(); // 这时上传对象的实例
-
- // 点击后会发送提交请求,但是在发送请求前会先调用handleBeforeUpload函数
- function submitUpload(): void {
- upload.value!.submit();
- }
-
- // 这个函数必须返回boolean参数,当返回false时,会自动停止发送上传请求
- function handleBeforeUpload(file: UploadRawFile): boolean {
- const type = file.name.split('.')[file.name.split('.').length - 1]; // 注意这里不能像python一样写-1
- if(type !== 'zip') { // 要求上传的时zip
- alert("必须上传zip格式的文件!");
- return false;
- }
-
- upload_data['a'] = '111'; // 在这里配置参数
- return true;
- }
-
- // 移除之前上传的内容,并用新的内容替代
- function handleExceed: UploadProps['onExceed'] = (files) => {
- upload.value!.clearFiles();
- const file = files[0] as UploadRawFile;
- file.uid = genFileId();
- upload.value!.handleStart(file);
- }
-
- function handleSuccess(response: any):void {
- console.log(response);
- }
-
- function handleError(error: Error):void {
- alert(error);
- }
- </script>
这里有一个坑要注意,如果BeforeUpload中用到了异步函数,或者BeforeUpload本身就是异步函数的话,会导致BeforeUpload异步函数中的返回值无法控制submit,这个也有解决方案,但是并不好用,我建议直接把异步的函数包在调用submit接口的外面,这样可以很好的规避这个问题。
使用el-tabs当切换页面是,其实是无法获取到当前处于哪一个页面的。我们可以给el-tabs添加一个点击触发的事件,在事件内由全局变量记录当前页面。但是这样会带来一个问题就是,el-tabs生成时不会激活任何页面,因此要给el-tabs绑定一个v-model,值就等于被激活页面的name属性的值。代码如下:
- <template>
- <div class="test">
- <el-tabs v-model="store.cur_tab" type="border-card" @tab-click="handleClick">
- <el-tab-pane label="first" name="first">
- <p>first</p>
- </el-tab-pane>
- <el-tab-pane label="second" name="second">
- <p>second</p>
- </el-tab-pane>
- </el-tabs>
- </div>
- </template>
-
- <script lang="ts" setup>
- import { mainStore } from '@/store';
- import { toRaw } from '@vue/reactivity';
- import type { TabsPaneContext } from 'element-plus';
-
- let store = mainStore();
-
- function handleClick(tab: TabsPaneContext, event: Event): void {
- store.cur_tab = toRaw(toRaw(tab).props).name;
- }
- </script>
-
- <style></style>
- <el-date-picker style="width:100%;"</el-date-picker>
-
- <el-date-picker style="width:250px;"</el-date-picker>
vue+element UI表单验证 - 走看看 (zoukankan.com)
未完待续。。。
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博客
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。