Quellcode durchsuchen

feat: 双沟设色页

任一存 vor 1 Jahr
Ursprung
Commit
13daaf46cb

BIN
src/assets/images/btn_bg-yellow.png


BIN
src/assets/images/icon_video.png


BIN
src/assets/images/shuang-gou-bg.jpg


BIN
src/assets/images/shuang-gou-para-1.png


BIN
src/assets/images/shuang-gou-para-2.png


BIN
src/assets/videos/she-se.mp4


BIN
src/assets/videos/shuang-gou.mp4


+ 6 - 0
src/router/index.js

@@ -1,6 +1,7 @@
 import { createRouter, createWebHashHistory } from 'vue-router'
 import HomeView from '../views/HomeView.vue'
 import MoreContent from '../views/MoreContent.vue'
+import ShuangGou from '../views/ShuangGou.vue'
 import PaintingDetail from '../views/PaintingDetail'
 
 // import store from '@/store/index.js'
@@ -22,6 +23,11 @@ const routes = [
     // component: TEXT,
   },
   {
+    path: '/shuang-gou',
+    name: 'ShuangGou',
+    component: ShuangGou,
+  },
+  {
     path: '/painting-detail',
     name: 'PaintingDetail',
     component: PaintingDetail,

+ 1 - 1
src/useFunctions/useSizeAdapt.js

@@ -3,7 +3,7 @@
 
 import { onBeforeUnmount, ref } from 'vue'
 
-export default function useSizeAdapt(windowWidthWhenDesign = 1920, windowHeightWhenDesign = 1080, needReactivity = true) {
+export default function useSizeAdapt(windowWidthWhenDesign = 1920, windowHeightWhenDesign = 1080 - 71 - 37, needReactivity = true) {
   const windowSizeInCssForRef = ref('')
   const windowSizeWhenDesignForRef = ref('')
   const scaleRate = ref(-1)

+ 40 - 1
src/utils.js

@@ -74,5 +74,44 @@ export default {
       ret += charSet.charAt(Math.floor(Math.random() * charSet.length))
     }
     return ret
-  }
+  },
+  mapPosFromDraftToWindow(posRaw, objectFit = 'cover', draftWidth = 1920, draftHeight = 1080, windowWidth = null, windowHeight = null) {
+    if (!windowWidth) {
+      windowWidth = window.innerWidth
+    }
+    if (!windowHeight) {
+      windowHeight = window.innerHeight
+    }
+    if (objectFit === 'cover') {
+      if (windowWidth / windowHeight > draftWidth / draftHeight) { // 实际窗口更宽扁,设计图与实际窗口等宽,上下被裁减
+        const scale = windowWidth / draftWidth
+        return {
+          x: posRaw.x * scale,
+          y: posRaw.y * scale - (draftHeight * scale - windowHeight) / 2,
+        }
+      } else { // false: 实际窗口更窄高,设计图与实际窗口等高,左右被裁减
+        const scale = windowHeight / draftHeight
+        return {
+          x: posRaw.x * scale - (draftWidth * scale - windowWidth) / 2,
+          y: posRaw.y * scale,
+        }
+      }
+    } else if (objectFit === 'contain') {
+      if (windowWidth / windowHeight > draftWidth / draftHeight) { // true: 实际窗口更宽扁,设计图与实际窗口等高,左右留白
+        const scale = windowHeight / draftHeight
+        return {
+          x: posRaw.x * scale + (windowWidth - draftWidth * scale) / 2,
+          y: posRaw.y * scale
+        }
+      } else { // false: 实际窗口更窄高,设计图与实际窗口等宽,上下留白
+        const scale = windowWidth / draftWidth
+        return {
+          x: posRaw.x * scale,
+          y: posRaw.y * scale + (windowHeight - draftHeight * scale) / 2,
+        }
+      }
+    } else {
+      throw (`invalid objectFit value: ${objectFit}`)
+    }
+  },
 }

+ 4 - 2
src/views/MoreContent.vue

