Vue項目中經常會遇到使用ElementUI實現圖片上傳的需求~(已完成✔)
(1)安裝官網組件Upload
打開官網有個Upload 上傳組件-通過點擊或者拖拽上傳文件:本次項目中用到了:圖片列表縮略圖結構
<!-- action-表示圖片要上傳到的後臺api地址-->
<!-- on-preview-點擊預覽圖片的時候觸發的事件-->
<!-- on-remove-點擊叉號移除圖標的時候觸發的事件-->
<!-- file-list-文件列表-->
<!-- list-type-可以設置當前上傳的圖片的預覽方式的呈現方式-->觸發的函數需要在methods裏定義一下:
handlePreview() {}, // 處理圖片預覽的時候事件
handleRemove() {} // 點擊移除圖片的處理函數
(2)判斷是否上傳成功
那麼點擊上傳圖片看看效果:可以看出來,本地上傳成功,但是不要高興的太早。F12打開看看network查看狀態:
可以看出來,本地上傳成功,但是無效的token說明上傳還沒成功
思路:本地上傳成功,還會爲什麼報錯--無效token呢??
是因爲,還記得嗎?剛開始做項目的時候我們使用axios來發送ajax請求,除了home和login登錄頁面外其他的都需要攜帶token請求頭,纔能有效訪問頁面。就是說每一次使用axios發送ajax請求都需要攜帶請求token,纔能有權限。
那麼上傳圖片的時候調用的upload方法沒有使用axios。所有報錯token無效。UI組件已經是封裝的ajax請求了,這沒帶請求頭
(3)Upload組件設置token請求頭Authorization字段
看看upload組件官網有沒有給我們通過給token值:
既然有了,那麼可以給headers設置請求頭字段Authorization。在data裏定義
//template標籤代碼
<el-upload
class="upload-demo"
action="https://www.mememem.top:8888/api/private/v1/upload"
:on-preview="handlePreview"
:on-remove="handleRemove"
list-type="picture" :headers="headersObj">
<el-button size="small" type="primary">點擊上傳</el-button>
<div slot="tip" style="font-size: 8px;margin:5px 0">只能上傳jpg/png文件,且不超過500kb</div>
</el-upload>
//data裏的代碼
// 圖片上傳組件添加Authorization請求頭對象,
// 每一次方式請求都有了token請求頭,從session裏拿到
headersObj: {
Authorization: window.sessionStorage.getItem('token')
}
(4)上傳成功!
最終都成功啦!!!效果
(5)和服務器返回地址連接
還有:後臺需要的參數裏有: pics參數。指向是服務器返回的圖片的臨時路徑:
上傳成功後F12裏有兩個返回路徑:tmp_path是服務器返回的臨時存儲路徑
下一步是:上傳成功後把服務器返回的臨時路徑對象的形式添加到pics路徑裏
怎麼監聽圖片已經成功上傳呢?只有上傳成功,立即監聽on-Success函數:
(6)刪除已上傳的圖片
已經上傳好了,下一步需要實現刪除功能。官網提供了on-remove函數,就是點擊刪除的時候出發該函數。然後我們從pics數組中刪除就可以
data裏一個tmp_path是將要刪除的臨時路徑:
★ 移除圖片有三步:
1,獲取將要刪除的圖片的臨時路徑
2,從pics數組中找到該圖片的對應的索引值
3,調用數組的splice方法,把圖片信息對象從pics數組中移除
// 獲取將要刪除的圖片的臨時路徑
const filePath = file.response.data.tmp_path
// 從pics數組中找到該圖片的對應的索引值
// x是每一項,如果是每一項裏的x.pic === filePath的時候就說明找到了該對象的索引值
const i = this.addForm.pics.findIndex(x => x.pic === filePath
)
// 調用數組的splice方法,把圖片信息對象從pics數組中移除
this.addForm.pics.splice(i, 1)
console.log(this.addForm)
上傳-刪除試試,看看效果:
刪除後只剩下了一個圖片地址,說明上傳操作成功
(7)圖片的預覽效果功能
官網有個方法,在點擊已上傳的圖片的時候出發的方法 on-preview
點擊文件名稱--預覽的時候就出發,並且返回完整真正的路徑信息:URL纔是完整的路徑,URL地址-瀏覽器能範圍圖片信息
那麼先data裏定義一個空數組,獲取到的完整的URL路徑存儲在看數組中。然後在創建對話框,在對話框裏顯示出來。
// 處理圖片預覽的時候事件
handlePreview(file) {
console.log(file)
this.previewPath =file.response.data.url
},
(8)對話框裏預覽圖片
所有圖片上傳-對話框預覽圖片-移除功能實現完成。最終效果:
code
<template>
<div>
<!-- 麪包屑-->
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/home' }">首頁</el-breadcrumb-item>
<el-breadcrumb-item>商品管理</el-breadcrumb-item>
<el-breadcrumb-item>添加商品</el-breadcrumb-item>
</el-breadcrumb>
<!-- 卡片視圖區-->
<el-card>
<!-- 提示區域-->
<el-alert title="添加商品信息" type="warning" center show-icon :closable="false">
</el-alert>
<!-- 步驟條-->
<el-steps :space="200" :active="activeIndex-0" finish-status="success" align-center>
<el-step title="基本信息"></el-step>
<el-step title="商品參數"></el-step>
<el-step title="商品屬性"></el-step>
<el-step title="商品圖片"></el-step>
<el-step title="商品內容"></el-step>
<el-step title="完成"></el-step>
</el-steps>
<!-- tabs標籤頁-->
<el-form :model="addForm" :rules="addFormRules" ref="addFormRef" label-width="100px" label-position="top">
<el-tabs v-model="activeIndex" :tab-position="'left'" :before-leave="beforeTabLeave" @tab-click="tabClicked">
<el-tab-pane label="基本信息" name="0">
<el-form-item label="商品名稱" prop="goods_name">
<el-input v-model="addForm.goods_name"></el-input>
</el-form-item>
<el-form-item label="商品價格" prop="goods_price">
<el-input v-model="addForm.goods_price" type="number"></el-input>
</el-form-item>
<el-form-item label="商品重量" prop="goods_weight">
<el-input v-model="addForm.goods_weight"></el-input>
</el-form-item>
<el-form-item label="商品數量" prop="goods_number">
<el-input v-model="addForm.goods_number" type="number"></el-input>
</el-form-item>
<el-form-item label="商品分類" prop="goods_cat">
<el-cascader
expand-trigger="hover "
v-model="addForm.goods_cat"
:options="catelist"
:props="cateProps"
@change="handleChange">
</el-cascader>
</el-form-item>
</el-tab-pane>
<el-tab-pane label="商品參數" name="1">
<!-- 渲染表單item項-->
<el-form-item :label="item.attr_name" v-for="item in manyTableData" :key="item.attr_id ">
<!-- 複選框組-->
<el-checkbox-group v-model="item.attr_vals">
<el-checkbox size="mini" border :label="cb" v-for="(cb,i) in item.attr_vals" :key="i"></el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-tab-pane>
<el-tab-pane label="商品屬性" name="2">
<el-form-item :label="item.attr_name" v-for="item in onlyTableData" :key="item.attr_id">
<el-input v-model="item.attr_vals"></el-input>
</el-form-item>
</el-tab-pane>
<el-tab-pane label="商品圖片" name="3">
<!-- action-表示圖片要上傳到的後臺api地址-->
<!-- on-preview-點擊預覽圖片的時候觸發的事件-->
<!-- on-remove-點擊叉號移除圖標的時候觸發的事件-->
<!-- file-list-文件列表-->
<!-- list-type-可以設置當前上傳的圖片的預覽方式的呈現方式-->
<el-upload
class="upload-demo"
action="https://www.mememme.top:8888/api/private/v1/upload"
:on-preview="handlePreview"
:on-remove="handleRemove"
list-type="picture" :headers="headersObj" :on-success="handleSuccess">
<el-button size="small" type="primary">點擊上傳</el-button>
<div slot="tip" style="font-size: 8px;margin:5px 0">只能上傳jpg/png文件,且不超過500kb</div>
</el-upload>
</el-tab-pane>
<el-tab-pane label="商品內容" name="4">商品內容</el-tab-pane>
</el-tabs>
</el-form>
</el-card>
<!-- 圖片預覽對話框-->
<el-dialog
title="提示" :visible.sync="previewVisible" width="50%">
<img :src="previewPath" alt="" style="width: 100%">
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
activeIndex: '0',
//添加商品的表單對象
addForm: {
goods_name: '', //商品名稱
goods_price: 0, //價格
goods_weight: 0, //重量
goods_number: 0, //數量
goods_cat: [], //商品所屬於的分類數組
pics: [], //圖片數組
},
addFormRules: {
goods_name: [
{required: true, message: '請輸入商品名稱', trigger: 'blur'}
],
goods_price: [
{required: true, message: '請輸入商品價格', trigger: 'blur'}
],
goods_weight: [
{required: true, message: '請輸入商品重量', trigger: 'blur'}
],
goods_number: [
{required: true, message: '請輸入商品數量', trigger: 'blur'}
],
goods_cat: [
{required: true, message: '請輸入商品數量', trigger: 'blur'}
]
}, //必應驗證規則對象
catelist: [], //獲取商品分類數據列表
manyTableData: [], //標籤商品參數數組
onlyTableData: [], //靜態屬性數據
previewPath: [], //預覽圖片的時候路徑數組
cateProps: {
label: 'cat_name',
value: 'cat_id',
children: 'children'
},
// 圖片上傳組件添加Authorization請求頭對象,
// 每一次方式請求都有了token請求頭,從session裏拿到
headersObj: {
Authorization: window.sessionStorage.getItem('token')
},
previewVisible: false, //隱藏顯示圖片預覽對話框
}
},
created() {
this.getCateList()
},
methods: {
// 獲取所有分類數據
async getCateList() {
const {data: res} = await this.$http.get('categories')
if (res.meta.status !== 200) {
return this.$message.error('獲取商品分類失敗!')
}
this.$message.success('獲取商品分類成功!')
this.catelist = res.data
console.log(res.data)
},
// 級聯選擇器變化時觸發的函數
handleChange() {
console.log(this.addForm.goods_cat)
if (this.addForm.goods_cat.length !== 3) {
this.addForm.goods_cat = []
this.$message.info('去選擇三級商品分類')
}
},
beforeTabLeave(activeName, oldActiveName) {
// console.log('即將要離開的標籤'+ oldActiveName)
// console.log('即將要進入的標籤'+ activeName)
// return false
//禁止切換--需要添加條件:在第一個0標籤和不是三級分類length的時候--禁止return false
// 那麼: 當前的標籤在第一個0 並且 被選中的是不是三級分類的話 禁止切換
if (oldActiveName === '0' && this.addForm.goods_cat.length !== 3) {
this.$message.error('請選擇商品分類!')
return false
}
},
// 標籤頁點擊切換的時候觸發事件
// 需要點擊商品名稱的時候觸發,需要判斷是否點擊了第二個商品名稱 activeIndex === '1'
async tabClicked() {
// console.log(this.activeIndex)
if (this.activeIndex === '1') {
// console.log('訪問的是動態參數面板--商品參數標籤')
// this.$http.get(`categories/${this.addForm.goods_cat[2]}`)
const {data: res} = await this.$http.get(`categories/${this.cateId}/attributes`,
{params: {sel: 'many'}})
if (res.meta.status !== 200) {
return this.$message.error('獲取商品參數失敗!')
}
this.$message.success('獲取商品參數成功!')
console.log(res.data)
res.data.forEach(item => {
item.attr_vals = item.attr_vals.length === 0 ? [] : item.attr_vals.split(' ')
})
this.manyTableData = res.data
}
if (this.activeIndex === '2') {
const {data: res} = await this.$http.get(`categories/${this.cateId}/attributes`,
{params: {sel: 'only'}})
if (res.meta.status !== 200) {
return this.$message.error('獲取靜態屬性失敗!')
}
console.log(res.data)
this.onlyTableData = res.data
this.$message.success('獲取靜態屬性數據成功!')
}
},
// 處理圖片預覽的時候事件
handlePreview(file) {
// console.log(file)
this.previewPath = file.response.data.url
this.previewVisible = true
},
// 點擊移除圖片的處理函數
handleRemove(file) {
// console.log(file)
// 有三步:
// 1,獲取將要刪除的圖片的臨時路徑
// 2,從pics數組中找到該圖片的對應的索引值
// 3,調用數組的splice方法,把圖片信息對象從pics數組中移除
// 獲取將要刪除的圖片的臨時路徑
const filePath = file.response.data.tmp_path
// 從pics數組中找到該圖片的對應的索引值
// x是每一項,如果是每一項裏的x.pic === filePath的時候就說明找到了該對象的索引值
const i = this.addForm.pics.findIndex(x => x.pic === filePath
)
// 調用數組的splice方法,把圖片信息對象從pics數組中移除
this.addForm.pics.splice(i, 1)
console.log(this.addForm)
},
handleSuccess(response) {
// console.log(response)
// 1,拼接得到圖片信息
const picInfo = {pic: response.data.tmp_path}
// 2,圖片信息push到pics裏的數組中
this.addForm.pics.push(picInfo)
console.log(this.addForm)
},
},
computed: {
cateId() {
if (this.addForm.goods_cat.length === 3) {
return this.addForm.goods_cat[2]
}
return null
}
}
}
</script>
<style scoped lang="less">
.el-checkbox {
margin: 0 5px 0 0 !important;
}
.previewImg {
width: 100%;
}
</style>