Prechádzať zdrojové kódy

更新依赖项,添加motion-v库以支持动画效果,调整tsconfig以使用node模块解析,更新rspack配置以优化样式导入,重构首页组件以使用Motion组件实现视差效果,调整样式文件以确保布局一致性,删除不再使用的CSS变量文件。

xbx 1 týždeň pred
rodič
commit
219b70e1a8

+ 1 - 1
config/rspack.base.config.ts

@@ -112,7 +112,7 @@ export const baseConfig = {
               sassOptions: {
                 includePaths: [path.resolve(__dirname, '../src/styles')],
               },
-              additionalData: '@import "@/styles/variables.scss";',
+              additionalData: '@use "@/styles/variables.scss" as *;',
             },
           },
         ],

+ 1 - 0
package.json

@@ -30,6 +30,7 @@
     "axios": "^1.9.0",
     "dayjs": "^1.11.13",
     "mitt": "^3.0.1",
+    "motion-v": "^1.5.0",
     "pinia": "^3.0.3",
     "postcss": "^8.5.6",
     "postcss-loader": "^8.1.1",

+ 106 - 0
pnpm-lock.yaml

@@ -29,6 +29,9 @@ importers:
       mitt:
         specifier: ^3.0.1
         version: 3.0.1
+      motion-v:
+        specifier: ^1.5.0
+        version: 1.5.0(vue@3.5.14(typescript@5.8.3))
       pinia:
         specifier: ^3.0.3
         version: 3.0.3(typescript@5.8.3)(vue@3.5.14(typescript@5.8.3))
@@ -620,6 +623,9 @@ packages:
   '@types/sockjs@0.3.36':
     resolution: {integrity: sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==}
 
+  '@types/web-bluetooth@0.0.20':
+    resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==}
+
   '@types/web-bluetooth@0.0.21':
     resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==}
 
@@ -731,14 +737,23 @@ packages:
   '@vue/shared@3.5.14':
     resolution: {integrity: sha512-oXTwNxVfc9EtP1zzXAlSlgARLXNC84frFYkS0HHz0h3E4WZSP9sywqjqzGCP9Y34M8ipNmd380pVgmMuwELDyQ==}
 
+  '@vueuse/core@10.11.1':
+    resolution: {integrity: sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==}
+
   '@vueuse/core@13.5.0':
     resolution: {integrity: sha512-wV7z0eUpifKmvmN78UBZX8T7lMW53Nrk6JP5+6hbzrB9+cJ3jr//hUlhl9TZO/03bUkMK6gGkQpqOPWoabr72g==}
     peerDependencies:
       vue: ^3.5.0
 
+  '@vueuse/metadata@10.11.1':
+    resolution: {integrity: sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==}
+
   '@vueuse/metadata@13.5.0':
     resolution: {integrity: sha512-euhItU3b0SqXxSy8u1XHxUCdQ8M++bsRs+TYhOLDU/OykS7KvJnyIFfep0XM5WjIFry9uAPlVSjmVHiqeshmkw==}
 
+  '@vueuse/shared@10.11.1':
+    resolution: {integrity: sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==}
+
   '@vueuse/shared@13.5.0':
     resolution: {integrity: sha512-K7GrQIxJ/ANtucxIXbQlUHdB0TPA8c+q5i+zbrjxuhJCnJ9GtBg75sBSnvmLSxHKPg2Yo8w62PWksl9kwH0Q8g==}
     peerDependencies:
@@ -1501,6 +1516,20 @@ packages:
     resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
     engines: {node: '>= 0.6'}
 
+  framer-motion@12.22.0:
+    resolution: {integrity: sha512-qG07rR8/mboCNU34nORbrIbBXbJzP4aDqBdr67TAIVlMryDEOwh7LXjylWovlnPCMg78ExoY0Gn2F1fV+3DNIw==}
+    peerDependencies:
+      '@emotion/is-prop-valid': '*'
+      react: ^18.0.0 || ^19.0.0
+      react-dom: ^18.0.0 || ^19.0.0
+    peerDependenciesMeta:
+      '@emotion/is-prop-valid':
+        optional: true
+      react:
+        optional: true
+      react-dom:
+        optional: true
+
   fresh@0.5.2:
     resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
     engines: {node: '>= 0.6'}
@@ -1588,6 +1617,9 @@ packages:
     resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
     engines: {node: '>= 0.4'}
 
+  hey-listen@1.0.8:
+    resolution: {integrity: sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==}
+
   hookable@5.5.3:
     resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==}
 
