目录
写在前面
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>
el-table:span-method
使用span-method方法可以合并行或列,官网上的说明不是很详细,这边直接拿官网的示例解释一下,比如我们想实现以下效果,将id奇偶行合并。
我们先给el-table添加一个span-method属性
<el-table
:data="tableData"
:span-method="objectSpanMethod"
border
style="width: 100%; margin-top: 20px"
>
</el-table>
然后我们定义一个接口,这个其实不定义也是可以的。
- User是表格数据的接口,请根据实际修改
- row表示表格每一行的数据
- column表示表格每一列的数据
- rowIndex表示表格的行索引,不包括表头,从0开始
- columnIndex表示表格的列索引,从0开始
要注意这里的变量除了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,
}
}
}
}
el-table树状表格递归显示数据及双击单元格修改功能
树状表格递归显示数据
先来看看效果,这个是我们的数据,假设是一个描述图书馆藏书情况的多层嵌套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>
el-upload
这个组件用于文件上传,先上一些参考文章
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>
el-tabs
记录当前tab页
使用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>
一些小技巧或坑
- element属性的值如果是函数或变量,则需要在属性前加上冒号
- element事件前要加上@
date-picker
- 默认的日期格式是Fri Jul 1 2022 00:00:00 GMT+0800(中国标准时间),增加value-format=”YYYY-MM-DD HH:mm:ss”属性可以转换成2022-07-01 00:00:00格式
- 宽度控制:用css设置样式无法控制宽度,可以在元素中增加一个style属性
<el-date-picker style="width:100%;"</el-date-picker> <el-date-picker style="width:250px;"</el-date-picker>
table
- 如果所有的el-table-column都设置了width,则可能出现无法占满整个屏幕的现象,这时只要把其中一个el-table-column的width改成min_width就可以了。
- fixed属性可以固定某个el-table-column,还可以通过赋值为’left’ 或 ‘right’将某一列固定在左边或右边。
- 刷新table:给table添加key属性并绑定一个ref变量,当更新了data时,我们修改一下key对应的变量值,就可以触发table的重新渲染,将新的数据显示出来。
- 动态的嵌套表格vue+elementUI表格嵌套表单,包含联级下拉框、动态增加行_小佩丫的博客-CSDN博客_element表格嵌套表单理解element-ui中的slot-scope的理解_dongdongdongJL的博客-CSDN博客_element slot-scope
form
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博客
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/100778.html