1. 程式人生 > >input file 實現上傳預覽圖片,以base64上傳,相容IE8+,firefox,chrome

input file 實現上傳預覽圖片,以base64上傳,相容IE8+,firefox,chrome

前言

最近在公司開發一個專案,其中涉及到一個公能,主要是上傳一些小圖片,而且在網站上需要大量引用這個小圖片的,對於上傳一些小的頭像等。一開始覺得直接上傳就好了,但是發現這樣子的話,一個小圖片就會發送一個http請求資源,大量的小圖片的請求資源的話,會造成伺服器資源的負擔。而且我希望在使用者頭像上傳也可以不直接上傳image,以其他的方式上傳,可以將影象的資訊儲存在資料庫中,這樣子對於小圖片還是有好處的。經過了幾天的認真思考的查詢資料,自己寫了一個基於jquery實現的小外掛。就可以簡單的實現了小圖片的以base64的DATA URL 的協議上傳。

基本功能

1、基於外掛,可以自定義樣式,預覽框的大小

2、可以設定上傳圖片的型別,圖片的大小(建議100kb以內)

3、相容IE8+,firefox,chrom

4、以DAT URL協議實現圖片上傳前預覽,包括圖片的實際大小

5、返回上傳成功或者失敗的資訊

程式碼

previewUpload.js外掛程式碼:

