No bb first look at the effect
The source address
Bb two sentences
I am currently working on a vUe-based background management project. Usually the project progress statistics are carried out on the chan walk. So ~ Then the leader felt that the drag effect is ok, can we add it to our project. If the leader says so, do it.
All technologies: Vue + vuedraggable
Drag implementation based on vueDraggable plug-in development.
The home page is a two-column streaming layout, and each component can be dragged up or down, or left or right.
Basic steps
layout
This layout is the most common two-column layout, using flex layout. The left side is adaptive and the right side is fixed width.
.layout-container {
display: flex;
.left {
flex: 1;
margin-right: 40px;
}
.right {
width: 550px; }}Copy the code
Drag and drop to realize
The VueDraggable plug-in is used here. Needs to be introduced into the component. Draggable is the equivalent of a drag container, and this one obviously requires two draggable containers. So add two separate drag containers to.left. right. By default, drag and drop is already available. Plugins are still powerful.
<div class="layout-container"> <! <div class="left"> <draggable v-bind="dragOptions" class="list-group" :list="item" > //... Drag an element or component </draggable> </div> <! <div class="right"> <draggable v-bind="dragOptions" class="list-group" :list="item" > Drag an element or component </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>Copy the code
But it’s still a little different from what I wanted.
Drag left and right versus drag only from the title bar
This section is relatively simple by simply configuring the relevant configuration items. Dragging left and right requires specifying the same group attribute for the drag container. Specifying a title element drag requires that handle be configured as the selector name of the dragable element.
The following describes common configuration items:
- The options are as follows: Disabled: Boolean Specifies whether the sortable object is available. If the value is true, sorTable objects cannot be sorted by drag and drop. If the value is false, sorTable objects can be sorted by drag and drop.
- Group: used for setting containers that can be dragged and dropped. If two containers have the same configuration item, they can be dragged together.
- Animation: number unit: ms, defines the time for sorting the animation;
- Handle: a string in the format of a simple CSS selector. The element matching the selector in the list unit becomes the drag handle. Only by holding down the drag handle can the list unit be dragged.
- Filter: a string in the format of a simple CSS selector that defines which list elements cannot be dragged and dropped. Multiple selectors can be set, separated by commas (,).
- Draggable: A string formatted as a simple CSS selector that defines which list units can be dragged and dropped
- GhostClass: a string formatted as a simple CSS selector. When you drag a list unit, a copy is generated as a shadow unit to simulate the sorting of the dragged unit. This configuration item is used to add a class to the shadow unit.
- ChosenClass: a string in the form of a simple CSS selector that adds a class to a list element when selected;
- ForceFallback: Boolean If set to true, will not use native HTML5 drag-and-drop.
- FallbackClass: string The style of the mouse attached to the cell during drag-and-drop when forceFallback is set to true;
The configuration is as follows:
computed: {
dragOptions() {
return {
animation: 30.handle: ".drag-handle".group: "description".ghostClass: "ghost".chosenClass: "sortable".forceFallback: true}; }}Copy the code
Styles adjust as you drag
When we drag, we need to do three things. When you drag, the drag element shows only the title bar, and the two-column list shows only the title element and grays out the position to be moved.
-
Drag elements show only the title bar: By default, drag effects for HTML5 elements are turned on. Obviously not here. Changing the forceFallback to false turns off the html5 default. Change the drag element class name via chosenClass: “sortable”. Hide it directly with CSS
.sortable { .component-box { display: none; height: 0; }}Copy the code
-
The two-column list only shows the header element and here I’m using two events.
- OnStart: function The callback function that the list unit drags to start
- OnEnd: function Callback function after the list unit drag-and-drop ends
<div class="layout-container" :class="{drag:dragging}"> //... </div> Copy the code
data() { return { dragging: false }; }, methods: { onStart() { this.dragging = true; }, onEnd() { this.dragging = false; }}Copy the code
.drag { .component-box { display: none; }}Copy the code
Add the.drag class name to.layout-container at the beginning of the drag. When the drag is complete, remove the class name.
-
The location to be moved is grayed out, which requires the ghostClass: “Ghost” configuration item above. And add the corresponding CSS.
.ghost { .drag-handle { background: rgb(129.168.187); }}Copy the code
Well, it’s almost done…
Show dynamic Components
The next step is the dynamic presentation of the data. This is where the dynamic components in VUE are needed. Attached is the link to the official document click to view.
Then the content of each dragged element is written as a component, with dynamic components to achieve free dragging.
// Import the used component
import {
timeline,
calendar,
welcome,
carousel,
imgs,
KonList
} from "@/components/DragComponents";
components: {
draggable,
timeline,
calendar,
welcome,
carousel,
imgs,
KonList
}
Copy the code
Cooperate with V-for to circulate the data and then display it dynamically.
<component :is="element.name"/>
Copy the code
This involves data format related, can directly look at the end of the code… I won’t expand on it here.
Keeping data
After the drag, we need to cache the drag sequence in the front end. After the next entry, we can continue to use the dragged data.
// Get the new layout
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;
},
// Set the new layout
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));
}
Copy the code
This way I only need to get the new layout in Mounted.
mounted() {
this.getLayout();
}
Copy the code
After dragging, set the new layout
onEnd() {
this.dragging = false;
this.setLayout();
}
Copy the code
In the project, it is still suggested to cooperate with the backend for user layout data storage. After each drag, the new layout data request interface is saved in the database and stored in the cache at the same time. When the page is reentered, the data is read from the cache, and if not, the interface at the back end is asked to fetch the user’s layout and store it in the cache again. If so, read the data directly from the cache.
One last word
In fact, the above effect is not particularly difficult, simple spend some time, look at the relevant documents, can make, record in the nuggets above, just want to share my ideas with you. At the same time, I hope to communicate with you and make progress together.
Life is not easy, come on
Attached source code: project address
<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: "Follow up address".id: "5" },
{ name: "imgs".title: "May's best new crop.".id: "4" },
{ name: "timeline".title: "Schedule component".id: "2" },
{ name: "carousel".title: "Revolving light assembly".id: "1" },
{ name: "calendar".title: "Calendar Component".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>
Copy the code