html部分

<template>
<div class="views">
<video style="width: 100vw; height: calc(100vh - 18vh)" object-fit="fill"></video>
<!-- <img style="width: 100vw; height: calc(100vh - 18vh)" :src="str" alt="" srcset=""> -->
<div class="picture" @click="pictureClick">
<i class="iconfont icon-picture"></i>
</div>
<div @click="handlePhotographClick" class="action"></div>
<div class="folder" @click="folderClick">
<i class="iconfont icon-folder"></i>
</div>
<div class="bac">
<div>
<div class="img_box" v-for="(img, index) in srcList" :key="img.src + index">
<i class="iconfont icon-guanbi" @click="delImg(img.name, index)"></i>
<img src="../../../../public/img/files1.png" v-if="img.name === 'files'" />
<img :src="img.src" v-else />
<span>{{ index + 1 }}</span>
</div>
</div>
<div>
<button class="btn" @click="upload">确认</button>
</div>
</div>
</div>
</template>

js部分

<script>
export default {
data() {
return {
imageUrl: '',
// 媒体流,用于关闭摄像头
mediaStreamTrack: null,
fileName: '', // 上传文件名
fileList: [], // 上传文件列表
isCamera: true, // 是否是摄像头
imgBase64: '', // 图片base64
photoList: [], // 图片列表
localHeight: 0, // 本地视频高度
srcList: [], // 图片路径列表
}
},
mounted() {
this.invokingCamera()
},
destroyed() {
this.handlePhotographCloseClick()
},
methods: {
// 调用摄像头
invokingCamera() {
const self = this
// 注意本例需要在HTTPS协议网站中运行,新版本Chrome中getUserMedia接口在http下不再支持。
// 老的浏览器可能根本没有实现 mediaDevices,所以我们可以先设置一个空的对象
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {}
}
// 一些浏览器部分支持 mediaDevices。我们不能直接给对象设置 getUserMedia
// 因为这样可能会覆盖已有的属性。这里我们只会在没有getUserMedia属性的时候添加它。
if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = function (constraints) {
// 首先,如果有getUserMedia的话,就获得它
const getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia
// 一些浏览器根本没实现它 - 那么就返回一个error到promise的reject来保持一个统一的接口
if (!getUserMedia) {
return Promise.reject(new Error('getUserMedia is not implemented in this browser'))
}
// 否则,为老的navigator.getUserMedia方法包裹一个Promise
return new Promise(function (resolve, reject) {
getUserMedia.call(navigator, constraints, resolve, reject)
})
}
}
const constraints = {
audio: false,
video: {
// 前置摄像头
facingMode: { exact: 'environment' },
// 手机端相当于高
width: Math.max(window.innerWidth, window.innerHeight),
// 手机端相当于宽
height: Math.min(window.innerWidth, window.innerHeight),
},
}
navigator.mediaDevices
.getUserMedia(constraints)
.then(function (stream) {
self.mediaStreamTrack = stream
const video = document.querySelector('video')
// 旧的浏览器可能没有srcObject
if ('srcObject' in video) {
video.srcObject = stream
} else {
// 防止在新的浏览器里使用它,应为它已经不再支持了
video.src = window.URL.createObjectURL(stream)
}
video.onloadedmetadata = function (e) {
video.play()
}
})
.catch(function (err) {
console.log(err.name + ': ' + err.message)
})
},
// 关闭摄像头
handlePhotographCloseClick() {
if (this.mediaStreamTrack) {
// 关闭摄像头
this.mediaStreamTrack.getTracks().forEach(function (track) {
track.stop()
})
this.mediaStreamTrack = null
}
},
// 拍照
handlePhotographClick() {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
const video = document.querySelector('video')
canvas.width = Math.min(video.videoWidth, video.videoHeight)
canvas.height = Math.max(video.videoWidth, video.videoHeight)
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
// 将图片转为base64
const base64Image = canvas.toDataURL('image/png')
// const str = base64Image.replace('data:image/png;base64,', '')
// // 文件对象数组
// this.photoList.push(this.convertBlobToFile(this.convertBase64ToBlob(str), new Date().getTime()))
// 图片路径数组
this.srcList.push({
src: base64Image,
// src: this.str,
name: new Date().getTime() + '.png',
})
},
folderClick() {
// 选择文件
var input = document.createElement('input')
input.type = 'file'
input.accept = '.doc,.docx,.txt,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,.pdf'
input.addEventListener('change', (e) => {
// console.log(e.target.files, 'eeeeee')
// 读取选择的文件
this.fileList.push(e.target.files)
this.srcList.push({
src: null,
name: 'files',
})
})
// 触发点击事件,打开文件
input.click()
},
pictureClick() {
const self = this
// 选择图片
var input = document.createElement('input')
input.type = 'file'
input.accept = 'image/*'
input.multiple = true
// 点击事件处理函数
input.addEventListener('change', function () {
if (this.files && this.files[0]) {
// 读取选择的图片文件
var reader = new FileReader()
reader.onload = (e) => {
// 图片加载完成后,将图片URL赋值给input的src属性,即可显示图片
// console.log(e.target.result, 'e.target.result')
const type = this.files[0].type.split('/')[1]
self.srcList.push({
src: e.target.result,
name: new Date().getTime() + '.' + type,
})
}
reader.readAsDataURL(this.files[0])
}
})
// 触发点击事件,打开图库
input.click()
},
// 转换为blob格式
convertBase64ToBlob(base64Str) {
// 将base64字符串转为二进制数据
const byteCharacters = atob(base64Str)
// 创建Blob对象
const blob = new Blob([byteCharacters], { type: 'application/octet-stream' })
return blob
},
// 将blob转为file对象
convertBlobToFile(blob, fileName) {
// 创建File对象
const type = fileName.split('.')[1]
const file = new File([blob], fileName, { type: `image/${type}` })
return file
},
delImg(name, index) {
// 删除图片
if (name === 'files') {
this.fileList.splice(index, 1)
}
this.srcList.splice(index, 1)
},
upload() {
// 上传按钮
if (this.srcList.length > 0) {
for (let i = 0; i < this.srcList.length; i++) {
// 文件对象数组
if (this.srcList[i].src === null) {
continue
}
const type = this.srcList[i].name.split('.')[1]
this.photoList.push(this.convertBlobToFile(this.convertBase64ToBlob(this.srcList[i].src.replace(`data:image/${type};base64,`, '')), new Date().getTime() + `.${type}`))
}
}
const fileObj = []
for (let i = 0; i < this.fileList.length; i++) {
fileObj.push(this.fileList[i][0])
}
for (let i = 0; i < this.photoList.length; i++) {
fileObj.push(this.photoList[i])
}
console.log(fileObj, 'fileObj')
},
},
}
</script>

