vue?elementui?實現(xiàn)圖片上傳后拖拽排序功能示例代碼
很久沒寫技術(shù)博客了,今天是春節(jié)假期前最后一天上班,沒什么事情,就隨便寫寫吧,這次就分享一下之前封裝的一個圖片上傳組件的實現(xiàn)過程,這里主要分享下拖拽排序功能的一種實現(xiàn)方式。
2021-11-17 更新:
文末附完整源碼及使用示例代碼
2021-08-30 更新:
新增vue3支持組件,采用script setup語法+ts語言,并拓展了一些功能,代碼見文章末尾。
1、主要技術(shù)棧
vue2、elementui2、vuedraggable2
2、需求分析
產(chǎn)品的要求就是多圖上傳完后,可以對圖片列表進(jìn)行拖拽排序。本身elementui的el-upload組件已經(jīng)支持很多功能,但是唯獨沒有拖拽排序,它的多圖上傳是按你上傳時選擇的文件的順序來展示。
一般產(chǎn)品提出的復(fù)雜功能咱開發(fā)人員都是盡量簡化或者砍掉哈哈,不過呢這個功能還是對用戶非常友好的,秉承著用戶至上的原則那就接下吧。
3、思路
要是用原生js手寫一個拖拽功能做起來會很復(fù)雜,h5的draggable原生api有點雞肋,很難實現(xiàn)一個比較好的交互效果,用js的mouseover不錯,但是要實現(xiàn)最終完整的交互效果還是很費時間精力,所以還是找插件吧,通過拖拽插件和el-upload結(jié)合實現(xiàn)。
然后網(wǎng)上找到一個vuedraggable插件,github傳送門,看demo效果還可以,那么問題來了,vuedraggable的使用方式是這樣的:
<draggable v-model="myArray" group="people" @start="drag=true" @end="drag=false"> <div v-for="element in myArray" :key="element.id">{{element.name}}</div> </draggable>
就是通過slot插槽的方式傳遞列表,只對插槽內(nèi)第一層級的元素起作用。而el-upload使用上傳后生成的列表是動態(tài)生成的且無法手動控制,也就是說vuedraggable無法作用到el-upload生成的圖片列表,那就放棄使用el-upload的圖片列表,自己手動寫個列表盒子來展示圖片,并把這個列表放在vuedraggable組件插槽中,上傳完后把獲取的url地址賦值過去。
DOM結(jié)構(gòu)大概如下:
<vuedraggable tag="ul" draggable=".draggable-item"> <!-- 拖拽元素 --> <li v-for="(item, index) in imgList" :key="item + index" class="draggable-item" > <el-image :src="item" :preview-src-list="[item]"></el-image> </li> <!-- 上傳按鈕 --> <el-upload slot="footer"> <i class="el-icon-plus uploadIcon"></i> </el-upload> </vuedraggable>
4、其他一些處理點
(1)圖片刪除
我的效果是鼠標(biāo)懸浮在圖片上時圖片右上角展示刪除按鈕,鼠標(biāo)移下時消失,這樣會有一個問題就是用鼠標(biāo)拖拽完圖片后可能出現(xiàn)拖拽之前的位置換了新圖片但刪除按鈕還在,處理方式就是給vuedraggable綁定拖拽開始和拖拽結(jié)束事件,拖拽開始時添加隱藏刪除按鈕的類名,使拖拽過程中都不顯示刪除按鈕,拖拽結(jié)束再移除這個類名恢復(fù)正常。
onDragStart (e) { e.target.classList.add('hideShadow') }, onDragEnd (e) { e.target.classList.remove('hideShadow') }
(2)圖片預(yù)覽
單擊圖片即可預(yù)覽,我這里使用了el-image的組件,設(shè)置preview-src-list屬性就可以實現(xiàn)預(yù)覽,但是它的預(yù)覽會保留預(yù)覽時的狀態(tài),包括圖片翻頁的位置,所以這里就不要它的圖片翻頁功能了,直接通過數(shù)組[]包裹下該圖片的地址字符串。
<el-image :src="item" :preview-src-list="[item]"></el-image>
(3)上傳數(shù)量限制
由于圖片上傳仍然使用的el-upload組件,而圖片上傳是接口請求異步的,所以無法通過判斷圖片展示列表數(shù)量來控制圖片超限,那還是繼續(xù)使用el-upload自帶的上傳限制功能吧,也就是綁定on-exceed屬性。
需要處理的一點是在圖片展示列表刪除單張圖片后要同步下el-upload組件里上傳完的圖片數(shù)據(jù),這樣它才能正確判斷數(shù)量是否超限,而它的圖片數(shù)據(jù)都存儲在el-upload元素的uploadFiles屬性里,這個屬性在elementui官方文檔里沒有說明,可以通過給el-upload綁定一個ref屬性,通過this.$refs.uploadRef.uploadFiles獲取,里面是一個數(shù)組,數(shù)組項是對象格式,有name、url、status、uid四個屬性,uid需要保證值的唯一性,
5、使用方式示例
引入封裝好的組件imgUpload,可以配合element的表單組件el-form:
<el-form label-position="right" label-width="120px" :model="formData" ref="formRef" > <el-form-item label="文章圖片:" prop="imgList"> <imgUpload v-model="formData.imgList"/> </el-form-item> </el-form> ...... <script> import imgUpload from '@/components/imgUpload' export default { components: { imgUpload } data () { return { formData: { imgList: [] // formData初始值要帶上imgList屬性,以保證數(shù)據(jù)響應(yīng)式 } } } ...... } </script>
- 使用封裝好的組件時通過 v-model=“formData.imgList” 綁定了formData對象的imgList屬性,那么在vue的data給formData設(shè)置初始值時就必須添加imgList屬性,給一個默認(rèn)值空數(shù)組即可。(因為vue2.0默認(rèn)無法監(jiān)聽對象新增的屬性,所以初始結(jié)構(gòu)里就要包含這個屬性才能有響應(yīng)式,或者通過this.$set()手動添加響應(yīng)式也可以。)
6、其他說明
組件本身對外暴露了很多配置項,包括一些配置項都依賴el-upload組件,這也是沒有自己手寫上傳功能的主要原因。
el-upload標(biāo)簽的action屬性是圖片上傳接口地址,記得換成你們公司自己的穩(wěn)定接口,然后根據(jù)你們接口返回的數(shù)據(jù)格式修改onSuccessUpload方法里的處理。
7、vue3語法封裝
(1)前置條件
- vue版本:v3.2.0以上(因為用到了script setup語法,該語法在v3.2.0才轉(zhuǎn)為正式api,script setup語法使用參考)
- vuedraggable版本:v4.1.0以上
- element-plus版本:v1.0.2-beta.70,因為element-plus一直在不斷更新,最新版會有一些不兼容問題,比如新版移除了自帶字體圖標(biāo),只能手動導(dǎo)入。
(2)imgUpload.vue組件完整代碼:
傳送門
8、常見問題
題外話:
- 這個組件封裝已經(jīng)在實際項目中經(jīng)受過考驗,不要懷疑。
- 對于評論區(qū)和私信的問題,基本都是vue的使用問題,對vue的雙向數(shù)據(jù)綁定理解不到位,或者使用經(jīng)驗不足導(dǎo)致的,而非本文組件的封裝問題。
(1)刪除或拖拽操作后數(shù)據(jù)沒有變化
這種大多是數(shù)據(jù)響應(yīng)式的問題,常見于vue2.x版本,vue2.x里數(shù)據(jù)字段需要在data里提前定義好初始值或者后面通過this.$set手動設(shè)置,才能有數(shù)據(jù)響應(yīng)式,vue3.x里得益于proxy api的優(yōu)勢不會有這個問題。
特別是數(shù)據(jù)回顯的時候,容易出現(xiàn)問題,列舉以下幾個場景解決方式:
直接在一個頁面里:
方式1:先在data里定義好字段,獲取詳情接口拿到回顯數(shù)據(jù)后再賦值數(shù)據(jù)。
data () { return { formData: { imgList: [], } } }, methods: { getDetail () { setTimeout(() => { const res = { imgList: ['https://abc.png'] } this.formData = res }, 1000) } }
方式2:data里未定義字段,獲取詳情接口拿到回顯數(shù)據(jù)后通過this.$set賦值。
data () { return { formData: {} } }, methods: { getDetail () { setTimeout(() => { const res = { imgList: ['https://abc.png'] } this.$set(this.formData, 'imgList', res.imgList) }, 1000) } }
組件里props接收回顯數(shù)據(jù):
方式1:先在data里定義好字段,watch監(jiān)聽props接收的回顯數(shù)據(jù)再賦值。
props: { detailData: { type: Object, default () { return {} } } }, data () { return { formData: { imgList: [], } } }, watch: { detailData: { deep: true, handler (val) { this.formData = val } } },
方式2:通過computed get set 配合 this.$set 添加響應(yīng)式
props: { ? detailData: { ?? ?type: Object, ? ? default () { ?? ? ?return {} ?? ?} ? } }, computed: { ? formData: { ? ? get () { ? ? ? const obj = this.detailData ? ? ? !obj.imgList && this.$set(obj, 'imgList', []) ? ? ? return obj ? ? }, ? ? set (val) { ? ? ? this.$emit('update:formData', val) ? ? } ? }, }
9、完整源碼
為了更方便閱讀以及代碼示例,已經(jīng)把源碼和使用示例上傳到了github(傳送門),歡迎star。
到此這篇關(guān)于vue elementui 實現(xiàn)圖片上傳后拖拽排序功能的文章就介紹到這了,更多相關(guān)vue elementui拖拽排序內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vite打包出現(xiàn)"default"?is?not?exported?by?"no
這篇文章主要給大家介紹了關(guān)于vite打包出現(xiàn)"default"?is?not?exported?by?"node_modules/...問題解決的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-11-11關(guān)于vuex的數(shù)據(jù)持久化處理方式
這篇文章主要介紹了關(guān)于vuex的數(shù)據(jù)持久化處理方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-10-10詳解Vue的數(shù)據(jù)及事件綁定和filter過濾器
這篇文章主要為大家介紹了Vue的數(shù)據(jù)及事件綁定和filter過濾器,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-01-01vue form表單使用resetFields函數(shù)出現(xiàn)的問題
這篇文章主要介紹了vue form表單使用resetFields函數(shù)出現(xiàn)的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-05-05