自從Vue3 Beta發佈以來,我就嘗試在小項目中使用它了,不得不說真是香,雖然對新手可能不太友好,但是對於用過React Hooks的人來說簡直不要太爽,解決了React Hooks多次運行以及性能優化等多項心智負擔,但是就在剛剛做好的一個動效在自己手機上完美運行,美滋滋的拿去給同事測試,然而同事的蘋果手機卻沒有任何動態效果:
而在我的手機效果是這樣的:
這個特效的邏輯是這樣的:首先獲取後置攝像頭權限進行拍攝,然後在視頻上方循環播放幀動畫(其實就是仿AR),由於公司無力開發AR模型,只能讓美工渲圖然後web端做個僞AR,那麼問題來了,如果是WebGL做出來的模型即使代碼量很大,也依然就幾百K頂多1M,但是幀動畫就不一樣了,美工給了我幾百張圖,每一張大概在50k左右,加在一起十多M二十來M的,加載時間太長了,所以需要一個等待動畫,這個等待動畫就是一個小心心,小心心裏面是你攝像頭目前拍攝到的畫面,這個小心心會隨着你加載的圖片的數量而越來越大,當加載完畢後小心心佔滿全屏(也就是看不到小心心啦)。
組件間傳值
在幀動畫那個組件裏請求的圖片,但是圖片請求了多少張這個數值需要傳遞到小心心那個組件去,發現$emit這種vue2傳值法居然不好使了!
// 子組件
import { defineComponent } from 'vue'
export default defineComponent((props, ctx) => {
ctx.$emit('event', '來自子組件的值')
return {}
})
<!--父組件-->
<Child @event="getChildValue"/>
那個ctx就相當於vue2.x的this
然而這種在vue2.x中十分常見的傳值方法在這裏卻沒有任何效果。
Vue3傳值方式
那麼該如何傳值呢?試試在React Hooks的那種自定義Hook再試試:
//抽取出來一個js文件
import { ref } from 'vue'
const count = ref(0)
export default number => {
count.value = number || count.value
return { count }
}
<!--子組件A-->
<template>
<span>{{count}}</span>
</template>
<script>
import { defineComponent } from 'vue'
import useCount from '../use/useCount'
export default defineComponent(_ => {
const { count } = useCount()
return { count }
})
</script>
<!--子組件B-->
<template>
<button @click="addCount">+</button>
<a href="#">{{count}}</a>
</template>
<script>
import { defineComponent } from 'vue'
import useCount from '../use/useCount'
export default defineComponent(_ => {
const { count } = useCount()
const addCount = _ => count.value++
return { count, addCount }
})
</script>
<!--父組件-->
<template>
<A/>
<B/>
</template>
<script>
import A from './A'
import B from './B'
export default {
components: { A, B }
}
</script>
可以看到和React Hooks的自定義Hook用法很相似。
watch + onMounted在IOS下的坑
本來是需要監聽請求圖片那個組件傳回來的值來給小心心組件,每多請求回來一張圖,小心心就放大一些,直到小心心充滿屏幕。
於是乎我這樣寫了:
import { onMounted } from 'vue'
import { useXxx } from '../use/useXxx'
// 只貼出了關鍵代碼
setup () {
const { val } = useXxx()
onMounted(_ => {
// 此處省略若干行業務代碼
watch(val, v => console.log(v))
})
}
這段代碼在我的PC端和移動端都運行良好打印出值來,並且沒有任何的報錯,所以我才自信滿滿的去給別人看,結果一碰見蘋果手機就……
解決方案
把watch函數提到生命週期函數外部使用。
import { onMounted } from 'vue'
import { useXxx } from '../use/useXxx'
// 只貼出了關鍵代碼
setup () {
const { val } = useXxx()
watch(val, v => console.log(v))
onMounted(_ => {
// 此處省略若干行業務代碼
})
}
建議不要將watch函數與各種生命週期函數放在一起混用,否則可能會出現意想不到的bug。