Parcourir la source

feat: 古诗列表页

任一存 il y a 1 an
Parent
commit
d488e34566
48 fichiers modifiés avec 532 ajouts et 1 suppressions
  1. BIN
      src/assets/images/RW/1_01.png
  2. BIN
      src/assets/images/RW/1_02.png
  3. BIN
      src/assets/images/RW/1_03.png
  4. BIN
      src/assets/images/RW/1_04.png
  5. BIN
      src/assets/images/RW/1_05.png
  6. BIN
      src/assets/images/RW/2_01.png
  7. BIN
      src/assets/images/RW/2_02.png
  8. BIN
      src/assets/images/RW/2_03.png
  9. BIN
      src/assets/images/RW/2_04.png
  10. BIN
      src/assets/images/RW/2_05.png
  11. BIN
      src/assets/images/RW/3_01.png
  12. BIN
      src/assets/images/RW/3_02.png
  13. BIN
      src/assets/images/RW/3_03.png
  14. BIN
      src/assets/images/RW/3_04.png
  15. BIN
      src/assets/images/RW/3_05.png
  16. BIN
      src/assets/images/RW/3_06.png
  17. BIN
      src/assets/images/RW/3_07.png
  18. BIN
      src/assets/images/RW/3_08.png
  19. BIN
      src/assets/images/RW/3_09.png
  20. BIN
      src/assets/images/RW/4_01.png
  21. BIN
      src/assets/images/RW/4_02.png
  22. BIN
      src/assets/images/RW/4_03.png
  23. BIN
      src/assets/images/RW/4_04.png
  24. BIN
      src/assets/images/RW/4_05.png
  25. BIN
      src/assets/images/RW/4_06.png
  26. BIN
      src/assets/images/RW/4_07.png
  27. BIN
      src/assets/images/RW/4_08.png
  28. BIN
      src/assets/images/RW/4_09.png
  29. BIN
      src/assets/images/RW/bg_caizhi.jpg
  30. BIN
      src/assets/images/RW/play.mp4
  31. BIN
      src/assets/images/RW/titile_mozhu-min.png
  32. BIN
      src/assets/images/poem-list/1-min.png
  33. BIN
      src/assets/images/poem-list/2-min.png
  34. BIN
      src/assets/images/poem-list/3-min.png
  35. BIN
      src/assets/images/poem-list/bg.jpg
  36. BIN
      src/assets/images/poem-list/button-ming-active.png
  37. BIN
      src/assets/images/poem-list/button-ming.png
  38. BIN
      src/assets/images/poem-list/button-qing-active.png
  39. BIN
      src/assets/images/poem-list/button-qing.png
  40. BIN
      src/assets/images/poem-list/button-song-active.png
  41. BIN
      src/assets/images/poem-list/button-song.png
  42. BIN
      src/assets/images/poem-list/button-tang-active.png
  43. BIN
      src/assets/images/poem-list/button-tang.png
  44. BIN
      src/assets/images/poem-list/button-yuan-active.png
  45. BIN
      src/assets/images/poem-list/button-yuan.png
  46. 6 0
      src/router/index.js
  47. 2 1
      src/useFunctions/useSmoothSwipe.js
  48. 524 0
      src/views/PoemList.vue

BIN
src/assets/images/RW/1_01.png


BIN
src/assets/images/RW/1_02.png


BIN
src/assets/images/RW/1_03.png


BIN
src/assets/images/RW/1_04.png


BIN
src/assets/images/RW/1_05.png


BIN
src/assets/images/RW/2_01.png


BIN
src/assets/images/RW/2_02.png


BIN
src/assets/images/RW/2_03.png


BIN
src/assets/images/RW/2_04.png


BIN
src/assets/images/RW/2_05.png


BIN
src/assets/images/RW/3_01.png


BIN
src/assets/images/RW/3_02.png


BIN
src/assets/images/RW/3_03.png


BIN
src/assets/images/RW/3_04.png


BIN
src/assets/images/RW/3_05.png


BIN
src/assets/images/RW/3_06.png


BIN
src/assets/images/RW/3_07.png


