h5移动端使用video实现拍照、上传文件对象、选择相册,做手机兼容。
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实现拍照、上传文件对象、选择相册,做手机兼容。的更多相关文章
- android 拍照上传文件 原生定位
最近公司需要一个android拍照上传和定位功能的的单一功能页面,一开始选择ionic cordova angular的一套H5框架,但是遇到和上传文件报错的问题,bug找了一天没找到原因,怀疑是io ...
- NSURLSession/NSURLConnection的上传文件方法(已做了更新)
最好的学习方法就是 领悟 + 证悟. 此篇文章的理论基础主要是与HTTP网络通信协议相关.为集中精力,可以先把TCP/IP协议这些置之不理,也就是先只关注HTTP的请求和响应的结构.HTTP完整的原理 ...
- jquery.form.js mvc 上传文件 layer 选择框与等待效果
HTML <form role="form" id="form1"> <div class="form-group"> ...
- JQuery Ajax 使用FormData上传文件对象
FormData部分: 先new FormData对象 :let somedata = new FormData(),然后将数据添加进去,这里我们使用append()进行添加. 这里举一个上传头像的例 ...
- webAPP如何实现移动端拍照上传(Vue组件示例)?
摘要:使用HTML5编写移动Web应用,主要是为了尝试一下“一套代码多处运行”,一个webapp几乎可以不加修改的运行在PC/Android/iOS等上面运行.但是写到现在觉得虽然这种方式弊大于利,不 ...
- 【Demo】HTML5 拍照上传
本文主要讲解 手机浏览器 如何拍照 为什么会有这个需求 最近做一个项目要用到拍照然后上传照片,但是网页拍照一般都是用Flash做的,而我们主要是H5页面,如果在微信里面有权限就可以通过JSSDK调起摄 ...
- jquery上传文件控件Uploadify
基于jquery的文件上传控件,支持ajax无刷新上传,多个文件同时上传,上传进行进度显示,删除已上传文件. 要求使用jquery1.4或以上版本,flash player 9.0.24以上. 有两个 ...
- WebUploader分片断点上传文件(二)
写在前面: 这几天,有去研究一下WebUploader上传文件,前面的博客有记录下使用WebUploader简单上传文件的例子,今天就把分片断点上传的例子也记录下吧,在博客园中,也查看了一些资料,基本 ...
- WebUploader上传文件(一)
写在前面: 文件上传方式很多的,对于大文件的上传,在本次项目中也有涉及,主要是用了分片断点上传大文件.所以就去了解了一下WebUploader,先从简单的上传文件开始吧~ 在代码中写注释,这样看的比较 ...
- 20-1 django上传文件和项目里上传头像如何查看
一 普通上传方式 1 views def upload(request): if request.method == "POST": # print(request.POST) # ...
随机推荐
- 《CUDA编程:基础与实践》读书笔记(1):CUDA编程基础
1. GPU简介 GPU与CPU的主要区别在于: CPU拥有少数几个快速的计算核心,而GPU拥有成百上千个不那么快速的计算核心. CPU中有更多的晶体管用于数据缓存和流程控制,而GPU中有更多的晶体管 ...
- Visual Studio Code(vscode)下载慢 插件安装失败解决方案
目录 一.系统环境 二.前言 三.Visual Studio Code(vscode)简介 四.解决Visual Studio Code(vscode)下载慢的问题 4.1 问题描述 4.2 解决方案 ...
- JOIN 关联表中 ON、WHERE 后面跟条件的区别
SQL中join连接查询时条件放在on后与where后的区别 数据库在通过连接两张或多张表来返回记录时,都会生成一张中间的临时表,然后再将这张临时表返回给用户. 在使用left jion时,on和wh ...
- 《Python魔法大冒险》007 被困的精灵:数据类型的解救
小鱼和魔法师深入魔法森林,树木之间流淌着神秘的光芒,每一片叶子都似乎在低语着古老的咒语.不久,他们来到了一个小湖旁,湖中央有一个小岛,岛上困着一个透明的泡泡,里面有一个悲伤的精灵. 小鱼看着那个精灵, ...
- redhat7 team bonding 双网卡绑定 主备 负载均衡
team简介 team也被称为网络组,是将多个网卡聚合在一起,从而实现冗错和提高吞吐量.适用于redhat7.0以上版本,至多可支持8块网卡.team相对于之前的bonding技术,能提供更好的性能和 ...
- Centos7中防火墙打开3306端口(亲测)
开放3306端口 firewall-cmd --zone=public --add-port=3306/tcp --permanent 开启防火墙 systemctl start firewa ...
- JUC并发编程(2)—synchronized锁原理
目录 乐观锁和悲观锁介绍 synchronized用法介绍 synchronized和ReentrantLock的区别 经典8锁问题案例 从字节码角度分析synchronized实现 synchron ...
- 关于如何解决visualc++6.0打开文件闪退的一种方式(附带解决输入法无法显示)
这里我把VisualC++6.0安装程序和filetool分享在我的网盘里面了 网盘下载QAQ 链接:https://pan.baidu.com/s/1azSMX_cOKgb64WT7-gTdbQ?p ...
- 基本操作:vscode-git使用和命令
Git简介 GIt /git/ 是一个开源的分布式版本控制系统,可以有效.高速的处理从很小到很大的项目版本管理: 通俗的说,解决的问题是: 正常开发,一个团队需要很多人来共同开发 ...
- linux 查找命令(whatis,free,df,top)
whatis whatis命令是用于查询一个命令执行什么功能,并将查询结果打印到终端上,等同于 man -f: # whatis grep grep (1) - print lines matchin ...