h5相机功能

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' })
相关推荐
Pedantic1 小时前
SwiftUI 手势层级(Gesture Hierarchy)详解
前端
飘尘1 小时前
前端转型全栈(Java后端)的快速上手指引
前端·后端·全栈
一颗烂土豆1 小时前
Meshopt 压缩深度解析,为什么它比 Draco 更快
前端·javascript·webgl
浏览器工程师2 小时前
AI Agent 接浏览器任务,先别让它一路点到底
前端·后端
雨季mo浅忆2 小时前
VSCode自动格式化三要素
前端
爱勇宝3 小时前
深扒 Anthropic 1680 位工程师简历:应届生几乎没机会,AI 公司最缺的不是博士
前端·后端·程序员
kyriewen4 小时前
同事每天催我 Code Review,我写了个脚本让 AI 替我 review PR——现在他反过来催 AI 了
前端·javascript·ai编程
user20585561518136 小时前
Windows 项目安装时报 `node-sass` 错误,如何快速处理
前端
LiaCode6 小时前
Redis 在生产项目的使用
前端·后端