BIN
src/assets/images/RW/3_08.png


BIN
src/assets/images/RW/3_09.png


BIN
src/assets/images/RW/4_01.png


BIN
src/assets/images/RW/4_02.png


BIN
src/assets/images/RW/4_03.png


BIN
src/assets/images/RW/4_04.png


BIN
src/assets/images/RW/4_05.png


BIN
src/assets/images/RW/4_06.png


BIN
src/assets/images/RW/4_07.png


BIN
src/assets/images/RW/4_08.png


BIN
src/assets/images/RW/4_09.png


BIN
src/assets/images/RW/bg_caizhi.jpg


BIN
src/assets/images/RW/play.mp4


BIN
src/assets/images/RW/titile_mozhu-min.png


BIN
src/assets/images/poem-list/1-min.png


BIN
src/assets/images/poem-list/2-min.png


BIN
src/assets/images/poem-list/3-min.png


BIN
src/assets/images/poem-list/bg.jpg


BIN
src/assets/images/poem-list/button-ming-active.png


BIN
src/assets/images/poem-list/button-ming.png


BIN
src/assets/images/poem-list/button-qing-active.png


BIN
src/assets/images/poem-list/button-qing.png


BIN
src/assets/images/poem-list/button-song-active.png


BIN
src/assets/images/poem-list/button-song.png


BIN
src/assets/images/poem-list/button-tang-active.png


BIN
src/assets/images/poem-list/button-tang.png


BIN
src/assets/images/poem-list/button-yuan-active.png


BIN
src/assets/images/poem-list/button-yuan.png


+ 6 - 0
src/router/index.js

@@ -3,6 +3,7 @@ import HomeView from '../views/HomeView.vue'
 import MoreContent from '../views/MoreContent.vue'
 import ShuangGou from '../views/ShuangGou.vue'
 import BambooList from '../views/BambooList.vue'
+import PoemList from '../views/PoemList.vue'
 import PaintingDetail from '../views/PaintingDetail'
 
 // import store from '@/store/index.js'
