效果圖如下所示:
創(chuàng)新互聯(lián)公司10多年成都定制網(wǎng)頁(yè)設(shè)計(jì)服務(wù);為您提供網(wǎng)站建設(shè),網(wǎng)站制作,網(wǎng)頁(yè)設(shè)計(jì)及高端網(wǎng)站定制服務(wù),成都定制網(wǎng)頁(yè)設(shè)計(jì)及推廣,對(duì)純水機(jī)等多個(gè)方面擁有豐富的網(wǎng)站制作經(jīng)驗(yàn)的網(wǎng)站建設(shè)公司。

源碼地址
bb兩句
最近在做一個(gè)基于vue的后臺(tái)管理項(xiàng)目。平時(shí)項(xiàng)目進(jìn)度統(tǒng)計(jì)就在上禪道上進(jìn)行。so~ 然后領(lǐng)導(dǎo)就感覺(jué)這個(gè)拖拽效果還行,能不能加到咱們項(xiàng)目里面。 既然領(lǐng)導(dǎo)發(fā)話,那就開(kāi)干。。
所有技術(shù):vue + vuedraggable
拖動(dòng)的實(shí)現(xiàn)基于 vuedraggable 的插件開(kāi)發(fā)。
主頁(yè)為兩欄流式布局,每一個(gè)組件可以在上下拖動(dòng),也可以左右拖動(dòng)。

基本步驟
布局
這塊布局為最為普通的兩欄布局,這里采用flex布局。左邊自適應(yīng),右邊為固定寬。
.layout-container {
display: flex;
.left {
flex: 1;
margin-right: 40px;
}
.right {
width: 550px;
}
} 拖拽實(shí)現(xiàn)
這里使用 vuedraggable 插件。需要在組件里面引入使用。 draggable 相當(dāng)于拖拽容器,這塊很明顯需要兩個(gè)拖拽的容器。所以分別在 .left .right 中添加兩個(gè)拖拽容器。在默認(rèn)情況下,這里已經(jīng)可以進(jìn)行拖拽了。插件的效果還是很強(qiáng)大。
<div class="layout-container">
<!--左欄-->
<div class="left">
<draggable
v-bind="dragOptions"
class="list-group"
:list="item"
>
// ... 拖拽元素或組件
</draggable>
</div>
<!--右欄-->
<div class="right">
<draggable
v-bind="dragOptions"
class="list-group"
:list="item"
>
// ... 拖拽元素或組件
</draggable>
</div>
</div>
<script>
import draggable from "vuedraggable";
export default {
components: {draggable},
computed: {
dragOptions() {
return {
animation: 30,
handle: ".drag-handle",
group: "description",
ghostClass: "ghost",
chosenClass: "sortable",
forceFallback: true
};
}
}
};
</script>但是, 和我想要的效果還是相差一點(diǎn)。
左右拖動(dòng) 與 僅標(biāo)題欄拖動(dòng)
這塊只需要配置相關(guān)的配置項(xiàng)就可以比較簡(jiǎn)單。 左右拖動(dòng)需要給拖拽容器指定相同的 group 屬性。指定標(biāo)題元素拖動(dòng)需要配置 handle 為可拖動(dòng)元素的選擇器名稱。
下面簡(jiǎn)單介紹下常用的配置項(xiàng):
采用相關(guān)配置如下:
computed: {
dragOptions() {
return {
animation: 30,
handle: ".drag-handle",
group: "description",
ghostClass: "ghost",
chosenClass: "sortable",
forceFallback: true
};
}
}拖動(dòng)時(shí)樣式調(diào)整
在拖動(dòng)的時(shí)候,我們需要做三個(gè)事情。拖動(dòng)時(shí),拖動(dòng)元素只顯示標(biāo)題欄,兩欄內(nèi)列表只顯示標(biāo)題元素以及將要移動(dòng)的位置變灰。
1.拖動(dòng)元素只顯示標(biāo)題欄: 在默認(rèn)情況下,會(huì)開(kāi)啟 html5 元素的拖動(dòng)效果。這里明顯不需要。 forceFallback 改為 false 則可以關(guān)閉 html5 的默認(rèn)效果。順便通過(guò) chosenClass: "sortable" 修改拖動(dòng)元素class 類名。直接用css進(jìn)行隱藏
.sortable {
.component-box {
display: none;
height: 0;
}
}2.兩欄內(nèi)列表只顯示標(biāo)題元素 這里我借助兩個(gè)事件實(shí)現(xiàn)。
<div class="layout-container" :class="{drag:dragging}">
//...
</div>
data() {
return {
dragging: false
};
},
methods: {
onStart() {
this.dragging = true;
},
onEnd() {
this.dragging = false;
}
}
.drag {
.component-box {
display: none;
}
}在開(kāi)始拖動(dòng)的時(shí)候給 .layout-container 添加 .drag 的 class 名。拖動(dòng)結(jié)束時(shí),移除class名。
將要移動(dòng)的位置變灰
這里需要用到上面 ghostClass: "ghost" 配置項(xiàng)。并添加相應(yīng)的css。
.ghost {
.drag-handle {
background: rgb(129, 168, 187);
}
}好了基本已經(jīng)實(shí)現(xiàn)了。。。

