0%

VueJs - TypeError: Cannot read properties of null (reading 'insertBefore')

TypeError: Cannot read properties of null (reading ‘‘insertBefore’’)

在寫 vue 的時候遇到了這個問題

原本的寫法是這樣的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<script setup lang="ts">
const getStrongKey = computed(() => {
return currentSong.value?.Key || 0 + Date.now() + Math.random()
})
</script>

<template>
<div class="transition-all duration-300" :class="[_bg_class]" @click="changePageToSinging">
<video
v-if="currentSong?.Category !== songCategory.Youtube"
ref="video"
crossorigin="anonymous"
class="transition-all duration-300"
:loop="loop"
:class="[_video_class]"
:style="{ height: `${videoHeight}` }"
/>
<YoutubeVideo
v-else
:key="`${getStrongKey}`"
:video-id="`${youtubeLinkId}`"
:class-name="`transition-all duration-300 w-full ${[_video_class]}`"
:style="{ height: `${videoHeight}` }"
/>
</div>
</template>

我有在 YoutubeVideo 這個 component 裡面加上 key,但是還是會出現這個錯誤
給你們看一下 YoutubeVideo 的寫法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<!-- eslint-disable no-console -->
<script setup lang="ts">
import PlayerFactory from 'youtube-player'
import type { YouTubePlayer } from 'youtube-player/dist/types'

const props = defineProps<{
videoId: string
className: string
style: Object
}>()

const songStore = useSongStore()
const functionStore = useFunctionStore()
const pageStore = usePageStore()
const { isPlay, isPlayReady } = storeToRefs(functionStore)
const {midiSpeedMultiple, midiSpeed} = storeToRefs(songStore)

let player: YouTubePlayer

onMounted(() => {
console.log(props)
player = PlayerFactory('ytplayer', {
videoId: props.videoId || '',
height: '100%',
width: '100%',
playerVars: {
autoplay: 1,
controls: 0,
modestbranding: 1,
rel: 0,
},
})
songStore.setCurrentTime(0)
})

onUnmounted(() => {
player.destroy()
})

const getStyle = computed(() => {
if (currentPageIndex.value === pageNames.Singing)
return { ...props.style, width: `${width.value}px` }
return { ...props.style }
})
</script>

<template>
<div :class="className" :style="{ ...getStyle }">
<div id="ytplayer" style="height: 100%; width: 100%;" />
</div>
</template>

好像是因為 <YoutubeVideo />v-else 的條件已經不成立了
然後你只有元件的 key 改的話
他的子元素還會在
只是會抽換父元素

我自己的猜測啦
有可能就是子元素去指向空的父元素才會出錯
那反正之後我就直接換成 <YoutubeVideo /> 外面再包一層 <div /> 就好了
然後改的話 key 就變成是改外層的 <div /> 的 key
據說是這樣就可以刷新整個 dom subtree

改完之後大概長這樣:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<div class="transition-all duration-300" :class="[_bg_class]" @click="changePageToSinging">
<video
v-if="currentSong?.Category !== songCategory.Youtube"
ref="video"
crossorigin="anonymous"
class="transition-all duration-300"
:loop="loop"
:class="[_video_class]"
:style="{ height: `${videoHeight}` }"
/>
<div v-else :key="`${getStrongKey}`">
<YoutubeVideo
v-if="currentSong?.Category === songCategory.Youtube"
:video-id="`${youtubeLinkId}`"
:class-name="`transition-all duration-300 w-full ${[_video_class]}`"
:style="{ height: `${videoHeight}` }"
/>
</div>
</template>

總之就是能動了
有點通靈…
求 vue 的維護者解釋QQ