Kaynağa Gözat

fix:横竖屏翻转问题

lvkun996 1 yıl önce
ebeveyn
işleme
3ba2c1a51f

+ 3 - 0
index.html

@@ -2,6 +2,9 @@
 <html>
   <head>
     <meta charset="UTF-8" />
+    <meta name="viewport" content="user-scalable=no">
+    <meta name="viewport" content="overflow-scrolling=touch">
+    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, orientation=portrait">
     <script>
       var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
         CSS.supports('top: constant(a)'))

+ 3 - 1
src/App.vue

@@ -12,4 +12,6 @@ onHide(() => {
   console.log("App Hide");
 });
 </script>
-<style></style>
+<style>
+
+</style>

+ 36 - 67
src/components/luojigou-board/luojigou-board.vue

@@ -1,8 +1,8 @@
 <template>
-  <view class="luojigou-board" >
-    <view class="board" :style="{scale: adaptatio, transformOrigin: '50% 0%'}" >
-      <image class="board-img" :src="boardUrl" />
-      <view class="board-header" :style="{zIndex: viewZindex.headerView}" id="game-label" >
+<view class="luojigou-board" >
+  <view class="board" :style="{ transform: `scale(${adaptatio})` ,transformOrigin: '50% 0%'}" >
+    <image class="board-img" :src="boardUrl" />
+    <view class="board-header" :style="{zIndex: viewZindex.headerView}" id="game-label" >
         <view class="trumpt" @click="emits('playAudio')">
           <!-- <image class="dog" :src="staticImg.trumptDog"   /> -->
           <image
@@ -23,29 +23,29 @@
           class="luojigou-dog"
           :src="staticImg.luojigouDog"
         />
-      </view>
-      <view  class="card" :style="{zIndex: viewZindex.quesView}"  >
+    </view>
+    <view  class="card" :style="{zIndex: viewZindex.quesView}"  >
         <view class="ques"  id="quesRef" >
           <image id="ques-url"  :src="props.board.quesUrl" alt=""  />
         </view>
-      </view>
-      <view class="ans"  id="ansRef" :style="{zIndex: viewZindex.quesView}">
-        <image :src="props.board.ansUrl" alt="" />
-      </view>
-      <canvas
-        type="2d"
-        canvas-id="magnifier-canvas"
-        id="magnifier-canvas"
-        :style="{width: '600rpx', height: '772rpx', zIndex: viewZindex.magnifierView}"
-      ></canvas>
-      <movable-area 
+    </view>
+    <view class="ans"  id="ansRef" :style="{zIndex: viewZindex.quesView}">
+      <image :src="props.board.ansUrl" alt="" />
+    </view>
+    <canvas
+      type="2d"
+      canvas-id="magnifier-canvas"
+      id="magnifier-canvas"
+      :style="{width: 600 + 'rpx', height: 772  + 'rpx', zIndex: viewZindex.magnifierView}"
+    ></canvas>
+    <movable-area
       v-if="props.cardType !== undefined" 
       class="movable-area"
       id="movableAreaRef" 
       :style="{
         width: 357 * rate+ 'rpx', 
         height: 466 * rate  + 'rpx',
-        top: 102 * rate / adaptatio + 'rpx', 
+        top: 102 * rate / adaptatio + 'rpx',
         left: 50  + '%',
         transform: `translateX(-${50}%)`,
         zIndex: viewZindex.moveView,
@@ -82,22 +82,15 @@
           :src="staticImg.successFlag"
         />
       </movable-view>
-      </movable-area>
-      <!-- 新手引导 -->
-      <view class="intro" v-if="viewZindex.introView > 0" :style="{zIndex: viewZindex.introView}" @click="nextIntro" >
-        <view class="lingheight"  >
-        </view>
-      </view>
-    </view>
-
-   
+    </movable-area>
   </view>
+</view>
 
 </template>
 
 <script setup lang="ts" name="luojigou-board" >
 import { defineProps, reactive, ref, computed, getCurrentInstance, defineEmits, watch } from 'vue'
