Skip to content

Commit 21eca04

Browse files
committed
新增鼠标Hover交互效果4
1 parent e5ea89b commit 21eca04

File tree

3 files changed

+224
-0
lines changed

3 files changed

+224
-0
lines changed
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
<script setup lang="ts">
2+
import { ref, onMounted, onUnmounted } from "vue";
3+
4+
interface Props {
5+
url: string;
6+
}
7+
8+
const SPEED = 36;
9+
10+
const { url } = defineProps<Props>();
11+
12+
const containerRef = ref<HTMLDivElement | null>(null);
13+
const frameId = ref<number>(0);
14+
const xRef = ref<number>(0);
15+
const yRef = ref<number>(0);
16+
17+
const rotateLoop = () => {
18+
if (containerRef.value) {
19+
const { clientWidth, clientHeight } = containerRef.value;
20+
let nextX = xRef.value;
21+
let nextY = yRef.value;
22+
if (yRef.value <= 0) {
23+
if (xRef.value >= clientWidth) {
24+
nextX = clientWidth;
25+
nextY = SPEED;
26+
} else if (nextX + SPEED > clientWidth) {
27+
nextY = nextX + SPEED - clientWidth;
28+
nextX = clientWidth;
29+
} else {
30+
nextX += SPEED;
31+
nextY = 0;
32+
}
33+
} else if (xRef.value >= clientWidth) {
34+
if (yRef.value >= clientHeight) {
35+
nextX = clientWidth - SPEED;
36+
nextY = clientHeight;
37+
} else if (nextY + SPEED > clientHeight) {
38+
nextX = clientWidth - (nextY + SPEED - clientHeight);
39+
nextY = clientHeight;
40+
} else {
41+
nextX = clientWidth;
42+
nextY += SPEED;
43+
}
44+
} else if (yRef.value >= clientHeight) {
45+
if (xRef.value <= 0) {
46+
nextX = 0;
47+
nextY = clientHeight - SPEED;
48+
} else if (nextX - SPEED < 0) {
49+
nextY = clientHeight - (SPEED - nextX);
50+
nextX = 0;
51+
} else {
52+
nextX -= SPEED;
53+
nextY = clientHeight;
54+
}
55+
} else {
56+
if (yRef.value <= 0) {
57+
nextX = SPEED;
58+
nextY = 0;
59+
} else if (nextY - SPEED < 0) {
60+
nextX = SPEED - nextY;
61+
nextY = 0;
62+
} else {
63+
nextX = 0;
64+
nextY = Math.max(nextY - SPEED, 0);
65+
}
66+
}
67+
xRef.value = nextX;
68+
yRef.value = nextY;
69+
containerRef.value.setAttribute(
70+
"style",
71+
`--url: url("${url}"); --x: ${nextX}px; --y: ${nextY}px`
72+
);
73+
frameId.value = window.requestAnimationFrame(rotateLoop);
74+
}
75+
};
76+
77+
const onMouseEnter = () => {
78+
if (containerRef.value) {
79+
frameId.value = window.requestAnimationFrame(rotateLoop);
80+
}
81+
};
82+
83+
const onMouseLeave = () => {
84+
if (containerRef.value) {
85+
frameId.value && window.cancelAnimationFrame(frameId.value);
86+
containerRef.value.setAttribute(
87+
"style",
88+
`--url: url("${url}"); --x: 0px; --y: 0px`
89+
);
90+
}
91+
};
92+
93+
onMounted(() => {
94+
if (containerRef.value && url) {
95+
containerRef.value.setAttribute("style", `--url: url("${url}")`);
96+
}
97+
});
98+
99+
onUnmounted(() => {
100+
frameId.value && window.cancelAnimationFrame(frameId.value);
101+
});
102+
</script>
103+
104+
<template>
105+
<div style="width: 100%">
106+
<div
107+
class="container"
108+
@mouseenter="onMouseEnter"
109+
@mouseleave="onMouseLeave"
110+
ref="containerRef"
111+
>
112+
<div class="content" />
113+
</div>
114+
</div>
115+
</template>
116+
117+
<style scoped lang="scss">
118+
.container {
119+
$borderRadius: 24px;
120+
width: 280px;
121+
height: 396px;
122+
display: flex;
123+
justify-content: center;
124+
align-items: center;
125+
border-radius: $borderRadius;
126+
cursor: pointer;
127+
overflow: hidden;
128+
position: relative;
129+
130+
&::before {
131+
content: "";
132+
opacity: 0;
133+
position: absolute;
134+
inset: 0;
135+
border-radius: $borderRadius;
136+
background: conic-gradient(#03a9f4, #e91e63, #9c27b0, #ff5722, #03a9f4);
137+
mask: radial-gradient(
138+
circle at var(--x) var(--y),
139+
#000,
140+
#000,
141+
transparent,
142+
transparent,
143+
transparent
144+
);
145+
}
146+
147+
&:hover {
148+
transform: scale(1.1);
149+
&::before {
150+
opacity: 1;
151+
}
152+
}
153+
154+
.content {
155+
border-radius: $borderRadius;
156+
overflow: hidden;
157+
position: absolute;
158+
inset: 3px;
159+
160+
&::before,
161+
&::after {
162+
content: "";
163+
position: absolute;
164+
background: var(--url);
165+
background-size: cover;
166+
background-position: center;
167+
border-radius: $borderRadius;
168+
}
169+
170+
&::before {
171+
inset: 0;
172+
filter: blur(20px);
173+
}
174+
175+
&::after {
176+
inset: 40px;
177+
}
178+
}
179+
}
180+
</style>
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<script setup lang="ts">
2+
import Card from "./Card.vue";
3+
import car1 from "images/html/car1.png";
4+
import car2 from "images/html/car2.png";
5+
import car3 from "images/html/car3.png";
6+
7+
const cardList = [car1, car2, car3];
8+
</script>
9+
10+
<template>
11+
<div style="width: 100%">
12+
<div class="container">
13+
<div class="content">
14+
<Card
15+
v-for="(url, index) in cardList"
16+
class="item"
17+
:url="url"
18+
:key="index"
19+
/>
20+
</div>
21+
</div>
22+
</div>
23+
</template>
24+
25+
<style scoped lang="scss">
26+
.container {
27+
width: 100%;
28+
height: 560px;
29+
display: flex;
30+
justify-content: center;
31+
align-items: center;
32+
33+
.content {
34+
width: 66%;
35+
max-width: 1200px;
36+
min-width: 900px;
37+
display: flex;
38+
justify-content: space-between;
39+
align-items: center;
40+
}
41+
}
42+
</style>

src/pages/html/InteractiveDesign/index.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import DragShopping from "./components/DragShopping.vue";
99
import MouseHover1 from "./components/MouseHover1.vue";
1010
import MouseHover2 from "./components/MouseHover2.vue";
1111
import MouseHover3 from "./components/MouseHover3/index.vue";
12+
import MouseHover4 from "./components/MouseHover4/index.vue";
1213
import SlideButtonTab from "./components/SlideButtonTab.vue";
1314
import FlipBook from "./components/FlipBook.vue";
1415
import Switchs from "./components/Switchs/index.vue";
@@ -30,6 +31,7 @@ const boxList = [
3031
{ element: MouseHover1 },
3132
{ element: MouseHover2 },
3233
{ element: MouseHover3 },
34+
{ element: MouseHover4 },
3335
{ element: SlideButtonTab },
3436
{ element: FlipBook },
3537
{ element: Switchs },

0 commit comments

Comments
 (0)