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. Nginx反向代理服务流式输出设置

    Nginx反向代理服务流式输出设置 1.问题场景 提问:为什么我部署的服务没有流式响应 最近在重构原有的GPT项目时,遇到gpt回答速度很慢的现象.在使用流式输出的接口时,接口响应速度居然还是达到了3 ...

  2. 轻松玩转70亿参数大模型!借助Walrus在AWS上部署Llama2

    Llama 2 是 Meta 的下一代开源大语言模型.它是一系列经过预训练和微调的模型,参数范围从 70 亿到 700 亿个.Meta Llama 2 可免费用于研究和商业用途并且提供了一系列具有不同 ...

  3. Go语言-Slice详解

    Go语言中的slice表示一个具有相同类型元素的可变长序列,语言本身提供了两个操作方法: 创建:make([]T,len,cap) 追加: append(slice, T ...) 同时slice支持 ...

  4. 快手商品详情API接口如何使用

    使用快手开的API接口获取商品详情,可按照以下步骤进行: 1.注册账号并创建应用 注册开发者账号,并在账号后台中创建一个应用,获得AppKey和AppSecret等信息.这些信息是使用API接口访问快 ...

  5. API接口的应用场景

    API数据接口的应用非常广泛,不同的行业和领域都可以使用API数据接口来获取所需的数据,从而实现数据分析.数据挖掘.数据统计等操作.以下是一些常见的API数据接口应用场景: 电商平台:例如淘宝.京东等 ...

  6. ATtiny88初体验(七):TWI

    ATtiny88初体验(七):TWI TWI模块介绍 ATtiny88的TWI模块兼容Phillips I2C以及SMBus,支持主从模式,支持7bit地址,最大允许128个不同的从机地址.在多主机模 ...

  7. DHCP是什么

    DHCP 1. DHCP是什么 协议,一种应用层的网络协议,他可以动态地分配网络中的IP地址和其他网络配置的参数以及网络设备,通俗一点讲,每台设备的IP地址,子网掩码,网关等网络参数信息都是由他来完成 ...

  8. 利用SpringBoot项目做一个Mock挡板;基于事件发布动态自定义URL和响应报文

    导入SpringbootWEb依赖 <!--web项目驱动--> <dependency> <groupId>org.springframework.boot< ...

  9. Django框架项目之git笔记——版本控制器、git介绍、git使用

    文章目录 版本控制器 git 简介 git与svn比较 git的工作流程 版本库间的通信 git分支管理 git使用 流程(核心总结) 安装 基础命令 将已有的文件夹 - 初始化为git仓库 在指定目 ...

  10. macbook-键盘连击问题001

    最近一段时间,我的笔记本(17年款 macbook pro 13寸)经常出现键盘连击问题. 最大的表现是 e/n/i 这几个按键,按下的时候,会有概率的出现两个或三个. 这不是个案 搜索了一下,有不少 ...