box-sizing-50

问题描述:vuepc电脑可以获取设备吗 大家好,给大家分享一下一个有趣的事情,很多人还不知道这一点。下面详细解释一下。现在让我们来看看!

如何在VSCode解决办法可以设置div的box-sizing:border-box(盒模型)~

box-sizing-50的相关图片

VUE2实现录像(PC端)可拍照 下载 预览 选取指定摄像头和麦克风设备 源代码可直接使用 原创。

2022-10-16 17:57:44。

嗯呐FT 

码龄1年

关注

2022.10月份 谷歌是最新版本 使用vue2写 。

下面的这些代码可以在谷歌浏览器的本地(localhost)和https环境下执行。中间有大量的注释可查看,基本上看一遍就懂,前面的坑我基本都踩过了。

如果是http环境的话,我下面这些代码是执行不了的,因为我做了获取指定设备的功能,如果要http环境中使用,需要把获取指定设备的相关代码删掉才能用,而且需要去谷歌的这个地址配置一下才能用,最下面我会介绍怎么在http环境中用。

功能如下:

1.可获取多个摄像头设备并选择其一进行录制。

2.录制的过程中拔掉摄像头监听结束录制。

3.可在录制中进行拍照生成png图片 可预览 可下载。

4.录制完成会生成一个有声音和画面的webm格式视频 可在线预览下载。

5.录制的过程中计时(最小误差)

界面展示(界面我就做个小Demo 没有过多去弄好看点 重要是script部分)

先上代码 -- html部分

<template>。

<div class="publish">。

<div class="box">。

<div class="videoPart">。

<div class="videoRecord" @mouseenter="hoverVideo(0)" @mouseleave="hoverVideo(1)">。

<video id="videoCamera" :width="videoWidth" :height="videoHeight" autoPlay></video>。

<div class="hoverVideoOutside" v-if="ifHoverVideo && ifStartRecord" >。

<div class="hoverVideoInside">。

<div class="hoverVideoInsideInside">。

<div class="hoverVideoBtn"><div class="hoverVideoBtnInside"></div></div>。

<span>{{recordHMSTime}}</span>。

</div>。

</div>。

</div>。

</div>。

<canvas id="canvasCamera" class="canvas" :width="videoWidth" :height="videoHeight"></canvas> 。

<video v-if="showVideo" :src="videoSrc" autoplay controls></video>。

<img v-if="showImg" class="imgClass" :src="imgSrc" alt="">。

</div>。

<div>。

<el-select v-model="deviceId" placeholder="请选择摄像头" @change="selectVideoChange" @focus="findVideoDevice" :disabled="ifStartRecord">。

<el-option。

v-for="item in deviceArr"。

:key="item.deviceId"。

:label="item.label"。

:value="item.deviceId">。

</el-option>。

</el-select>。

<el-button v-if="!ifStartRecord" @click="startRecord" icon="el-icon-video-camera" size="small">开始录制</el-button>。

<el-button v-else @click="stopRecord" icon="el-icon-switch-button" size="small">结束录制</el-button>。

<el-button @click="photographBtn" icon="el-icon-camera" size="small">拍照</el-button>。

</div>。

<vxe-table。

border

resizable。

show-overflow。

ref="xTable"。

height="500"。

:row-config="{isHover: true}"。

:data="tableData">。

<vxe-column type="seq" width="60"></vxe-column>。

<vxe-column field="name" title="Name"></vxe-column>。

<vxe-column title="操作" width="200" show-overflow>。

<template #default="{ row }">。

<vxe-button type="text" icon="vxe-icon-edit" @click="preview(row)">预览</vxe-button>。

<vxe-button type="text" icon="vxe-icon-edit" @click="download(row)">下载</vxe-button>。

</template>。

</vxe-column>。

</vxe-table>。

</div> 。

</div>

</template>。

CSS代码

<style scoped>。

.canvas{

opacity: 0!important;。

}

.videoPart{

position: relative;。

display: flex;。

align-items: center;。

}

