最近做的是一個前後臺分離的項目,而Ueditor上傳圖片是要與服務器後臺交互,所以一直找一個簡單的方法,能讓ueditor直接上傳圖片到七牛雲,然後ueditor引入圖片鏈接就好了。上傳圖片不經過自己應用後臺,提高系統的吞吐量。
該效果的原理是使用自定義工具觸發js上傳到七牛雲,並添加到ueditor的內容中
效果演示
使用自定義工具欄上傳圖片到七牛雲,先看看演示效果
工具欄上添加了一個插入圖片的按鈕,這個按鈕的圖片是上傳到到七牛雲的,點擊這個按鈕
出現選擇圖片按鈕,點擊打開,這時候就可以看到圖片添加到編輯內容區域了
並且這個圖片鏈接是引用七牛雲的
實現原理
首先是添加自定義工具欄按鈕,需要編寫以下幾步代碼:
注:不要用min.js,否則無法修改源碼
(1)啓用自定義按鈕:在ueditor.config.js配置中添加自定義的按鈕名稱,這裏我取名爲qiniuimage
(2)添加自定義按鈕到ueditor,在ueditor.all.js中搜btnCmds即可:
(3)添加自定義按鈕的註釋:注意看文件和對應位置,我都做了標註
(4)自定義按鈕圖片定義:注意看文件路徑,ueditor.css,這裏我複製了一下之前圖片按鈕的樣式,這裏說明一下,ueditor所有的工具欄按鈕圖片在一個png裏面,默認都加上了background-image屬性,所以我直接用了現成的圖片,直接指定工具欄所處位置就好了,這裏的 -380px 0px 就是image圖片標識的位置
(5)添加自定義按鈕的相應js事件:這裏解釋一下,在ueditor.all.js裏面通過UE.commands['按鈕名']添加按鈕響應事件,我直接複製了打印(print)的事件代碼修改了下
好,至此按鈕添加完成了,現在已經可以在ueditor上看到新定義的按鈕了。可以看到,我的js就是觸發上傳按鈕的單擊事件,我界面上還有個上傳按鈕(因爲我界面有多個上傳圖片的地方),具體內容參看後文
注意:必須引用非min.js,即ueditor.all.js
講到這裏我普及一下三個點,針對於對七牛雲原生api不熟的
(1) 七牛雲上傳必須關聯一個input爲file的按鈕,你選擇這個按鈕,上傳完會觸發七牛FileUploaded事件,重要的事情說三遍,
必須關聯一個input爲file的按鈕,必須關聯一個input爲file的按鈕,必須關聯一個input爲file的按鈕
(2)上面我這個app.putDataBuffer是我的一個自定義方法,請無視,主要用來保存我的想要添加圖片的位置的
(3)流程圖
下面來講解一下如何上傳圖片到到七牛雲,首先根據官方sdk文檔,copy了一下代碼,並對其中關鍵部分做了修改
scope.uploader = Qiniu.uploader({
runtimes: 'html5,flash,html4', // 上傳模式,依次退化
browse_button: 'pickfiles', // 上傳選擇的點選按鈕,必需
// 在初始化時,uptoken,uptoken_url,uptoken_func三個參數中必須有一個被設置
// 切如果提供了多個,其優先級爲uptoken > uptoken_url > uptoken_func
// 其中uptoken是直接提供上傳憑證,uptoken_url是提供了獲取上傳憑證的地址,如果需要定製獲取uptoken的過程則可以設置uptoken_func
uptoken: app.getDataBuffer("qiniuToken"), // uptoken是上傳憑證,由其他程序生成
// uptoken_url: '/uptoken', // Ajax請求uptoken的Url,強烈建議設置(服務端提供)
//uptoken_func: function(){ // 在需要獲取uptoken時,該方法會被調用
// // do something
// return uptoken;
//},
get_new_uptoken: false, // 設置上傳文件的時候是否每次都重新獲取新的uptoken
// downtoken_url: '/downtoken',
// Ajax請求downToken的Url,私有空間時使用,JS-SDK將向該地址POST文件的key和domain,服務端返回的JSON必須包含url字段,url值爲該文件的下載地址
unique_names: true, // 默認false,key爲文件名。若開啓該選項,JS-SDK會爲每個文件自動生成key(文件名)
// save_key: true, // 默認false。若在服務端生成uptoken的上傳策略中指定了sava_key,則開啓,SDK在前端將不對key進行任何處理
domain: 'http://p357khip9.bkt.clouddn.com', // bucket域名,下載資源時用到,必需
container: 'publish-add-button', // 上傳區域DOM ID,默認是browser_button的父元素
max_file_size: '100mb', // 最大文件體積限制
flash_swf_url: 'path/of/plupload/Moxie.swf', //引入flash,相對路徑
max_retries: 3, // 上傳失敗最大重試次數
dragdrop: true, // 開啓可拖曳上傳
drop_element: 'container', // 拖曳上傳區域元素的ID,拖曳文件或文件夾後可觸發上傳
chunk_size: '4mb', // 分塊上傳時,每塊的體積
auto_start: true, // 選擇文件後自動上傳,若關閉需要自己綁定事件觸發上傳
//x_vars : {
// 查看自定義變量
// 'time' : function(up,file) {
// var time = (new Date()).getTime();
// do something with 'time'
// return time;
// },
// 'size' : function(up,file) {
// var size = file.size;
// do something with 'size'
// return size;
// }
//},
init: {
'FilesAdded': function(up, files) {
plupload.each(files, function(file) {
// 文件添加進隊列後,處理相關的事情
});
},
'BeforeUpload': function(up, file) {
// 每個文件上傳前,處理相關的事情
},
'UploadProgress': function(up, file) {
// 每個文件上傳時,處理相關的事情
},
'FileUploaded': function(up, file, info) {
//獲取圖片鏈接
var domain = up.getOption('domain');
var res = JSON.parse(info.response);
var sourceLink = domain + "/" + res.key;
if(app.getDataBuffer("picposition") == 'mainPic'){
scope.view.item.mainPic = sourceLink;
}
if(app.getDataBuffer("picposition") == 'content'){
scope.editor.execCommand('inserthtml','<img src="'+sourceLink+'"/>');
}
},
'Error': function(up, err, errTip) {
debugger;
//上傳出錯時,處理相關的事情
},
'UploadComplete': function() {
//隊列文件處理完畢後,處理相關的事情
},
'Key': function(up, file) {
// 若想在前端對每個文件的key進行個性化處理,可以配置該函數
// 該配置必須要在unique_names: false,save_key: false時才生效
var key = "";
// do something with key here
return key
}
}
});
注:這個scope.uploader只是爲了保存qiniu的實例,你這麼寫 var myQiniu = new Qiniu(...)效果完全一樣
其中有幾個必須字段需要說明下(也就是需要自己定義的地方),
browse_button: 上傳圖片按鈕的ID,點擊該按鈕觸發圖片上傳
container:上傳圖片按鈕的容器ID(父級domid),點擊該dom觸發圖片上傳
uptoken:上傳憑證,由後臺生成。這裏有兩個生成策略,一個是一次生成長期使用(我採用的,獲取後存在全局中),一個是每個憑證是一次性使用,每次請求都要重新生成。這個根據你們自己的後臺邏輯傳值
get_new_uptoken:false表示每次上傳不重新獲取上傳憑證
unique_names:true若開啓該選項,JS-SDK會爲每個文件自動生成key(文件名)
domain:bucket域名,下載資源時用到,必需,這個是後臺給的,相當於名字
這裏貼一下我的dom結構
<li v-show="!item.mainPic" id="publish-add-button" class="pics addbutton">
<img src="../../images/pic_add.png" @click="openFileDialog" />
<input type="file" style="display: none" id="pickfiles" accept="image/jpeg,image/jpg,image/png" />
</li>
最後一個關鍵的就是上傳成功回調事件了
'FileUploaded': function(up, file, info) {
//獲取圖片鏈接
var domain = up.getOption('domain');
var res = JSON.parse(info.response);
var sourceLink = domain + "/" + res.key;
if(app.getDataBuffer("picposition") == 'mainPic'){
scope.view.item.mainPic = sourceLink;
}
if(app.getDataBuffer("picposition") == 'content'){
scope.editor.execCommand('inserthtml','<img src="'+sourceLink+'"/>');
}
},
這裏獲取的sourceLink就是圖片的全路徑了,app.getDataBuffer和app.putDataBuffer是獲取和設置全局變量的地方。前文我也說過,我界面上有多處上傳圖片的地方,我用了一個全局變量保存我這次添加圖片的位置,然後觸發添加圖片的按鈕,最後上傳成功後判斷圖片應該添加到哪個位置。
最後使用ueditor的exeCommand函數,插入了一段html,這個html就是img
至此,所有功能完成。
總結
通過觸發ueditor自定義按鈕方式,觸發自定義上傳圖片代碼,完美繞過ueditor的上傳圖片機制(與後臺交互),使得圖片上傳不消耗應用服務器的流量,提高了系統的吞吐量和性能。