Yansen 2 年之前
父節點
當前提交
b4420b53a7
共有 9 個文件被更改,包括 200 次插入80 次删除
  1. 二進制
      public/images/pg1/md2-header.png
  2. 二進制
      public/images/pg2/map.png
  3. 二進制
      public/video/9年活动.mp4
  4. 8
    1
      src/App.vue
  5. 79
    0
      src/components/InkEffect.vue
  6. 60
    0
      src/pages/pg1/Md1.vue
  7. 25
    11
      src/pages/pg1/Md3.vue
  8. 2
    67
      src/pages/pg3/Ink.vue
  9. 26
    1
      src/store/index.js

二進制
public/images/pg1/md2-header.png 查看文件


二進制
public/images/pg2/map.png 查看文件


二進制
public/video/9年活动.mp4 查看文件


+ 8
- 1
src/App.vue 查看文件

@@ -6,7 +6,7 @@
6 6
   import Loading from './First.vue';
7 7
 
8 8
   const { el } = useModel('audio');
9
-  const { setUser } = useModel('user');
9
+  const { setUser, contries } = useModel('user');
10 10
   const show = ref(false);
11 11
   
12 12
   const { share, getCode, redirect } = wxsdk();
@@ -18,6 +18,13 @@
18 18
     } else {
19 19
       track(code).then(res => {
20 20
         const { user, num } = res;
21
+
22
+        // 随机设置国家种植数量
23
+        const avg = (num || 0) / 8;
24
+        Object.keys(contries).forEach(key => {
25
+          contries[key] = avg + Math.floor(Math.random() * 100)
26
+        });
27
+
21 28
         setUser({
22 29
           ...(user || {}),
23 30
           num: num || 0,

+ 79
- 0
src/components/InkEffect.vue 查看文件

@@ -0,0 +1,79 @@
1
+<template>
2
+  <canvas ref="canvasRef"></canvas>
3
+</template>
4
+
5
+<script setup>
6
+  import { onBeforeMount, onMounted, ref, watch } from 'vue';
7
+
8
+  const canvasRef = ref();
9
+  const renderRef = ref();
10
+  const props = defineProps({
11
+    src: String,
12
+    active: Boolean,
13
+    speed: {
14
+      type: Number,
15
+      default: 5,
16
+    }
17
+  })
18
+
19
+  let frameId = null;
20
+  let i = 0;
21
+
22
+  watch(() => props.active, (newVal, oldVal) => {
23
+    if (newVal && !oldVal) {
24
+      if (renderRef.value) {
25
+        i = 0;
26
+        renderRef.value();
27
+      }
28
+    }
29
+  })
30
+
31
+  onMounted(() => {
32
+    const canv = canvasRef.value;
33
+    const ctx = canv.getContext("2d");
34
+    const img = new Image();
35
+    const imgMask = new Image();
36
+    
37
+    img.onload = function() {
38
+      canv.width = img.naturalWidth;
39
+      canv.height = img.naturalHeight;
40
+    }
41
+
42
+    img.src = props.src;
43
+    imgMask.src = './images/cloud-texture.png'
44
+    
45
+    function draw() {
46
+      i += props.speed;
47
+      
48
+      let maskX = (canv.width - (70 + i)) / 2,
49
+          maskY = (canv.height - (40 + i)) / 2;
50
+      
51
+      ctx.clearRect(0, 0, canv.width, canv.height);
52
+      ctx.globalCompositeOperation = "source-over";
53
+      
54
+      ctx.drawImage(imgMask, maskX, maskY, 70 + i, 40 + i);
55
+      
56
+      ctx.globalCompositeOperation = "source-in";
57
+      ctx.drawImage(img, 0, 0, img.naturalWidth, img.naturalHeight);
58
+      
59
+      frameId = window.requestAnimationFrame(draw);
60
+
61
+      if (i >= 5000) {
62
+        i = 0;
63
+        window.cancelAnimationFrame(frameId);
64
+      }
65
+    }
66
+
67
+    renderRef.value = draw;
68
+
69
+    if (props.active) {
70
+      draw();
71
+    }
72
+  });
73
+
74
+  onBeforeMount(() => {
75
+    if (frameId) {
76
+      window.cancelAnimationFrame(frameId);
77
+    }
78
+  });
79
+</script>

+ 60
- 0
src/pages/pg1/Md1.vue 查看文件

@@ -14,13 +14,58 @@
14 14
           播撒和平的种子。<br>
15 15
           近20万枚紫金草徽章佩戴在了人们的心口。
16 16
         </p>
17
+        <div class="map-img" ref="mapRef" />
17 18
       </div>
18 19
     </div>
19 20
   </Modal>
20 21
 </template>
21 22
 
22 23
 <script setup>
24
+  import { onMounted, ref, watch } from 'vue';
23 25
   import Modal from '@/components/Modal.vue';
26
+
27
+  const mapRef = ref()
28
+  const loaded = ref(false);
29
+  const dep = ref(true);
30
+
31
+  const callback = (t) => {
32
+    const maxHeight = 27837
33
+    const rawHeight = 489
34
+    const img = mapRef.value
35
+    const height = img.offsetHeight
36
+    const pos = t * rawHeight
37
+
38
+    const backgroundPosition = `0 -${(pos * height) / rawHeight}px`
39
+    img.style.backgroundPosition = backgroundPosition
40
+
41
+    if (pos >= maxHeight - rawHeight) {
42
+      return true
43
+    }
44
+  }
45
+  
46
+  onMounted(() => {
47
+    loaded.value = true;
48
+  });
49
+
50
+  let times = 0;
51
+  let execed = false;
52
+  watch([loaded, dep], (values) => {
53
+    console.log(values)
54
+    if (execed) return;
55
+
56
+    if (values[0] && values[1]) {
57
+      execed = true;
58
+      
59
+      const i = setInterval(() => {
60
+        const isOver = callback(times);
61
+        times += 1;
62
+
63
+        if (isOver) {
64
+          clearInterval(i);
65
+        }
66
+      }, 2000 / 16);
67
+    }
68
+  });
24 69
 </script>
25 70
 
26 71
 <style lang="less" scoped>
@@ -38,8 +83,23 @@
38 83
   .md1-context {
39 84
     box-sizing: border-box;
40 85
     padding-top: 20px;
86
+    padding-bottom: 20px;
41 87
     font-size: 12px;
42 88
     text-align: center;
43 89
   }
90
+
91
+  .map-img {
92
+    margin: auto;
93
+    @width: 70vw;
94
+    @height: (@width / 832 * 489);
95
+
96
+    width: @width;
97
+    height: @height;
98
+    
99
+    background-image: url(/images/pg2/map.png);
100
+    background-repeat: no-repeat;
101
+    background-position: 0 0;
102
+    background-size: 100% auto;
103
+  }
44 104
 }
45 105
 </style>

+ 25
- 11
src/pages/pg1/Md3.vue 查看文件

@@ -1,10 +1,24 @@
1 1
 <template>
2 2
   <Modal>
3 3
     <div class="md3-box md-bg">
4
-      <div class="md3-header">
5
-        <img src="/images/pg1/logo.png" alt="">
4
+      <div class="md3-header ">
5
+        <Animate
6
+          comp="img"
7
+          name="animate__fadeInDown"
8
+          src="/images/pg1/md2-header.png"
9
+          alt=""
10
+          :ready="true"
11
+        />
6 12
       </div>
7 13
       <div class="md3-context">
14
+        <video
15
+          webkit-playsinline
16
+          playsinline
17
+          preload="auto"
18
+          autoplay="autoplay"
19
+          controls="controls"
20
+          src="/video/9年活动.mp4"
21
+        ></video>
8 22
       </div>
9 23
     </div>
10 24
   </Modal>
@@ -12,6 +26,7 @@
12 26
 
13 27
 <script setup>
14 28
   import Modal from '@/components/Modal.vue';
29
+  import Animate from '@/components/Animate.vue';
15 30
 </script>
16 31
 
17 32
 <style lang="less" scoped>
@@ -21,23 +36,22 @@
21 36
   box-sizing: border-box;
22 37
   padding: 16px;
23 38
 
24
-  .md3-bg {
25
-    position: absolute;
26
-    top: 10px;
27
-    right: 5px;
28
-    width: 50px;
29
-    z-index: 0;
30
-  }
31
-
32 39
   .md3-header {
33 40
     box-sizing: border-box;
34
-    width: 32vw;
41
+    width: 80%;
42
+    margin: auto;
35 43
   }
36 44
 
37 45
   .md3-context {
38 46
     box-sizing: border-box;
39 47
     padding-top: 60px;
40 48
     font-size: 12px;
49
+    position: relative;
50
+    z-index: 10;
51
+
52
+    video {
53
+      width: 100%;
54
+    }
41 55
   }
42 56
 }
43 57
 </style>

+ 2
- 67
src/pages/pg3/Ink.vue 查看文件

@@ -1,83 +1,18 @@
1 1
 <template>
2 2
   <div class="ink-box">
3 3
     <div>
4
-      <canvas class="ink-cover" ref="canvasRef"></canvas>
4
+      <InkEffect class="ink-cover" :src="src" :active="active" />
5 5
       <!-- <img class="ink-back" :src="src" alt="" > -->
6 6
     </div>
7 7
   </div>
8 8
 </template>
9 9
 
10 10
 <script setup>
11
-  import { onBeforeMount, onMounted, ref, watch } from 'vue';
12
-
13
-  const canvasRef = ref();
14
-  const renderRef = ref();
11
+  import InkEffect from '@/components/InkEffect.vue';
15 12
   const props = defineProps({
16 13
     src: String,
17 14
     active: Boolean,
18 15
   })
19
-
20
-  let frameId = null;
21
-  let i = 0;
22
-
23
-  watch(() => props.active, (newVal, oldVal) => {
24
-    if (newVal && !oldVal) {
25
-      if (renderRef.value) {
26
-        i = 0;
27
-        renderRef.value();
28
-      }
29
-    }
30
-  })
31
-
32
-  onMounted(() => {
33
-    const canv = canvasRef.value;
34
-    const ctx = canv.getContext("2d");
35
-    const img = new Image();
36
-    const imgMask = new Image();
37
-    
38
-    img.onload = function() {
39
-      canv.width = img.naturalWidth;
40
-      canv.height = img.naturalHeight;
41
-    }
42
-
43
-    img.src = props.src;
44
-    imgMask.src = './images/cloud-texture.png'
45
-    
46
-    function draw() {
47
-      i += 5;
48
-      
49
-      let maskX = (canv.width - (70 + i)) / 2,
50
-          maskY = (canv.height - (40 + i)) / 2;
51
-      
52
-      ctx.clearRect(0, 0, canv.width, canv.height);
53
-      ctx.globalCompositeOperation = "source-over";
54
-      
55
-      ctx.drawImage(imgMask, maskX, maskY, 70 + i, 40 + i);
56
-      
57
-      ctx.globalCompositeOperation = "source-in";
58
-      ctx.drawImage(img, 0, 0, img.naturalWidth, img.naturalHeight);
59
-      
60
-      frameId = window.requestAnimationFrame(draw);
61
-
62
-      if (i >= 5000) {
63
-        i = 0;
64
-        window.cancelAnimationFrame(frameId);
65
-      }
66
-    }
67
-
68
-    renderRef.value = draw;
69
-
70
-    if (props.active) {
71
-      draw();
72
-    }
73
-  });
74
-
75
-  onBeforeMount(() => {
76
-    if (frameId) {
77
-      window.cancelAnimationFrame(frameId);
78
-    }
79
-  });
80
-
81 16
 </script>
82 17
 
83 18
 <style lang="less" scoped>

+ 26
- 1
src/store/index.js 查看文件

@@ -1,4 +1,4 @@
1
-import { ref } from 'vue';
1
+import { reactive, ref } from 'vue';
2 2
 import createStore from '@zjxpcyc/vue-tiny-store';
3 3
 
4 4
 const useAudio = () => {
@@ -38,9 +38,34 @@ const useUser = () => {
38 38
 
39 39
   const setUser = v => user.value = v;
40 40
 
41
+  const contries = reactive({
42
+    "中国": 0,
43
+    "芬兰": 0,
44
+    "土耳其": 0,
45
+    "德国": 0,
46
+    "英国": 0,
47
+    "瑞士": 0,
48
+    "美国": 0,
49
+    "加拿大": 0,
50
+    "日本": 0,
51
+    "韩国": 0,
52
+    "马来西亚": 0,
53
+    "澳大利亚": 0,
54
+    "新西兰": 0,
55
+    "新加坡": 0,
56
+  });
57
+
58
+  const updateContries = (key) => {
59
+    contries[key] += 1;
60
+    if (user.value) {
61
+      user.value.num += 1;
62
+    }
63
+  }
64
+
41 65
   return {
42 66
     user,
43 67
     setUser,
68
+    contries,
44 69
   }
45 70
 }
46 71