展示動(dòng)態(tài)組件
接下來(lái)就是數(shù)據(jù)的動(dòng)態(tài)展示了。 這里需要vue中的動(dòng)態(tài)組件了。。附上官方文檔連接點(diǎn)擊查看。
然后里面每個(gè)拖動(dòng)的元素的內(nèi)容都寫成組件,搭配動(dòng)態(tài)組件實(shí)現(xiàn)自由拖動(dòng)。
// 將所用組件引入
import {
timeline,
calendar,
welcome,
carousel,
imgs,
KonList
} from "@/components/DragComponents";
components: {
draggable,
timeline,
calendar,
welcome,
carousel,
imgs,
KonList
}配合 v-for 對(duì)數(shù)據(jù)進(jìn)行循環(huán),然后進(jìn)行動(dòng)態(tài)展示。
<component :is="element.name"/>
這塊涉及到數(shù)據(jù)格式相關(guān)的,可以直接看文末的代碼。。。 這里就就不展開(kāi)說(shuō)了。。
數(shù)據(jù)保持
在拖動(dòng)結(jié)束后,我們需要將拖動(dòng)的順序緩存在前端,當(dāng)下次進(jìn)入后,可以繼續(xù)使用拖動(dòng)后的數(shù)據(jù)。
// 獲取新的布局
getLayout() {
let myLayout = JSON.parse(window.localStorage.getItem("kon"));
if (!myLayout || Object.keys(myLayout).length === 0)
myLayout = this.layout;
const newLayout = {};
for (const side in myLayout) {
newLayout[side] = myLayout[side].map(i => {
return this.componentList.find(c => c.id === i);
});
}
this.mainData = newLayout;
},
// 設(shè)置新的布局
setLayout() {
const res = {};
for (const side in this.mainData) {
const item = this.mainData[side].map(i => i.id);
res[side]=item;
}
window.localStorage.setItem("kon", JSON.stringify(res));
}這樣我只需要在 mounted 中獲取新的布局。。
mounted() {
this.getLayout();
}
在拖動(dòng)結(jié)束后,設(shè)置新的布局
onEnd() {
this.dragging = false;
this.setLayout();
}
在項(xiàng)目中,還是建議配合后端進(jìn)行用戶布局的數(shù)據(jù)存儲(chǔ),每次拖動(dòng)后將新的布局?jǐn)?shù)據(jù)請(qǐng)求接口保存在數(shù)據(jù)庫(kù),同時(shí)存入緩存中。當(dāng)再次進(jìn)入頁(yè)面的時(shí)候,讀取緩存中的數(shù)據(jù),沒(méi)有的話請(qǐng)求后端的接口拿到用戶的布局,然后再次存入緩存中。有的話直接讀取緩存中的數(shù)據(jù)。
最后說(shuō)兩句
其實(shí)上面的效果也不是特別難,簡(jiǎn)單花點(diǎn)時(shí)間,看看相關(guān)文檔,就能做出來(lái),,記錄在掘金上面,只是想和大家分享我的思路。同時(shí)希望和大家一起交流,一起進(jìn)步。

