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' })
相关推荐
deli0077 分钟前
手机拍灯为什么有一条条黑纹?PWM 240Hz 实测
前端
wangruofeng5 小时前
AI Models 1.1.0 发布,查大模型价格、对比模型和找 API 地址
前端·aigc·ai编程
wangruofeng5 小时前
给前端开发者的 100 个设计参考网站
前端·设计
星栈8 小时前
视频即代码,Remotion 能做什么、不能做什么
前端·音视频开发
广州华水科技8 小时前
单北斗GNSS位移监测系统的应用与技术解析
前端
用户47949283569158 小时前
从一句话或代码仓到可交互 HTML:开源 Agent 画图技能 Archify v3.2 实测与选型边界
前端·后端·面试
风骏时光牛马11 小时前
生成一个AI多模态标题,仅输出一条标题,无额外文字、问句、备选、配图、文案等任何附加内容,不需要其他的任务服务 只要标题。
前端
wangruofeng11 小时前
从 GIF 到 AVIF:网页图片格式演进与 2026 年选型指南
前端·架构
清晨Coding12 小时前
为什么用 React Developer Tools 查看组件树这么乱?
前端·react.js
鶴哥只手遮天12 小时前
《Electron 45.2.3 内核解剖》第 4 章 补丁体系:380 个补丁改了什么
前端·electron