css部分

<style scoped lang="stylus">
.views{
width: 100vw;
height: 100vh;
background-color: #ccc;
position: relative .picture{
position: absolute;
left: 1rem;
z-index: 9;
bottom: 4rem;
.icon-picture{
font-size: 1rem;
font-weight: bold;
}
}
.folder{
position: absolute;
right: 1rem;
z-index: 9;
bottom: 4rem;
.icon-folder{
font-size: 1rem;
font-weight: bold;
}
}
.action{
position: absolute;
bottom: 20vh;
left: 50%;
margin-left: -35px;
border-radius: 50px;
border: 10px solid #ccc;
box-shadow: 0 0 10px black;
background-color: #fff;
width: 70px;
height: 70px;
display: flex;
justify-content: center;
z-index :99
}
.bac {
overflow-x: scroll;
white-space: nowrap; /* 横向内容不换行 */
align-items: flex-end; /* 图片索引在左下角 */
} .img_box {
margin-top: 10px;
position: relative;
display: inline-block; /* img_box横向排列 */
margin-left: 8px;
margin-bottom: 8px;
} .icon-guanbi {
position: absolute;
top: -10px;
right: -10px;
width: 20px;
height: 20px;
font-size : 20px;
color: #fff;
color:red;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
} img {
// width: 100px;
height:15vh;
margin-left: 8px
} span {
position: absolute;
bottom: 0;
left: 0;
margin-left: 4px;
margin-bottom: 4px;
color: #fff;
background-color: #64e8ff;
padding: 4px;
font-size: 20px;
border-radius: 2px 2px 2px 6px;
}
.btn{
color: #fff;
border: none;
background: #029afc;
height: 1rem;
width: 1.5rem;
position: absolute;
right: 0;
bottom: 1rem;
z-index: 99;
border-radius: 10px;
line-height: 1rem;
}
}
</style>

以上代码可以直接复制使用,留个关注吧。

