Vue-web-cam 若正常使用沒問題,但若將 Component 包在 v-if
內時則表現不如預期,必須配合一些 Workaround 解決。
Version
macOS Catalina 10.15.6
WebStorm 2020.2
Vue 2.6.11
Vue-web-cam 1.9.0
Simple v-if
<template>
<div>
<div>
<button type="button" @click="onToggle">Toggle Camera</button>
</div>
<div>
<div v-if="isIfCamera">
<web-cam ref="webcam" :device-id="deviceId" width="100%" @cameras="onCameras"/>
<select v-model="deviceId">
<option>-- Select Device --</option>
<option v-for="device in devices" :key="device.deviceId" :value="device.deviceId">{{ device.label }}</option>
</select>
</div>
</div>
</div>
</template>
<script>
import { WebCam } from 'vue-web-cam'
let onCameras = function(cameras) {
this.devices = cameras
let first = this.devices[0]
if (first) this.deviceId = first.deviceId
}
let onToggle = function() {
this.isIfCamera = !this.isIfCamera
}
export default {
name: 'App',
components: {
WebCam
},
data: () => ({
deviceId: null,
devices: [],
isIfCamera: false
}),
methods: {
onCameras,
onToggle,
}
}
</script>
第 7 行
<div v-if="isIfCamera">
<web-cam ref="webcam" :device-id="deviceId" width="100%" @cameras="onCameras"/>
<select v-model="deviceId">
<option>-- Select Device --</option>
<option v-for="device in devices" :key="device.deviceId" :value="device.deviceId">{{ device.label }}</option>
</select>
</div>
若想將 vue-web-camera 放在 v-if
內控制,直覺會將 <web-cam>
放在 <div>
內搭配 v-if
。
40 行
isIfCamera: false
一開始不顯示。
28 行
let onToggle = function() {
this.isIfCamera = !this.isIfCamera
}
在 onToggle()
內將 isIfCamera
model 做 toggle。
這種做法雖然直覺,但會發現只有第一次會成功,第二次之後就無法 toggle,主要是因為
v-if
會摧毀 component,導致之後 toggle 失常
v-if && v-show
<template>
<div>
<div>
<button type="button" @click="onToggle">Toggle Camera</button>
</div>
<div>
<div v-if="isIfCamera">
<div v-show="isShowCamera">
<web-cam ref="webcam" :device-id="deviceId" width="100%" @cameras="onCameras"/>
<select v-model="deviceId">
<option>-- Select Device --</option>
<option v-for="device in devices" :key="device.deviceId" :value="device.deviceId">{{ device.label }}</option>
</select>
</div>
</div>
</div>
</div>
</template>
<script>
import { WebCam } from 'vue-web-cam'
let onCameras = function(cameras) {
this.devices = cameras
let first = this.devices[0]
if (first) this.deviceId = first.deviceId
}
let onToggle = function() {
if (!this.isIfCamera) {
this.isIfCamera = true
} else if (this.isShowCamera) {
this.isShowCamera = false
this.$refs.webcam.stop()
}
else {
this.isShowCamera = true
this.$refs.webcam.start()
}
}
export default {
name: 'App',
components: {
WebCam
},
data: () => ({
deviceId: null,
devices: [],
isIfCamera: false,
isShowCamera: true
}),
methods: {
onCameras,
onToggle,
}
}
</script>
第 7 行
<div v-if="isIfCamera">
<div v-show="isShowCamera">
<web-cam ref="webcam" :device-id="deviceId" width="100%" @cameras="onCameras"/>
<select v-model="deviceId">
<option>-- Select Device --</option>
<option v-for="device in devices" :key="device.deviceId" :value="device.deviceId">{{ device.label }}</option>
</select>
</div>
</div>
因為 v-if
會摧毀 component,所以 v-if
只用來第一次建立 component,之後就用 v-show
toggle,如此可保 component 不被摧毀。
51 行
isIfCamera: false,
isShowCamera: true
isIfCamera
model 控制 component 第一次建立,isShowCamera
model 控制 component toggle。
30 行
let onToggle = function() {
if (!this.isIfCamera) {
this.isIfCamera = true
} else if (this.isShowCamera) {
this.isShowCamera = false
this.$refs.webcam.stop()
}
else {
this.isShowCamera = true
this.$refs.webcam.start()
}
}
- 若
isIfCamera
為false
,表示 component 尚未建立,將isIfCamera
設定為true
建立 component - 若
isShowCamera
為true
,表示目前 compoent 正常顯示,將isShowCamera
設定為false
隱藏 camera,並搭配this.$refs.webcam.stop()
關閉 camera - 若
isShowCamera
為false
,表示目前 compoent 隱藏中,將isShowCamera
設定為true
顯示 camera,並搭配this.$refs.webcam.start()
顯示 camera
Conclusion
- Vue-web-camera 再搭配
v-if
使用上頗為 tricky,必須同時搭配v-if
與v-show
,且手動使用stop()
與start()
控制 camera 關閉與啟動