The first effect
I’m going to build the wheel series and the second component is the commonly used drag component.
Most of the time, we need to let the user to customize their own menu order, or the order of some buttons, so this time, how to give the user to customize the order? Drag and drop is the easiest to understand, as anyone who has ever played with a phone knows how to drag a desktop app to change position.
Component requirement analysis
- Sort mode – there is element swap mode and element insert mode,
- Arrangement mode – There is list mode, and Flex layout mode, where flex layout mode is divided into three equal parts and can be appended to user passed parameters later
- Sets the total width of the box and the height of the drag element
- The incoming
drag-ary
Let users add custom content - The drag-and-drop callback returns an object that is the index value of the two elements for the user to use
Drag and drop the principle
What are the common drag-and-drop operations? The whole process probably has the following steps:
1. Click on the dragged element with the mouse
2, hold down the mouse, move the mouse
3. Drag the element to a certain position and release the mouse
The process involves three dom events: the onmousedown, onmousemove, onmouseup. So the basic idea of drag is:
1. Trigger onMouseDown by clicking on the dragged element
(1) Set drag of the current element to true, indicating that it can be dragged
(2) Record the coordinates x and Y of the current mouse
(3) Record the coordinates x and y of the current element
2. Move the mouse to trigger onMousemove
(1) Determine whether the element can be dragged. If so, go to Step 2; otherwise, return directly
(2) If the element can be dragged, set the coordinate of the element
The x-coordinate of the element = the horizontal distance the mouse moved + the x-coordinate of the element = the x-coordinate of the mouse now – the x-coordinate before the mouse + the x-coordinate of the element originally
The y coordinate of the element = the horizontal distance of the mouse movement + the original y coordinate of the element = the current Y coordinate of the mouse – the y coordinate before the mouse + the original Y coordinate of the element
3. Release the mouse to trigger onMouseup
(1) Set the drag state of the mouse to false
Once the drag is implemented, you can do some boundary determination, traverse the incoming array, calculate whether the drag element is on the return of the target element, return the index value, and then reorder it
code
<template>
<div class="drag">
<div :style="{width : boxWidth==='auto'? 'auto': boxWidth+'px'}"
:class="getmode"
>
<div :style="{transform: `translate(${x}px,${y}px)` , width:dragInfo.width,height:dragInfo.height, background:dragInfo.color}"
class="box"
v-show="isDrag" v-html="dragAry[dragInfo.index].html">
</div>
<div :class="[ setBlcock,isTargetDrag&&dragIndex ===index? 'isTargetDrag':'', !dragMode&&isDrag&&dragInfo.index ===index?'active':'', isTargetDrag&&dragIndex ===index&&dragMode?'dragModeAct':'']"
:key="index"
:ref="'block'+index"
:style="{background:dragMode&&isDrag && index===Number(dragInfo.index) ? actInfo.color: item.color , height:dragHeight==='auto'? 'auto':dragHeight+'px'}"
@mousedown.prevent="dragMove($event,index)"
v-for="(item,index) in dragAry"
v-html="dragMode&&isDrag && index===Number(dragInfo.index)? actInfo.html :item.html"
>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'drag'.props: {
/ / element ordering pattern 1: change | 0: insert
dragMode: {
type: [Number.Boolean].default: 1
},
/ / element pattern flex | list
mode: {
type: String.default: 'flex'
},
/ / box width 'auto' | number
boxWidth: {
type: [Number.String].default: 'auto'
},
/ / drag the element height 'auto' | custom level
dragHeight: {
type: [Number.String].default: 50
},
// Array of elements passed in [color: ", HTML: "]
dragAry: {
type: Array.default: []}},computed: {
// Calculate the arrangement mode
getmode() {
return this.mode === 'list' ? 'blockList' : 'blockFlex'
},
// Calculate the arrangement mode
setBlcock() {
return this.mode === 'list' ? 'lblock' : 'fblock'}},data() {
return {
x: 0.// Drag the x coordinate
y: 0.// Drag the y coordinate
isDrag: false.// Whether to drag
// Dragging element information
dragInfo: {
width: ' '.height: ' '.background: ' '.index: 0
},
// Target element information
actInfo: {
color: ' '.text: ' '
},
// Whether to target the element
isTargetDrag: false.// Index value of the target element
dragIndex: null,}},methods: {
// Drag logic
dragMove(ev, index) {
const {color} = this.dragAry[index]
const {clientX, clientY} = ev
const {offsetLeft, offsetTop, offsetWidth, offsetHeight, parentElement} = ev.currentTarget
const dx = clientX - offsetLeft, dy = clientY - offsetTop
let moveX, moveY
this.isDrag = true
this.x = offsetLeft
this.y = offsetTop
this.dragInfo.width = offsetWidth + 'px'
this.dragInfo.height = offsetHeight + 'px'
this.dragInfo.index = index
this.dragInfo.color = color
document.onmousemove = (moveEv) = > {
moveEv.preventDefault()
moveX = moveEv.clientX - dx
moveY = moveEv.clientY - dy
if (moveX < 0) {
moveX = 0
}
if (moveX > parentElement.offsetWidth - offsetWidth) {
moveX = parentElement.offsetWidth - offsetWidth
}
if (moveY < 0) {
moveY = 0
}
if (moveY > parentElement.offsetHeight - offsetHeight) {
moveY = parentElement.offsetHeight - offsetHeight
}
this.dragAry.forEach((item, indexs) = > {
const [{offsetLeft: ox, offsetTop: oy}] = this.$refs['block' + indexs]
if (moveX + offsetWidth / 2 > ox && moveX + offsetWidth / 2 < ox + offsetWidth &&
moveY + offsetHeight / 2 > oy && moveY + offsetHeight / 2 < oy + offsetHeight) {
this.dragIndex = indexs
this.isTargetDrag = true
this.actInfo.html = this.dragAry[indexs].html
this.actInfo.color = this.dragAry[indexs].color
}
})
this.x = moveX
this.y = moveY
}
document.onmouseup = () = > {
if (this.isTargetDrag) {
const tempIndex = index, temp = this.dragAry[tempIndex]
if (this.dragMode) {
this.$set(this.dragAry, tempIndex, this.dragAry[this.dragIndex])
this.$set(this.dragAry, this.dragIndex, temp)
} else {
this.dragAry.splice(this.dragIndex + 1.0, temp)
this.dragAry.splice(tempIndex, 1)}this.$emit('dragMouseup', {index, dragIndex: this.dragIndex})
}
this.isDrag = false
this.isTargetDrag = false
document.onmousemove = null
document.onmousedown = null}}}}</script>
<style scoped>
.box {
color: #fff;
position: absolute;
cursor: move;
transition-duration: 100ms;
transition-timing-function: ease-out;
z-index: 111111;
background: red;
}
.active {
background: #fff ! important;
border: 1px dashed # 000;
}
.blockFlex {
width: 500px;
display: flex;
margin: 0 auto;
flex-wrap: wrap;
position: relative;
transition-duration: 500ms;
transition-timing-function: ease-out;
overflow: hidden;
}
.fblock {
width: calc(calc(100% / 3) - 10px);
margin: 5px;
height: 50px;
color: #fff;
box-sizing: border-box;
background: red;
cursor: move;
transition-duration: 500ms;
transition-timing-function: ease;
overflow: hidden;
}
.blockList {
position: relative;
margin: 0 auto;
transition-duration: 500ms;
transition-timing-function: ease-out;
}
.lblock {
width: 100%;
height: 50px;
margin-bottom: 20px;
color: #fff;
box-sizing: border-box;
background: red;
cursor: move;
transition-duration: 500ms;
transition-timing-function: ease;
}
.isTargetDrag {
cursor: move;
transform: scale(1.1);
transition-duration: 500ms;
transition-timing-function: ease-in;
position: relative;
}
.isTargetDrag:before{
border: 1px dashed red;
content: ' ';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.dragModeAct {
background: #fff ! important;
}
</style>
Copy the code
Props parameters
parameter | instructions | type | The default value |
---|---|---|---|
mode | pattern | String | 100 |
drag-mode | Insert mode or swap places | Number | 0 |
box-width | The width of the box | String | auto |
drag-height | Drag element height | String | 100 |
drag-ary | Passing in a drag array, the Object field can add color and HTML | Array | [] |
dragMouseup | Returns the current and target index values of the drag | Events |
The last
This drag component is so realized, but there are still many deficiencies, or can not meet the development needs of a large part of the user, but the wheel can not be done overnight, or need time to slowly polish, explore what needs.
In addition, seeing my own wheels have more than 200 downloads is still a little excited!! ^_^
Finally, NPM and Github are attached
npm install nigo-vue-drag
Copy the code
or
yarn add nigo-vue-drag
Copy the code
The warehouse address
git clone https://github.com/shinewen189/nigo-vue-drag.git
Copy the code