hookehuyr

refactor(animation): 优化SVG容器布局并添加窗口大小监听

调整了SVG容器的布局和样式,使其更适应不同屏幕尺寸。添加了窗口大小变化的监听功能,动态更新SVG的viewBox属性,确保内容始终居中且比例正确。同时优化了按钮的定位和样式,提升了用户体验。
1 <!-- 1 <!--
2 * @Date: 2025-03-28 09:23:04 2 * @Date: 2025-03-28 09:23:04
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-03-28 21:28:07 4 + * @LastEditTime: 2025-03-28 21:56:54
5 * @FilePath: /mlaj/src/views/animation.vue 5 * @FilePath: /mlaj/src/views/animation.vue
6 * @Description: 贝塞尔曲线动画路径组件 6 * @Description: 贝塞尔曲线动画路径组件
7 * 7 *
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
13 --> 13 -->
14 <template> 14 <template>
15 <div class="animation-container"> 15 <div class="animation-container">
16 - <div style="position: fixed; top: 0; right: 0"> 16 + <div style="position: fixed; top: 100px; right: 0; z-index: 999;">
17 <button 17 <button
18 class="next-button" 18 class="next-button"
19 @click="nextStep" 19 @click="nextStep"
...@@ -22,7 +22,13 @@ ...@@ -22,7 +22,13 @@
22 下一步 22 下一步
23 </button> 23 </button>
24 </div> 24 </div>
25 - <svg width="100%" height="100%" viewBox="0 0 1000 1200" class="animation-svg"> 25 + <svg
26 + width="100%"
27 + height="100%"
28 + :viewBox="svgViewBox"
29 + class="animation-svg"
30 + preserveAspectRatio="xMidYMid meet"
31 + >
26 <!-- 定义箭头标记 --> 32 <!-- 定义箭头标记 -->
27 <defs> 33 <defs>
28 <marker 34 <marker
...@@ -102,7 +108,7 @@ ...@@ -102,7 +108,7 @@
102 </template> 108 </template>
103 109
104 <script setup> 110 <script setup>
105 -import { ref, computed } from "vue"; 111 +import { ref, computed, onMounted, onUnmounted } from "vue";
106 import img_svg1 from "@/assets/1.svg"; 112 import img_svg1 from "@/assets/1.svg";
107 import img_svg2 from "@/assets/2.svg"; 113 import img_svg2 from "@/assets/2.svg";
108 import img_svg3 from "@/assets/3.svg"; 114 import img_svg3 from "@/assets/3.svg";
...@@ -273,33 +279,94 @@ const svgObj = [ ...@@ -273,33 +279,94 @@ const svgObj = [
273 }, 279 },
274 }, 280 },
275 ]; 281 ];
282 +// 计算SVG容器尺寸
283 +const containerSize = computed(() => {
284 + const container = document.querySelector('.animation-container');
285 + if (!container) return { width: 0, height: 0 };
286 + return {
287 + width: container.clientWidth,
288 + height: container.clientHeight
289 + };
290 +});
291 +
292 +// 监听窗口大小变化
293 +const updateContainerSize = () => {
294 + containerSize.value = {
295 + width: document.querySelector('.animation-container')?.clientWidth || 0,
296 + height: document.querySelector('.animation-container')?.clientHeight || 0
297 + };
298 +};
299 +
300 +onMounted(() => {
301 + updateContainerSize();
302 + window.addEventListener('resize', updateContainerSize);
303 +});
304 +
305 +onUnmounted(() => {
306 + window.removeEventListener('resize', updateContainerSize);
307 +});
308 +
309 +// 更新svgViewBox计算属性
310 +const svgViewBox = computed(() => {
311 + const maxX = Math.max(...points.value.map(p => p.x));
312 + const maxY = Math.max(...points.value.map(p => p.y));
313 + const minX = Math.min(...points.value.map(p => p.x));
314 + const minY = Math.min(...points.value.map(p => p.y));
315 + const padding = 100;
316 +
317 + // 计算内容的宽高比
318 + const contentWidth = maxX - minX + padding * 2;
319 + const contentHeight = maxY - minY + padding * 2;
320 + const contentRatio = contentWidth / contentHeight;
321 +
322 + // 获取容器的宽高比
323 + const containerRatio = containerSize.value.width / containerSize.value.height;
324 +
325 + // 根据宽高比调整viewBox
326 + if (containerRatio > contentRatio) {
327 + // 容器更宽,以高度为基准
328 + const adjustedWidth = contentHeight * containerRatio;
329 + const extraPadding = (adjustedWidth - contentWidth) / 2;
330 + return `${minX - padding - extraPadding} ${minY - padding} ${adjustedWidth} ${contentHeight}`;
331 + } else {
332 + // 容器更高,以宽度为基准
333 + const adjustedHeight = containerRatio ? contentWidth / containerRatio : contentHeight;
334 + const extraPadding = isFinite(adjustedHeight) ? (adjustedHeight - contentHeight) / 2 : 0;
335 + return `${minX - padding} ${minY - padding - extraPadding} ${contentWidth} ${adjustedHeight}`;
336 + }
337 +});
276 </script> 338 </script>
277 339
278 <style scoped> 340 <style scoped>
279 .animation-container { 341 .animation-container {
280 - display: flex; 342 + position: relative;
281 - flex-direction: column; 343 + width: 100%;
282 - justify-content: center; 344 + height: 100vh;
283 - align-items: center;
284 - min-height: 100vh;
285 background: #f5f5f5; 345 background: #f5f5f5;
286 - padding: 1.25rem; 346 + padding: 1rem;
287 box-sizing: border-box; 347 box-sizing: border-box;
348 + overflow: hidden;
288 } 349 }
289 350
290 .animation-svg { 351 .animation-svg {
291 - max-width: 100%; 352 + position: absolute;
292 - max-height: 100vh; 353 + top: 0;
293 - margin: 0 auto; 354 + left: 0;
355 + width: 100%;
356 + height: 100%;
357 + margin: 0;
358 + display: block;
294 } 359 }
295 360
296 @media screen and (max-width: 768px) { 361 @media screen and (max-width: 768px) {
297 .animation-container { 362 .animation-container {
298 - padding: 0.9375rem; 363 + padding: 0.5rem;
299 } 364 }
300 365
301 .animation-svg { 366 .animation-svg {
302 - height: 80vh; 367 + width: 100%;
368 + height: auto;
369 + min-height: 90vh;
303 } 370 }
304 371
305 .next-button { 372 .next-button {
......