1. 在HTML文件中引入需要的文件。
<!-- 引入批量上傳的插件 -->
<link href="/public/admin/diyUpload/css/webuploader.css" rel="stylesheet" type="text/css" />
<link href="/public/admin/diyUpload/css/diyUpload.css" rel="stylesheet" type="text/css" />
<!-- 依賴於Jquery,如果在頭文件中已經引入,此處可註釋 -->
<!-- <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script> -->
<script src="/public/admin/diyUpload/js/webuploader.html5only.min.js" type="text/javascript"></script>
<script src="/public/admin/diyUpload/js/diyUpload.js" type="text/javascript"></script>
2. 在HTML文件中定義一個標籤,指定插件要加載的位置,另外定義一個隱藏表單域,用於上傳成功後保存返回的地址。
<div>
<!-- 加載批量上傳插件 -->
<div id="photoLibrary"></div>
<!-- 用隱藏表單域保存上傳成功的圖片地址,以便與其它數據一起提交 -->
<div id="photoList"></div>
</div>
3. 在HTML文件中加載插件。
<script>
// 初始化批量上傳插件
$(function () {
let photoStr = "";
$('#photoLibrary').diyUpload({
// 上傳的路由器地址
url: '/admin/goods/goodsUploadPhoto',
success: function (response) {
// 將上傳的址址放到臨時的隱藏表單域中,與其它字段一起提交
photoStr = '<input type="hidden" name="goods_image_list[]" value="' + response.link + '"></input>';
$('#photoList').append(photoStr);
},
error: function (data) {
console.log(data);
}
})
})
</script>
4. 配置初始化插件中上傳圖片的地址。
// router.js
'use strict';
module.exports = app => {
const { router, controller } = app;
router.post('/admin/goods/goodsUploadPhoto',controller.admin.goods.goodsUploadPhoto);
};
5. 爲插件上傳圖片的路由編寫控制器。
// app/controller/admin/goods.js
'use strict';
const Fs = require('fs');
// cnpm i mz-modules --save
// 此模塊解決上傳卡死
const Pump = require('mz-modules/pump');
const Controller = require('egg').Controller;
class GoodsController extends Controller {
// 編輯器的圖片批量上傳
async goodsUploadPhoto() {
// autoFields: true 表示除了文件的其它字段
let parts = this.ctx.multipart({ autoFields: true });
let files = {}, stream;
// 循環獲取數據流
while ((stream = await parts()) != null) {
if (!stream.filename) {
// 多文件上傳時,只能break,不能return
break;
}
// 文件表單的name
let fieldname = stream.fieldname;
// 獲取上傳文件路徑與入庫保存路徑
let dir = await this.service.tools.getUploadFile(stream.filename);
// 上傳路徑
let target = dir.uploadDir;
// 寫入上傳文件
let writeStream = Fs.createWriteStream(target);
await Pump(stream, writeStream);
// 將多個上傳圖片統一拼接爲一個對象,便於訪問
files = Object.assign(files, {
[fieldname]: dir.saveDir
});
// 生成縮略圖 target爲圖片地址
this.service.tools.jimpImg(target);
}
// 返回的格式要按編輯器約定的格式
this.ctx.body = {
link: files.file
}
}
}
module.exports = GoodsController;
6. 控制器中調用服務中的getUploadFile方法。
// app/service/tools.js
'use strict';
const Path = require('path');
const Service = require('egg').Service;
// 引入格式化時間模塊
// cnpm i silly-datetime --save
const Sd = require('silly-datetime');
// 引入模塊智能生成上傳文件夾
// cnpm i mz-modules --save
const Mkdirp = require('mz-modules/mkdirp');
// 引入生成縮略圖的模塊
// cnpm install jimp --save
// https://github.com/oliver-moran/jimp/tree/master/packages/jimp
const Jimp = require('jimp');
class ToolService extends Service {
// 獲取當前時間戳
async getTime(){
let now = new Date();
return now.getTime();
}
// 處理要上傳的文件名
async getUploadFile(filename){
// 獲取當前日期
let now = Sd.format(new Date(),'YYYYMMDD');
// 創建文件目錄(將存放地址與日期進行拼接);
let dir = Path.join(this.config.uploadDir,now);
// 按dir去創建文件夾,如果沒有則生成,如果有則忽略
await Mkdirp(dir);
// 以時間戳命名文件
let timestamp = await this.getTime();
// 圖片的保存路徑(文件夾 + 時間戳 + 後輟名)
let uploadDir = Path.join(dir,timestamp + Path.extname(filename));
return{
// 上傳的地址
uploadDir:uploadDir,
// 保存在數據庫的地址
saveDir:uploadDir.slice(3).replace(/\\/g,'/')
}
}
// 生成縮略圖方法
async jimpImg(target){
Jimp.read(target, (err, lenna) => {
if (err) throw err;
// 生成200乘以200大小,品質爲90,並重命名文件
lenna.resize(200,200).quality(90).write(target+'_200x200'+Path.extname(target));
})
}
}
module.exports = ToolService;
7. 處理上傳圖片時,由於Egg安全驗證機制導致無法上傳的問題。
// config/config.default.js
'use strict';
module.exports = appInfo => {
const config = exports = {};
config.keys = appInfo.name + '_1585450669767_9677';
config.session = {
key: 'SESSION_ID',
maxAge: 8640000,
httpOnly: true,
encrypt: true,
renew: true
}
// 上傳文件存放的全局地址
config.uploadDir = 'app/public/admin/upload';
// 上傳文件的配置
// https://github.com/eggjs/egg-multipart
config.multipart = {
// 允許上傳的圖片格式
whitelist: ['.png', '.jpg', '.jpeg'],
// 文件允許大小
fileSize: '50mb',
// 上傳字段的數量
fields: '50'
}
// 處理編輯器上傳圖片的安全驗證機制
exports.security = {
csrf: {
// 爲指定的URL忽略csrf驗證
ignore: ctx => {
if ( ctx.request.url == '/admin/goods/goodsUploadPhoto') {
return true;
}
return false;
},
}
}
return config
};
8. 解決上傳按鈕無法點擊的問題
#photoLibrary div:nth-child(2) {
width: 100%!important;
height: 100%!important;
}
注意:#photoLibrary即爲載插件標籤的ID。
9. 上傳效果圖