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

  1. Sort mode – there is element swap mode and element insert mode,
  2. 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
  3. Sets the total width of the box and the height of the drag element
  4. The incomingdrag-aryLet users add custom content
  5. 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