h5移动端使用video实现拍照、上传文件对象、选择相册,做手机兼容。的更多相关文章

  1. android 拍照上传文件 原生定位

    最近公司需要一个android拍照上传和定位功能的的单一功能页面,一开始选择ionic cordova angular的一套H5框架,但是遇到和上传文件报错的问题,bug找了一天没找到原因,怀疑是io ...

  2. NSURLSession/NSURLConnection的上传文件方法(已做了更新)

    最好的学习方法就是 领悟 + 证悟. 此篇文章的理论基础主要是与HTTP网络通信协议相关.为集中精力,可以先把TCP/IP协议这些置之不理,也就是先只关注HTTP的请求和响应的结构.HTTP完整的原理 ...

  3. jquery.form.js mvc 上传文件 layer 选择框与等待效果

    HTML <form role="form" id="form1"> <div class="form-group"> ...

  4. JQuery Ajax 使用FormData上传文件对象

    FormData部分: 先new FormData对象 :let somedata = new FormData(),然后将数据添加进去,这里我们使用append()进行添加. 这里举一个上传头像的例 ...

  5. webAPP如何实现移动端拍照上传(Vue组件示例)?

    摘要:使用HTML5编写移动Web应用,主要是为了尝试一下“一套代码多处运行”,一个webapp几乎可以不加修改的运行在PC/Android/iOS等上面运行.但是写到现在觉得虽然这种方式弊大于利,不 ...

  6. 【Demo】HTML5 拍照上传

    本文主要讲解 手机浏览器 如何拍照 为什么会有这个需求 最近做一个项目要用到拍照然后上传照片,但是网页拍照一般都是用Flash做的,而我们主要是H5页面,如果在微信里面有权限就可以通过JSSDK调起摄 ...

  7. jquery上传文件控件Uploadify

    基于jquery的文件上传控件,支持ajax无刷新上传,多个文件同时上传,上传进行进度显示,删除已上传文件. 要求使用jquery1.4或以上版本,flash player 9.0.24以上. 有两个 ...

  8. WebUploader分片断点上传文件(二)

    写在前面: 这几天,有去研究一下WebUploader上传文件,前面的博客有记录下使用WebUploader简单上传文件的例子,今天就把分片断点上传的例子也记录下吧,在博客园中,也查看了一些资料,基本 ...

  9. WebUploader上传文件(一)

    写在前面: 文件上传方式很多的,对于大文件的上传,在本次项目中也有涉及,主要是用了分片断点上传大文件.所以就去了解了一下WebUploader,先从简单的上传文件开始吧~ 在代码中写注释,这样看的比较 ...

  10. 20-1 django上传文件和项目里上传头像如何查看

    一 普通上传方式 1 views def upload(request): if request.method == "POST": # print(request.POST) # ...

随机推荐

  1. CVE-2023-2825-GitLab目录穿越poc

    Gitlab CVE-2023-2825 目录穿越漏洞 前言 昨天 GitLab 出了一个版本目录穿越漏洞(CVE-2023-2825),可以任意读取文件.当时我进行了黑盒测试并复现了该漏洞. &qu ...

  2. JNDI注入的本地搭建和分析

    JNDI注入的本地搭建和分析   JNDI概述 JNDI(The java Naming and Directory Interface,java命名和目录接口)是一组在Java应用中访问命名和目录服 ...

  3. GitHub Deskhub使用

    (适合已经知道git是啥但是还不太熟到同学看-) GitHub deskhub就是一个图形化的github管理工具啦,比起来命令行使用舒服100倍哈哈哈- 链接:https://desktop.git ...

  4. 在原生APP中集成Unity容器

    随着技术的发展,越来越多的APP期望拥有3D,AR的能力.要达到这个目标可以选择使用原生开发,也可以使用Unity成熟的3D开发技术链,通过嵌入的方式将Unity容器嵌入到APP中.这里介绍的是通过嵌 ...

  5. Doris 再次启动FE失败的思考

    Doris再次启动FE失败的思考 背景描述 在昨天已经成功下载安装最新稳定版docker.拉取doris-0.15.0版本的镜像.将镜像挂载道本地Doris源码目录.完成了doris的编译之后,今天在 ...

  6. 一台服务器上部署 Redis 伪集群

    哈喽大家好,我是咸鱼 今天这篇文章介绍如何在一台服务器(以 CentOS 7.9 为例)上通过 redis-trib.rb 工具搭建 Redis cluster (三主三从) redis-trib.r ...

  7. 用了这么久SpringBoot却还不知道的一个小技巧

    前言 你可能调第三方接口喜欢启动application,修改,再启动,再修改,顺便还有个不喜欢写JUnitTest的习惯. 你可能有一天想要在SpringBoot启动后,立马想要干一些事情,现在没有可 ...

  8. 【uniapp】【微信小程序】wxml-to-canvas

    真是搞吐了,研究了整整两天,困死我了 本来使用生成二维码插件好好的,插件页也支持导出二维码图片,可是领导说要带上文件的名称,那就涉及html转图片了,当然也可以改二维码插件的源码,不过源码做了混淆,看 ...

  9. Solution -「九省联考 2018」IIIDX

    Description Link. 给出一个堆,然后让你填数进去,使得其满足小根堆的性质,并使编号靠前的点的数最大. Solution 考虑贪心,把原数列降序排序,然后因为这个东西是整除分块的形式,所 ...

  10. 在线问诊 Python、FastAPI、Neo4j — 构建问题分类器

    目录 构建字典数据 构建 Trie 字典树 按实体组装字典 问题分析 将问题进行分析,和系统已有的分类进行关联 构建字典数据 将构建的知识图片字典化, 用于后面对问题的解析,下图为症状的字典,其它字典 ...