指令
@erp/common 提供的 Vue 自定义指令,用于扩展 DOM 元素的功能。
可用指令
- v-lazy - 图片懒加载,进入视口时加载图片
- v-lazy-load - 通用懒加载,进入视口时触发回调
- v-tip - Tooltip 提示,鼠标悬停显示提示信息
引入方式
typescript
import { vLazy, vLazyLoad, vTip } from '@erp/common'v-lazy
图片懒加载指令,当图片进入可视区域时才加载。
注册指令
typescript
// 全局注册
app.directive('lazy', vLazy)
// 局部注册
export default {
directives: {
lazy: vLazy
}
}基础用法
vue
<template>
<!-- 基础用法 -->
<img v-lazy="imageUrl" />
<!-- 动态切换图片 -->
<img v-lazy="currentImage" />
</template>
<script setup>
import { ref } from 'vue'
const imageUrl = ref('https://example.com/image.jpg')
const currentImage = ref('https://example.com/image1.jpg')
// 切换图片时会自动重新懒加载
const changeImage = () => {
currentImage.value = 'https://example.com/image2.jpg'
}
</script>工作原理
- 初始时显示透明占位图
- 使用 IntersectionObserver 监听元素是否进入视口
- 进入视口后异步加载真实图片
- 加载成功后替换 src,并缓存已加载的图片
特性
- 自动使用 IntersectionObserver(性能更好)
- 降级支持 scroll 事件监听
- 图片加载成功后自动缓存
- 支持动态更换图片源
立即加载
添加 immediately 属性可跳过懒加载检测:
vue
<img v-lazy="imageUrl" immediately />v-lazy-load
通用 DOM 元素懒加载指令,当元素进入可视区域时触发回调。
注册指令
typescript
app.directive('lazyLoad', vLazyLoad)基础用法
vue
<template>
<!-- 函数形式 -->
<div v-lazy-load="handleLoad">
懒加载内容
</div>
<!-- 对象形式 -->
<div v-lazy-load="{ load: handleLoad, param: itemId }">
懒加载内容
</div>
</template>
<script setup>
// 返回 true 表示加载成功,不再触发
// 返回 false 表示加载失败,下次进入视口继续触发
const handleLoad = (el, param) => {
console.log('元素进入视口', el, param)
return true
}
// 支持异步
const handleAsyncLoad = async (el, param) => {
await fetchData(param)
return true
}
</script>参数说明
typescript
// 函数形式
type LazyLoadCallback = (el: HTMLElement, param?: any) => boolean | Promise<boolean>
// 对象形式
interface LazyLoadOptions {
/** 加载回调函数 */
load: LazyLoadCallback
/** 传递给回调的参数,参数变化时会重新触发加载 */
param?: any
}使用示例
列表项懒加载
vue
<template>
<div
v-for="item in list"
:key="item.id"
v-lazy-load="{ load: loadItemDetail, param: item.id }"
>
<div v-if="item.loaded">{{ item.detail }}</div>
<div v-else>加载中...</div>
</div>
</template>
<script setup>
const loadItemDetail = async (el, itemId) => {
const item = list.value.find(i => i.id === itemId)
if (item && !item.loaded) {
const detail = await fetchItemDetail(itemId)
item.detail = detail
item.loaded = true
}
return true
}
</script>图表懒加载
vue
<template>
<div v-lazy-load="initChart" ref="chartRef" style="height: 300px">
<!-- 图表容器 -->
</div>
</template>
<script setup>
import * as echarts from 'echarts'
const chartRef = ref()
let chart = null
const initChart = (el) => {
if (!chart) {
chart = echarts.init(el)
chart.setOption({
// 图表配置
})
}
return true
}
</script>v-tip
Tooltip 提示指令,鼠标悬停时显示提示信息。
注册指令
typescript
app.directive('tip', vTip)基础用法
vue
<template>
<!-- 字符串形式 -->
<span v-tip="'这是提示内容'">悬停显示提示</span>
<!-- 自动使用元素文本 -->
<span v-tip>这段文字会作为提示内容</span>
<!-- 对象形式 -->
<span v-tip="{ content: '提示内容', position: 'bottom' }">
悬停显示提示
</span>
</template>参数说明
typescript
// 字符串形式
v-tip="'提示内容'"
// 对象形式
interface TipOptions {
/** 提示内容,不传则使用元素的 textContent */
content?: string
/** 提示位置 */
position?: 'top' | 'bottom' | 'left' | 'right'
/** 仅在内容溢出时显示 */
overflowShow?: boolean
}使用示例
文本溢出提示
vue
<template>
<!-- 仅当文本溢出时显示完整内容 -->
<div
v-tip="{ overflowShow: true }"
class="ellipsis"
>
这是一段很长的文本,可能会被截断显示省略号
</div>
</template>
<style>
.ellipsis {
width: 200px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>表格单元格提示
vue
<template>
<vxe-column field="remark" title="备注">
<template #default="{ row }">
<span v-tip="row.remark" class="cell-text">
{{ row.remark }}
</span>
</template>
</vxe-column>
</template>不同位置
vue
<template>
<span v-tip="{ content: '上方提示', position: 'top' }">上</span>
<span v-tip="{ content: '下方提示', position: 'bottom' }">下</span>
<span v-tip="{ content: '左侧提示', position: 'left' }">左</span>
<span v-tip="{ content: '右侧提示', position: 'right' }">右</span>
</template>指令对比
| 指令 | 用途 | 触发时机 |
|---|---|---|
v-lazy | 图片懒加载 | 图片进入视口 |
v-lazy-load | 通用懒加载 | 元素进入视口 |
v-tip | 提示信息 | 鼠标悬停 |