;(function($){
	$.fn.previewUpload=function(options){
		/**
		*預設選項配置
		*
		*/
		var defaults={
			//預覽框的樣色設定
			'preview':{
				'border':'1px dashed',
				'width':200,//必須int 
				'height':250,//必須int 

			},
			//上傳操作框樣式,預設為空,不做設定
			'uploadImage':{},
			//選擇圖片的按鈕樣式
			'btnCss':{
				'display':'inline-block',
				'line-height':'28px',
				'font-size':'14px',
				'text-align':'center',	
				'border':'1px solid #d0d0d5',
				'border-radius':'4px',
				'padding':'0 15px',
				'min-width':'40px',
				'background-color':'#fff',
				'background-repeat':'no-repeat',
				'background-position':'center',
				'-webkit-transition':'border-color .15s, background-color .15s',
				'transition':' border-color .15s, background-color .15s',
				'outline':'0 none',
				'cursor':'pointer',
				'overflow':'visible',
				'border':'1px solid #00a5e0',
				'background-color':'#00a5e0',
				'color':'#fff',
				'float':'left',
			},
			//input file的樣式
			'inputCss':{
				'position':'absolute',
				'clip':'rect(0 0 0 0)',
			},
			//彈出框選擇檔案的型別
			'imageType':null,
			//設定圖片的大小,int
			'imgSize':100,
			// 允許上傳的圖片格式
			'typeAllow':'jpeg,jpg,png,gif',
			// 定義選擇檔案時,彈出框檔案顯示型別,預設是所有圖片
			'acceptType':'image/*',
			//讀取base64編碼的圖片資料
			'imgblod':null,
			// ajax非同步提交的資料的url
			'url':null,
			// 從php返回html元素的最外層id
			/**
			*eg:<span id="resinfo"><font color=green>上傳成功</font></span>
			*/
			'infoid':'resinfo',
			//設定返回資訊在頁面顯示的實際時間
			'statTime':2000

		}

		/**
		*繼承覆蓋預設配置
		*
		*/
		var config=$.extend(defaults,options);
			config.sizeWarming='圖片太大,請選擇小於'+config.imgSize+'kb的圖片';
			config.typeWarming='您上傳的圖片格式不正確,請重新選擇!';
			config.browerWarming='瀏覽器版本太低';
		/**
		*例項化物件this
		*將this賦值全域性的變數
		*/
		var previewUploadDiv=$(this);

		/**
		*動態建立html元素
		*
		*/
		var previewImage,uploadImage,imgTips;

		previewImage='<div class="previewImage" id="localImag"><img src="" id="preview"></div>';

		uploadImage='<div class="uploadImage" style="margin-top:5px;">\
						<label class="btn-select-img" for="img" >選擇圖片</label>\
						<form id="imgform" method="post" action='+config.url+'>\
							<input type="file" id="img" name="myimg">\
						</form>\
						<button class="btn btn-sm btn-info btn-upload-img" style="margin-left:20px;">上傳</button>\
						<span class="imgsizespan"></span>\
					</div>';
		imgTips='<div class="imgTips"style="float:left">小於'+config.imgSize+'kb的'+config.typeAllow+'</div>';

		/**
		*新增append
		*/
		previewUploadDiv.append(previewImage+uploadImage+imgTips);


		/**
		*設定樣式
		*
		*/
		//預覽框樣式
		previewUploadDiv.find('div.previewImage').css(config.preview);

		//上傳操作按鈕框上傳圖片按鈕樣式的樣式
		previewUploadDiv.find('div.uploadImage').css(config.uploadImage);

		/**上傳圖片按鈕樣式
		*滑鼠移動樣式
		*
		*/
		previewUploadDiv.find('div.uploadImage label.btn-select-img').css(config.btnCss).mouseover(function(){
			$(this).css({
				'background-color':'#00b4f5',
				'border-color': '#00b4f5',
				'color':'#fff'
			});
		}).mouseout(function(){
			$(this).css(config.btnCss);
		});


		/**input file的框的樣式,主要是將該框隱藏透明掉
		*同時指定瀏覽器接受的檔案型別,即選擇檔案彈出框的符合的檔案
		*
		*/
		previewUploadDiv.find('input#img').css(config.inputCss).attr('accept',config.acceptType);

		/**
		*圖片預覽函式
		*
		*/
		function setImagePreview(){
			//獲取圖片物件
			var imgObj=document.getElementById("img");
	 		// 獲取預覽框物件
			var imgObjPreview=document.getElementById("preview");
			//判斷獲取的物件是否存在,chrom和firefox
			if(imgObj.files && imgObj.files[0]){
				// 檢查大小和格式
				var valid=checkSize(imgObj);
				if(valid){
					//火狐下,直接設img屬性
					imgObjPreview.style.display = 'block';
					//火狐下,width,height要有單位'px'
					imgObjPreview.style.width = (config.preview.width-2)+'px';
					imgObjPreview.style.height = (config.preview.height-2)+'px';
					// imgObjPreview.src = docObj.files[0].getAsDataURL(imgObj.files[0]);
					//判斷瀏覽器的核心類別
					var URL = window.URL || window.webkitURL; 
					var objURL=URL.createObjectURL(imgObj.files[0]);

					//html5中的FileReader,將讀取圖片以base64的編碼資料
					var reader = new FileReader();
					//DATA URL 協議讀取base64編碼資料
					// 格式:data:image/gif;base64,......
					reader.readAsDataURL(imgObj.files[0]);

					//讀取資料完成,觸發一次事件函式
					if(imgObjPreview.src = objURL){
						/**每次呼叫createObjectURL的時候,一個新的URL物件就被建立了.
						*即使你已經為同一個檔案建立過一個URL. 
						*如果你不再需要這個物件,要釋放它,需要使用URL.revokeObjectURL()方法.
						*當頁面被關閉,瀏覽器會自動釋放它,但是為了最佳效能和記憶體使用,當確保不再用得到它的時候,就應該釋放它.
						*/
						//等圖片載入完畢,再釋放記憶體
						imgObjPreview.onload=function(){
							URL.revokeObjectURL(objURL);
						}
						//讀取完圖片資料觸發時間執行
						reader.onload = function(){ 
								// 將讀取的base64資料賦值配置的全域性變數
		                		config.imgblod=this.result;
		           		}
					}else{
						reader.onload = function(){
								// 將讀取的base64資料賦值配置的全域性變數
		                		config.imgblod=this.result;
		                		imgObjPreview.src=this.result;
		           		}
					}
					
           		}else{
           			return false;
           		}			 
			}else{
				//IE下,使用濾鏡
				imgObj.select();
				imgObj.blur();
				//獲取文字內容值,在IE中input type=file 選擇檔案之後input顯示的是檔案在本地的路徑
				var imgSrc = document.selection.createRange().text;
				var localImagId = document.getElementById("localImag");
				//必須設定初始大小
				localImagId.style.width =config.preview.width-2;
				localImagId.style.height =config.preview.height-2;
				//判斷格式 
				var imgType=imgSrc.split('.')[1];
				if(config.typeAllow.indexOf(imgType)==-1){
					// config.ievolid=0;
					alert(config.typeWarming);
					return false;
				}
				//獲取圖片大小
				var img=new Image();
				img.src=imgSrc;
				// 圖片載入完畢執行
				img.onload=function(e){
        			var imgSize=Math.ceil(img.fileSize/1024);
        			if(imgSize>config.imgSize){
        				img=null;
						alert(config.sizeWarming);
						return false;
					}else{
						//將圖片顯示在預覽框
						try{
							localImagId.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale)";
							localImagId.filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = imgSrc;
							previewUploadDiv.find('span.imgsizespan').text(imgSize+'kb');
						}
						catch(e)
						{
							alert(config.typeWarming);
							return false;
						}
						imgObjPreview.style.display ='none';
						document.selection.empty();
						return ;	
    				}
				}
			}
			return true;
		}

		/**
		*限制上傳圖片的大小和格式
		*firefox和chrome
		*/
		function checkSize(imgObj){
			var imgSize,imgType;
			if(imgObj.files && imgObj.files[0]){
				// 單位位元組->kb
				imgSize=Math.ceil(imgObj.files[0]['size']/1024);
				//圖片型別
				imgType=imgObj.files[0]['type'].split('/')[1];
				// 大小比較
				if(imgSize>config.imgSize){
					alert(config.sizeWarming);
					return false;
				}
				//判斷型別 
				if(config.typeAllow.indexOf(imgType)==-1){
					alert(config.typeWarming);
					return false;
				}
				previewUploadDiv.find('span.imgsizespan').text(imgSize+'kb');
				return true;
			}else{
				return true;
			}
		}

		/**
		*ajax非同步將資料post服務端
		*
		*/
		function ajaxpost(){
			previewUploadDiv.find('button.btn-upload-img').text('正在儲存');
			//支援html5的瀏覽器,IE9+
			if(config.imgblod){
				/**
				*ajax非同步提交資料
				*
				*/
				$.post(config.url,{'base64Data':config.imgblod,'type':'base64'},function(data){
					if(data){
						previewUploadDiv.find('button.btn-upload-img').text('上傳');
						previewUploadDiv.find('span.imgsizespan').html(data);
						//啟動一個非同步定時器
						setTimeout(function(){
							previewUploadDiv.find('span.imgsizespan').empty();
						},config.statTime);
					}
				});
			/**IE8以下的瀏覽器
			*只能將圖片上傳,再進行base641編碼
			*
			*/
			}else{
				//先移除iframe
				previewUploadDiv.find('iframe#uploadiframe').remove();
				//動態建立form表單上傳屬性
				previewUploadDiv.find('form#imgform').attr('enctype','multipart/form-data').attr("encoding", "multipart/form-data").attr('target','uploadiframe');
				var iframeDiv = document.createElement('div');
				iframeDiv.className='iframeDiv';
				iframeDiv.innerHTML='<iframe id="uploadiframe" name="uploadiframe" style="display:none"></iframe>';

				previewUploadDiv.append(iframeDiv);

				//立即執行回撥函式
				(function(callback){
					//表單提交上傳
					previewUploadDiv.find('form#imgform').submit();
					//setInterval() 方法返回的id控制代碼
					config.timeid=setInterval(callback,200);
				})(function(){
					//ie特有document.all
					if(document.all){
						var content=document.getElementById('uploadiframe').contentDocument.getElementById(config.infoid).innerHTML;
						if(content){
							previewUploadDiv.find('button.btn-upload-img').text('上傳');
							previewUploadDiv.find('span.imgsizespan').html(content);
							//啟動一個非同步定時器
							setTimeout(function(){
								previewUploadDiv.find('span.imgsizespan').empty();
							},config.statTime);
							//關閉setInterval()迴圈函式
							window.clearInterval(config.timeid);
						}				
					}
				});
			}
		}
		/**
		*監聽input file的檔案圖片是否改變
		*
		*/
		// juqery1.8低版本存在live(),jquery1.9+移除live(),用on()函式
		if(previewUploadDiv.find('input#img').live){
			previewUploadDiv.find('input#img').live('change',setImagePreview);
		}else{
			previewUploadDiv.find('input#img').on('change',setImagePreview);
		}
		
		/**
		*監聽是否上傳
		*
		*/
		if(previewUploadDiv.find('button.btn-upload-img').live){
			previewUploadDiv.find('button.btn-upload-img').live('click',ajaxpost);
		}else{
			previewUploadDiv.find('button.btn-upload-img').on('click',ajaxpost);
		}
				
	}
})(jQuery);
上面的程式碼裡面有一些可能一下子無法理解,建議查詢一下資料。

