소스 검색

提取出序列帧组件

任一存 3 년 전
부모
커밋
df4b4bc365
4개의 변경된 파일113개의 추가작업 그리고 104개의 파일을 삭제
  1. 0 60
      src/components/HelloWorld.vue
  2. 100 0
      src/components/SerialFrames.vue
  3. 2 0
      src/main.js
  4. 11 44
      src/views/HomeView.vue

+ 0 - 60
src/components/HelloWorld.vue

@@ -1,60 +0,0 @@
-<template>
-  <div class="hello">
-    <h1>{{ msg }}</h1>
-    <p>
-      For a guide and recipes on how to configure / customize this project,<br>
-      check out the
-      <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
-    </p>
-    <h3>Installed CLI Plugins</h3>
-    <ul>
-      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
-      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router" target="_blank" rel="noopener">router</a></li>
-      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-vuex" target="_blank" rel="noopener">vuex</a></li>
-      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
-    </ul>
-    <h3>Essential Links</h3>
-    <ul>
-      <li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
-      <li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
-      <li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
-      <li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
-      <li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
-    </ul>
-    <h3>Ecosystem</h3>
-    <ul>
-      <li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
-      <li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
-      <li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
-      <li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
-      <li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
-    </ul>
-  </div>
-</template>
-
-<script>
-export default {
-  name: 'HelloWorld',
-  props: {
-    msg: String
-  }
-}
-</script>
-
-<!-- Add "scoped" attribute to limit CSS to this component only -->
-<style scoped lang="less">
-h3 {
-  margin: 40px 0 0;
-}
-ul {
-  list-style-type: none;
-  padding: 0;
-}
-li {
-  display: inline-block;
-  margin: 0 10px;
-}
-a {
-  color: #42b983;
-}
-</style>

+ 100 - 0
src/components/SerialFrames.vue

@@ -0,0 +1,100 @@
+<template>
+  <div
+    class="frames-wrap"
+  >
+    <img
+      v-for="index of frameTotalNum"
+      v-show="frameCurNum === index - 1 ||
+        frameCurNum - 1 === index - 1
+      "
+      :key="index"
+      :src="imageSrcFunc(index)"
+      alt=""
+      @load="onFrameLoad(index - 1)"
+      @error="onFrameError(index - 1)"
+    >
+  </div>
+</template>
+
+<script>
+export default {
+  props: {
+    frameTotalNum: {
+      type: Number,
+      required: true,
+    },
+    frameInterval: {
+      type: Number,
+      default: 41.667
+    },
+    imageSrcFunc: {
+      type: Function,
+      required: true,
+    }
+  },
+  emits: ['over'],
+  data() {
+    return {
+      frameCurNum: 0,
+      frameStateList: new Array(this.frameTotalNum),
+      frameIntervalId: null,
+      isPlaying: false,
+    }
+  },
+  mounted() {
+  },
+  unmounted() {
+    clearInterval(this.frameIntervalId)
+  },
+  methods: {
+    onFrameLoad(idx) {
+      this.frameStateList[idx] = true
+    },
+    onFrameError(idx) {
+      this.frameStateList[idx] = false
+    },
+    play() {
+      if (this.isPlaying) {
+        return
+      }
+      this.isPlaying = true
+      this.frameCurNum = 0
+      this.frameIntervalId = setInterval(() => {
+        const frameNumBackup = this.frameCurNum
+        this.frameCurNum++
+        if (this.frameCurNum === this.frameTotalNum) {
+          clearInterval(this.frameIntervalId)
+          this.isPlaying = false
+          this.$emit('over')
+          return
+        }
+
+        while (this.frameStateList[this.frameCurNum] === false) {
+          this.frameCurNum++
+        }
+        if (this.frameStateList[this.frameCurNum] === undefined) {
+          this.frameCurNum = frameNumBackup
+        }
+      }, this.frameInterval)
+    },
+    stop() {
+      if (!this.isPlaying) {
+        return
+      }
+      clearInterval(this.frameIntervalId)
+      this.isPlaying = false
+      this.frameCurNum = 0
+    },
+  },
+}
+</script>
+
+<style lang="less" scoped>
+  .frames-wrap {
+    > img {
+      width: 100%;
+      height: 100%;
+      object-fit: contain;
+    }
+  }
+</style>