@@ -34,6 +35,11 @@ const routes = [
     component: BambooList,
   },
   {
+    path: '/poem-list',
+    name: 'PoemList',
+    component: PoemList,
+  },
+  {
     path: '/painting-detail',
     name: 'PaintingDetail',
     component: PaintingDetail,

+ 2 - 1
src/useFunctions/useSmoothSwipe.js

@@ -96,7 +96,8 @@ export default function useSmoothSwipe({
   }
 
   function onWheel(e) {
-    translateLength.value += e.deltaY / 2.5
+    translateLength.value += e.deltaY / 0.5
+    console.log(translateLength.value)
   }
 
   /**

+ 524 - 0
src/views/PoemList.vue

@@ -0,0 +1,524 @@
+<template>
+  <div class="poem-list">
+    <div
+      ref="scrollTarget"
+      class="scroll-target"
+    >
+      <div
+        class="layer-4"
+        :style="{
+          left: layer4Left + 'px',
+        }"
+      >
+        <img
+          class="bg"
+          src="@/assets/images/poem-list/bg.jpg"
+          alt=""
+          draggable="false"
+        >
+        <img
+          class="bg"
+          src="@/assets/images/poem-list/bg.jpg"
+          alt=""
+          draggable="false"
+        >
+        <img
+          class="bg"
+          src="@/assets/images/poem-list/bg.jpg"
+          alt=""
+          draggable="false"
+        >
+      </div>
+
+      <div
+        class="layer-3"
+        :style="{
+          left: layer3Left + 'px',
+        }"
+      >
+        <img
+          class="bamboo"
+          src="@/assets/images/poem-list/3-min.png"
+          alt=""
+          draggable="false"
+        >
+        <img
+          class="bamboo"
+          src="@/assets/images/poem-list/3-min.png"
+          alt=""
+          draggable="false"
+        >
+      </div>
+
+      <div
+        class="layer-2"
+        :style="{
+          left: layer2Left + 'px',
+        }"
+      >
+        <img
+          class="bamboo"
+          src="@/assets/images/poem-list/2-min.png"
+          alt=""
+          draggable="false"
+        >
+        <img
+          class="bamboo"
+          src="@/assets/images/poem-list/2-min.png"
+          alt=""
+          draggable="false"
+        >
+      </div>
+
+      <div
+        class="layer-1"
+        :style="{
+          left: layer1Left + 'px',
+        }"
+      >
+        <img
+          class="bamboo"
+          src="@/assets/images/poem-list/1-min.png"
+          alt=""
+          draggable="false"
+        >
+        <img
+          class="bamboo"
+          src="@/assets/images/poem-list/1-min.png"
+          alt=""
+          draggable="false"
+        >
+
+        <!-- 诗句内容 -->
+        <div
+          v-for="(item, index) in poemList"
+          :key="index"
+          class="poem"
+        >
+          <div class="title-wrap">
+            <h1>《{{ item["标题"] }}》</h1>
+            <div class="sub-title">
+              <span class="author">{{ item["作者"] }}</span>
+              <span class="age">{{ item["朝代"] }}</span>
+            </div>
+          </div>
+          <p>{{ item["正文"] }}</p>
+        </div>
+      </div>
+    </div>
+
+    <div class="shadow-bottom">
+      <menu class="age-list">
+        <button
+          v-for="(item, idx) in ageList"
+          :key="item.id"
+          class="age"
+          :class="{
+            active: activeAgeIdx === idx,
+          }"
+          @click="onClickAge(item)"
+        >
+          <img
+            class="img-normal"
+            :src="require(`@/assets/images/poem-list/button-${item.id}.png`)"
+            alt=""
+            draggable="false"
+          >
+          <img
+            class="img-active"
+            :src="require(`@/assets/images/poem-list/button-${item.id}-active.png`)"
+            alt=""
+            draggable="false"
+          >
+        </button>
+      </menu>
+    </div>
+
+    <!-- todo -->
+    <BtnBack @click="router.replace('/?back=1')" />
+
+    <OperationTip
+      class="operation-tip"
+      :text="'左右滑动'"
+      :color="'green'"
+    />
+  </div>
+</template>
+
+<script setup>
+import { ref, computed, watch, onBeforeMount, nextTick } from "vue"
+import { useRoute, useRouter } from "vue-router"
+import { useStore } from "vuex"
+import useSmoothSwipe from "@/useFunctions/useSmoothSwipe.js"
+import { useWindowSize } from "@vueuse/core"
+import OperationTip from "@/components/OperationTip.vue"
+
+const route = useRoute()
+const router = useRouter()
+const store = useStore()
+
+const windowWidthDesign = 7681 * 2
+const windowHeightDesign = 1080 - 71 - 37 // 设计稿里视口高度。注意要减去上下边栏
+
+const scrollTarget = ref(null)
+const { width: windowWidth, height: windowHeight } = useWindowSize()
+
+const maxTranslateLength = computed(() => {
+  return (windowHeight.value * windowWidthDesign) / windowHeightDesign - 800 // 有的图层不够长导致移动到最右侧不好看,隐藏掉。
+})
+
+const {
+  translateLength,
+} = useSmoothSwipe({
+  scrollTargetRef: scrollTarget,
+  maxTranslateLength,
+  viewportWidth: windowWidth,
+})
+
+// layer4Left位移
+const layer4SpeedFactor = 0.6
+const layer4InitialLeft = 0
+const layer4Left = ref(layer4InitialLeft)
+
+// layer3Left位移
+const layer3SpeedFactor = 0.8
+const layer3InitialLeft = 0
+const layer3Left = ref(layer3InitialLeft)
+
+// layer2Left位移
+const layer2SpeedFactor = 1
+const layer2InitialLeft = 0
+const layer2Left = ref(layer2InitialLeft)
+
+// layer1Left位移
+const layer1InitialLeft = 0
+const layer1Left = ref(layer1InitialLeft)
+
+watch(
+  translateLength,
+  (v) => {
+    layer4Left.value = layer4InitialLeft - v * layer4SpeedFactor
+    layer3Left.value = layer3InitialLeft - v * layer3SpeedFactor
+    layer2Left.value = layer2InitialLeft - v * layer2SpeedFactor
+    layer1Left.value = layer1InitialLeft - v
+  },
+  {
+    immediate: true,
+  }
+)
+
+const poemList = configExcel["诗词"]
+
+const ageList = [
+  {
+    name: '唐',
+    id: 'tang',
+    startPos: 0,
+  },
+  {
+    name: '宋',
+    id: 'song',
+    startPos: 3000,
+  },
+  {
+    name: '元',
+    id: 'yuan',
+    startPos: 5500,
+  },
+  {
+    name: '明',
+    id: 'ming',
+    startPos: 8500
+  },
+  {
+    name: '清',
+    id: 'qing',
+    startPos: 11200
+  },
+]
+
+function onClickAge(item) {
+  translateLength.value = item.startPos * windowHeight.value / windowHeightDesign
+}
+const activeAgeIdx = ref(0)
+watch(translateLength, (v) => {
+  for (let index = ageList.length - 1; index >= 0; index--) {
+    const element = ageList[index]
+    if (element.startPos * windowHeight.value / windowHeightDesign <= translateLength.value ) {
+      activeAgeIdx.value = index
+      break
+    }
+  }
+})
+</script>
+
+<style lang="less" scoped>
+.poem-list {
+  background-color: #fefefe;
+  position: absolute;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 100%;
+  user-select: none;
+
+  > .scroll-target {
+    height: 100%;
+    width: 100%;
+    display: flex;
+    gap: 100px;
+    overflow: hidden;
+
+    > .layer-4 {
+      position: absolute;
+      height: 100%;
+      display: flex;
+      > .bg {
+        flex: 0 0 auto;
+        height: 100%;
+      }
+    }
+
+    > .layer-3 {
+      position: absolute;
+      height: 33%;
+      bottom: 0;
+      display: flex;
+      > .bamboo {
+        flex: 0 0 auto;
+        height: 100%;
+      }
+      > .bamboo:nth-of-type(1){
+        margin-left: calc((1250px) * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+      }
+      > .bamboo:nth-of-type(2){
+        margin-left: calc((171px + 1250px) * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+      }
+    }
+
+    > .layer-2 {
+      position: absolute;
+      height: 100%;
+      display: flex;
+      > .bamboo {
+        flex: 0 0 auto;
+        height: 100%;
+      }
+      > .bamboo:nth-of-type(1){
+        margin-left: calc((193px) * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+      }
+      > .bamboo:nth-of-type(2){
+        margin-left: calc((720px + 193px) * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+      }
+    }
+
+    > .layer-1 {
+      position: absolute;
+      height: 100%;
+      display: flex;
+      > .bamboo {
+        flex: 0 0 auto;
+        height: 100%;
+      }
+      > .bamboo:nth-of-type(1){
+        margin-left: calc((418px) * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+      }
+      > .bamboo:nth-of-type(2){
+        margin-left: calc((800px + 418px) * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+      }
+      >.poem {
+        position: absolute;
+        left: 0;
+        top: 10.1%;
+        writing-mode: vertical-rl;
+        > .title-wrap {
+          position: relative;
+          width: fit-content;
+          height: fit-content;
+          > h1 {
+            font-family: KingHwa_OldSong, KingHwa_OldSong;
+            font-weight: 400;
+            font-size: calc(48px * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+            color: #303030;
+            line-height: calc(56px * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+            white-space: pre;
+          }
+          > .sub-title {
+            position: absolute;
+            left: 0;
+            top: 50%;
+            transform: translate(-140%, -50%);
+            display: flex;
+            align-items: center;
+            > .author {
+              white-space: pre;
+              font-family: KaiTi;
+              font-weight: 400;
+              font-size: calc(24px * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+              color: #BAA565;
+              margin-inline-end: 0.5em;
+            }
+            > .age {
+              display: inline-block;
+              width: calc(24px * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+              height: calc(24px * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+              background-color: #b6a261;
+              border-radius: 50%;
+              display: flex;
+              justify-content: center;
+              align-items: center;
+              font-family: KaiTi;
+              font-weight: 400;
+              font-size: calc(20px * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+              color: #ffffff;
+            }
+          }
+        }
+        > p {
+          position: absolute;
+          right: calc(120px * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+          top: 75%;
+          font-family: KaiTi;
+          font-weight: 400;
+          font-size: calc(26px * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+          color: #303030;
+          line-height: 1.6em;
+          white-space: pre;
+          letter-spacing: 0.2em;
+        }
+      }
+      .poem:nth-of-type(1) {
+        top: calc(210px * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+        left: calc(260px * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+      }
+      .poem:nth-of-type(2) {
+        left: calc(830px * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+      }
+      .poem:nth-of-type(3) {
+        left: calc(1700px * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+      }
+      .poem:nth-of-type(4) {
+        left: calc(2500px * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+      }
+      .poem:nth-of-type(5) {
+        left: calc(3550px * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+        >p{
+          transform: translateY(-15%);
+        }
+      }
+      .poem:nth-of-type(6) {
+        left: calc(3950px * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+      }
+      .poem:nth-of-type(7) {
+        left: calc(4300px * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+      }
+      .poem:nth-of-type(8) {
+        left: calc(5100px * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+      }
+      .poem:nth-of-type(9) {
+        left: calc(6000px * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+        >p{
+          transform: translateY(-12%);
+        }
+      }
+      .poem:nth-of-type(10) {
+        left: calc(6800px * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+      }
+      .poem:nth-of-type(11) {
+        transform: translateY(40%);
+        left: calc((7200px + 260px) * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+      }
+      .poem:nth-of-type(12) {
+        left: calc((7200px + 830px) * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+        >p{
+          transform: translateY(-40%);
+        }
+      }
+      .poem:nth-of-type(13) {
+        left: calc((7200px + 1700px) * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+      }
+      .poem:nth-of-type(14) {
+        left: calc((7200px + 2500px) * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+      }
+      .poem:nth-of-type(15) {
+        left: calc((7200px + 3550px) * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+      }
+      .poem:nth-of-type(16) {
+        left: calc((7200px + 3950px) * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+      }
+      .poem:nth-of-type(17) {
+        left: calc((7200px + 4300px) * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+      }
+      .poem:nth-of-type(18) {
+        left: calc((7200px + 5100px) * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+      }
+      .poem:nth-of-type(19) {
+        transform: translateY(-10%);
+        left: calc((7200px + 6000px) * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+        >p{
+          transform: translateY(-80%);
+        }
+      }
+      .poem:nth-of-type(20) {
+        left: calc((7200px + 6800px) * v-bind('windowHeight') / v-bind('windowHeightDesign'));
+      }
+    }
+  }
+
+  >.shadow-bottom{
+    position: absolute;
+    left: 0;
+    bottom: 0;
+    width: 100%;
+    height: 12.4%;
+    background: linear-gradient(0deg, #888 0%, rgba(0,0,0,0) 100%);
+    >menu.age-list{
+      position: absolute;
+      left: 50%;
+      bottom: 30px;
+      transform: translateX(-50%);
+      display: flex;
+      align-items: center;
+      gap: 20px;
+      >button.age{
+        width: 47px;
+        height: 47px;
+        position: relative;
+        >img{
+          position: absolute;
+          left: 0;
+          top: 0;
+          width: 100%;
+          height: 100%;
+        }
+        >img.img-normal{
+          display: block;
+        }
+        >img.img-active{
+          display: none;
+        }
+      }
+      >button.age:hover, button.age.active{
+        >img.img-normal{
+          display: none;
+        }
+        >img.img-active{
+          display: block;
+        }
+      }
+    }
+  }
+
+  > .operation-tip {
+    position: absolute;
+    right: calc(
+      44 / v-bind("windowSizeWhenDesignForRef") *
+        v-bind("windowSizeInCssForRef")
+    );
+    bottom: calc(
+      74 / v-bind("windowSizeWhenDesignForRef") *
+        v-bind("windowSizeInCssForRef")
+    );
+  }
+}
+</style>