H5实现移动端拍照、照片数量限制、图片压缩、上传图片功能(代码完整,即写即用)

时间:2024-04-03 15:33:08

HTML代码:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta name="viewport"
			content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
		<title></title>
		<link rel="stylesheet" type="text/css" href="style.css" />
	</head>
	<body>
        <section class="upload-section">
		    <article class="upload-piclist">
			    <div class="upload-file">
						<input type="file" id="file" accept="image/*" multiple onchange="imgChange()" />
				</div>
			</article>
		</section>
		<button id='subBtn'>提交</button>

    </body>

</html>

JS代码:

(1)拍照、相册选择

let picmax = 5; //限制上传数量 
function imgChange() {
	let file = document.getElementById('file').files;
	let imglist = document.querySelectorAll('.upload-Picitem');
	let piclist = document.getElementsByClassName('upload-piclist')[0];
	let filelist = file.length + imglist.length > picmax ? 5 - imglist.length : file.length + imglist.length;
	if (file.length + imglist.length >= 5) { // 当图片个数大于等于5时,隐藏上传按钮
		let uploadfile = document.getElementsByClassName('upload-file')[0]
		uploadfile.style.display = "none"
	}
	for (let i = 0; i < filelist; i++) {
		readerfile(file[i]).then(e => {
			// 对生成的base64照片进行压缩
			//  第一个参数就是需要压缩的base64
			// 第二个是压缩系数 0-1,
			// 第三个压缩后的回调 用来获取压缩处理后的 base64
			compressImg(e,0.5,buildImgDiv);
		})
	}
}

(2)照片压缩

function compressImg (base64, multiple,callback) {
  // 第一个参数就是需要加密的base64,
  // 第二个是压缩系数 0-1,
  // 第三个压缩后的回调 用来获取处理后的 base64
  if (!base64) {
	return
  }
  // const _this = this
  const length = base64.length / 1024
  // 压缩方法
  let newImage = new Image()
  let quality = 0.6    // 压缩系数0-1之间
  newImage.src = base64
  newImage.setAttribute('crossOrigin', 'Anonymous') // url为外域时需要
  let imgWidth,
	  imgHeight
  let w = undefined
  newImage.onload = function () {
	// 这里面的 this 指向 newImage
	// 通过改变图片宽高来实现压缩
	w = this.width * multiple
	imgWidth = this.width
	imgHeight = this.height
	let canvas = document.createElement('canvas')
	let ctx = canvas.getContext('2d')
	if (Math.max(imgWidth, imgHeight) > w) {
	  if (imgWidth > imgHeight) {
		canvas.width = w
		// 等比例缩小
		canvas.height = w * (imgHeight / imgWidth)
	  } else {
		canvas.height = w
		// 等比例缩小
		canvas.width = w * (imgWidth / imgHeight)
	  }
	} else {
	  canvas.width = imgWidth
	  canvas.height = imgHeight
	  // quality 设置转换为base64编码后图片的质量,取值范围为0-1  没什么压缩效果
	  // 还是得通过设置 canvas 的宽高来压缩
	  quality = 0.6
	}
	ctx.clearRect(0, 0, canvas.width, canvas.height)
	ctx.drawImage(this, 0, 0, canvas.width, canvas.height) //  // 这里面的 this 指向 newImage
	let smallBase64 = canvas.toDataURL('image/jpeg', quality) // 压缩语句
	// 如想确保图片压缩到自己想要的尺寸,如要求在50-150kb之间,请加以下语句,quality初始值根据情况自定
	// while (smallBase64.length / 1024 > 150) {
	// quality -= 0.01;
	// smallBase64 = canvas.toDataURL("image/jpeg", quality);
	// }
	// 防止最后一次压缩低于最低尺寸,只要quality递减合理,无需考虑
	// while (smallBase64.length / 1024 < 50) {
	// quality += 0.001;
	// smallBase64 = canvas.toDataURL("image/jpeg", quality);
	// }
 
	// 必须通过回调函数返回,否则无法及时拿到该值,回调函数异步执行
	console.log(`压缩前:${length}KB`)
	console.log(`压缩后:${smallBase64.length / 1024} KB`);
	
	callback(smallBase64)
  }
}

(3)接收压缩后的base64照片,组装前端

// 压缩完成后的回调函数,接收压缩后的base64
function buildImgDiv(imgBase64){
	let piclist = document.getElementsByClassName('upload-piclist')[0];
					
	let html = document.createElement('div');
	html.className = 'upload-Picitem';
	html.innerHTML = '<img src=' + imgBase64 + ' alt="pic">';
	html.innerHTML += '<span class="closeClass"></span>';
	piclist.appendChild(html);
	
	// 关闭按钮定义事件
	$(".closeClass").unbind('click').bind('click', function(evt) {
		evt.stopPropagation();
		evt.currentTarget.parentElement.remove()
	
		// 当图片个数小于5时,显示上传按钮
		let file2 = document.getElementById('file').files;
		let imglist2 = document.querySelectorAll('.upload-Picitem');
		console.log(file2.length + imglist2.length)
		if (file2.length + imglist2.length <= 5) {
			let uploadfile2 = document.getElementsByClassName('upload-file')[0]
			uploadfile2.style.display = "inline-block"
		}
	
	})
	
}

(4)其他用到的函数

1)readerfile,返回base64的图片

function readerfile(file) {
	return new Promise((resolve, reject) => {
		let reader = new FileReader();
		reader.addEventListener("load", function() {
			resolve(reader.result);
		}, false)
		if (file) {
			reader.readAsDataURL(file)
		}
	})
}

