##自定义指令的使用 参考官方文档:https://cn.vuejs.org/guide/reusability/custom-directives.html

1. 在utils文件夹下新建directive文件夹

用来存放需要自定义的指令文件,该文件用于创建指令以及编写操作逻辑代码,目录结构

```

directive

├── index.js  //导入需要的指令,并汇总导出,

└── highlight //文本高亮指令

|    └── index.js

└── Focus //聚焦指令

|    └── index.js

└── SlideIn   //元素平滑上升指令

|     └── index.js

└── ···

     └── ···

```

2. 编写自定义指令文件

下面会列举三个自定义指令的例子(文本高亮、聚焦、元素平滑上升)

3. 在directive文件夹下新建index.js文件,

在该文件中导入需要的指令,然后调用directive()方法,将自定义的指令挂载到app.directive()方法中,

import SildeIn from './SlideIn'
import Focus from './Focus'
import Highlight from './highlight'  //导入自定义指令

const directives = {  //汇总自定义指令
  SildeIn//元素平滑上升指令 这里就是指令名 在文本中使用方法就是 v-指令名
  Focus,//聚焦指令
  Highlight//文本高亮指令
}

export default {  //导出自定义指令
  install(app) {// 以安装的方式插到app中
    Object.keys(directives).forEach((key) => {    // 遍历directives对象的key
      app.directive(key, directives[key])  // 将每个directive注册到app中
    })
  }
}

4. 在main.js中导入自定义指令,并全局注册,

import Directives from '@/utils/directive/index.js'
function initApp() {
  const app = createApp(App)
  // app.use(pinia)
  // app.use(elementIcon)
  // app.use(router)
  app.use(Directives) //全局注册
  app.mount('#app')
}
initApp()

5. 指令的使用方式

:v-指令名="指令方法",指令方法可以是函数也可以是对象,例如

<div v-SildeIn class="w-3/4 h-96 bg-slate-700 mt-14">{{ item }}</div>
<p v-highlight:color="color">这段文本会高亮显示,用来演示动态传参</p>
<input v-Focus type="text" placeholder="这个input会自动聚焦" />

### 例子1:自动聚焦

页面中

<input v-Focus type="text" placeholder="这个input会自动聚焦" />

/Focus/index.js  指令js

export default {
  mounted(el) {
    console.log(el)
    el.focus() //DOM操作输入框聚焦
  }
}

### 例子2:文本高亮 这里演示说明动态传参

页面中

<templete>
  <p v-highlight>这段文本会高亮显示,不传参</p>
  <p v-highlight:color="color">
    这段文本会高亮显示,用来演示动态传参,第一个color是参,第二个color是值
  </p>
  <input v-model="color" placeholder="这是一个输入框,输入颜色值可以动态更新文本高亮颜色" />
</templete>
<script>
const color = ref('#f00') //定义响应式变量
</script>

//highlight/index.js 指令js

export default {
  beforeMount(el, binding) {
    // 获取传递的参数
    const arg = binding.arg //从这里获取参数名,也就是第一个color
    const value = binding.value //从这里获取参数值,也就是第二个color
    // 将参数保存在指令上下文中
    el._directiveContext = { arg, value }
    el.style.backgroundColor = value || '#f00' //DOM操作,设置背景颜色
  },
  updated(el, binding) {
    // 获取更新后的参数
    const value = binding.value //更新后的参数值
    el.style.backgroundColor = value //更新DOM

    // 从指令上下文中获取之前保存的参数
    // const { arg } = el._directiveContext
    // console.log('参数:', arg, '值:', value)
  }
}

### 例子3:元素平滑上升

页面中使用:

<div v-SildeIn class="w-3/4 h-96 bg-slate-700 mt-14">{{ item }}</div>

/SildeIn/index.js 指令JS

const DISTANCE = 100 //定义动画的距离
const duration = 500 //定义动画的持续时间 //也可以接收用户的一些配置

const animationMap = new WeakMap() // 记录元素和动画的对应关系 WeakMap房防止内存泄漏

const ob = new IntersectionObserver((entries) => {
  //创建一个监听者,监听元素啊是否进入可视区域
  for (const entry of entries) {
    //遍历监听者
    if (entry.isIntersecting) {
      //如果元素进入可视区域
      const animation = animationMap.get(entry.target)
      if (animation) {
        // console.log(animation)
        animation.play()
        ob.unobserve(entry.target) //动画播放完毕后取消监听
      }
      // console.log(entry.target)
    }
  }
})
/**
 * 判断元素是否在可视区域之下
 * @param {Element} el - 要判断的元素
 * @returns {boolean} - 若元素在可视区域之上则返回true,否则返回false
 */
function isBelowViewport(el) {
  const rect = el.getBoundingClientRect()
  return rect.top - DISTANCE > window.innerHeight
}
export default {
  mounted(el) {
    if (!isBelowViewport(el)) {
      //判断元素是否在可视区域之下
      return //如果不在可视区域之下则直接返回   //  因为动画只需要在元素进入可视区域时才播放,所以只需要在元素进入可视区域时调用mounted方法即可 视口内容和视口之上的元素都不需要播放动画
    }
    const animation = el.animate(
      [
        {
          transform: `translateY(${DISTANCE}px)`,
          opacity: 0.3
        },
        {
          transform: `translateY(0)`,
          opacity: 1
        }
      ],
      {
        duration: duration,
        easing: 'ease-in'
      }
    )
    //创建动画用   animate(keyframes, options),animate方法返回一个Animation实例,可以调用play()方法来播放动画,调用pause()方法来暂停动画
    animation.pause() //创建动画后先将所有动画暂停
    ob.observe(el) //监听元素是否进入可视区域,如果进入就播放动画,如果不进入就暂停动画
    animationMap.set(el, animation) //将元素和动画的对应关系记录在WeakMap中
  },
  unmounted(el) {
    console.log('unmounted')
    ob.unobserve(el)
  }
}

Logo

前往低代码交流专区

更多推荐