uni-app render获取video DOM异常
uni-app render获取video DOM异常
开发环境 | 版本号 | 项目创建方式 |
---|---|---|
Windows | 22H2 | HBuilderX |
产品分类:uniapp/App
PC开发环境操作系统:Windows
HBuilderX类型:正式
HBuilderX版本号:3.98
手机系统:Android
手机系统版本号:Android 11
手机厂商:vivo
手机机型:IQOO NEO 855竞速版
页面类型:vue
vue版本:vue2
打包方式:云端
项目创建方式:HBuilderX
示例代码:
<template>
<div class="face">
<div class="face-meiti">
<view style="font-size: 40rpx;font-weight: 600;text-align: center;" @click="test.init">
开始检测
</view>
<div class="tip">{{tip}}</div>
<video ref="video" id="video" objectFit="cover" class="video" :controls="false"
:show-center-play-btn="false" :autoplay="true" :loop="true"></video>
<canvas ref="canvas" :style="canvasStyle" canvas-id="myCanvas" id="myCanvas" class="myCanvas"></canvas>
<view
style="display: flex;justify-content: space-between;align-items: center;position: fixed;bottom: 0;left: 0;right:0;">
<template v-if="src && src.length > 0">
<template v-for="(item, index) in src">
<image style="width: 100%;" :key="index" :src="item.src" mode="widthFix"></image>
</template>
</template>
</view>
</div>
</div>
</template>
<script lang="renderjs" module="test">
import '@/static/tracking/tracking-min.js';
import '@/static/tracking/data/face-min.js';
export default {
data() {
return {
tip: '请正对摄像头',
mediaStreamTrack: null,
video: null, // 播放器实例
trackerTask: null, //tracking实例
uploadLock: true, // 上传锁
faceflag: false, //是否进行拍照
src: [],
canvasStyle: {}
}
},
mounted() {
this.init()
},
methods: {
init(options) {
const _this = this;
console.log("document.querySelector('.video')", document.querySelector('.video').children[0].children.length);
if (document.querySelector('.video') && document.querySelector('.video').children[0] !== null && document
.querySelector('.video').children[0].children[0] !== null && document.querySelector('.myCanvas') &&
document.querySelector('.myCanvas').children[0] !== null) {
this.video = this.mediaStreamTrack = document.querySelector('.video').children[0].children[0];
this.getUserMedia = navigator.mediaDevices.getUserMedia = navigator.mediaDevices.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia || navigator.msGetUserMedia;
navigator.mediaDevices.getUserMedia({
'video': true
}, function(stream) {
_this.video.srcObject = stream
}, function(err) {
_this.tip = '摄像头调用失败'
})
_this.initTracker(options)
}
},
initTracker(options) {
const _this = this;
let tracker = new window.tracking.ObjectTracker('face');
tracker.setInitialScale(4);
tracker.setStepSize(2);
tracker.setEdgesDensity(0.1);
this.trackerTask = window.tracking.track(this.video, tracker, {
camera: true
});
tracker.on('track', function(event) {
if (event.data.length == 0) {
if (!_this.faceflag) {
_this.tip = '未检测到人脸'
}
} else if (event.data.length > 0) {
_this.tip = '识别成功,正在拍照,请勿乱动~';
let canvas = document.querySelector('.myCanvas').children[0];
const context = canvas.getContext('2d', {
willReadFrequently: true
});
event.data.forEach(function(rect) {
if (!_this.faceflag) {
_this.faceflag = true;
context.drawImage(_this.video, 0, 0, '390', '390');
const base64Img = canvas.toDataURL('image/jpeg');
if (_this.src.length < 3) {
_this.src.push({
src: base64Img
})
setTimeout(function() {
_this.faceflag = false
}, 500)
} else {
uni.showToast({
title: '检测认证已完成'
})
}
}
});
}
})
}
}
}
</script>
<script>
export default {
data() {
return {
tip: '请正对摄像头',
mediaStreamTrack: null,
video: null, // 播放器实例
trackerTask: null, //tracking实例
uploadLock: true, // 上传锁
faceflag: false, //是否进行拍照
src: [],
canvasStyle: {}
}
},
mounted() {
const _this = this;
uni.getSystemInfo({
success(res) {
_this.canvasStyle = {
width: res.windowWidth + 'px',
height: res.windowWidth + 'px',
}
}
})
},
}
</script>
<style lang="scss">
.face {
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: flex-start;
padding: 60rpx 0;
box-sizing: border-box;
.face-meiti {
position: relative;
.tip {
text-align: center;
font-size: 24rpx;
padding-bottom: 30rpx;
}
video {
display: block;
width: 360rpx;
height: 360rpx;
-webkit-border-radius: 180rpx;
-moz-border-radius: 180rpx;
border-radius: 180rpx;
object-fit: cover;
border: 2rpx solid #000;
box-sizing: border-box;
margin: 0 auto;
}
canvas {
position: fixed;
top: 0;
left: 100vw;
}
}
img {
width: 100%;
height: auto;
}
}
</style>
在浏览器中运行时,document.querySelector(’.video’).children[0].children[0]可以正确获取到想要的DOM,document.querySelector(’.video’).children[0].children.length 是6,app端document.querySelector(’.video’).children[0].children.length 是0
在 uni-app
中,如果你尝试通过 render
或 ref
获取 video
组件的 DOM 元素时遇到异常,可能是由于以下几个原因导致的。以下是一些常见的问题和解决方案:
1. video
组件未正确绑定 ref
确保你在 video
组件上正确绑定了 ref
,并且在使用 this.$refs
获取时,ref
名称是正确的。
<template>
<video ref="myVideo" src="your-video-url.mp4"></video>
</template>
<script>
export default {
mounted() {
const videoElement = this.$refs.myVideo;
console.log(videoElement);
}
}
</script>
2. video
组件未正确渲染
在 uni-app
中,video
组件可能在某些平台上(如小程序)并不是标准的 HTML5 video
元素,而是原生组件。因此,直接通过 ref
获取的 DOM 元素可能不是标准的 video
元素。
如果你需要操作 video
组件,建议使用 uni-app
提供的 API 来操作,而不是直接操作 DOM。
this.$refs.myVideo.play(); // 使用 uni-app 提供的 API
3. 平台差异
uni-app
支持多端编译,不同平台(如 H5、小程序、App)对 video
组件的实现方式可能不同。在 H5 平台上,video
组件是标准的 HTML5 video
元素,但在小程序或 App 上,video
组件可能是原生组件。
如果你需要跨平台兼容,建议使用 uni-app
提供的 API 来操作 video
组件,而不是直接操作 DOM。
4. 异步问题
如果你在 mounted
钩子中获取 video
元素时遇到问题,可能是因为 video
组件还未完全渲染。你可以尝试在 nextTick
中获取 video
元素。
this.$nextTick(() => {
const videoElement = this.$refs.myVideo;
console.log(videoElement);
});
5. 使用 uni.createVideoContext
如果你在小程序或 App 中需要操作 video
组件,可以使用 uni.createVideoContext
来创建 video
上下文,然后通过该上下文来操作 video
组件。
const videoContext = uni.createVideoContext('myVideo', this);
videoContext.play();
在模板中,你需要为 video
组件指定一个 id
:
<template>
<video id="myVideo" src="your-video-url.mp4"></video>
</template>