vue3 自定义全局指令
vue3 项目结构如下
frontend
┣ src
┃ ┣ assets
┃ ┣ components
┃ ┃ ┣ Loading
┃ ┃ ┃ ┣ index.ts
┃ ┃ ┃ ┗ index.vue
┃ ┃ ┗ index.ts
┃ ┣ directives
┃ ┃ ┣ lazy
┃ ┃ ┃ ┗ index.ts
┃ ┃ ┗ index.ts
┃ ┣ layout
┃ ┃ ┗ index.vue
┃ ┣ pages
┃ ┃ ┣ home
┃ ┃ ┃ ┗ index.vue
┃ ┣ router
┃ ┃ ┗ index.ts
┃ ┣ App.vue
┃ ┣ global.d.ts
┃ ┣ main.ts
┃ ┣ shims.d.ts
┃ ┗ vite-env.d.ts
┣ types
┃ ┣ auto-imports.d.ts
┃ ┗ components.d.ts
┣ .dockerignore
┣ .editorconfig
┣ .eslintrc
┣ .gitignore
┣ .npmrc
┣ README.md
┣ commitlint.config.js
┣ commitlint.config.ts
┣ index.html
┣ package.json
┣ pnpm-lock.yaml
┣ tsconfig.json
┣ tsconfig.node.json
┣ unocss.config.ts
┗ vite.config.ts
主要工作目录在 directives
文件夹下
创建 lazy 指令
在 directives
目录下创建 lazy
文件夹,然后在 lazy
文件夹下创建 index.ts
文件。
文件内容如下:
ts
import errorImage from '~/assets/ai_compass.png'
const imageIsExist = (src: string) => {
return new Promise((resolve) => {
const img = new Image()
img.onload = () => {
resolve(true)
}
img.onerror = () => {
resolve(false)
}
img.src = src
})
}
export const lazy = {
mounted(el: Element) {
const src = el.getAttribute('custom-src')!
const io = new IntersectionObserver(([{ isIntersecting }]) => {
if (isIntersecting) {
imageIsExist(src).then((exist) => {
if (exist)
el.setAttribute('src', src)
else
el.setAttribute('src', errorImage)
io.disconnect()
})
}
})
io.observe(el)
},
}
export default {
name: 'lazy',
directive: lazy,
}
上述代码中,imageIsExist
函数用于判断图片是否存在,lazy
函数用于判断图片是否在可视区域内,如果在可视区域内,则加载图片,否则不加载。
注册 lazy 指令
在 directives
目录下创建 index.ts
文件,文件内容如下:
ts
import type { App } from 'vue'
interface Directive {
name: string
directive: Record<string, () => {}>
}
const directives = import.meta.glob<Record<string, Directive>>('./**/*.ts', { eager: true })
export function setDirectives(app: App) {
Object.keys(directives).forEach((key) => {
app.directive(directives[key].default.name, directives[key].default.directive)
})
}
上述代码中,directives
用于获取 directives
目录下所有的指令,然后遍历注册。
引入指令
在 main.ts
文件中引入指令,文件内容如下:
ts
import { createApp } from 'vue'
import App from './App.vue'
import { setComponents } from './components'
import { setDirectives } from './directives'
async function bootstrap() {
const app = createApp(App)
setComponents(app)
setDirectives(app)
app.mount('#app')
}
bootstrap()
使用指令
在 home
文件夹下创建 index.vue
文件,文件内容如下:
html
<img v-lazy class="w-100% h-100% rounded-full box-border" :src="errorImage" :custom-src="image" />
挂载指令后,图片就会在可视区域内时才加载,否则不加载,并且加载失败时会显示默认图片。