h5相机功能
利用vant + input file
<template>
<div class="mb10">
<div
v-for="(item, index) in info.imgList"
:key="index"
class="imgItem f32 mr20"
@click="preview(item, index)"
>
<img :src="doFileUrl(item)" alt="" srcset="" />
<van-icon
v-if="!disabled"
class="close f34 txt-f6"
name="close"
@click.stop="deleteImg(item, index)"
/>
</div>
<div
v-show="info.imgList.length < maxCount && !disabled"
class="btnUpload f32 mr10"
@click="clickUpload"
>
<van-icon name="plus" />
<input
ref="camera"
class="cameraInput"
type="file"
name="file"
accept="image/*"
capture="camera"
@change="uploadImg"
/>
</div>
</div>
<!-- 底部弹出 -->
<van-action-sheet
v-model:show="showChoose"
:actions="info.actions"
cancel-text="取消"
close-on-click-action
@cancel="onCancel"
@select="selectAction"
/>
</template>
<script lang="ts" setup>
import { ref, getCurrentInstance, reactive, onMounted, defineExpose } from 'vue'
import { Action, InfoInterface } from './config'
import { fileUpload } from '@/utils/fileHttp'
const emit = defineEmits(['chooseFIle'])
/**
* @description: 传参
* @return {*}
* @Date Changed:
*/
interface Props {
// 文件list
fileList: string | null | any[]
// 上传数量
maxCount?: number
//尺寸 这个暂时没用
maxSize?: number
// 缩略图大小 px 和 rem
disabled?: boolean
// 图片类型
accept?: string[]
type?: number[]
// 是否全部允许
allowAllAccept?: boolean
isRequire?: boolean
//
}
const props = withDefaults(defineProps<Props>(), {
fileList: () => [],
maxCount: 1,
maxSize: 5 * 1024 * 1024,
disabled: false,
accept: () => ['image'],
type: () => [0],
allowAllAccept: false,
isRequire: false
})
/**
* @description: 通用参数
* @return {*}
* @Date Changed:
*/
const { proxy }: any = getCurrentInstance()
const router = proxy.commond.router()
const route = proxy.commond.route()
const { Toast } = proxy.commond
const info = reactive<InfoInterface>({
imgList: [],
actions: []
// aaaaaa: []
})
let toastLoading: any = null
const token = proxy.commond.getToken()
/**
* @description: 生命周期
* @return {*}
* @Date Changed:
*/
onMounted(() => {
init()
})
const init = () => {
// 拍照模式
const arr: Action[] = []
props.type.forEach((item: number) => {
arr.push(list[item])
})
info.actions = arr
}
//----------------------------------------------------------- 底部弹出选择拍照模式
const showChoose = ref(false)
const list: Action[] = [
{
name: '拍照',
type: 'ShowView',
value: 'CameraView'
},
{
name: '相册',
type: 'ShowView',
value: 'PhotoView'
},
{
name: '文件上传',
type: 'uploadFile',
value: 'fileView'
}
]
const clickUpload = () => {
showChoose.value = true
}
const onCancel = () => {
showChoose.value = false
}
const selectAction = async (action: Action, index: number) => {
if (action.value === 'CameraView') {
// 拍照
console.log(proxy.$refs.camera)
proxy.$refs.camera.click()
showChoose.value = false
}
// if (res.length > 0) {
// const arr = proxy.commond.deepClone(info.imgList)
// res.map((ele) => {
// arr.push(`OSS_FILE_${ele.resourcesId}/${ele.fullFileName}`)
// })
// emit('success', arr)
// showChoose.value = false
// }
}
/**
* @description: 上传文件
* @return {*}
*/
const uploadImg = (e: any) => {
// 这里可以做一些限制 比如 文件大小 文件类型等
// ----------
const file = e.target.files[0]
// 原生请求
toastLoading = proxy.commond.Toast.loading({
duration: 0,
forbidClick: true,
message: '开始上传...'
})
fileUpload(file)
.then((data: any) => {
const url = `OSS_FILE_${data.result.resourcesId}/${data.result.fullFileName}`
info.imgList.push(url)
emit('chooseFIle', info.imgList, file)
toastLoading.clear()
proxy.$refs.camera.value = ''
})
.catch((err) => {
toastLoading.clear()
proxy.commond.Toast(err.message)
proxy.$refs.camera.value = ''
})
}
const doFileUrl = (resourcesId: string): string => {
return proxy.commond.doFileUrl(resourcesId)
}
/**
* @description: 删除照片
* @param {*} val
* @param {*} index
* @return {*}
*/
const deleteImg = (val: string, index: number) => {
info.imgList.splice(index, 1)
emit('chooseFIle', info.imgList, '')
}
/**
* @description: 图片预览
* @param {*} val
* @param {*} index
* @return {*}
*/
const preview = (val: string, index: number) => {
const arr: string[] = []
info.imgList.forEach((ele) => {
arr.push(doFileUrl(ele))
})
proxy.commond.ImagePreview({
images: arr,
startPosition: index
})
}
defineExpose({
selectAction,
preview
})
</script>
<style lang="scss" scoped>
.cameraInput {
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
display: none;
}
.btnUpload {
position: relative;
text-align: center;
background-color: #fbfdff;
border: 1px dashed #c0ccda;
border-radius: 6px;
box-sizing: border-box;
display: inline-block;
width: 148px;
height: 148px;
cursor: pointer;
line-height: 146px;
vertical-align: top;
}
.imgItem {
display: inline-block;
position: relative;
border: 1px dashed #c0ccda;
width: 148px;
height: 148px;
cursor: pointer;
img {
margin-top: 4px;
width: 140px;
height: 140px;
}
.close {
position: absolute;
right: -14px;
top: -10px;
background: #fff;
border-radius: 100px;
color: $danger;
}
}
</style>
/**
* @description: 上传文件景天参数
* @return {*}
* @Date Changed:
*/
export interface Action {
name: string
type: string
value: string
}
/**
* @description:图片返回值处理
* @return {*}
* @Date Changed:
*/
export interface ImgFace {
resourcesId: string
resourceUrl: string
fullFileName: string
fileName: string
id: string
}
/**
* @descriptioninfo
* @return {*}
* @Date Changed:
*/
export interface InfoInterface {
imgList: string[]
actions: Action[]
}
export interface fileBox {
show: boolean
url: string
}
使用
// 调用相机
<GlFace ref="face" :file-list="[]" @chooseFIle="chooseFIle"></GlFace>
const face = ref(null)
face.value.selectAction({ value: 'CameraView' })