管理员页面
搜索防抖
ts
// 防抖搜索
const handleSearch = debounce(() => {
querySearch.value = querySearch.value.trim();
getAdminUserList()
}, 500)
vue
<div class="search-right">
<el-input v-model="querySearch" style="width: 240px;margin-right: 4px;" placeholder="用户名" clearable
:prefix-icon="Search" @clear='clearQuerySearch' @input="handleSearch" />
<el-button class="search-right-button-item" @click="getAdminUserList">
<ele-Search style="width: 1em; height: 1em; margin-right: 4px;"></ele-Search>
<span>搜索</span>
</el-button>
</div>
defineProps问题
ts
这通常是因为传递给子组件的 RolesList 是一个对象,而 Vue 的 props 是默认浅层侦听的。当你更新数组的内容而不是整个引用时,子组件并没有感知到变化。
问题原因
浅层侦听 (shallow):Vue 对 props 默认是浅层侦听,如果父组件更新的是对象/数组内部的内容(如 push、splice 等),子组件可能不会感知到变化。
数据初始化时机:如果你在传递数据时 RolesList 尚未赋值完成,子组件可能会接收到一个空数组。
RolesList定义类型
你需要给 RolesList
指定具体的数组元素类型。例如,假设你的角色列表每一项是一个对象,包含 id
、name
和 remark
属性,可以这样定义类型:
ts
<script lang="ts">
import { defineProps } from 'vue';
interface Role {
id: number;
name: string;
remark: string;
}
const props = defineProps<{
RolesList: Role[];
}>();
</script>
<template>
<el-option
v-for="item in RolesList"
:key="item.id"
:label="item.remark"
:value="item.name"
/>
</template>
在 Vue 3 中使用 TypeScript 时,defineProps 默认不会推断数组中元素的具体类型,因此 item 被推断为 unknown 类型。为了解决这个问题,可以在 defineProps 中显式声明 RolesList 的类型。
解决方法:为 RolesList 定义类型
你需要给 RolesList 指定具体的数组元素类型。例如,假设你的角色列表每一项是一个对象,包含 id、name 和 remark 属性,可以这样定义类型:
修改代码如下:
vue
复制代码
<script lang="ts">
import { defineProps } from 'vue';
interface Role {
id: number;
name: string;
remark: string;
}
const props = defineProps<{
RolesList: Role[];
}>();
</script>
<template>
<el-option
v-for="item in RolesList"
:key="item.id"
:label="item.remark"
:value="item.name"
/>
</template>
关键点解析
定义接口 Role:
通过 interface Role 定义每个角色对象的类型,包括 id(数字)、name(字符串)、remark(字符串)。
为 RolesList 指定类型:
使用 defineProps<{ RolesList: Role[] }>() 明确地将 RolesList 定义为一个包含 Role 对象的数组。
自动推断 item 类型:
因为 RolesList 的类型是 Role[],v-for 中的 item 会被推断为 Role 类型。
现在,item.id、item.name 和 item.remark 都有类型提示。
格式化数据
ts
interface TreeNode {
id: number;
label: string;
children?: TreeNode[];
[key: string]: any; // 允许其他字段存在
}
interface TransformedNode {
id: number;
value: number;
label: string;
children?: TransformedNode[];
}
const transformedList = ref<TransformedNode[]>([]);
// 递归处理树形结构
const transformTree = (nodes: TreeNode[]): TransformedNode[] => {
return nodes.map((node) => ({
id: node.id,
value: node.id, // 设置 value 为 id
label: node.label,
children: node.children ? transformTree(node.children) : undefined, // 递归处理子节点
}));
};
清空校验结果
父组件
ts
<UserForm ref="userform" :RolesList="state.RolesList" :OrganTreeList="state.OrganTreeList"
v-model:scene="scene">
</UserForm>
const userform = ref();
// 创建用户
const handleCreateUser = () => {
// 切换场景
scene.value = 1
// 重置表单数据 清空校验结果
userform.value.resetFiledResult()
}
子组件
ts
<el-form ref="formRef"
// form对象
const formRef = ref<any>()
// 清空校验结果
const resetFiledResult = () =>{
// 重置为初始值,并移除校验结果
formRef.value.resetFields()
}
// 暴漏数据
defineExpose({UserParams,resetFiledResult})
动态按钮状态
ts
定义表单验证规则: 确保 username、passwd、organs、roles 都通过验证。
动态计算按钮是否禁用: 通过计算属性动态判断是否满足条件。
绑定按钮的 disabled 属性: 根据计算属性的结果启用或禁用按钮。
vue
<template>
<div>
<el-form :model="UserParams" :rules="rules" ref="userForm" @submit.native.prevent>
<el-form-item label="用户名" prop="username">
<el-input v-model="UserParams.username" placeholder="请输入用户名" />
</el-form-item>
<el-form-item label="密码" prop="passwd">
<el-input v-model="UserParams.passwd" type="password" placeholder="请输入密码" />
</el-form-item>
<el-form-item label="组织机构" prop="organs">
<el-select v-model="UserParams.organs" placeholder="请选择机构" multiple>
<el-option label="机构A" value="A"></el-option>
<el-option label="机构B" value="B"></el-option>
</el-select>
</el-form-item>
<el-form-item label="角色" prop="roles">
<el-input v-model="UserParams.roles" placeholder="请输入角色" />
</el-form-item>
<el-button :disabled="isSubmitDisabled" type="primary" @click="handleSubmit">
确定
</el-button>
</el-form>
</div>
</template>
<script>
import { ref, computed } from 'vue';
export default {
setup() {
// 表单数据
const UserParams = ref({
id: '',
username: '',
passwd: null,
orgId: '',
organs: [],
roles: '',
mobile: '',
nickName: '',
email: '',
avatar: '',
});
// 表单验证规则
const rules = {
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
passwd: [{ required: true, message: '请输入密码', trigger: 'blur' }],
organs: [{ type: 'array', required: true, message: '请选择组织机构', trigger: 'change' }],
roles: [{ required: true, message: '请输入角色', trigger: 'blur' }],
};
const userForm = ref(null);
// 动态计算按钮是否禁用
const isSubmitDisabled = computed(() => {
// 检查必须的字段是否有值
const { username, passwd, organs, roles } = UserParams.value;
const isFieldsFilled = username && passwd && organs.length > 0 && roles;
return !isFieldsFilled; // 禁用按钮条件:字段未填写
});
// 提交处理逻辑
const handleSubmit = () => {
userForm.value.validate((valid) => {
if (valid) {
console.log('表单验证通过,提交数据:', UserParams.value);
} else {
console.log('表单验证失败');
}
});
};
return {
UserParams,
rules,
userForm,
isSubmitDisabled,
handleSubmit,
};
},
};
</script>
密码加解密
ts
import * as CryptoJS from 'crypto-js';
/**
* AES 解密函数
* @param encryptedWord 加密的 Base64 编码密文
* @returns 解密后的明文字符串
*/
export function Decrypt(encryptedWord: string): string {
const key = CryptoJS.enc.Utf8.parse('123123'); // 与加密时相同的密钥字符串
const iv = CryptoJS.enc.Utf8.parse('123132'); // 与加密时相同的初始向量字符串
// 使用 AES 解密
const decrypted = CryptoJS.AES.decrypt(encryptedWord, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.ZeroPadding,
});
// 解密后的数据是一个 WordArray,需要转换为 UTF-8 字符串
return decrypted.toString(CryptoJS.enc.Utf8);
}
解密方法说明
ts
密钥与初始向量:
解密方法中的密钥 (key) 和初始向量 (iv) 必须与加密方法保持一致。
CryptoJS.AES.decrypt:
接受加密的字符串和密钥,用于解密数据。
返回值是一个 WordArray。
toString(CryptoJS.enc.Utf8):
将解密后的 WordArray 转换为明文字符串。
示例
ts
假设加密后的密文是 encryptedString:
const encryptedString = Encrypt('hello world'); // 加密
console.log('加密后的密文:', encryptedString);
const decryptedString = Decrypt(encryptedString); // 解密
console.log('解密后的明文:', decryptedString);
加密后的密文: [加密后的 Base64 字符串]
解密后的明文: hello world
数组的最后一个
ts
方法 2: 使用 slice 方法
const lastItem = arr.slice(-1)[0];
优点: 如果数组为空,会返回 undefined,更加安全。
示例:
const arr = [1, 2, 3, 4];
const lastItem = arr.slice(-1)[0];
console.log(lastItem); // 输出: 4
使用闭包传递参数
在 Vue 3 中,如果 :before-change 回调函数不能直接传递参数,可以通过以下方法来控制指定的开关,而不是所有开关:
方法 1: 使用闭包传递参数
为每个开关的 before-change 动态绑定一个闭包函数,在闭包中传递指定的参数。
ts
<template>
<el-switch
v-for="item in switches"
:key="item.id"
v-model="item.value"
:before-change="switchBeforeChangeWrapper(item.id)"
/>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const switches = ref([
{ id: 1, value: false },
{ id: 2, value: true },
{ id: 3, value: false },
]);
// 闭包函数包装
const switchBeforeChangeWrapper = (id) => {
return (newValue) => switchBeforeChange(id, newValue);
};
// 具体的 before-change 回调函数
const switchBeforeChange = (id, newValue) => {
console.log(`Switch with ID ${id} is changing to ${newValue}`);
// 控制逻辑
return new Promise((resolve) => {
setTimeout(() => {
// 模拟异步检查,比如确认弹窗
resolve(newValue); // 同意更改
}, 1000);
});
};
return {
switches,
switchBeforeChangeWrapper,
};
},
};
</script>
实际代码
vue
<el-table-column prop="inotice" label="短信通知" width="120">
<template #default="scope">
<el-switch v-model="scope.row.inotice" :loading="scope.row.switchLoading"
:before-change="switchBeforeChangeWrapper(scope.row.id)" @change="switchChange" />
</template>
</el-table-column>
ts
// 在源数据中添加字段 用于控制加载效果
// 获取管理用户列表
const getAdminUserList = async () => {
// query参数
const params = {
current: currentPage.value,
size: pageSize.value,
uname: querySearch.value,
orgs: organsStr
}
// 发送请求
try {
await reqAdminUserList(params).then((res) => {
// 存储数据
totalCount.value = res.list.total
// 遍历-并添加加载字段
const tmpList = res.list.records.map((item: any) => {
item.switchLoading = false
return item
})
AdminUserList.value = tmpList
})
} catch (error) {
console.error(error)
}
}
// 闭包函数包装
const switchBeforeChangeWrapper = (id: any) => {
return () => switchBeforeChange(id);
}
// 开关切换状态前回调
const switchBeforeChange = (id: any) => {
AdminUserList.value.forEach((element: any) => {
if (element.id === id) {
element.switchLoading = true
}
});
return new Promise<boolean>((resolve, reject) => {
setTimeout(() => {
AdminUserList.value.forEach((element: any) => {
if (element.id === id) {
element.switchLoading = false
}
});
// 消息提示
// 提示消息
ElNotification({
title: '成功',
message: `切换成功`,
type: 'success',
})
return resolve(true)
}, 1000)
})
}
el-switch转换1和0
ts
配合 :active-value 和 :inactive-value
可以通过 el-switch 的 active-value 和 inactive-value 来控制绑定的值,将字符串 '1' 和 '0' 转换为布尔值 true 和 false。
<template>
<el-switch
v-model="scope.row.inotice"
:active-value="'1'"
:inactive-value="'0'"
/>
</template>
剪切板插件
ts
可以通过 clipboard.js 插件实现复制当前选中行对象的账号、密码,并生成自定义格式和自定义网址的功能。
npm install clipboard
安装 clipboard.js 安装 clipboard.js 插件:
npm install clipboard
创建按钮和绑定事件 为每一行数据生成一个“复制”按钮,按钮会触发复制操作。
自定义复制内容 使用 clipboard.js 的 text 参数,自定义需要复制的内容(如账号、密码、格式和网址)。
示例代码
vue
<template>
<div>
<el-table :data="tableData" border style="width: 100%">
<el-table-column prop="account" label="账号" />
<el-table-column prop="password" label="密码" />
<el-table-column label="操作">
<template #default="scope">
<!-- 复制按钮 -->
<el-button
type="primary"
size="small"
class="copy-btn"
:data-account="scope.row.account"
:data-password="scope.row.password"
@click="handleCopy(scope.row)"
>
复制
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import Clipboard from 'clipboard';
export default {
data() {
return {
// 示例表格数据
tableData: [
{
account: 'user1',
password: 'password1',
},
{
account: 'user2',
password: 'password2',
},
],
};
},
mounted() {
// 初始化 Clipboard
this.clipboard = new Clipboard('.copy-btn', {
text: (trigger) => {
const account = trigger.getAttribute('data-account');
const password = trigger.getAttribute('data-password');
// 自定义格式化内容
return `账号: ${account}\n密码: ${password}\n网址: https://example.com`;
// 格式化内容2
return `
--------------------------------------------
账号: ${account}
密码: ${password}
网址: http://jdgz.xwydl.com/show/temper/
--------------------------------------------
`.trim();
},
});
// 复制成功提示
this.clipboard.on('success', (e) => {
this.$message.success('复制成功!');
e.clearSelection();
});
// 复制失败提示
this.clipboard.on('error', () => {
this.$message.error('复制失败,请重试!');
});
},
beforeDestroy() {
// 销毁 Clipboard 实例
if (this.clipboard) {
this.clipboard.destroy();
}
},
methods: {
// 处理点击复制事件(可以扩展逻辑)
handleCopy(row) {
console.log('复制内容:', row);
},
},
};
</script>
ts
点击表格中的“复制”按钮时,将复制如下格式的内容到剪贴板:
makefile
复制代码
账号: user1
密码: password1
网址: https://example.com
成功时弹出提示框“复制成功!”。
ts
自定义扩展
动态网址
如果网址需要动态生成,可以在 text 方法中根据行数据生成。
return `账号: ${account}\n密码: ${password}\n网址: https://yourwebsite.com/${account}`;
复制多个字段
可以扩展复制的内容,添加更多字段。
样式优化
使用 el-tooltip 添加鼠标悬停提示,比如显示“点击复制”。
<el-tooltip content="点击复制" placement="top">
<el-button type="primary" size="small" class="copy-btn" ...>
复制
</el-button>
</el-tooltip>
遍历10个div
vue
<template>
<div style="padding: 10px;" v-for="(_, index) in 10" :key="index">
<div style="display: flex; align-items: center; justify-content: space-between; height: 30px;">
<el-skeleton-item
v-for="itemWidth in skeletonWidths"
:key="itemWidth + index"
variant="text"
:style="{ marginBottom: '16px', width: `${itemWidth}px`, height: '30px', marginLeft: itemWidth === skeletonWidths[0] ? '0' : '50px' }"
/>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
name: "SkeletonTable",
setup() {
// 定义每个 skeleton-item 的宽度
const skeletonWidths = [150, 150, 150, 150, 150, 80, 180, 150];
return {
skeletonWidths,
};
},
});
</script>
el-tabel同时绑定两个数组
ts
你可以通过一个计算属性来实现这一逻辑。当 rackTableData 有数据时显示它,没有数据时显示 roomTableData。
以下是具体实现方式:
vue
<script setup>
import { computed } from 'vue';
const props = defineProps(['rackTableData', 'roomTableData']);
// 创建一个计算属性,根据 rackTableData 的有无数据动态返回 tableData
const tableData = computed(() => {
return props.rackTableData && props.rackTableData.length > 0
? props.rackTableData
: props.roomTableData;
});
</script>
<template>
<el-table :data="tableData" style="width: 100%;">
<!-- Table 内容 -->
</el-table>
</template>
el-statistic字体样式设置
vue
<el-statistic :value="outputValue" :value-style="{ fontSize: '24px', color: '#42b983', fontWeight: 'bold' }">
<template #title>
<div style="display: inline-flex; align-items: center">
Ratio of men to women
<el-icon style="margin-left: 4px" :size="12">
<Male />
</el-icon>
</div>
</template>
<template #suffix >
<el-icon style="vertical-align: -0.125em;font-size: 20px;">
<Odometer />
</el-icon>
</template>
</el-statistic>
vertical-align
ts
在 CSS 中,vertical-align 是一个用于设置元素的垂直对齐方式的属性,主要用于 内联元素、内联块级元素、表格单元格的对齐。
ts
语法
vertical-align: value;
常见取值
- 基于文字基线对齐:
baseline
(默认值):元素的基线与其父元素的基线对齐。top
:元素顶部与其父元素内容区的顶部对齐。bottom
:元素底部与其父元素内容区的底部对齐。middle
:元素的垂直中心与其父元素的基线加上 1/2 x 行高对齐。
- 与父容器对齐:
sub
:将元素对齐到父元素下标的位置。super
:将元素对齐到父元素上标的位置。text-top
:将元素对齐到父元素文本顶部。text-bottom
:将元素对齐到父元素文本底部。
- 百分比值:
- 使用百分比值(例如
50%
),相对于元素的行高进行偏移。
- 使用百分比值(例如
使用场景
内联元素对齐 如果一个图标(如
<img>
)嵌入到文字中,图标默认可能会和文字基线对齐。可以使用vertical-align
来调整其位置:html<span>文本 <img src="icon.png" style="vertical-align: middle;"> 文本</span>
表格内容对齐 表格中的内容可以通过
vertical-align
设置:html<table> <tr> <td style="vertical-align: top;">顶部对齐</td> <td style="vertical-align: middle;">中间对齐</td> <td style="vertical-align: bottom;">底部对齐</td> </tr> </table>
块级元素中无效 如果
vertical-align
用在块级元素(如<div>
),是无效的。通常需要结合flexbox
或grid
布局实现垂直对齐。
示例
html
<div style="line-height: 50px;">
<span style="vertical-align: top;">顶部对齐</span>
<span style="vertical-align: middle;">中间对齐</span>
<span style="vertical-align: bottom;">底部对齐</span>
</div>
注意事项
vertical-align
是专门为内联内容设计的,不能直接用于块级元素。- 如果需要让整个块级元素垂直居中,可以结合
flexbox
或其他布局技术
css
display: flex;
align-items: center;
justify-content: center;
height: 100px;
el-滚动条
vue
<el-scrollbar class="timeline-scrollbar">
<el-timeline style="max-width: 600px">
<el-timeline-item timestamp="2018/4/12" placement="top">
<el-card>
<h4>Update Github template</h4>
<p>Tom committed 2018/4/12 20:46</p>
</el-card>
</el-timeline-item>
<el-timeline-item timestamp="2018/4/3" placement="top">
<el-card>
<h4>Update Github template</h4>
<p>Tom committed 2018/4/3 20:46</p>
</el-card>
</el-timeline-item>
<el-timeline-item timestamp="2018/4/2" placement="top">
<el-card>
<h4>Update Github template</h4>
<p>Tom committed 2018/4/2 20:46</p>
</el-card>
</el-timeline-item>
</el-timeline>
</el-scrollbar>
<style scoped lang="scss">
.timeline-scrollbar {
height: 300px;
/* 固定高度 */
border: 1px solid #ebeef5;
/* 边框(可选) */
padding: 10px;
/* 内边距(可选) */
}
</style>
手动写滚动条
vue
<div class="timeline-container">
<el-timeline>
<el-timeline-item
v-for="item in timelineData"
:key="item.id"
:timestamp="item.timestamp"
placement="top"
>
{{ item.content }}
</el-timeline-item>
</el-timeline>
</div>
</template>
css
.timeline-container::-webkit-scrollbar {
width: 6px; /* 滚动条宽度 */
}
.timeline-container::-webkit-scrollbar-thumb {
background-color: #c0c4cc; /* 滚动条颜色 */
border-radius: 3px; /* 圆角 */
}
.timeline-container::-webkit-scrollbar-track {
background-color: #f5f5f5; /* 滚动条轨道颜色 */
}
.timeline-container {
height: 300px; /* 固定高度 */
overflow-y: auto; /* 启用垂直滚动条 */
border: 1px solid #ebeef5; /* 可选,方便观察容器边界 */
padding: 10px;
}
</style>
限制文字长度
ts
可以通过 HTML 和 CSS 实现限制文字长度,并在鼠标悬停时显示完整内容
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文字长度限制</title>
<style>
.text-container {
max-width: 200px; /* 限制最大宽度 */
white-space: nowrap; /* 不换行 */
overflow: hidden; /* 超出部分隐藏 */
text-overflow: ellipsis; /* 显示省略号 */
position: relative;
cursor: pointer;
}
/* 悬停时显示完整文字 */
.text-container:hover::after {
content: attr(data-full-text); /* 显示完整文字内容 */
position: absolute;
top: 100%; /* 放置在文字下方 */
left: 0;
background-color: #fff;
color: #000;
border: 1px solid #ccc;
padding: 5px;
white-space: normal; /* 允许换行 */
z-index: 10;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
max-width: 300px; /* 限制弹框宽度 */
}
</style>
</head>
<body>
<div class="text-container" data-full-text="河南省郑州市管城回族区郑州市城东航海路口机房-复建21084">
河南省郑州市管城回族区郑州市城东航海路口机房-复建21084
</div>
</body>
</html>
文字限制和省略号 使用以下 CSS 属性来限制文字长度并显示省略号:
max-width
: 限制最大宽度。white-space: nowrap
: 禁止换行。overflow: hidden
: 隐藏超出部分。text-overflow: ellipsis
: 超出部分显示为省略号。
完整文字显示
- 借助
data-full-text
属性存储完整文字内容。 hover::after
伪元素在鼠标悬停时显示完整文字。position: absolute
用于定位完整文字弹框。
自适应弹框 弹框宽度受 max-width
限制,文字过长时可换行显示。
Vue示例
vue
<template>
<div
class="text-container"
:data-full-text="text"
>
{{ text }}
</div>
</template>
<script>
export default {
props: {
text: {
type: String,
required: true,
},
},
};
</script>
<style>
.text-container {
max-width: 200px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
position: relative;
cursor: pointer;
}
.text-container:hover::after {
content: attr(data-full-text);
position: absolute;
top: 100%;
left: 0;
background-color: #fff;
color: #000;
border: 1px solid #ccc;
padding: 5px;
white-space: normal;
z-index: 10;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
max-width: 300px;
}
</style>
使用el-tooltip实现
vue
<template>
<div class="text-container">
<el-tooltip
class="item"
effect="dark"
:content="text"
placement="top"
>
<span class="ellipsis-text">{{ text }}</span>
</el-tooltip>
</div>
</template>
<script>
export default {
data() {
return {
text: "河南省郑州市管城回族区郑州市城东航海路口机房-复建21084",
};
},
};
</script>
<style>
.text-container {
max-width: 200px; /* 限制最大宽度 */
}
.ellipsis-text {
display: inline-block;
max-width: 100%; /* 适应容器宽度 */
white-space: nowrap; /* 不换行 */
overflow: hidden; /* 超出部分隐藏 */
text-overflow: ellipsis; /* 显示省略号 */
cursor: pointer;
}
</style>
ts
el-tooltip 的作用:
鼠标悬停时弹出完整内容。
content 属性用于设置要显示的完整文字。
placement 设置弹框位置(如 top、bottom 等)。
ellipsis-text 的作用:
使用 CSS 的 text-overflow: ellipsis 实现文字超出时显示省略号。
容器宽度:
max-width 限制文字显示区域的宽度,防止弹框和文字样式不一致。
vue
<template>
<div>
<div
class="text-container"
v-for="(item, index) in items"
:key="index"
>
<el-tooltip
class="item"
effect="dark"
:content="item"
placement="top"
>
<span class="ellipsis-text">{{ item }}</span>
</el-tooltip>
</div>
</div>
</template>
<script>
export default {
data() {
return {
items: [
"河南省郑州市管城回族区郑州市城东航海路口机房-复建21084",
"北京市朝阳区建国路88号院2号楼",
"上海市浦东新区世纪大道100号",
"广州市天河区珠江新城华强路66号",
],
};
},
};
</script>
<style>
.text-container {
max-width: 200px;
margin-bottom: 10px; /* 每个项目间距 */
}
.ellipsis-text {
display: inline-block;
max-width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
cursor: pointer;
}
</style>
ts
省略号:超出容器宽度时显示省略号。
鼠标悬停:完整内容在 el-tooltip 中显示,样式与 Element Plus 保持一致。
响应式:max-width 和 text-overflow 确保组件能适应动态内容和不同宽度。