@@ -2036,6 +2068,17 @@ packages:
   mlly@1.7.4:
     resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==}
 
+  motion-dom@12.22.0:
+    resolution: {integrity: sha512-ooH7+/BPw9gOsL9VtPhEJHE2m4ltnhMlcGMhEqA0YGNhKof7jdaszvsyThXI6LVIKshJUZ9/CP6HNqQhJfV7kw==}
+
+  motion-utils@12.19.0:
+    resolution: {integrity: sha512-BuFTHINYmV07pdWs6lj6aI63vr2N4dg0vR+td0rtrdpWOhBzIkEklZyLcvKBoEtwSqx8Jg06vUB5RS0xDiUybw==}
+
+  motion-v@1.5.0:
+    resolution: {integrity: sha512-AIwI0U0ZlxDgdtjZKNzSpUo+X3IKRUGNqrdf+hig3TIehxgFds4gSL3amqsx9iZIGjYnGDdlwuqxKPYR1cxiTQ==}
+    peerDependencies:
+      vue: '>=3.0.0'
+
   mrmime@2.0.1:
     resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}
     engines: {node: '>=10'}
@@ -2945,6 +2988,17 @@ packages:
     resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
     engines: {node: '>= 0.8'}
 
+  vue-demi@0.14.10:
+    resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==}
+    engines: {node: '>=12'}
+    hasBin: true
+    peerDependencies:
+      '@vue/composition-api': ^1.0.0-rc.1
+      vue: ^3.0.0-0 || ^2.6.0
+    peerDependenciesMeta:
+      '@vue/composition-api':
+        optional: true
+
   vue-eslint-parser@10.1.3:
     resolution: {integrity: sha512-dbCBnd2e02dYWsXoqX5yKUZlOt+ExIpq7hmHKPb5ZqKcjf++Eo0hMseFTZMLKThrUk61m+Uv6A2YSBve6ZvuDQ==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -3649,6 +3703,8 @@ snapshots:
     dependencies:
       '@types/node': 22.15.19
 
+  '@types/web-bluetooth@0.0.20': {}
+
   '@types/web-bluetooth@0.0.21': {}
 
   '@types/ws@8.18.1':
@@ -3825,6 +3881,16 @@ snapshots:
 
   '@vue/shared@3.5.14': {}
 
+  '@vueuse/core@10.11.1(vue@3.5.14(typescript@5.8.3))':
+    dependencies:
+      '@types/web-bluetooth': 0.0.20
+      '@vueuse/metadata': 10.11.1
+      '@vueuse/shared': 10.11.1(vue@3.5.14(typescript@5.8.3))
+      vue-demi: 0.14.10(vue@3.5.14(typescript@5.8.3))
+    transitivePeerDependencies:
+      - '@vue/composition-api'
+      - vue
+
   '@vueuse/core@13.5.0(vue@3.5.14(typescript@5.8.3))':
     dependencies:
       '@types/web-bluetooth': 0.0.21
@@ -3832,8 +3898,17 @@ snapshots:
       '@vueuse/shared': 13.5.0(vue@3.5.14(typescript@5.8.3))
       vue: 3.5.14(typescript@5.8.3)
 
+  '@vueuse/metadata@10.11.1': {}
+
   '@vueuse/metadata@13.5.0': {}
 
+  '@vueuse/shared@10.11.1(vue@3.5.14(typescript@5.8.3))':
+    dependencies:
+      vue-demi: 0.14.10(vue@3.5.14(typescript@5.8.3))
+    transitivePeerDependencies:
+      - '@vue/composition-api'
+      - vue
+
   '@vueuse/shared@13.5.0(vue@3.5.14(typescript@5.8.3))':
     dependencies:
       vue: 3.5.14(typescript@5.8.3)
@@ -4673,6 +4748,12 @@ snapshots:
 
   forwarded@0.2.0: {}
 
+  framer-motion@12.22.0:
+    dependencies:
+      motion-dom: 12.22.0
+      motion-utils: 12.19.0
+      tslib: 2.8.1
+
   fresh@0.5.2: {}
 
   fresh@2.0.0: {}
@@ -4744,6 +4825,8 @@ snapshots:
     dependencies:
       function-bind: 1.1.2
 
+  hey-listen@1.0.8: {}
+
   hookable@5.5.3: {}
 
   hpack.js@2.1.6:
@@ -5129,6 +5212,25 @@ snapshots:
       pkg-types: 1.3.1
       ufo: 1.6.1
 
+  motion-dom@12.22.0:
+    dependencies:
+      motion-utils: 12.19.0
+
+  motion-utils@12.19.0: {}
+
+  motion-v@1.5.0(vue@3.5.14(typescript@5.8.3)):
+    dependencies:
+      '@vueuse/core': 10.11.1(vue@3.5.14(typescript@5.8.3))
+      framer-motion: 12.22.0
+      hey-listen: 1.0.8
+      motion-dom: 12.22.0
+      vue: 3.5.14(typescript@5.8.3)
+    transitivePeerDependencies:
+      - '@emotion/is-prop-valid'
+      - '@vue/composition-api'
+      - react
+      - react-dom
+
   mrmime@2.0.1: {}
 
   ms@2.0.0: {}
@@ -6008,6 +6110,10 @@ snapshots:
 
   vary@1.1.2: {}
 
+  vue-demi@0.14.10(vue@3.5.14(typescript@5.8.3)):
+    dependencies:
+      vue: 3.5.14(typescript@5.8.3)
+
   vue-eslint-parser@10.1.3(eslint@9.26.0(jiti@2.4.2)):
     dependencies:
       debug: 4.4.1

+ 3 - 0
pnpm-workspace.yaml

@@ -0,0 +1,3 @@
+ignoredBuiltDependencies:
+  - '@tailwindcss/oxide'
+  - core-js

+ 6 - 3
src/App.vue

@@ -1,10 +1,13 @@
 <script setup lang="ts">
-
-
+import { App, ConfigProvider } from 'ant-design-vue';
 </script>
 
 <template>
-  <router-view />
+  <ConfigProvider>
+    <App>
+      <router-view />
+    </App>
+  </ConfigProvider>
 </template>
 
 <style scoped lang="css">

+ 2 - 0
src/styles/index.scss

@@ -68,6 +68,8 @@ button {
 
 #app {
   text-align: center;
+  width: 100%;
+  height: 100%;
 }
 
 @media (prefers-color-scheme: light) {

+ 4 - 3
src/styles/reset.scss

@@ -1,9 +1,10 @@
 /* Reset CSS */
-* {
+*, :after, :before {
+  box-sizing: border-box;
+  border: 0 solid;
   margin: 0;
   padding: 0;
-  box-sizing: border-box;
-}
+} 
 
 html, body, div, span, applet, object, iframe,
 h1, h2, h3, h4, h5, h6, p, blockquote, pre,

+ 0 - 2
src/styles/variables.css

@@ -1,2 +0,0 @@
-@charset "UTF-8";
-/* 全局 SCSS 变量 */

+ 71 - 8
src/views/home/components/ParallaxBackground.vue

@@ -1,21 +1,84 @@
 <template>
-    <div ref="containerRef" class="absolute inset-0 overflow-hidden">
-        <div v-for="(image, index) in images" :key="index" class="absolute inset-0 bg-cover bg-center bg-no-repeat" :style="{ backgroundImage: `url(${image})` }"></div>
-    </div>
+  <div ref="containerRef" class="absolute inset-0 overflow-hidden">
+    <Motion
+      v-for="(image, index) in images"
+      :key="index"
+      class="absolute inset-0 bg-cover bg-center bg-no-repeat"
+      :style="getImageStyle(image, index)"
+    >
+    </Motion>
+  </div>
 </template>
 <script setup lang="ts">
-import { useScroll, useTransform, motion } from 'motion-v';
-import {ref} from 'vue';    
+import { useScroll, useTransform, Motion } from 'motion-v';
+import { ref, computed } from 'vue';
 import bg1 from '@/assets/imgs/home/bg1.png';
 
+defineOptions({
+  name: 'ParallaxBackground',
+});
+
 interface ParallaxBackgroundProps {
-    images: string[]
+  images: string[];
 }
 //内容容器
 const containerRef = ref<HTMLElement | null>(null);
 
-const images = ref<string[]>([bg1]);   
+//照片地址后期换cdn
+const images = ref<string[]>([bg1]);
+
+//vue-motion
+const { scrollYProgress } = useScroll({
+  target: containerRef,
+  offset: ['start start', 'end start'],
+});
+
+// 获取视差百分比,实现阶梯式效果
+const getParallaxPercentage = (index: number): string => {
+  // 预定义的阶梯式百分比
+  const percentages = ['50%', '30%', '10%'];
+  
+  // 如果索引在预定义范围内,直接返回对应百分比
+  if (index < percentages.length) {
+    return percentages[index];
+  }
+  
+  // 对于超出预定义范围的索引,使用递减公式
+  // 从10%开始,每增加一个索引,减少2%,但不低于0%
+  const percentage = Math.max(10 - (index - 2) * 2, 0);
+  return `${percentage}%`;
+};
+
+// 创建图片样式对象
+const imageStyles = ref<Record<number, any>>({});
 
+// 初始化每个图片的样式
+images.value.forEach((image, index) => {
+  // 为每个图层创建不同的变换速度,使用阶梯式百分比
+  const yTransform = useTransform(
+    scrollYProgress,
+    [0, 1],
+    ['0%', getParallaxPercentage(index)]
+  );
 
+  // 将变换值存储到样式对象中
+  imageStyles.value[index] = {
+    backgroundImage: `url(${image})`,
+    y: yTransform,
+    height: `${100 - index * 10}%`,
+    zIndex: -index - 1,
+    filter: 'brightness(0.7) contrast(1.1)',
+    backgroundSize: 'contain',
+    backgroundPosition: 'center',
+  };
+});
 
-</script>
+// 获取特定图片的样式
+const getImageStyle = (image: string, index: number) => {
+  return (
+    imageStyles.value[index] || {
+      backgroundImage: `url(${image})`,
+    }
+  );
+};
+</script>

+ 6 - 6
src/views/home/index.vue

@@ -1,10 +1,10 @@
 <template>
-    <div class="min-h-screen flex flex-col  relative w-full">
-        <HomeNav />
-        <ParallaxBackground />
-    </div>
+  <div class="min-h-screen flex flex-col relative w-full" style="height: 300vh;">
+    <HomeNav />
+    <ParallaxBackground />
+  </div>
 </template>
 <script setup lang="ts">
 import HomeNav from './components/nav.vue';
-import ParallaxBackground from './components/parallaxBackground.vue';
-</script>
+import ParallaxBackground from './components/ParallaxBackground.vue';
+</script>

+ 1 - 1
tsconfig.json

@@ -10,7 +10,7 @@
     "skipLibCheck": true,
     "isolatedModules": true,
     "resolveJsonModule": true,
-    "moduleResolution": "bundler",
+    "moduleResolution": "node",
     "useDefineForClassFields": true,
     "allowImportingTsExtensions": true,
     "sourceMap": true,