vue3+vite项目中多处使用el-tooltip组件进行提示,避免重复代码过多封装公共组件,通过接收鼠标当前event位置和要展示的提示信息,在组件内部进行数据处理并展示。
按需引入element-Plus
未安装ui插件需安装,建议按需引入避免包体积过大,如果已安装跳过当前步骤开始组件封装。
- 自动导入插件下载
javascript
npm install -D unplugin-vue-components unplugin-auto-import
- 手动导入样式包
javascript
npm i unplugin-element-plus -D
- 配置文件添加自动导入(以vite为例)
javascript
// vite.config.ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
// 按需配置导入
import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite";
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
import ElementPlus from "unplugin-element-plus/vite";
export default defineConfig({
plugins: [
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
// 按需引入css样式
ElementPlus({}),
],
})
- 完整vite.config.ts配置项文件
上述代码以完成按需引入功能可直接使用,下述展示完整配置项文件包括按需引入,通配符、build打包等可借鉴。
javascript
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
// 通配符引入
import { fileURLToPath, URL } from "node:url";
// 按需导入
import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite";
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
import ElementPlus from "unplugin-element-plus/vite";
// 内置控制台元素检查(如使用执行npm i vite-plugin-vue-devtools)
// import vueDevTools from 'vite-plugin-vue-devtools'
export default defineConfig({
// 端口号ip
server: {
host: "0.0.0.0",
port: 8000,
},
plugins: [
vue(),
// vueDevTools(),
// 按需导入ui插件
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
// 按需引入css样式
ElementPlus({}),
],
// 配置@通用符,指向src文件夹
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)),
},
},
// 预处理加载scss文件,注册全局变量(可自主配置修改文件名和路径即可)
css: {
preprocessorOptions: {
scss: {
additionalData: `@import "@/assets/styles/variables.scss";`,
},
},
},
build: {
// 是否生成调试文件(增加打包体积默认不需要)
sourcemap: false,
// 压缩格式,默认esbuild,terser更小
minify: "terser",
terserOptions: {
// 移除生产环境console/debugger
compress: {
drop_console: true,
drop_debugger: true,
},
},
// 自定义输出目录
outDir: "custom-dist",
// 配置资源分类
rollupOptions: {
output: {
// 非入口和入口文件的js放入js目录
chunkFileNames: "js/[name]-[hash].js",
entryFileNames: "js/[name]-[hash].js",
// 资源文件命名规则
assetFileNames: (assetInfo) => {
// CSS文件
if (assetInfo.name?.endsWith(".css")) {
return "css/[name]-[hash][extname]";
}
// 图片资源
const imgExts = [".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp"];
if (assetInfo.name && imgExts.some((ext) => assetInfo.name?.endsWith(ext))) {
return "images/[name]-[hash][extname]";
}
// 字体文件
const fontExts = [".woff", ".woff2", ".eot", ".ttf", ".otf"];
if (assetInfo.name && fontExts.some((ext) => assetInfo.name?.endsWith(ext))) {
return "fonts/[name]-[hash][extname]";
}
// 其他资源
return "assets/[name]-[hash][extname]";
},
},
},
},
});
公共组件封装
创建文件:src/components/customTooltip/index.vue
javascript
<!--
el-tooltip 配置说明:
- placement: 提示框位置,top/right/bottom/left 等
- virtual-ref: 虚拟引用,用于自定义定位
- virtual-triggering: 启用虚拟触发模式
- visible: 控制提示框显示/隐藏
- popper-class: 自定义弹出框类名
- trigger: 触发方式,manual 表示手动控制
- show-arrow: 是否显示箭头
-->
<template>
<el-tooltip
placement="top"
:virtual-ref="virtualRef"
virtual-triggering
:visible="visible"
popper-class="custom-tooltip"
trigger="manual"
:show-arrow="true"
>
<template #content>
<div style="white-space: pre-line">{{ content }}</div>
</template>
</el-tooltip>
</template>
<script setup lang="ts">
import { ref, watch } from "vue";
defineOptions({
name: "CustomTooltipPage",
});
const props = defineProps<{
// 是否显示
visible: boolean;
// 提示内容
content: string;
// 位置信息(由鼠标事件提供)
position?: { x: number; y: number };
}>();
// 虚拟引用,用于 el-tooltip 的虚拟定位,转换位置信息为 el-tooltip 需要的虚拟 DOM 结构
const virtualRef = ref<{
getBoundingClientRect: () => DOMRect;
} | null>(null);
// 监听位置变化,更新虚拟 DOM 位置
watch(
() => props.position,
(newPos) => {
if (newPos) {
// 创建虚拟 DOM 矩形信息
virtualRef.value = {
getBoundingClientRect: () =>
({
width: 0, // 宽度为0,tooltip 会自适应内容
height: 0, // 高度为0,tooltip 会自适应内容
x: newPos.x, // x 坐标
y: newPos.y, // y 坐标
left: newPos.x, // 左边界
right: newPos.x, // 右边界
top: newPos.y, // 上边界
bottom: newPos.y, // 下边界
} as DOMRect),
};
}
},
{ immediate: true }
);
</script>
<style lang="scss" scoped></style>
样式调整
el-tooltip样式需要再全局scss文件处理,避免层级不够或样式丢失。
- 例:src/assets/style/elementPlus.scss。
javascript
// tooltip全局样式
.custom-tooltip {
// 亮色主题
--el-bg-color-overlay: rgba(5, 130, 150, 1);
--el-border-color-light: rgba(0, 255, 244, 1);
// 暗色主题
--el-bg-color: #fff;
--el-text-color-primary: rgba(5, 130, 150, 1);
--el-border-color: rgba(0, 255, 244, 1);
font-size: 10px !important;
padding: 2px 5px !important;
border: 1px solid var(--el-border-color) !important;
}
组件使用
当前展示为页面组件导入,如果需要配置全局在main.ts手动配置即可。
- cameraList为自定义循环数组,可替换为div行数据,主要功能在鼠标移入移出。
- mouseenter鼠标移入传递内容、坐标轴,鼠标移出隐藏,不在组件内部处理便于使用。
javascript
<template>
<div
v-for="(item, index) in cameraList"
:key="'camera' + index"
@mouseenter="showTooltip($event, item)"
@mouseleave="hideTooltip"
>
<!-- ...自定义盒子内容 -->
</div>
<!-- 提示框组件 -->
<CustomTooltip
:visible="tooltipVisible"
:content="tooltipContent"
:position="tooltipPosition"
/>
</template>
// 组件导入
import CustomTooltip from "@/components/customTooltip/index.vue";
// tooltip是否显示
const tooltipVisible = ref(false);
// 提示内容
const tooltipContent = ref("");
// 位置
const tooltipPosition = ref<{ x: number; y: number } | undefined>(undefined);
// tooltip显示事件
const showTooltip = (event: MouseEvent, cell: any) => {
if (cell.status === "none") return;
// 自定义字符串拼接,换行使用\n
tooltipContent.value = `名称:${cell.name}\nip:${cell.ip}\n编号:${cell.no}`;
// 传递鼠标当前坐标轴
tooltipPosition.value = {
x: event.clientX,
y: event.clientY,
};
tooltipVisible.value = true;
};
// 隐藏tooltip事件
const hideTooltip = () => {
tooltipVisible.value = false;
};