本文目录:
- 1、CSS中,input添加padding-left:30px后被推长的问题。
- 2、Linux命令: tail
- 3、CSS,这两个文本框没有垂直对齐,怎么解决?谢谢。
- 4、前端里面box-sizing:border-box作用是什么?
- 5、vuepc电脑可以获取设备吗
- 6、Linux命令:tar
CSS中,input添加padding-left:30px后被推长的问题。
最简单的解决办法就是不用padding-left,改用text-indent:
text-indent: 30px
(我上次回答你的问题时不就是这样的吗?你也不想想我为什么不用padding?)
原因:元素的实际宽度=width+border+padding,所以如果padding不为0,元素的实际宽度就会被拉宽了。而text-indent是段落前空位(就是写文章时每一段前面的空格),不会影响到元素的实际宽度。
Linux命令: tail
Linux中的tail命令用来显示文件的最后几行至标准输出中,默认tail命令打印其相应文件的最后10行,其作用正好与head命令相反。
tail [options] file..
tail命令常用options参数
-n:这里的K指的是行数,该选项表示输出最后K行,在此基础上,如果使用-n +K,则表示从文件的第K行开始输出。
-c:这里的K指的是字节数,该选项表示输出文件最后K个字节的内容,在此基础上,使用-c +K则表示从文件第K个字节开始输出。
-f:输出文件变化后新增加的数据。
-q:不显示处理信息。
tail命令常用实例
示例1:查看/etc/vimrc的文件内容
tail /etc/vimrc
示例2:查看文件最后几行内容
tail -n 2 /etc/vimrc
CSS,这两个文本框没有垂直对齐,怎么解决?谢谢。
你好,你的html这样的结构,默认就是自动水平对齐的。现在是您的css代码写的不正确才会导致两个input上下偏移。
你只需在 .textMoRen 和 .spanWenBenKuangZuHeRongQi 上分别加上 vertical-align: middle 即可对齐,具体效果如图
希望我的回答能够帮到您
前端里面box-sizing:border-box作用是什么?
把内边距和边框,都算在一个盒子模型内,总宽度内,如果没有这个,宽度=内边距+边框
vuepc电脑可以获取设备吗
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=”cha-d6bf-9f9e-10b8-f216 publish”
div class=”cha-9f9e-10b8-f216-d480 box”
div class=”cha-10b8-f216-d480-818d videoPart”
div class=”cha-f216-d480-818d-ddf2 videoRecord” @mouseenter=”hoverVideo(0)” @mouseleave=”hoverVideo(1)”
video id=”videoCamera” :width=”videoWidth” :height=”videoHeight” autoPlay/video
div class=”cha-0395-6937-304c-dd89 hoverVideoOutside” v-if=”ifHoverVideo ifStartRecord”
div class=”cha-6937-304c-dd89-6404 hoverVideoInside”
div class=”cha-304c-dd89-6404-5d1c hoverVideoInsideInside”
div class=”cha-dd89-6404-5d1c-a195 hoverVideoBtn”div class=”cha-6404-5d1c-a195-19ab hoverVideoBtnInside”/div/div
span{{recordHMSTime}}/span
/div
/div
/div
/div
canvas id=”canvasCamera” class=”cha-5d1c-a195-19ab-f7cc canvas” :width=”videoWidth” :height=”videoHeight”/canvas
video v-if=”showVideo” :src=”videoSrc” autoplay controls/video
img v-if=”showImg” class=”cha-a195-19ab-f7cc-7d79 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 = hour10?’0’+hour:hour
const cMin = min10?’0’+min:min
const cSe = se10?’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.如果还有什么问题再在评论区问吧。。
Ryzen的简单介绍”>
Linux命令:tar
原单词 tar命令最初的设计目的是将文件备份到磁带上(tape archive),因而得名tar
实物长这样
tar 命令是linux系统中常用的 压缩文件 和 解压缩文件命令
tar 命令的参数 异常之多,咱们只学习满足 压缩文件 和 解压缩文件 命令的参数就可以了
mark style=”box-sizing: border-box; background-color: rgb(255, 255, 0); color: rgb(0, 0, 0);”工作中应用于安装软件,搭建应用,部署环境/mark
举例: 将root目录下的 adir目录和a.txt文件 压缩为 test.tar.gz
注意是大写C
如果 不使用-C参数 则默认解压至当前工作目录
举例: 将 test.tar.gz 压缩文件解压到/root目录
-c 建立新的备份文件。
-x 从备份文件中还原文件。
-v 显示指令执行过程。
-f 指定备份文件。
-z 通过gzip指令处理备份文件。(如果解压文件后缀是.tar,没有.gz则不需要使用-z参数)
-C 指定解压到的目录
使用xshell连接linux
在root 目录下 新建 tarTest目录
进入tarTest目录
压缩 /root/lnTest文件夹 和 /root/Centos-7.repo 文件 到 /root/tarTest目录下,压缩文件名为 test.tar.gz
进入/root/tarTest目录
解压test.tar.gz到当前目录(/root/tarTest)
解压test.tar.gz到/root/rmTest目录
【Ryzen】的内容来源于互联网,如引用不当,请联系我们修改。