Skip to content

指令

@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>

工作原理

  1. 初始时显示透明占位图
  2. 使用 IntersectionObserver 监听元素是否进入视口
  3. 进入视口后异步加载真实图片
  4. 加载成功后替换 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提示信息鼠标悬停

基于 MIT 许可发布