thinkphp5整合H-ui後臺(五)整合webUploader
阿新 • • 發佈:2019-02-04
在所有的程式語言中,都有對檔案上傳處理的知識點,這裡不多贅述。在H-ui中,有一個功能強大的檔案上傳元件webUploader,今天就來說明和整合一下它。
先看一下webUploader整合後的效果:
1、頁面中使用webUploader
這裡就以部落格的增加頁面(blogAdd.html)為例,首先在頁面中引入webUploader所需要的css樣式和js檔案:
2、webUploader的一些配置
例項化webUploader中,配置webUploader與後臺訪問的路徑、上傳檔案的數量等等,如圖:
配置到了這裡,其實webUploader的頁面配置就已經差不多了。另外一些細節的配置,這裡舉一個例子,如果客戶操作的時候,上傳的數量超出了我們配置的數量,我們怎麼友好提示呢?如圖:
在webUploader中,有許多自定義的錯誤編碼,如圖:
我們只要按照這些編碼在錯誤事件中註冊就行:
在測試過程中,如果報出其餘的錯誤編碼,那麼只要根據錯誤編碼的意思對映對應的中文描述就行
3、後臺處理webUploader的上傳
我們在配置中訪問後臺的路徑是server: '__URL__/webuploader/fileUpload',所以我們建立一個與之對應的類WebuploaderController.php,那麼這個類的fileUpload函式其實就是將webuploader傳到後臺的檔案有我們自己的邏輯儲存到指定的目錄,並返回網頁訪問的URL,這裡直接上程式碼:
其中,image_url是我們自定義的表單隱藏域,用於存放於資料庫中。
最後通過webuploader上傳的檔案放置在了'../public/image/single/日期資料夾'中。
4、其它說明
webUploader多張圖片的上傳其實和單圖上傳差不多,webUploader也是一張一張的輪流上傳,只是我們在處理的時候要動態的獲取每張圖片的名稱,好進一步處理對應的訪問URL。
先看一下webUploader整合後的效果:
1、頁面中使用webUploader
這裡就以部落格的增加頁面(blogAdd.html)為例,首先在頁面中引入webUploader所需要的css樣式和js檔案:
<link href="__ADMIN__/lib/webuploader/0.1.5/webuploader.css" rel="stylesheet" type="text/css" /> <script type="text/javascript" src="__ADMIN__/lib/webuploader/0.1.5/webuploader.min.js"></script>
然後是複製webUploader示例中的html程式碼:
webUploader初始化和配置程式碼(有點長):<input type="hidden" id="image_url" name="image_url" /> <div class="row cl"> <label class="form-label col-xs-4 col-sm-2">縮圖:</label> <div class="formControls col-xs-8 col-sm-9"> <div class="uploader-list-container"> <div class="queueList"> <div id="dndArea" class="placeholder"> <div id="filePicker-2"></div> <!-- <p> 當前元件的說明 --> <p>縮圖,只能選擇一張</p> </div> </div> <div class="statusBar" style="display:none;"> <div class="progress"> <span class="text">0%</span> <span class="percentage"></span> </div> <div class="info"></div> <div class="btns"> <div id="filePicker2"></div> <div class="uploadBtn">開始上傳</div> </div> </div> </div> </div> </div>
我們這麼一鍋粥的將程式碼copy過來,看上去webupload好像很複雜,有點無從下手的感覺。然而很多的程式碼都只是webupload自己需要呼叫的一些自定義函式,我們只要拿來用就可以。接下來我們詳細討論下webUploader的配置<script type="text/javascript"> /*WebUploader 圖片上傳初始化配置*/ (function( $ ){ // 當domReady的時候開始初始化 $(function() { var $wrap = $('.uploader-list-container'), // 圖片容器 $queue = $( '<ul class="filelist"></ul>' ) .appendTo( $wrap.find( '.queueList' ) ), // 狀態列,包括進度和控制按鈕 $statusBar = $wrap.find( '.statusBar' ), // 檔案總體選擇資訊。 $info = $statusBar.find( '.info' ), // 上傳按鈕 $upload = $wrap.find( '.uploadBtn' ), // 沒選擇檔案之前的內容。 $placeHolder = $wrap.find( '.placeholder' ), $progress = $statusBar.find( '.progress' ).hide(), // 新增的檔案數量 fileCount = 0, // 新增的檔案總大小 fileSize = 0, // 優化retina, 在retina下這個值是2 ratio = window.devicePixelRatio || 1, // 縮圖大小 thumbnailWidth = 110 * ratio, thumbnailHeight = 110 * ratio, // 可能有pedding, ready, uploading, confirm, done. state = 'pedding', // 所有檔案的進度資訊,key為file id percentages = {}, // 判斷瀏覽器是否支援圖片的base64 isSupportBase64 = ( function() { var data = new Image(); var support = true; data.onload = data.onerror = function() { if( this.width != 1 || this.height != 1 ) { support = false; } } data.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=="; return support; } )(), // 檢測是否已經安裝flash,檢測flash的版本 flashVersion = ( function() { var version; try { version = navigator.plugins[ 'Shockwave Flash' ]; version = version.description; } catch ( ex ) { try { version = new ActiveXObject('ShockwaveFlash.ShockwaveFlash') .GetVariable('$version'); } catch ( ex2 ) { version = '0.0'; } } version = version.match( /\d+/g ); return parseFloat( version[ 0 ] + '.' + version[ 1 ], 10 ); } )(), supportTransition = (function(){ var s = document.createElement('p').style, r = 'transition' in s || 'WebkitTransition' in s || 'MozTransition' in s || 'msTransition' in s || 'OTransition' in s; s = null; return r; })(), // WebUploader例項 uploader; if ( !WebUploader.Uploader.support('flash') && WebUploader.browser.ie ) { // flash 安裝了但是版本過低。 if (flashVersion) { (function(container) { window['expressinstallcallback'] = function( state ) { switch(state) { case 'Download.Cancelled': alert('您取消了更新!') break; case 'Download.Failed': alert('安裝失敗') break; default: alert('安裝已成功,請重新整理!'); break; } delete window['expressinstallcallback']; }; var swf = 'expressInstall.swf'; // insert flash object var html = '<object type="application/' + 'x-shockwave-flash" data="' + swf + '" '; if (WebUploader.browser.ie) { html += 'classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" '; } html += 'width="100%" height="100%" style="outline:0">' + '<param name="movie" value="' + swf + '" />' + '<param name="wmode" value="transparent" />' + '<param name="allowscriptaccess" value="always" />' + '</object>'; container.html(html); })($wrap); // 壓根就沒有安轉。 } else { $wrap.html('<a href="http://www.adobe.com/go/getflashplayer" target="_blank" border="0"><img alt="get flash player" src="http://www.adobe.com/macromedia/style_guide/images/160x41_Get_Flash_Player.jpg" /></a>'); } return; } else if (!WebUploader.Uploader.support()) { alert( 'Web Uploader 不支援您的瀏覽器!'); return; } // 例項化 uploader = WebUploader.create({ pick: { id: '#filePicker-2', label: '點選選擇圖片' }, formData: { uid: 123 }, dnd: '#dndArea', paste: '#uploader', swf: '__ADMIN__/lib/webuploader/0.1.5/Uploader.swf', chunked: false, chunkSize: 512 * 1024, server: '__URL__/webuploader/fileUpload', // runtimeOrder: 'flash', // accept: { // title: 'Images', // extensions: 'gif,jpg,jpeg,bmp,png', // mimeTypes: 'image/*' // }, // 不壓縮image, 預設如果是jpeg,檔案上傳前會壓縮一把再上傳! resize: false, // 只允許選擇圖片檔案。 accept: { title: 'Images', extensions: 'gif,jpg,jpeg,bmp,png', mimeTypes: 'image/*' }, // 禁掉全域性的拖拽功能。這樣不會出現圖片拖進頁面的時候,把圖片開啟。 disableGlobalDnd: true, fileNumLimit: 5, fileSizeLimit: 200 * 1024 * 1024, // 200 M fileSingleSizeLimit: 50 * 1024 * 1024 // 50 M }); // 拖拽時不接受 js, txt 檔案。 uploader.on( 'dndAccept', function( items ) { var denied = false, len = items.length, i = 0, // 修改js型別 unAllowed = 'text/plain;application/javascript '; for ( ; i < len; i++ ) { // 如果在列表裡面 if ( ~unAllowed.indexOf( items[ i ].type ) ) { denied = true; break; } } return !denied; }); uploader.on('dialogOpen', function() { console.log('here'); }); // uploader.on('filesQueued', function() { // uploader.sort(function( a, b ) { // if ( a.name < b.name ) // return -1; // if ( a.name > b.name ) // return 1; // return 0; // }); // }); // 新增“新增檔案”的按鈕, uploader.addButton({ id: '#filePicker2', label: '繼續新增' }); uploader.addButton({ id: '#filePicker', label: '選擇檔案', multiple : true }); uploader.on('ready', function() { window.uploader = uploader; }); // 當有檔案新增進來時執行,負責view的建立 function addFile( file ) { var $li = $( '<li id="' + file.id + '">' + '<p class="title">' + file.name + '</p>' + '<p class="imgWrap"></p>'+ '<p class="progress"><span></span></p>' + '</li>' ), $btns = $('<div class="file-panel">' + '<span class="cancel">刪除</span>' + '<span class="rotateRight">向右旋轉</span>' + '<span class="rotateLeft">向左旋轉</span></div>').appendTo( $li ), $prgress = $li.find('p.progress span'), $wrap = $li.find( 'p.imgWrap' ), $info = $('<p class="error"></p>'), showError = function( code ) { switch( code ) { case 'exceed_size': text = '檔案大小超出'; break; case 'interrupt': text = '上傳暫停'; break; default: text = '上傳失敗,請重試'; break; } $info.text( text ).appendTo( $li ); }; if ( file.getStatus() === 'invalid' ) { showError( file.statusText ); } else { // @todo lazyload $wrap.text( '預覽中' ); uploader.makeThumb( file, function( error, src ) { var img; if ( error ) { $wrap.text( '不能預覽' ); return; } if( isSupportBase64 ) { img = $('<img src="'+src+'">'); $wrap.empty().append( img ); } else { $.ajax('lib/webuploader/0.1.5/server/preview.php', { method: 'POST', data: src, dataType:'json' }).done(function( response ) { if (response.result) { img = $('<img src="'+response.result+'">'); $wrap.empty().append( img ); } else { $wrap.text("預覽出錯"); } }); } }, thumbnailWidth, thumbnailHeight ); percentages[ file.id ] = [ file.size, 0 ]; file.rotation = 0; } file.on('statuschange', function( cur, prev ) { if ( prev === 'progress' ) { $prgress.hide().width(0); } else if ( prev === 'queued' ) { $li.off( 'mouseenter mouseleave' ); $btns.remove(); } // 成功 if ( cur === 'error' || cur === 'invalid' ) { console.log( file.statusText ); showError( file.statusText ); percentages[ file.id ][ 1 ] = 1; } else if ( cur === 'interrupt' ) { showError( 'interrupt' ); } else if ( cur === 'queued' ) { percentages[ file.id ][ 1 ] = 0; } else if ( cur === 'progress' ) { $info.remove(); $prgress.css('display', 'block'); } else if ( cur === 'complete' ) { $li.append( '<span class="success"></span>' ); } $li.removeClass( 'state-' + prev ).addClass( 'state-' + cur ); }); $li.on( 'mouseenter', function() { $btns.stop().animate({height: 30}); }); $li.on( 'mouseleave', function() { $btns.stop().animate({height: 0}); }); $btns.on( 'click', 'span', function() { var index = $(this).index(), deg; switch ( index ) { case 0: uploader.removeFile( file ); return; case 1: file.rotation += 90; break; case 2: file.rotation -= 90; break; } if ( supportTransition ) { deg = 'rotate(' + file.rotation + 'deg)'; $wrap.css({ '-webkit-transform': deg, '-mos-transform': deg, '-o-transform': deg, 'transform': deg }); } else { $wrap.css( 'filter', 'progid:DXImageTransform.Microsoft.BasicImage(rotation='+ (~~((file.rotation/90)%4 + 4)%4) +')'); // use jquery animate to rotation // $({ // rotation: rotation // }).animate({ // rotation: file.rotation // }, { // easing: 'linear', // step: function( now ) { // now = now * Math.PI / 180; // var cos = Math.cos( now ), // sin = Math.sin( now ); // $wrap.css( 'filter', "progid:DXImageTransform.Microsoft.Matrix(M11=" + cos + ",M12=" + (-sin) + ",M21=" + sin + ",M22=" + cos + ",SizingMethod='auto expand')"); // } // }); } }); $li.appendTo( $queue ); } // 負責view的銷燬 function removeFile( file ) { var $li = $('#'+file.id); delete percentages[ file.id ]; updateTotalProgress(); $li.off().find('.file-panel').off().end().remove(); } function updateTotalProgress() { var loaded = 0, total = 0, spans = $progress.children(), percent; $.each( percentages, function( k, v ) { total += v[ 0 ]; loaded += v[ 0 ] * v[ 1 ]; } ); percent = total ? loaded / total : 0; spans.eq( 0 ).text( Math.round( percent * 100 ) + '%' ); spans.eq( 1 ).css( 'width', Math.round( percent * 100 ) + '%' ); updateStatus(); } function updateStatus() { var text = '', stats; if ( state === 'ready' ) { text = '選中' + fileCount + '張圖片,共' + WebUploader.formatSize( fileSize ) + '。'; } else if ( state === 'confirm' ) { stats = uploader.getStats(); if ( stats.uploadFailNum ) { text = '已成功上傳' + stats.successNum+ '張照片至XX相簿,'+ stats.uploadFailNum + '張照片上傳失敗,<a class="retry" href="#">重新上傳</a>失敗圖片或<a class="ignore" href="#">忽略</a>' } } else { stats = uploader.getStats(); text = '共' + fileCount + '張(' + WebUploader.formatSize( fileSize ) + '),已上傳' + stats.successNum + '張'; if ( stats.uploadFailNum ) { text += ',失敗' + stats.uploadFailNum + '張'; } } $info.html( text ); } function setState( val ) { var file, stats; if ( val === state ) { return; } $upload.removeClass( 'state-' + state ); $upload.addClass( 'state-' + val ); state = val; switch ( state ) { case 'pedding': $placeHolder.removeClass( 'element-invisible' ); $queue.hide(); $statusBar.addClass( 'element-invisible' ); uploader.refresh(); break; case 'ready': $placeHolder.addClass( 'element-invisible' ); $( '#filePicker2' ).removeClass( 'element-invisible'); $queue.show(); $statusBar.removeClass('element-invisible'); uploader.refresh(); break; case 'uploading': $( '#filePicker2' ).addClass( 'element-invisible' ); $progress.show(); $upload.text( '暫停上傳' ); break; case 'paused': $progress.show(); $upload.text( '繼續上傳' ); break; case 'confirm': $progress.hide(); $( '#filePicker2' ).removeClass( 'element-invisible' ); $upload.text( '開始上傳' ); stats = uploader.getStats(); if ( stats.successNum && !stats.uploadFailNum ) { setState( 'finish' ); return; } break; case 'finish': stats = uploader.getStats(); if ( stats.successNum ) { alert( '上傳成功' ); } else { // 沒有成功的圖片,重設 state = 'done'; location.reload(); } break; } updateStatus(); } // 檔案上傳成功,給item新增成功class, 用樣式標記上傳成功。 /* uploader.on( 'uploadSuccess', function( file,data ) { alert(data.msg + "_" + data.success); $( '#'+file.id ).addClass('upload-state-success').find(".state").text("已上傳"); }); */ uploader.onUploadSuccess = function(file,data){ //上傳成功後,設定圖片訪問路徑 data = eval(data); if(data.success){ var imgurl = data.msg; $("#image_url").val(imgurl); } }; uploader.onUploadProgress = function( file, percentage ) { var $li = $('#'+file.id), $percent = $li.find('.progress span'); $percent.css( 'width', percentage * 100 + '%' ); percentages[ file.id ][ 1 ] = percentage; updateTotalProgress(); }; uploader.onFileQueued = function( file ) { fileCount++; fileSize += file.size; if ( fileCount === 1 ) { $placeHolder.addClass( 'element-invisible' ); $statusBar.show(); } addFile( file ); setState( 'ready' ); updateTotalProgress(); }; uploader.onFileDequeued = function( file ) { fileCount--; fileSize -= file.size; if ( !fileCount ) { setState( 'pedding' ); } removeFile( file ); updateTotalProgress(); }; uploader.on( 'all', function( type ) { var stats; switch( type ) { case 'uploadFinished': setState( 'confirm' ); break; case 'startUpload': setState( 'uploading' ); break; case 'stopUpload': setState( 'paused' ); break; } }); uploader.onError = function( code ) { if(code == 'Q_EXCEED_NUM_LIMIT'){ alert("縮圖只能上傳一張圖片"); return; } alert( 'Error: ' + code ); }; $upload.on('click', function() { if ( $(this).hasClass( 'disabled' ) ) { return false; } if ( state === 'ready' ) { uploader.upload(); } else if ( state === 'paused' ) { uploader.upload(); } else if ( state === 'uploading' ) { uploader.stop(); } }); $info.on( 'click', '.retry', function() { uploader.retry(); } ); $info.on( 'click', '.ignore', function() { alert( 'todo' ); } ); $upload.addClass( 'state-' + state ); updateTotalProgress(); }); })( jQuery ); </script>
2、webUploader的一些配置
例項化webUploader中,配置webUploader與後臺訪問的路徑、上傳檔案的數量等等,如圖:
配置到了這裡,其實webUploader的頁面配置就已經差不多了。另外一些細節的配置,這裡舉一個例子,如果客戶操作的時候,上傳的數量超出了我們配置的數量,我們怎麼友好提示呢?如圖:
在webUploader中,有許多自定義的錯誤編碼,如圖:
我們只要按照這些編碼在錯誤事件中註冊就行:
在測試過程中,如果報出其餘的錯誤編碼,那麼只要根據錯誤編碼的意思對映對應的中文描述就行
3、後臺處理webUploader的上傳
我們在配置中訪問後臺的路徑是server: '__URL__/webuploader/fileUpload',所以我們建立一個與之對應的類WebuploaderController.php,那麼這個類的fileUpload函式其實就是將webuploader傳到後臺的檔案有我們自己的邏輯儲存到指定的目錄,並返回網頁訪問的URL,這裡直接上程式碼:
<?php
namespace app\admin\controller;
use think\Controller;
use think\Exception;
use think\Request;
/**
*
* @author tim
*
*/
class WebuploaderController extends Controller
{
/**
* 1、獲取圖片並且儲存到伺服器指定的目錄下
* 2、生成圖片的URL訪問路徑,並返回
* */
public function fileUpload(Request $request){
try{
//獲取圖片物件
$filetemp = $request->file('file');
//存放伺服器上地址
$serverFile = $filetemp->move(ROOT_PATH.'/public/upload/image/single');
//訪問地址
$imageUrl = 'http://'.$_SERVER['HTTP_HOST'].str_replace(ROOT_PATH.'/public', '', $serverFile->getPathname());
$ajaxJson['success'] = true;
$ajaxJson['msg'] = $imageUrl;
}catch(Exception $e){
$ajaxJson['success'] = false;
}
return json_encode($ajaxJson);
}
}
當我們上傳成功後,頁面將返回訪問當前圖片的URL資訊獲取下來,其中,image_url是我們自定義的表單隱藏域,用於存放於資料庫中。
最後通過webuploader上傳的檔案放置在了'../public/image/single/日期資料夾'中。
4、其它說明
webUploader多張圖片的上傳其實和單圖上傳差不多,webUploader也是一張一張的輪流上傳,只是我們在處理的時候要動態的獲取每張圖片的名稱,好進一步處理對應的訪問URL。