talk is cheap show me the code
參考資料
前端元件
-
具體的樣式配置可以見element-ui的官網
-
第一種配置:選擇圖片後直接上傳(action是伺服器地址,http-request是上傳到伺服器前攔截request進行處理的操作):
<el-upload class="upload-demo" ref="upload" :action=domain :http-request=uploadImage :file-list="fileList" list-type="picture-card" :before-upload="beforeUpload" multiple> <i class="el-icon-plus"></i> <div class="el-upload__tip" slot="tip">只能上傳jpg/png檔案,且不超過500kb</div> </el-upload> 複製程式碼
一個參考的uploadImage()函式配置(這裡主要需要重新命名圖片名,我使用mongoose的Types生成一個唯一的ObjectId來進行重新命名,也可以使用時間戳等方式):
async uploadImage(req) { const config = { headers: {'Content-Type': 'multipart/form-data'} }; let filetype = '' if (req.file.type === 'image/png') { filetype = 'png' } else { filetype = 'jpg' } const keyName = this.bucket + "-" + Types.ObjectId().toString() + '.' + fileType; const formdata = new FormData(); formdata.append('file', req.file); formdata.append('key', keyName); axios.post('/api/uploadImage', formdata, config) .then(res => { this.fileList.push({ name: res.data.name, url: res.data.url, }); console.log('image upload succeed.'); }) .catch(err => { console.log(err.message) }) }, 複製程式碼
注意到:我們如果將圖片上傳到一個跨域伺服器是需要進行跨域處理的,後面我們就可以使用'/api'代替伺服器地址。
① 在Vue中我們可以修改config/index.js:proxyTable: { '/api': { target: 'https://example.com', // 介面的域名 secure: false, // 如果是https介面,需要配置這個引數 changeOrigin: true, // 如果介面跨域,需要進行這個引數配置 pathRewrite: {'^/api': ''} } }, 複製程式碼
② 在Nuxt中我們可以配置nuxt.config.js:
modules: ['@nuxtjs/axios','@nuxtjs/proxy'], proxy: [ '/api', { target: 'https://example.com', pathRewrite: {'^/api': '/'} } ], 複製程式碼
-
另一種配置:點選上傳按鈕後才上傳到伺服器(主要將上傳元件的
:auto-upload
設定為false
)。如果要實現圖片預覽可以新增一個處理函式:on-change="handleSuccess"
:handleSuccess(res, files) { this.fileList = [];//因為我這裡每次上傳只選擇一張圖片,所以清空 let file = files[files.length - 1]; let name = file.name; if(this.beforeUpload(file.raw)) { let imageUrl = window.URL.createObjectURL(file.raw); this.imageFile = file;//儲存imageFile this.fileList.push({name: name, url: imageUrl}); } }, 複製程式碼
上傳到七牛雲可以對uploadImage()函式進行修改:
try { //獲取上傳憑證token let uptoken = await this.$store.dispatch('getUploadToken'); const formdata = new FormData(); formdata.append('file', this.imageFile.raw); formdata.append('token', uptoken);//新增憑證 formdata.append('key', keyName); return new Promise((resolve, reject) => { axios.post('/upQiniu', formdata, config).then(res => { this.imageUrl = 'http://' + this.qiniuaddr + '/' + res.data.key; this.fileList = []; this.imageFile = null; resolve(this.imageUrl); }); }); } catch (e) { console.log('post failed!' + e.message); } 複製程式碼
後面我們要上傳可以直接呼叫uploadImage函式非同步返回圖片上傳後的路徑
後端配置
- 上傳到七牛雲,為了避免暴露金鑰,憑證token應該從後端獲取:
const qiniu = require('qiniu') //util/onfig/qiniu.js中放置七牛雲的訪問key和金鑰 import {accessKey, secretKey} from '../util/config/qiniu' //例如我在Vuex Store的action中新增了以下函式 getUploadToken() { const mac = new qiniu.auth.digest.Mac(accessKey, secretKey); const options = { scope: 'xxxxx',//你在七牛雲的空間名字 }; const putPolicy = new qiniu.rs.PutPolicy(options); return putPolicy.uploadToken(mac); }, 複製程式碼
- 上傳到本地資料夾,express+multiparty配置圖片上傳伺服器:
router.post('/uploadImage', async(req, res, next) => { var form = new multiparty.Form(); form.uploadDir = config.imagePath; form.maxFieldsSize = 2 * 1024 * 1024; var newName; await form.parse(req, (err, fields, files) => { if(err) { return res.status(500).json({message: "upload image failed: " + err}); } newName = fields.key[0];//因為element-ui每次上傳一張圖片,所以這裡考慮取出第一個即可 let newPath = config.imagePath + newName; let originalPath = files.file[0].path; try { fs.existsSync(originalPath);//本地圖片路徑是否存在 fs.renameSync(originalPath,newPath);//重新命名,這裡最好使用renameSync強制命名 return res.status(200).json({name: newName, url: config.imageURL + newName}); } catch (error) { return res.status(500).json({message: "upload image failed: " + error}); } }); }); 複製程式碼
一些難點
一個是上傳的formdata配置,注意配置config,如果上傳失敗檢查request中的formdata是否為空;另一個是跨域配置。
一個小記錄,歡迎指教