vue抽离自定义指令的方法

方法1:创建单独的指令文件

创建文件 src/directives/mouseParallax.js:

复制代码
import { nextTick } from 'vue'

export const mouseParallax = {
  mounted(el, binding) {
    initParallax(el, binding.value)
  },
  
  updated(el, binding) {
    // 图片切换时重新初始化
    nextTick(() => {
      initParallax(el, binding.value)
    })
  },
  
  unmounted(el) {
    cleanupParallax(el)
  }
}

// 初始化视差效果
const initParallax = (el, options = {}) => {
  // 清理之前的监听器
  cleanupParallax(el)
  
  // 获取当前显示的图片
  const currentImg = el.querySelector('img:not([style*="display: none"])')
  if (!currentImg) return
  
  let isHovered = false
  const moveFactor = options.moveFactor || 20
  
  const handleMouseEnter = () => {
    isHovered = true
    currentImg.style.transform = 'scale(1.05)'
  }
  
  const handleMouseLeave = () => {
    isHovered = false
    currentImg.style.transform = 'translate(0, 0) scale(1)'
  }
  
  const handleMouseMove = (event) => {
    if (!isHovered || !currentImg) return
    
    const rect = el.getBoundingClientRect()
    const mouseX = event.clientX - rect.left
    const mouseY = event.clientY - rect.top
    
    const centerX = rect.width / 2
    const centerY = rect.height / 2
    
    const offsetX = (mouseX - centerX) / centerX
    const offsetY = (mouseY - centerY) / centerY
    
    const transformX = offsetX * moveFactor
    const transformY = offsetY * moveFactor
    
    currentImg.style.transform = `translate(${transformX}px, ${transformY}px) scale(1.05)`
  }
  
  // 绑定事件
  el.addEventListener('mouseenter', handleMouseEnter)
  el.addEventListener('mouseleave', handleMouseLeave)
  el.addEventListener('mousemove', handleMouseMove)
  
  // 保存引用
  el._mouseParallaxHandlers = {
    mouseenter: handleMouseEnter,
    mouseleave: handleMouseLeave,
    mousemove: handleMouseMove,
    currentImg: currentImg
  }
}

// 清理函数
const cleanupParallax = (el) => {
  if (el._mouseParallaxHandlers) {
    el.removeEventListener('mouseenter', el._mouseParallaxHandlers.mouseenter)
    el.removeEventListener('mouseleave', el._mouseParallaxHandlers.mouseleave)
    el.removeEventListener('mousemove', el._mouseParallaxHandlers.mousemove)
    
    // 重置图片transform
    if (el._mouseParallaxHandlers.currentImg) {
      el._mouseParallaxHandlers.currentImg.style.transform = 'translate(0, 0) scale(1)'
    }
    
    delete el._mouseParallaxHandlers
  }
}

修改 src/main.js:

复制代码
import { createApp } from 'vue'
import App from './App.vue'
import { mouseParallax } from './directives/mouseParallax'

const app = createApp(App)

// 全局注册指令
app.directive('mouse-parallax', mouseParallax)

app.mount('#app')

方法2:作为插件注册

创建文件 src/directives/index.js:

复制代码
import { mouseParallax } from './mouseParallax'

const MouseParallaxPlugin = {
  install(app) {
    app.directive('mouse-parallax', mouseParallax)
  }
}

export default MouseParallaxPlugin

// 或者直接导出指令
export { mouseParallax }

在 main.js 中使用:

复制代码
import { createApp } from 'vue'
import App from './App.vue'
import MouseParallaxPlugin from './directives'

const app = createApp(App)
app.use(MouseParallaxPlugin)
app.mount('#app')

修改后的组件文件

修改 YourComponent.vue:

复制代码
<template>
  <div class="left" v-mouse-parallax="{ moveFactor: 30 }" :style="{ background: bgc }">
    <img v-for="n in 18" 
         :key="n" 
         :src="`../assets/img/itemImg${n.toString().padStart(2, '0')}.jpg`" 
         :alt="`图片${n}`"
         v-show="imgMessage === n"
         class="parallax-image">
  </div>
