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. JavaScript的Map和WeakMap

    熟悉JavaScript的Map和WeakMap Map Map的键/值可以是任何类型 基本API 初始化映射: //使用new关键字和Map构造函数进行初始化 const m1 = new Map( ...

  2. Jni GetMethodID中函数标识sig的详细解释

    在 JNI(Java Native Interface)中,GetMethodID 函数用于获取 Java 类的方法的标识符.这个函数的详细解释如下: cCopy code jmethodID Get ...

  3. Postgresql 批量插入命令COPY使用

    在很多场景下,我们经常会遇到将某个Excel或Csv文件中的数据,插入到Postgresql.对于这个需求,我们常规的处理办法就是将文件中的数据,按照文件表头名称转换成集合对象然后插入到数据库,当然这 ...

  4. vue中添加音频和视频

    视频播放功能 1. 安装vue-video-player npm install vue-video-player --save 或 yarn add vue-video-player --save ...

  5. 浅谈基于QT的截图工具的设计与实现

    本人一直在做属于自己的一款跨平台的截图软件(w4ngzhen/capi(github.com)),在软件编写的过程中有一些心得体会,所以有了本文.其实这篇文章酝酿了很久,现在这款软件有了雏形,也有空梳 ...

  6. MySQL高级9-锁

    一.简介 锁是计算机协调多个进程或线程并发访问某一资源的机制.在数据库中,除了传统的计算资源(CPU.RAM.i/O)的挣用以外,数据也是一种供许多用户共享的资源.如何保证数据并发访问的一致性,有效性 ...

  7. 基于Protege的知识建模实战

    一.Protege简介.用途和特点 1.Protege简介 Protege是斯坦福大学医学院生物信息研究中心基于Java开发的本体编辑和本体开发工具,也是基于知识的编辑器,属于开放源代码软件.这个软件 ...

  8. ContentPresenter使用DataTemplate

    在使用自定义样式内容时,有时也需要在自定义样式中绑定一下数据模板 可以使用ContentPresenter的ContentTemplate绑定定义好的资源 DateTemplate 用法代码如下 &l ...

  9. WEB组态编辑器插件(BY组态)介绍

    BY组态是一款非常优秀的纯前端的[web组态插件工具],采用标准HTML5技术,基于B/S架构进行开发,支持WEB端呈现,支持在浏览器端完成便捷的人机交互,简单的拖拽即可完成可视化页面的设计.可无缝嵌 ...

  10. 跳出循环可不要再用forEach,map也不好用,不妨直接用for循环

    需求:循环一个数组保持请求顺序请求接口,且当前数组的值为1时,又需要异步请求另一个接口根据返回status值跳出本次循环. 解决思路:使用for循环,首先在循环中判断数组中值为1的,用async和aw ...