+ 2 - 0
src/main.js

@@ -3,9 +3,11 @@ import App from './App.vue'
 import router from './router'
 import store from './store'
 import HotSpot from '@/components/HotSpot.vue'
+import SerialFrames from '@/components/SerialFrames.vue'
 
 createApp(App)
   .use(store)
   .use(router)
   .component('HotSpot', HotSpot)
+  .component('SerialFrames', SerialFrames)
   .mount('#app')

+ 11 - 44
src/views/HomeView.vue

@@ -148,23 +148,15 @@
       >
     </button>
 
-    <div
+    <SerialFrames
       v-show="[1].includes(tourState)"
-      class="treasure-frames-wrap"
-    >
-      <img
-        v-for="index of treasureFrameTotalNum"
-        v-show="treasureFrameCurNum === index - 1 ||
-          treasureFrameCurNum - 1 === index - 1
-        "
-        :key="index"
-        class="treasure-frame"
-        :src="require(`@/assets/treasure-frames/3_${(index-1).toString().padStart(5, '0')}.jpg`)"
-        alt=""
-        @load="onTreasureFrameLoad(index - 1)"
-        @error="onTreasureFrameError(index - 1)"
-      >
-    </div>
+      ref="treasure-serial-frames"
+      class="treasure-serial-frames"
+      :frame-total-num="treasureFrameTotalNum"
+      :frame-interval="40"
+      :image-src-func="(index) => require(`@/assets/treasure-frames/3_${(index - 1).toString().padStart(5, '0')}.jpg`)"
+      @over="tourState=2"
+    />
   </div>
 </template>
 
@@ -240,9 +232,6 @@ export default {
 
       // 文物展示相关
       treasureFrameTotalNum,
-      treasureFrameCurNum: 0,
-      treasureFrameStateList: new Array(treasureFrameTotalNum),
-      treasureFrameIntervalId: null,
 
       // 文物淡出相关
       treasureFadeOutProgress: {
@@ -293,23 +282,7 @@ export default {
     tourState: {
       handler(vNew, vOld) {
         if (vOld === 0 && vNew === 1) {
-          this.treasureFrameIntervalId = setInterval(() => {
-            const frameNumBackup = this.treasureFrameCurNum
-            this.treasureFrameCurNum++
-            if (this.treasureFrameCurNum === this.treasureFrameTotalNum) {
-              clearInterval(this.treasureFrameIntervalId)
-              this.treasureFrameCurNum = 0
-              this.tourState = 2
-              return
-            }
-
-            while (this.treasureFrameStateList[this.treasureFrameCurNum] === false) {
-              this.treasureFrameCurNum++
-            }
-            if (this.treasureFrameStateList[this.treasureFrameCurNum] === undefined) {
-              this.treasureFrameCurNum = frameNumBackup
-            }
-          }, 40)
+          this.$refs['treasure-serial-frames'].play()
         } else if (vOld === 1 && vNew === 2) {
           this.treasureFadeOutTween.start()
         }
@@ -484,8 +457,7 @@ export default {
       this.tourState = 3
       this.treasureFadeInTween.stop()
       this.treasureFadeOutTween.stop()
-      clearInterval(this.treasureFrameIntervalId)
-      this.treasureFrameCurNum = 0
+      this.$refs['treasure-serial-frames'].stop()
       if (this.$refs.treasure) {
         this.$refs.treasure.style.left = this.treasureFadeInInitialLeft + 'px'
         this.$refs.treasure.style.top = this.treasureFadeInInitialTop + 'px'
@@ -614,18 +586,13 @@ export default {
     z-index: 4;
     border: none;
   }
-  .treasure-frames-wrap {
+  .treasure-serial-frames {
     position: absolute;
     top: 0;
     left: 0;
     width: 100%;
     height: 100%;
     z-index: 3;
-    > img {
-      width: 100%;
-      height: 100%;
-      object-fit: contain;
-    }
   }
   @media screen and (max-height: 810px) {
     .people-far-wrap {