方法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;
}