生活不易,大家加油
附上源碼: 項(xiàng)目地址
<template>
<div :class="{drag:dragging}">
<div class="layout-container">
<div :class="key" v-for="(item, key) in mainData" :key="key">
<draggable
v-bind="dragOptions"
class="list-group"
:list="item"
@end="onEnd"
@start="onStart"
>
<transition-group name="list">
<div class="list-group-item" v-for="(element, index) in item" :key="index">
<div class="drag-handle">{{ element.title }}</div>
<div class="component-box">
<component :is="element.name"/>
</div>
</div>
</transition-group>
</draggable>
</div>
</div>
</div>
</template>
<script>
import draggable from "vuedraggable";
import {
timeline,
calendar,
welcome,
carousel,
imgs,
KonList
} from "@/components/DragComponents";
export default {
components: {
draggable,
timeline,
calendar,
welcome,
carousel,
imgs,
KonList
},
data() {
return {
dragging: false,
componentList: [
{ name: "KonList", title: "追番地址", id: "5" },
{ name: "imgs", title: "五月最強(qiáng)新番", id: "4" },
{ name: "timeline", title: "日程組件", id: "2" },
{ name: "carousel", title: "走馬燈組件", id: "1" },
{ name: "calendar", title: "日歷組件", id: "3" }
],
layout: {
left: ["5", "4"],
right: ["2", "1", "3"]
},
mainData: {}
};
},
computed: {
dragOptions() {
return {
animation: 30,
handle: ".drag-handle",
group: "description",
ghostClass: "ghost",
chosenClass: "sortable",
forceFallback: true
};
}
},
mounted() {
this.getLayout();
},
methods: {
onStart() {
this.dragging = true;
},
onEnd() {
this.dragging = false;
this.setLayout();
},
getLayout() {
let myLayout = JSON.parse(window.localStorage.getItem("kon"));
if (!myLayout || Object.keys(myLayout).length === 0)
myLayout = this.layout;
const newLayout = {};
for (const side in myLayout) {
newLayout[side] = myLayout[side].map(i => {
return this.componentList.find(c => c.id === i);
});
}
this.mainData = newLayout;
},
setLayout() {
const res = {};
for (const side in this.mainData) {
const item = this.mainData[side].map(i => i.id);
res[side]=item;
}
window.localStorage.setItem("kon", JSON.stringify(res));
}
}
};
</script>
<style lang="scss" scoped>
.layout-container {
height: 100%;
display: flex;
.left {
flex: 1;
margin-right: 40px;
}
.right {
width: 550px;
}
.list-group-item {
margin-bottom: 20px;
border-radius: 6px;
overflow: hidden;
background: #fff;
}
.component-box {
padding: 20px;
}
.drag-handle {
cursor: move;
height: 40px;
line-height: 40px;
color: #fff;
font-weight: 700;
font-size: 16px;
padding: 0 20px;
background: #6cf;
}
}
.drag {
.component-box {
display: none;
}
}
.list-enter-active {
transition: all .3s linear;
}
.list-enter,
.list-leave-to {
opacity: .5;
}
.sortable {
.component-box {
display: none;
height: 0;
}
}
.list-group {
> span {
display: block;
min-height: 20px;
}
}
.ghost {
.drag-handle {
background: rgb(129, 168, 187);
}
}
</style>總結(jié)
以上所述是小編給大家介紹的基于vue實(shí)現(xiàn)一個(gè)禪道主頁(yè)拖拽效果,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)創(chuàng)新互聯(lián)網(wǎng)站的支持!
如果你覺(jué)得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
網(wǎng)站欄目:基于vue實(shí)現(xiàn)一個(gè)禪道主頁(yè)拖拽效果
URL標(biāo)題:http://chinadenli.net/article48/jgjgep.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供軟件開(kāi)發(fā)、網(wǎng)頁(yè)設(shè)計(jì)公司、Google、云服務(wù)器、網(wǎng)站設(shè)計(jì)公司、服務(wù)器托管
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
移動(dòng)網(wǎng)站建設(shè)知識(shí)