html的程式碼:首先引入boostrap.min.css和jquery.js和上面的previewUpload.js檔案

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>By:DragonDean</title>
<link rel="stylesheet" type="text/css" href="bootstrap.min.css">
<script type="text/javascript" src="jquery-1.11.0.min.js"></script>
<script type="text/javascript" src="previewUpload.js"></script>
</head>
<body>
<div class="main" style="margin:0 auto;width:230px;height:350px;border:1px solid;padding:5px;" >	
</div>
</body>
</html>
<script type="text/javascript">
	$('div.main').previewUpload({
		//預覽框的樣色設定
		'preview':{
			'margin':'0 auto',
			'border':'1px dashed',
			'width':220,//必須int 
			'height':250,//必須int

		},
		//彈出框選擇檔案的型別
		'url':'test.php',
		'imgSize':20000
	});
</script>
可以看到html,用法很簡單,例項化一個jquery的物件即可,下面的自定義配置需要根據previewUpload.js的defaults的配置的key對應配置,就可以設定自己的需要引數。

php程式碼

<?php
header('Content-type:text/html;charset=utf-8');
	/**
	*firefox,chrom IE9+
	*post過來的已經是base64字元編碼
	*/
	if(isset($_POST['type']) && $_POST['type']!=''){
		$base64_image_content=$_POST['base64Data'];
		/**
		*do something
		*/
	}
	/**
	*IE8以下版本的只能上傳圖片,再用php編碼base64
	*/
	else{
		if(is_uploaded_file($_FILES['myimg']['tmp_name'])){
			$image_info = getimagesize($_FILES['myimg']['tmp_name']);
			$base64_image_content = "data:{$image_info['mime']};base64," . chunk_split(base64_encode(file_get_contents($_FILES['myimg']['tmp_name'])));
			/**
			*do something
			*/
		}
	}
	// 返回
	if($base64_image_content){
		echo '<span id="resinfo"><font color=green>上傳成功</font></span>';
		}else{
			echo '<span  id="resinfo"><font color=red>上傳失敗</font></span>';
		}
 ?>
php服務端就簡單點,我這裡直接獲取post的資料就直接返回了,還需要做一下型別的判斷和大小的判斷,最後也可以將base64資料儲存在資料庫裡,可以繼續拓展。

效果圖

1、初始化的顯示


2、點選“選擇圖片”可以預覽,點選"上傳"可以上傳圖片,同時顯示圖片的大小