.hoverVideoOutside{。

position: absolute;。

top: 0px;

left: 0px;

width: 500px;。

height: 300px;。

background:linear-gradient(#000,transparent 20%);。

z-index: 999;。

}

.hoverVideoInside{。

position: relative;。

width: 100%;。

height: 100%;。

}

.hoverVideoInsideInside{。

position: absolute;。

top: 10px;

left: 380px;。

padding: 2px;。

display: flex;。

justify-content: center;。

align-items: center;。

}

.hoverVideoBtn{。

width: 30px;。

height: 30px;。

border-radius: 50%;。

border: 2px solid red;。

padding: 3px;。

box-sizing: border-box;。

margin-right: 4px;。

}

.hoverVideoBtnInside{。

background: red;。

width: 20px;。

height: 20px;。

border-radius: 50%;。

box-sizing: 50%;。

}

span{

color: #fff;。

}

.videoRecord{。

position: relative;。

}

.imgClass{

width: 500px;。

height: 300px;。

}

</style>

逻辑部分

<script>

export default {。

name: 'HelloWorld',。

data() {

return {

ifOpenCamera: false,//控制摄像头开关。

ifStartRecord:false, //是否开始录制。

thisVideo: null,。

thisContext: null, //canvas。

thisCanvas: null,。

videoWidth: 500,。

videoHeight: 300,。

videoCecorded: [], //接受的数据流。

mediaRecorderData: {},。

videoSrc:'', //录制完的视频预览。

imgSrc:'',//录制完预览的图片地址。

deviceArr:[],//获取该电脑的摄像头。

deviceId:'', //选择哪个摄像头。

tableData:[], //录制完 制作表格数据。

showVideo:false, //录制完预览视频。

showImg:false,//录制完预览图片。

recordTime:0, //监听录像的时间。

recordHMSTime:'00:00:00', //监听录像的时间。

ifHoverVideo:false, //监听是否鼠标在视频的上面 显示录制时间。

timer:null, //每一秒执行一次计算录像的时间 这个是有误差的。

startTime:'', //记录开始录制的时间戳。

stream:null,。

}

},

created() {

this.initDevice();。

},

methods: {

initDevice(){。

this.$nextTick(() => {。

this.videoCecorded = []。

this.mediaRecorderData = null。

this.thisCanvas = document.getElementById('canvasCamera');。

this.thisContext = this.thisCanvas.getContext('2d');。

this.thisVideo = document.getElementById('videoCamera');。

// 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象。

console.log('navigator.mediaDevices', navigator.mediaDevices)。

if (navigator.mediaDevices === undefined) {。

navigator.mediaDevices = {}。

this.dialogVisible = !this.dialogVisible;。

console.log('http环境下没开那个谷歌权限 所以有点问题 得弹出提示弹窗 如果是本地或者https环境就基本不会走到这里')。

this.$message({。

message: '去谷歌浏览器配置网址',。

type: 'error'。

})

}

// 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象。

// 使用getUserMedia,因为它会覆盖现有的属性。

// 这里,如果缺少getUserMedia属性,就添加它。

if (navigator.mediaDevices.getUserMedia === undefined) {。

navigator.mediaDevices.getUserMedia = function (constraints) {。

// 首先获取现存的getUserMedia(如果存在)。

let getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.getUserMedia;。

// 有些浏览器不支持,会返回错误信息。

// 保持接口一致。

if (!getUserMedia) {。

return Promise.reject(new Error('getUserMedia is not implemented in this browser'))。

}

// 否则,使用Promise将调用包装到旧的navigator.getUserMedia。

return new Promise(function (resolve, reject) {。

getUserMedia.call(navigator, constraints, resolve, reject)。

})

}

}

this.findVideoDevice()。

})

},

// 每次点开下拉框的时候都要去获取现在有多少个设备 以防在打开这个网站之后把摄像头拔了等情况 。

async findVideoDevice(){。

this.deviceId = ''。

this.deviceArr = []。

const _this = this。

try{

// 获取你电脑中有什么设备。

let deviceArr = await navigator.mediaDevices.enumerateDevices();。

if(this.deviceArr.length == 0){。

this.$message({。

message: '没有摄像头设备',。

type: 'error'。

})

this.deviceArr = []。

return 。

}

console.log('设备',deviceArr)。

deviceArr.forEach(item=>{。

if(item.kind == 'videoinput'){。

this.deviceArr.push(item) //获取你电脑中有多少个摄像头设备。

}

})

}catch(error){。

console.log(error)。

this.deviceArr = []。

}

},

// 选择完是哪个摄像头以后执行的方法。

selectVideoChange(){。

this.$nextTick(() => {。

const _this = this;。

const constraints = {。

audio: true,。

video: { 。

width: _this.videoWidth, 。

height: _this.videoHeight, 。

transform: 'scaleX(-1)',。

deviceId:{exact:this.deviceId} 。

},

};

navigator.mediaDevices.getUserMedia(constraints).then(async(stream)=>{。

// 旧的浏览器可能没有srcObject。

if ('srcObject' in _this.thisVideo) {。

_this.thisVideo.srcObject = stream。

} else {。

// 避免在新的浏览器中使用它,因为它正在被弃用。

_this.thisVideo.src = window.URL && window.URL.createObjectURL(stream)。

} 。

_this.thisVideo.onloadedmetadata = function (e) {。

_this.thisVideo.play()。

} 。

_this.ifOpenCamera = true 。

}).catch(err => {。

this.errReponse(err)。

});

});

},

// 开始录制

startRecord() {。

if(this.deviceId == ''){。

this.$message({。

message: '请选择摄像头',。

type: 'error'。

})

return

}

const _this = this。

this.mediaRecorderData = null。

this.videoCecorded = []。

this.$nextTick(()=>{。

const constraints = {。

audio: true,。

video: { 。

width: this.videoWidth, 。

height: this.videoHeight, 。

transform: 'scaleX(-1)',。

deviceId:{exact:this.deviceId} //选取指定的设备来录制。

},

};

//必须在model中render后才可获取到dom节点,直接获取无法获取到model中的dom节点。

navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {。

_this.stream = stream。

// 这个要重写一次 。

// 我插第三方的视频录像设备的情况下 点击录像 然后把设备拔出来 这个时候画面是黑色的 。

// 如果没有重写下面的方法 插进设备后 点击录像 画面依然是黑色的 但是能录像 只是界面上不显示 。

if ('srcObject' in _this.thisVideo) {。

_this.thisVideo.srcObject = stream。

} else {。

// 避免在新的浏览器中使用它,因为它正在被弃用。

_this.thisVideo.src = window.URL && window.URL.createObjectURL(stream)。

}

_this.thisVideo.onloadedmetadata = function (e) {。

_this.ifOpenCamera = true 。

_this.thisVideo.play()。

}

_this.startRecording(stream);//调用录制控件方法,触发开始录制。

}).catch(err => {。

// 点录制之前断开设备连接 但选择框已经选了设备 就会触发这个err。

this.errReponse(err)。

});

})

},

//拍照按钮

photographBtn() {。

//先判断是否开启了摄像头。

if(!this.ifOpenCamera){。

this.$message({。

message: '摄像头都还没开呢 傻猪猪',。

type: 'error'。

})

return

}

// 点击,canvas画图。

this.thisContext.drawImage(this.thisVideo, 0, 0, this.videoWidth, this.videoHeight);。

// 如果图片尺寸不想 500 300 那就写下面这个。

// this.thisContext.drawImage(this.thisVideo, 0, 0, this.videoWidth, this.videoHeight,0,0,1000, 600); 。

const fileName = (new Date).toISOString().replace(/:|\./g,'-')。

const a = this.thisCanvas.toDataURL('image/png')。

const file = this.dataURLtoFile(a,fileName + 'png')。

this.tableData.push({。

id:2,

name:fileName + 'png',。

url:this.thisCanvas.toDataURL('image/png'),。

type:'png'。

})

},

//停止录制

stopRecord() {。

if (this.thisVideo && this.thisVideo !== null) {。

this.mediaRecorderData.stop(); //结束录制。

}

},

// 开始录制中

startRecording(stream) {。

console.log('stream 在开始的时候的',stream)。

let _this = this。

this.mediaRecorderData = new MediaRecorder(stream, {。

mimeType: 'video/webm;codecs=vp8,opus' //不加这个codecs=vp8,opus有时候下载下来之后看几秒就没了 残缺的视频。

});

this.mediaRecorderData.addEventListener("dataavailable", (e) => {。

if (e.data.size > 0) {。

_this.videoCecorded.push(e.data);//视频录制视频流数据 。

};

});

this.mediaRecorderData.addEventListener("stop", () => {。

console.log("结束录制");。

_this.updataVideo();//上传实时录制的视频。

_this.ifStartRecord = false。

_this.recordTime = 0。

_this.recordHMSTime = '00:00:00'。

clearTimeout(_this.timer)。

_this.timer = null。

});

this.mediaRecorderData.addEventListener("start", (e) => {。

console.log("开始 录制");。

_this.ifStartRecord = true。

_this.recordTime = 0。

_this.startTime = new Date().getTime();。

_this.timer = setTimeout(_this.fixed,1000)。

});

this.mediaRecorderData.start()。

},

// 上传录制视频方法,获取视频地址。

updataVideo() {。

const blob = new Blob(this.videoCecorded, {。

type: 'video/webm'。

});

const fileName = (new Date).toISOString().replace(/:|\./g,'-')。

this.tableData.push({。

id:2,

type:'webm',。

name:fileName + '.webm',。

url:URL.createObjectURL(blob)。

})

},

// 预览视频 图片

preview(row){。

if(row.type == 'png'){。

this.showImg = true。

this.showVideo = false。

this.imgSrc = row.url。

}else if(row.type == 'webm'){ 。

this.showVideo = true。

this.showImg = false。

this.videoSrc = row.url。

}else{

this.$message({。

message: '无法预览',。

type: 'error'。

})

}

},

download(row){。

let aTag = document.createElement('a');//创建一个a标签。

aTag.download = row.name;。

aTag.href = row.url;。

aTag.click();。

},

hoverVideo(num){。

if(num){

// 移出

this.ifHoverVideo = false。

}else{

// 移入

this.ifHoverVideo = true。

}

},

secondChangeMinute(second){。

const hour = parseInt(second / 3600)。

const min = parseInt(second / 60)。

const se = parseInt(second % 60)。

const cHour = hour<10?'0'+hour:hour。

const cMin = min<10?'0'+min:min。

const cSe = se<10?'0'+se:se。

return cHour + ':' + cMin + ':' + cSe。

},

fixed(){

this.recordTime += 1。

this.recordHMSTime = this.secondChangeMinute(this.recordTime)。

if(!this.stream.active){。

this.stopRecord()。

}

var offset = new Date().getTime() - (this.startTime + this.recordTime * 1000);。

var nextTime = 1000 - offset;。

if (nextTime < 0) nextTime = 0;。

this.timer = setTimeout(this.fixed, nextTime);。

},

errReponse(err){。

const message = err.message || err。

const response = {。

'permission denied': '浏览器禁止本页面使用摄像头或麦克风,请开启相关的权限',。

'requested device not found': '未检测到摄像头'。

}

console.log(response[ message.toLowerCase() ] || '未知错误');。

this.$message({。

message: response[ message.toLowerCase() ] || '未知错误',。

type: 'warning'。

})

},

dataURLtoFile: function(dataurl, filename) { 。

let arr = dataurl.split(','),。

mime = arr[0].match(/:(.*?);/)[1],。

bstr = atob(arr[1]),。

n = bstr.length,。

u8arr = new Uint8Array(n);。

while (n--) {。

u8arr[n] = bstr.charCodeAt(n);。

}

return new File([u8arr], filename, { type: mime });。

},

// 这个方法是给需要的人看的 演示打开摄像头的方法。

async openCamera(){。

await navigator.mediaDevices.getUserMedia({audio:true,video:true}).then(()=>{。

//我这个时候已经打开摄像头了。

}).catch(err=>{。

this.errReponse(err)。

})

},

// 这个方法是给需要的人看的 演示关闭摄像头的方法。

closeCamera(){。

this.thisVideo.srcObject.getTracks().forEach(item => {。

// 关闭当前所有已打开的设备(你刚刚选择的摄像头设备和你默认的麦克风)

item.stop()。

})

},

}

</script>。

问题解答区域:

1.录制的视频只能是webm格式吗?进度条呢?

答:我在写程序的时候发现只能写webm格式,如果是写MP4或者其他类型,视频下载下来是没有办法播放的,可能在移动端就没有问题,我还没有去尝试在移动端做这个功能。webm格式我所知道的有两个弊端,下载下来的时候无法拖动进度条,而且要在指定播放器中才能播放。如果想要解决这个进度条的问题,可以去看这个地址的解决方法。前端 mediaRecorder 录制视频源代码实例,和本地播放器无法定位进度条问题分析和解决_anne都的博客-CSDN博客_mediarecorder 进度条。

2.http问题

答:在http环境下是可以录制的,但是我上面的代码运行不了就是了。因为我添加了一个获取用户电脑中设备的功能,该功能在http环境下没有办法获取,可能是浏览器出于安全的问题。如果想要在http环境下录制,可以参考下面的这个地址,我也是百度了很久,看了很多别人的博客才得出的最终代码结果。地址如下:

=>1.JS调用媒体设备失败 --- getUserMedia undefine 问题(各浏览器配置方法)_<!--玄德-->的博客-CSDN博客_浏览器不支持getusermedia。

=>2.

PC端调用摄像头录制视频——vue标准写法_前端_森森的博客-CSDN博客_vue调用摄像头录像。

=>3.

JS基于页面实现音视频的录制(一)_画虎成鳖的博客-CSDN博客_js录制视频。

3.表格不一定要用vxetable,随便用 。

4.如果还有什么问题再在评论区问吧。。

的相关图片

盒子模型概述:

所有HTML元素都可以看作盒子,在CSS中,"box model"这一术语是用来设计和布局时使用。CSS盒模型本质上是一个盒子,封装周围的HTML元素,它包括:边距,边框,填充,和实际内容。盒模型允许我们在其它元素和周围元素边框之间的空间放置元素。下面的图片说明了盒子模型(Box Model):

盒子模型组成以及对应区域

盒子模型的组成:

Margin(外边距) - 清除边框外的区域,外边距是透明的。

Border(边框) - 围绕在内边距和内容外的边框。

Padding(内边距) - 清除内容周围的区域,内边距是透明的。

Content(内容) - 盒子的内容,显示文本和图像。

以上是html中盒子模型的结构,每个元素都可以用这个盒子模型来解析。在开发中,一个元素的样式表现形式,也是由这个盒子模型的每个部分来表现的。对应到css中样式的属性有一下几个纬度——

width, height, padding, border, margin。由于在不同的浏览器中,这几个属性所表示的盒子模型中的部分有所差异,所以又分为了标准盒子模型和怪异盒子模型。

一,标准盒子模型

解释:在标准盒子模型下

(1)css中的width, height属性,分别表示的是盒子模型中content的宽度和高度。

(2)css中的padding,表示的是盒子模型的的padding部分。

(3)css中的border,表示的是盒子模型中的border部分。

(4)css中的margin,表示的是盒子模型中的margin。

二,怪异盒子模型(ie盒子模型)

解释:在怪异盒子模型下

(1)css中的width, height属性,分别表示的是盒子模型中content的宽度和高度加上盒子模型中padding和border的宽度。

(2)css中的padding,表示的是盒子模型的的padding部分。

(3)css中的border,表示的是盒子模型中的border部分。

(4)css中的margin,表示的是盒子模型中的margin。

**段落性总结 —— 标准盒子模型和怪异盒子模型的区别**。

从上述的内容可以看出,标准盒子模型和怪异盒子模型的区别,完全体现在css中width和height这两个属性对盒子模型的表现上。

标准盒子模型:css中width/height=content的width/height。

怪异盒子模型:css中width/height=content的width/height+padding+border。

导致的结果:

由于标准盒子模型和怪异盒子模型的存在,这就导致当同一段css代码作用在同一个元素上时,在不同盒子模型下的浏览器中,元素所占的宽度和高度却不同。

三,css3中box-sizing下的盒子模型。

语法:(属性)box-sizing: (属性值)content-box/border-box/inherit;

box-sizing对盒子模型的影响:

(1)当“box-sizing“的值为”content-box“时,css中的width所包含的部分是盒子模型中content的宽度。此时和标准盒子模型表现一致。

(2)当“box-sizing“的值为”border-box“时,css中的width所包含的是盒子模型中的content的宽度+padding+border的宽度。此时和怪异盒子模型的表现一致。

总结:box-sizing属性,让开发人员可以控制浏览器的是以标准盒子模型表现,还是以怪异盒子模型表现。

box-sizing的兼容性:

到此盒子模型的所有内容全部阐述完毕。

最佳方案:由于box-sizing的兼容性在ie8及以上,那在不要求兼容ie8一下的项目中,可以使用box-sizing给所有元素统一设置盒子模型的表现形式。个人推荐:。

*{box-sizing:'border-box'}。

这样只要设置的width的宽度,就是这个元素在页面中真实的宽度了。不用再去计算padding和border对width的影响。

对于需要兼容ie8的项目,就需要针对不同的浏览器,添加特定的代码。或者避免指定宽度的元素border和padding的设置。

相关内容:

1.行内元素之间的水平margin,即两个元素margin之和。

2.块级元素之间的竖直margin, 即取最大的。

3.嵌套盒子之间的margin,即父元素的padding+子元素的margin。

4.margin可以设置为负值。

不同浏览器的css前缀:Element {。

-moz-box-sizing: content-box;。

-webkit-box-sizing: content-box;。

-o-box-sizing: content-box;。

-ms-box-sizing: content-box;。

box-sizing: content-box;。

参考:

w3c标准:https://www.runoob.com/cssref/css3-pr-box-sizing.html。

的相关图片

的相关图片

原文地址:http://www.qianchusai.com/box-sizing-50.html

xiaoxue/16589

xiaoxue/16589

lw/汽车生日蛋糕图片男孩,汽车生日蛋糕图片2021最新款

lw/汽车生日蛋糕图片男孩,汽车生日蛋糕图片2021最新款

小兵别-30,小兵别打我破解版无限钻石无限金币

小兵别-30,小兵别打我破解版无限钻石无限金币

xiaoxue/20820

xiaoxue/20820

xiaoxue/21135

xiaoxue/21135

snot-110

snot-110

天天刷大G什么梗

天天刷大G什么梗

成年版one一个致敬韩寒下载

成年版one一个致敬韩寒下载

104在爱情里意思是什么,104在爱情代表什么意思

104在爱情里意思是什么,104在爱情代表什么意思

cc/赣州火车站图片大全,赣州火车站具体位置

cc/赣州火车站图片大全,赣州火车站具体位置

知网在线平台 中国知网在线学习平台怎么找 学校知网在线阅读 中国知网免费入口登录工具下载 知网在线教学平台 知网在线投稿平台 知网免费图书馆在线阅读 知网研学在线阅读打不开 知网论文在线投稿流程 知网如何在线写论文 中国知网在线阅读期刊 知网专用阅读器 中国知网的外文不能在线阅读 手机知网不能在线阅读 知网手机在线阅读 中国知网文献免费阅读器 论文查重工具知网 知网ai综述写作神器防查重 知网不支持在线阅读 知网在线浏览 知网ai文献综述神器 知网在线阅读收费吗 知网阅读器推荐 知网免费在线 知网论文在线看 中国知网在线服务平台 觅知网ppt在线编辑 知网在线阅读方式 知网ai工具在哪里 知网在线投稿靠谱吗