@@ -270,8 +270,8 @@ watch(
 )
 
 function onClickShuangGouEntry() {
-  router.replace({
-    name: 'ShuanggouDetail',
+  router.push({
+    name: 'ShuangGou',
   })
 }
 
@@ -412,6 +412,7 @@ const OpenScene = () => {
           gap: calc(20px * v-bind("windowHeight") / v-bind("windowHeightDesign"));
           > div {
             .button-common-style();
+            padding-left: 0.12em;
             background-image: url(@/assets/images/fade-chapter-btn-bg-small.png);
             background-size: contain;
             background-repeat: no-repeat;
@@ -448,6 +449,7 @@ const OpenScene = () => {
           gap: calc(20px * v-bind("windowHeight") / v-bind("windowHeightDesign"));
           > div {
             .button-common-style();
+            padding-left: 0.12em;
             background-image: url(@/assets/images/fade-chapter-btn-bg-big.png);
             background-size: contain;
             background-repeat: no-repeat;

+ 249 - 0
src/views/ShuangGou.vue

@@ -0,0 +1,249 @@
+<template>
+  <div class="shuang-gou-page">
+    <img
+      class="bg"
+      src="@/assets/images/shuang-gou-bg.jpg"
+      alt=""
+      draggable="false"
+    >
+
+    <BtnBack @click="router.go(-1)" />
+    <HotspotComp
+      class="hotspot"
+      :style="{
+        left: hotspotX + 'px',
+        top: hotspotY + 'px',
+      }"
+      @click="onClickHotspot"
+    />
+    <img
+      class="para-1"
+      src="@/assets/images/shuang-gou-para-1.png"
+      alt=""
+      draggable="false"
+    >
+    <img
+      class="para-2"
+      src="@/assets/images/shuang-gou-para-2.png"
+      alt=""
+      draggable="false"
+    >
+    <div class="title">
+      <h1>双钩设色</h1>
+      <button class="play-video">
+        <img
+          class=""
+          src="@/assets/images/icon_video.png"
+          alt=""
+          draggable="false"
+        >
+      </button>
+    </div>
+
+    <div
+      v-if="isShowVideos"
+      class="videos"
+    >
+      <BtnBack @click="isShowVideos=false" />
+      <video
+        v-if="activeVideoIdx === 0"
+        src="@/assets/videos/shuang-gou.mp4"
+        controls
+        autoplay
+        playsinline
+        webkit-playsinline="true"
+        x5-video-player-type="h5"
+      />
+      <video
+        v-if="activeVideoIdx === 1"
+        src="@/assets/videos/she-se.mp4"
+        controls
+        autoplay
+        playsinline
+        webkit-playsinline="true"
+        x5-video-player-type="h5"
+      />
+      <menu>
+        <button
+          :class="{
+            active: activeVideoIdx === 0
+          }"
+          @click="activeVideoIdx = 0"
+        >
+          双钩
+        </button>
+        <button
+          :class="{
+            active: activeVideoIdx === 1
+          }"
+          @click="activeVideoIdx = 1"
+        >
+          设色
+        </button>
+      </menu>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref, computed, watch, onMounted, onBeforeUnmount, inject } from "vue"
+import { useRoute, useRouter } from "vue-router"
+import { useStore } from "vuex"
+import useSizeAdapt from '@/useFunctions/useSizeAdapt.js'
+
+const route = useRoute()
+const router = useRouter()
+const store = useStore()
+
+const {
+  windowSizeInCssForRef,
+  windowSizeWhenDesignForRef,
+} = useSizeAdapt()
+
+const $env = inject('$env')
+
+const hotspotX = ref(-100)
+const hotspotY = ref(-100)
+function setHotspotPos() {
+  const { x, y } = utils.mapPosFromDraftToWindow({ x: 610, y: 330 }, 'cover', 1920, 972)
+  hotspotX.value = x
+  hotspotY.value = y
+}
+setHotspotPos()
+onMounted(() => {
+  window.addEventListener('resize', setHotspotPos)
+})
+onBeforeUnmount(() => {
+  window.removeEventListener('resize', setHotspotPos)
+})
+
+const isShowVideos = ref(false)
+
+function onClickHotspot() {
+  isShowVideos.value = true
+}
+
+const activeVideoIdx = ref(0)
+
+</script>
+
+<style lang="less" scoped>
+.shuang-gou-page{
+  position: absolute;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 100%;
+  background-color: #fff;
+  >img.bg{
+    position: absolute;
+    top: 0;
+    left: 0;
+    height: 100%;
+    width: 100%;
+    object-fit: cover;
+  }
+  .hotspot{
+    position: absolute;
+    width: 48px;
+    height: 48px;
+  }
+  >img.para-1{
+    position: absolute;
+    bottom: 50%;
+    left: 47vw;
+    height: 64.5vh;
+    width: 17.9vh;
+    transform: translate(0, 50%);
+  }
+  >img.para-2{
+    position: absolute;
+    bottom: 0;
+    left: calc(47vw + 17.9vh + 7.61vh);
+    height: 84.57vh;
+    width: 28.40vh;
+  }
+  >.title{
+    position: absolute;
+    top: 8.13vh;
+    left: calc(47vw + 17.9vh + 7.61vh + 28.40vh + 14.51vh);
+    position: absolute;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    >h1{
+      flex: 0 0 auto;
+      writing-mode: vertical-lr;
+      font-family: KingHwa_OldSong, KingHwa_OldSong;
+      font-weight: 400;
+      font-size: 6.17vh;
+      color: #474747;
+      letter-spacing: 0.2em;
+    }
+    >button.play-video{
+      width: 4.32vh;
+      height: 4.32vh;
+      >img{
+        width: 100%;
+        height: 100%;
+      }
+    }
+    @media (max-aspect-ratio: 1250/835) {
+      left: initial;
+      right: 3vw;
+    }
+  }
+
+  >.videos{
+    position: absolute;
+    left: 0;
+    top: 0;
+    width: 100%;
+    height: 100%;
+    background: rgba(52,73,46,0.7);
+    backdrop-filter: blur(10px);
+    >video{
+      position: absolute;
+      left: 50%;
+      top: 50%;
+      transform: translate(-50%, -50%);
+      width: calc(1255 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      height: calc(735 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      object-fit: contain;
+      background: black;
+    }
+    >menu{
+      position: absolute;
+      top: 50%;
+      right: 0;
+      transform: translateY(-50%);
+      display: flex;
+      flex-direction: column;
+      justify-content: center;
+      align-items: center;
+      gap: calc(20 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      width: calc(334 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      >button{
+        width: calc(240 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        height: calc(60 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        font-family: KingHwa_OldSong, KingHwa_OldSong;
+        font-weight: 400;
+        font-size: calc(30 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        color: #FFFFFF;
+        line-height: calc(35 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+      }
+      >button.active{
+        font-family: KingHwa_OldSong, KingHwa_OldSong;
+        font-weight: 400;
+        font-size: calc(40 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        color: #72806D;
+        line-height: calc(47 / v-bind('windowSizeWhenDesignForRef') * v-bind('windowSizeInCssForRef'));
+        background-image: url(@/assets/images/btn_bg-yellow.png);
+        background-size: cover;
+        background-repeat: no-repeat;
+        background-position: center center;
+      }
+    }
+  }
+}
+</style>