-import { useStaticImg, useNavbarInfo, useSchedulerOnce, useQueryElInfo, useAdaptationIpadAndPhone, useMagnifier } from '@/hooks/index'
+import { useStaticImg, useNavbarInfo, useSchedulerOnce, useQueryElInfo, useAdaptationIpadAndPhone, useMagnifier,  } from '@/hooks/index'
 import type { CardModeEnum } from '@/enum/constant';
 import { useCalcQuantityStore } from '@/store/index';
 import { AudioController } from '@/controller/AudioController';
@@ -149,7 +142,7 @@ const state = reactive({
 })
 
 const viewZindex = ref({
-  moveView: 30, // 拖拽层
+  moveView: 32, // 拖拽层
   magnifierView: 31, // 放大镜
   quesView: 29, // 题卡
   headerView: 33,
@@ -175,6 +168,7 @@ const colorMap = new Map([
 ])
 
 
+
 const boardUrl = props.cardType == 1 ? staticImg.boardSix : staticImg.boardFour
 
 const ansRef = ref<UniApp.NodeInfo>()
@@ -185,8 +179,6 @@ useQueryElInfo('#quesRef', (nodeInfo) => quesRef.value = nodeInfo as UniApp.Node
 useQueryElInfo('#ansRef', (nodeInfo) =>  ansRef.value = nodeInfo as UniApp.NodeInfo, getCurrentInstance()!)
 useQueryElInfo('#movableAreaRef', (nodeInfo) => movableAreaRef.value = nodeInfo as UniApp.NodeInfo, getCurrentInstance()!)
 
-console.log('adaptatio:', adaptatio);
-
 const baseRatio = adaptatio
 
 const rate = baseRatio * 2
@@ -262,8 +254,6 @@ const touchend = (ev: TouchEvent, item: Buttons) => {
   if (item.disabled) return
 
   const { x: itemX, y: itemY } = TPos(ev.changedTouches[0].pageX, ev.changedTouches[0].pageY)
-
-  console.log("itemY:", itemY);
   
   // 返回原点 (没有放在答案区, 按钮回到初始位置)
   if (itemX < quesRef.value?.width! || itemY > ansRef.value?.height! ) {
@@ -271,10 +261,8 @@ const touchend = (ev: TouchEvent, item: Buttons) => {
   } else  {
   
     const index = getButtonIndex(itemY <= 0 ? 0 : itemY)
-    console.log('index:', index);
     
     const { x: targetX, y: targetY } = getButtonPosByIndex(index)
-    console.log(item.x , targetX , item.y, targetY);
     
     //  直接点击答案区的按钮,答案区按钮回到初始位置
     if (item.x == targetX && item.y == targetY) {
@@ -325,7 +313,6 @@ const touchend = (ev: TouchEvent, item: Buttons) => {
 // 判断答案 (学习计划适用逻辑)
 const checkAns = (index: number, itemData: Buttons) => {
   const targetData = props.board.ansList
-  console.log(targetData, index, itemData);
   
   // 移动到了正确位置
   if (targetData[index].ans === itemData.color) {
@@ -368,21 +355,6 @@ const checkAns = (index: number, itemData: Buttons) => {
   }
 }
 
-const nextIntro = () => {
-
-  viewZindex.value.introView = viewZindex.value.headerView + 1
-
-  viewZindex.value.quesView = viewZindex.value.introView + 1
-
-  viewZindex.value.magnifierView = viewZindex.value.quesView + 1
-
-  createMagnifier()
-  nextTick(() => {
-    a()
-  })
-  
-}
-
 /**
  * @description 放在onMounted生命周期里就可以生效,功能:把题卡放大缩小
  * @description 需要在touchStart时 设置 viewZindex.value.moveView = viewZindex.value.quesView + 1 
@@ -404,7 +376,6 @@ const createHammer = () => {
     }
   
     hammerState.scaleCount = hammerState.scaleIndex * e.scale;
-    console.log(hammerState.scaleCount);
     
     document.getElementById('quesRef')!.style.transform = `scale(${hammerState.scaleIndex * e.scale})`
   })
@@ -423,7 +394,6 @@ const createHammer = () => {
   hammer.on('panend', (e) => {
     hammerState.x = e.deltaX + hammerState.x; // 记录水平方向上的偏移量
     hammerState.y = e.deltaY + hammerState.y; // 记录垂直方向上的偏移量
-    console.log(hammerState.x);
     
     const node = document.getElementById('quesRef')
  
@@ -463,20 +433,21 @@ const createHammer = () => {
 
 }
 
-let a = () => {}
-let b = () => {}
+let draw = () => {}
+let clear = () => {}
 
 // 动态设置canvas的宽高
 
-watch(
+watch(         
   () => props.magnifierState,
   () => {
     if (props.magnifierState) {
-      a()
+      draw()
+      viewZindex.value.magnifierView = viewZindex.value.moveView + 1
     } else {
-      b()
+      clear()
+      viewZindex.value.moveView = viewZindex.value.magnifierView + 1
     }
-    console.log(props.magnifierState);
     
   }
 )
@@ -496,15 +467,15 @@ const createMagnifier = () => {
         rate: rate
       }
   ).then(r => {
-    a = r.draw
-    b = r.clear
+    draw = r.draw
+    clear = r.clear
   })
 }
 
-
-
 onMounted(() => {
-  createMagnifier()
+  useSchedulerOnce(() => {
+    createMagnifier()
+  }, 1000)
 })
 
 </script>
@@ -622,7 +593,6 @@ onMounted(() => {
             object-fit: cover;
           }
       }
-
       #magnifier-canvas {
         position: absolute;
         top: 206rpx;
@@ -632,7 +602,6 @@ onMounted(() => {
           border-radius: 40rpx;
         }
       }
-
       .ans .ans-item:last-child {
         border-bottom: none
       }
@@ -688,7 +657,7 @@ onMounted(() => {
         }
       }
   }
-  
+
   .mark-button {
     width: 100%;
     height: 100%;

+ 99 - 80
src/hooks/index.ts

@@ -1,7 +1,6 @@
 import type { StaticImg } from '@/utils/static'
 import { onLoad } from '@dcloudio/uni-app'
-import { toRefs } from 'vue'
-import { reactive } from 'vue'
+import { reactive, toRefs, nextTick} from 'vue'
 import { inject, onUnmounted, onMounted, type ComponentInternalInstance, ref} from 'vue'
 import { encode, decode} from 'js-base64'
 import hand from '@/assets/3-4.png'
@@ -55,7 +54,6 @@ export const useScheduler = (cb: () => void, delay: number) => {
   return stx
 }
 
-
 /**
  * @description 执行一定的定时器, 会在执行完后销毁
  * @param cb  回调函数
@@ -69,9 +67,7 @@ export const useSchedulerOnce = (
     cb()
     clearTimeout(timeId)
   }, delay)
-
   onUnmounted(() => clearTimeout(timeId))
-
 }
 
 /**
@@ -203,7 +199,6 @@ export const usePlatform = (): DEVICE.Platform => {
 
 }
 
-
 /**
  * 获取多设备动态适配的比率
  * @example
@@ -211,17 +206,42 @@ export const usePlatform = (): DEVICE.Platform => {
  *  node.width = node.width * rate * 2 + 'rpx
  */
 export const useAdaptationIpadAndPhone = () => {
+  // const { windowWidth, windowHeight } = uni.getWindowInfo()
+  // console.log(document.documentElement.clientWidth, document.documentElement.clientHeight);
   
-  const { windowWidth, windowHeight } = uni.getSystemInfoSync()
+  // const { screenWidth, screenHeight, windowWidth, windowHeight } = uni.getSystemInfoSync()
   
-  const rate = windowWidth / windowHeight
+
+
+  // console.log(window.screen.width, window.screen.height);
   
-  if ( rate > 0.5 ) { // 大于0.6 说明是平板 
-    return 667 / ( windowHeight )
-  } else {
-    return 1
+  console.log('useAdaptationIpadAndPhone');
+  
+  let a = window.innerWidth / window.innerHeight > 0.5 ? 667 / ( window.innerHeight ) : 1
+
+  const resizeHanlde = () => {
+    // 获取当前窗口的宽度
+    var screenWidth = window.innerWidth;
+    var screenHeight = window.innerHeight;
+
+    const rate = screenWidth / screenHeight 
+    
+    console.log(screenWidth, screenHeight );
+    if ( rate > 0.5 ) { // 大于0.6 说明是平板 
+      a = 667 / (  screenHeight )
+    } else {
+      a = 1
+    }
   }
 
+  // 监听窗口尺寸变化事件
+window.addEventListener('resize', resizeHanlde);
+  
+console.log('a', a);
+
+return a
+
+
 }
 
 export const useQueryParmas = async () => {
@@ -237,7 +257,6 @@ export const useQueryParmas = async () => {
   return {...toRefs(state)}
 }
 
-
 /**
  * 这是一个导出对象的TypeScript函数,有两个方法decode和encode,分别将Base64编码的字符串解码为JSON对象,将JSON对象编码为Base64编码的字符串。
  * @returns 正在返回名为“useBase64”的自定义挂钩。这个钩子有两个函数:`decode` 和 `encode`。 `decode` 函数将字符串作为输入并返回解析后的 JSON 对象。
@@ -288,26 +307,32 @@ export const useMagnifier = async (
   { ansUrl: string,  quesUrl: string, instance: ComponentInternalInstance, rate: number}
 ) => {
 
+  return
   const adaptatio = useAdaptationIpadAndPhone()
 
   let ctx: UniApp.CanvasContext = uni.createCanvasContext(canvasId)
 
   const deviceWidthRate = uni.getSystemInfoSync().windowWidth / 375
-  
-  const draw = async () => {
-    ctx.drawImage(quesUrl, 0, 0, 225 * deviceWidthRate, 386 * deviceWidthRate)
+
+  // 初始化放大镜的参数
+  const magnifierSize = 150 * deviceWidthRate  ; // 放大镜尺寸
+  const magnification = 1.5 ; // 放大倍数
+  const lineWidth = 4 * deviceWidthRate// 放大镜边框宽度
+
+    ctx.drawImage(quesUrl, 0, 0, 224 * deviceWidthRate, 386 * deviceWidthRate)
     ctx.save()
     ctx.drawImage(ansUrl, 225 * deviceWidthRate , 0, 75  * deviceWidthRate, 386 * deviceWidthRate)
     ctx.save()
     ctx.draw()
     ctx.restore();
-    // 创建 Image 对象并加载图片
-  
-    // 初始化放大镜的参数
-    const magnifierSize = 150 * deviceWidthRate  ; // 放大镜尺寸
-    const magnification = 1.5 ; // 放大倍数
-    const lineWidth = 4 * deviceWidthRate// 放大镜边框宽度
+
+    // console.log(' canvas.getBoundingClientRect().width:',  canvas.getBoundingClientRect().width);
     
+    // ctx.fillRect(0, 0, canvas.getBoundingClientRect().width /  adaptatio , canvas.getBoundingClientRect().height / adaptatio )
+    // ctx.setFillStyle('rgb(0, 0, 0)')
+    // ctx.draw()
+  // return
+    // 创建 Image 对象并加载图片
     await new Promise( resolve => {
       useSchedulerOnce(() => {
         resolve(true)
@@ -329,7 +354,7 @@ export const useMagnifier = async (
       }, instance);
     }) as string
     
-      function initMagnifier () {
+    function initMagnifier () {
         // 计算放大镜区域的位置和尺寸
         const startX = 0;
         const startY = 0;
@@ -364,16 +389,15 @@ export const useMagnifier = async (
         );
         ctx.draw()
         ctx.restore();
-      }
-    
-      initMagnifier();
-
-      // moveMagnifier({ touches: [{pageX:132 + i * 5, pageY: 340 + i * 12 }] })
-
-      function moveMagnifier (event: TouchEvent) {
-         
-        const mouseX = (event.touches[0].pageX - canvas.getBoundingClientRect().left) * adaptatio * deviceWidthRate
-        const mouseY = (event.touches[0].pageY - canvas.getBoundingClientRect().top ) * adaptatio * deviceWidthRate
+    }
+   
+    function moveMagnifier (event: TouchEvent) {
+        
+        event.preventDefault();
+        event.stopPropagation();
+        // * adaptatio * deviceWidthRate
+        const mouseX = (event.touches[0].pageX - canvas.getBoundingClientRect().left) / adaptatio 
+        const mouseY = (event.touches[0].pageY -  canvas.getBoundingClientRect().top) / adaptatio
 
         // 清空 Canvas
         ctx.clearRect(0, 0, canvas.clientWidth, canvas.clientHeight);
@@ -406,65 +430,60 @@ export const useMagnifier = async (
         );
         ctx.draw()
         ctx.restore();
-      }
-
-      const move = () => {
-
-          let x = canvas.getBoundingClientRect().left + magnifierSize / 2
-          let y = canvas.getBoundingClientRect().top + magnifierSize / 2
-  
-          // 设置目标位置
-          const targetX = 170;
-          const targetY = 460;
-  
-          // 设置动画参数
-          const animationDuration = 1000; // 1秒
-          let startTime: number = 0;
-          
-          // 动画函数
-          function animate() {
-  
-            if (!startTime) startTime = new Date().getTime();
-            const elapsedTime = new Date().getTime() - startTime;
-  
-            if (elapsedTime < animationDuration) {
-
-              // 计算当前位置
-              const progress = elapsedTime / animationDuration;
-              x = interpolate(x, targetX, progress);
-              y = interpolate(y, targetY, progress);
-              moveMagnifier({touches: [{pageX: x, pageY: y}]})
-  
-              // 继续下一帧绘制
-              requestAnimationFrame(animate);
-            }
-          }
-  
-          // 线性插值函数
-          function interpolate(start: number, end: number, progress: number) {
-            return start + (end - start) * progress;
-          }
-
-          requestAnimationFrame(animate);
-      }
+    }
   
-      // move()
-
+  const draw = async () => {
+      initMagnifier();
       // 监听鼠标移动事件,实现放大镜效果
-      canvas.addEventListener("touchmove", moveMagnifier );
+      canvas.addEventListener("touchmove", moveMagnifier);
     }
 
     const clear = () => {
       ctx.clearRect(0, 0, canvas.clientWidth, canvas.clientHeight);
       ctx.draw()
-      // canvas.removeEventListener('touchmove', moveMagnifier)
+      canvas.removeEventListener('touchmove', moveMagnifier)
     }
 
     onUnmounted(() => {
-      canvas.removeEventListener('touchmove', () => {})
+      canvas.removeEventListener('touchmove', moveMagnifier)
     })
     
     return {
       draw, clear
     }
-  };
+};
+
+
+
+/**
+ * 陀螺仪
+ */
+export const useGyro = async () => {
+  const handleOrientation = (event: DeviceOrientationEvent) => {
+
+    var alpha = event.alpha; // 设备绕 Z 轴的旋转角度(0 到 360 度)
+    var beta = event.beta!;   // 设备绕 X 轴的旋转角度(-180 到 180 度)
+    var gamma = event.gamma; // 设备绕 Y 轴的旋转角度(-90 到 90 度)
+
+    console.log('beta', beta);
+    
+    if ( beta > 45 && beta <= 270 ) {
+      console.log('顺时针横屏');
+    } else if ( beta < -45 && beta >= -270 ) {
+      console.log('逆時針横屏');
+    }
+
+  }
+  if (window.DeviceOrientationEvent) {
+    console.log();
+    
+    // 支持陀螺仪功能
+    window.addEventListener('deviceorientation', handleOrientation);
+  } else {
+    console.log('设备不支持陀螺仪功能');
+  }
+
+  onUnmounted(() => {
+    window.removeEventListener('deviceorientation', handleOrientation)
+  })
+}

+ 26 - 22
src/pages/GameView/index.vue

@@ -4,6 +4,7 @@
     id="game-view"
    
   >
+  <!--  :key="device.dire" -->
   <!--  :style="`pointer-events: ${state.mode === CardModeEnum.PREVIEW ? 'none' : 'all'}`" -->
     <navbar
       @goback="goback"
@@ -43,7 +44,7 @@
     </view>
   </view> 
 
-  <img v-if="gamePlayed" style="width: 100vw;height: 100vh;position: fixed; z-index: 1000000;scale: 1;" :src="staticImg.intro" alt="">
+  <img v-if="state.mode === CardModeEnum.OPRA && gamePlayed" style="width: 100vw;height: 100vh;position: fixed; z-index: 1000000;scale: 1;" :src="staticImg.intro" alt="">
 </template>
 
 
@@ -54,7 +55,7 @@ import { onLoad } from '@dcloudio/uni-app';
 import { reactive, onMounted } from 'vue'
 import { getCardDetailById, submitlearnPortAns } from '@/api/card'
 import { getCollectionDetailById } from '@/api/collection'
-import { useAudioMange, useScheduler, useBase64, useSchedulerOnce, usePlatform, useDeviceDire } from '@/hooks/index'
+import { useAudioMange, useScheduler, useBase64, useSchedulerOnce, usePlatform, useDeviceDire,useGyro } from '@/hooks/index'
 import { usePracticeStore, useOpraRecordStore, useGameCountdownStore, useCalcQuantityStore, useWisdomCoinStore } from '@/store'
 import riveAni from '@/components/rive-ani/rive-ani.vue';
 import { ref } from 'vue';
@@ -95,6 +96,8 @@ const base64 = useBase64()
 
 const staticImg = useStaticImg()
 
+// useGyro()
+
 onLoad(query => {
 
   let options
@@ -103,13 +106,11 @@ onLoad(query => {
     state.opraMode = state.queryParams.data.opraMode
     options = state.queryParams.data
   } else {
-    console.log(query);
     state.queryParams = base64.decode<API.P>(query!.p)
     state.opraMode = state.queryParams.data.opraMode
     options = state.queryParams.data
     // options = query!
   }
-  console.log(state.queryParams);
   
   state.mode = options.mode || CardModeEnum.PREVIEW
   state.collectionId = options.collectionId
@@ -117,7 +118,6 @@ onLoad(query => {
 
   wisdomCoinStore.total = options.userWisdomCoin
   wisdomCoinStore.remainderWisdomCoin = options.remainderWisdomCoin
-
 })
 
 const riveAniRef = ref()
@@ -159,21 +159,27 @@ const stx = useScheduler(() => {
   navbarState.countdownTotal++
 }, 1000)
 
+
 const getIntro = () => {
   // 先判断有没有玩过,如果没有玩过
-
-  const played = uni.getStorageSync('played')
-  if (!played) {
-    uni.setStorageSync('played', 1)
-
-    useSchedulerOnce(() => {
-      gamePlayed.value = 0
-    }, 6000)
+  
+  if (state.mode === CardModeEnum.OPRA) {
+    const played = uni.getStorageSync('played')
+    
+    if (!played) {
+      uni.setStorageSync('played', 1)
+      useSchedulerOnce(() => {
+        gamePlayed.value = 0
+        gameStart()
+      }, 6000)
+    } else {
+      gameStart()
+    }
+  } else {
+    gameStart()
   }
-
 }
 
-
 // 控制是否开启动画模式
 const changeMagnifier = (status: boolean) => {
   state.magnifierState = status
@@ -262,7 +268,6 @@ const gameCompleted = async () => {
 }
 
 const playAudio = () => {
-  console.log('audio播放');
   
   state.playLoading = true
   atx.play(state.card?.audio!)
@@ -270,7 +275,6 @@ const playAudio = () => {
 }
 
 // 获取试题集详情
-
 const GetCollectionDetailById = async () => {
   const { data } = await getCollectionDetailById(state.collectionId)
   if ( state.opraMode === OpraModeEnum.PRACTICE) {
@@ -291,7 +295,6 @@ const GetCardDetailById = async () => {
   const { data } = await getCardDetailById(state.cardId!, state.mode)
   state.card = data
   if (state.mode === CardModeEnum.OPRA) {
-   useSchedulerOnce(gameStart)
   }
 }
 
@@ -305,14 +308,16 @@ const goback = () => {
 }
 
 // 监听设备方向,如果是横屏,立马停止所有的计时
-useDeviceDire((dire: 'H' | 'V') => device.dire = dire)
+useDeviceDire((dire: 'H' | 'V') => {
+  device.dire = dire
+})
 
 onMounted(async () => {
 
   if (state.mode === 'preview') {
-    GetCardDetailById()
+    await GetCardDetailById()
   } else {
-    GetCollectionDetailById()
+    await GetCollectionDetailById()
   }
   getIntro()
 })
@@ -337,7 +342,6 @@ onMounted(async () => {
     padding-top: 46rpx;
     display: flex;
     justify-content: center;
-    
   }
 }