CSS代码(style.css)


  .upload-fh {
  	background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAYAAAA6/NlyAAAD1klEQVRoQ+XbTYhWVRgH8P8fwZUguFKi2pShbvqg2lhhG0PJlc40zQg62WhDg+jklIo1wViUNgwVTGSWWMngyvCjVdLHLrHaJaOBIIK2DHL7lweegcvL48D7vveee7xztu+d972/Ofec8zznPJe4T5qkRQC2AVgP4A8AMySvt3v7bPcP6rhe0lIAJwFsKvz+CZLb272f7MGSHnDsiy24WZKPNQosyUDWs88EsEGS3zQGLOkpx64OUG+T/LhdrF2f5SMt6QXHPhSghklOd4LNEixpo2OXBaitJL/rFJsdWFKvYxe3oO4A6Cd5phtsVmBJrwH4KgD9C+BVkj91i80GLGk3gKkA9I9jfy8DmwVY0kEAEwHoL8f+XRa2drCkDwG8E4B+A9BH8maZ2FrBkj4D8GYA+hHAKyT/KxtbG1iSRUiWCLS2045VFdjkYEm23HwPYHMAOk5yR1XQue9NFmlJskDCsC8FqCmSe6rGJuthSRYiGnZtgJogeSgFNglYkgX/hn08QI2RPJIKWzlYkqV1hn0kQL1B8ouU2ErBkixhN+zyADVA0j5L3iqZtCTZVoyBlrSILAmwNfZscqn/YOlgSf0AohTOkoBekj/XhS39kZa0E0A0Li0JMOzlOrGlgiWNAjgagCwJ6CF5tW5saWBJ7wEYD0CWBBj2Vg7YUsCSbB19KwBdcOz/uWC7BkuyzbRdAchOBfpygs7dS8eztKRvAQwEqGMkh3LEdtzDkj4CMBagJkna5JVt66iHJUX56jjJ97OVdhN4SLJtGdueaW3N7GFTLqgxPNetC2qWLqDtUGtf8Hif93CyOetwAf0ugGjC+tXRzYm0Cui9AD4JevpPRzcnli6gXwfwZYC+5mGm4WttHa3D892xJAspTwXX3Pae/qVOcelgX7JednS042F58bm60JWAHb3Ot3lWBDg7N5qpA10Z2NFPO/rRADdE8lhqdKVgR69y9BMBbpTkZEp05WBHP+jo5wJc0qQjCdjRdrZkOfSGAJ0s6UgGdrSdHhq6J0An2ThICi4EKMcBDAZom7mtgKUZ58NFoCQrYrFiltZmSYehm1MBUOjpwwAOBGhLOgzdnBqPAno/gA8CtMXdhr5S5rJVyxhuBUgaAfBpALOkw9CXykJnAfYZ3Iq9vw5glnQY+mIZ6GzAjt7iJ49RraWhf+gWnRXY0RaY2Frd/GrawkT2vFfVPhz0aLPqpQvoJx29JkA3qyK+gF7p6GcD9AjJz9sd09mN4WDJutdbLTdIRq8IzPs/yB7sE9nCeW+p8Hjbm2nDAKwcahbAdGPfTGt3nM53/V00ckNMKWY8LAAAAABJRU5ErkJggg==');
  	background-repeat: no-repeat;
  	background-size: 100% 100%;
  	height: 30px;
  	width: 30px;
  }

  .upload-hedaer {
  	height: 55px;
  	display: grid;
  	grid-template-columns: repeat(3, 1fr);
  	padding: 0 10px;
  	box-sizing: border-box;
  	align-items: center;
  	text-align: center;
  	background: #287cff;
  	color: #fff;
  	border-bottom: 1px solid #efefef;
  	font-size: 19px;
  }

  .upload-hedaer div:last-child {
  	text-align: right;
  }

  .upload-textarea {
  	width: 100%;
  	height: 60px;
  	font-size: 28px;
  	border: 1px solid #efefee;
  	max-height: 300px;
  }

  .upload-article-text {
  	width: 100%;
  	padding: 10px;
  	box-sizing: border-box;
  }

  .upload-file {
  	position: relative;
  	background: url('../../../images/z_add.png') no-repeat 50%/100% 100%;
  	/* width: 100px; */
  	height: 120px;
  	order: 9;
  }

  .upload-piclist {
  	padding: 0 10px;
  	box-sizing: border-box;
  	display: grid;
  	grid-template-columns: repeat(3, 120px);
  	justify-content: space-evenly;
  	grid-gap: 14px;
  }

  #file {
  	width: 100%;
  	height: 100%;
  	opacity: 0;
  }

  .upload-Picitem {
  	width: 100%;
  	height: 120px;
	position: relative;
  }

  .upload-Picitem>img {
  	width: 100%;
  	height: 100%;
  	object-fit: cover;
  }
  .upload-Picitem>.closeClass {
	display: inline-block;
	width: 32px;
	height: 32px;
  	background-image: url(../../../images/close3.png);
	position: absolute;
	top: 0px;
	right: 0px;
	z-index: 99999; 
  }

  .submit {
  	padding: 15px 0;
  	background-color: #287cff;
  	color: #fff;
  	text-align: center;
  	margin: 10px;
  	font-size: 20px;
  	border-radius: 10px;
  }

  .upload-sm {
  	padding: 10px;
  	box-sizing: border-box;
  	color: gray;
  }

  .upload-sm ol>li {
  	margin-bottom: 10px;
  }