</template>

<script setup>
import { ref } from 'vue'

const imgMessage = ref(1)
const bgc = ref('#ffffff')

// 切换图片的方法
const changeImage = (index) => {
  imgMessage.value = index
}
</script>

<style scoped>
.left {
  position: relative;
  width: 100%;
  height: 500px;
  overflow: hidden;
  cursor: pointer;
}

.parallax-image {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  will-change: transform;
  transition: transform 0.15s ease-out;
}
</style>

可选:在组件中局部注册

如果你只需要在特定组件中使用:

复制代码
<script setup>
import { ref } from 'vue'
import { mouseParallax } from '../directives/mouseParallax'

const imgMessage = ref(1)
const bgc = ref('#ffffff')

// 切换图片的方法
const changeImage = (index) => {
  imgMessage.value = index
}

// 局部注册指令
const vMouseParallax = mouseParallax
</script>

使用参数

你可以通过指令的值传递参数:

复制代码
<template>
  <!-- 基本使用 -->
  <div v-mouse-parallax>
  
  <!-- 传递参数 -->
  <div v-mouse-parallax="{ moveFactor: 30, scale: 1.1 }">
  
  <!-- 动态参数 -->
  <div v-mouse-parallax="parallaxConfig">
</template>

<script setup>
const parallaxConfig = ref({
  moveFactor: 25,
  scale: 1.08
})
</script>

然后在指令文件中:

复制代码
const initParallax = (el, options = {}) => {
  // ...
  const moveFactor = options.moveFactor || 20
  const scale = options.scale || 1.05
  // 使用这些参数
}
复制代码
// 全局注册指令
app.directive('mouse-parallax', mouseParallax)
// 基本使用
v-mouse-parallax

部分css样式

复制代码
  h1 {
      font-size: 2.8rem;
      margin-bottom: 10px;
      background: linear-gradient(to right, #6a11cb 0%, #2575fc 100%);
      -webkit-background-clip: text;
      -webkit-text-fill-color: transparent;
      text-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
    }

 li {
      flex: 1;
      min-width: 300px;
      max-width: 350px;
      height: 350px;
      border-radius: 20px;
      overflow: hidden;
      box-shadow: 0 15px 35px rgba(0, 0, 0, 0.3);
      transition: transform 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
      position: relative;
    }


img {
      width: 100%;
      height: 100%;
      object-fit: cover;
      transition: transform 0.2s ease-out;
      will-change: transform;
    }
相关推荐
风骏时光牛马1 小时前
生成一个移动端标题,只需要一个标题,不需要其他的任何文本。
前端
IT_陈寒2 小时前
Redis雪崩把我坑惨了,这是5年经验的教训
前端·人工智能·后端
SameX2 小时前
HarmonyOS ArkUI List 的侧滑删除 用 ListItem 的 swipeAction + endIcon 的做法
前端
usdoc文档预览4 小时前
USDOC系列之PPT文件在线编辑-VUE前端实现在线浏览器在线编辑PPT文档
前端·vue.js·编辑器·office365·ppt在线编辑·office文件在线编辑·文件在线编辑
Java小卷4 小时前
面向 schema 编程,轻松搞定 Element 虚拟化表格复杂应用场景
vue.js·低代码·element
用户2705077725244 小时前
Agent 调工具卡住?3 种超时与取消策略实测对比
前端
LuHang5 小时前
我一行代码没写,把领导派的活做成了公司内部系统😭
前端
明月_清风5 小时前
Meta 开源了一个 AI Native 组件库:Astryx,150+ React 组件,专为 AI Agent 而设计
前端·人工智能·ai编程
仨孩子的爹6 小时前
Lodop、hiprint 与 vue-print-designer:打印控件选型对比
vue.js
用户850869276156 小时前
秒杀系统中 Shell 脚本并发控制 Bug:究竟哪里出了
前端