vue custom panel instruction

vue custom panel instruction

In the development of the project, many panels with mask layer are used. These panels are rigid, fixed in size, fixed in position, unable to minimize and so on. I would like to use a vue custom instruction to solve these problems. For any panel, just add a v-panel instruction to the panel element, and the panel can be dragged!
The project documents are as follows:

Environment: vue2+scss, don't forget to introduce index.scss into App.vue!

1. Define panel and mask layer style panel.scss, and extend it with SCSS

.panel-dialog {
    width: 600px;
    height: 300px;
    position: absolute;
    z-index: 9000;
    top: 100px;
    left: 100px;
    border: 1px solid #d5d5d5;
    background: #fff;
    a {
        text-decoration: none;
    }
    .panel-dialog-title {
        height: 48px;
        line-height: 48px;
        padding-left: 12px;
        font-size: 16px;
        color: #535353;
        border-bottom: 1px solid #efefef;
        background: #3fa9f5;
        cursor: move;
    }
    .panel-dialog-content {
        padding: 15px 20px;
    }
    .panel-dialog-closebutton {
        width: 16px;
        height: 16px;
        display: block;
        position: absolute;
        top: 12px;
        right: 20px;
        background: url(assets/img/panel/close_def.png) no-repeat;
        cursor: pointer;
    }

    .panel-dialog-closebutton:hover {
        background: url(assets/img/panel/close_hov.png);
    }
}

/*shade*/
.panel-mask {
    width: 100%;
    height: 100%;
    background: #000;
    opacity: 0.4;
    /*Compatible with ie*/
    filter: Alpha(opacity=40);
    position: absolute;
    z-index: 8000;
    top: 0;
    left: 0;
}

/*panel change size -- start*/
.panel_resizeBR {
    position: absolute;
    width: 14px;
    height: 14px;
    right: 0;
    bottom: 0;
    overflow: hidden;
    cursor: nw-resize;
}
.panel_resizeL,
.panel_resizeT,
.panel_resizeR,
.panel_resizeB,
.panel_resizeLT,
.panel_resizeTR,
.panel_resizeLB {
    position: absolute;
    background: #000;
    overflow: hidden;
    opacity: 0;
    filter: alpha(opacity=0);
}
.panel_resizeL,
.panel_resizeR {
    top: 0;
    width: 5px;
    height: 100%;
    cursor: w-resize;
}
.panel_resizeR {
    right: 0;
}
.panel_resizeT,
.panel_resizeB {
    width: 100%;
    height: 5px;
    cursor: n-resize;
}
.panel_resizeT {
    top: 0;
}
.panel_resizeB {
    bottom: 0;
}
.panel_resizeLT,
.panel_resizeTR,
.panel_resizeLB {
    width: 8px;
    height: 8px;
    background: #FF0;
}
.panel_resizeLT {
    top: 0;
    left: 0;
    cursor: nw-resize;
}
.panel_resizeTR {
    top: 0;
    right: 0;
    cursor: ne-resize;
}
.panel_resizeLB {
    left: 0;
    bottom: 0;
    cursor: ne-resize;
}
/*panel change size -- end*/

2. JS function of operation element and panel - element.js

export default {
  // automatic centering
  autoCenter(el) {
    let bodyW = document.documentElement.clientWidth
    let bodyH = document.documentElement.clientHeight

    let elW = el.offsetWidth
    let elH = el.offsetHeight

    el.style.left = (bodyW - elW) / 2 + 'px'
    el.style.top = (bodyH - elH) / 2 + 'px'
  },
  // Full screen - Mask
  fillToBody(el) {
    el.style.width = document.documentElement.clientWidth + 'px'
    el.style.height = document.documentElement.clientHeight + 'px'
  },
  // Get element object
  byId(el) {
    return document.getElementById(el)
  },
  byClass(sClass, oParent) {
    let aClass = []
    let reClass = new RegExp('(^| )' + sClass + '( |$)')
    let aElem = this.byTagName('*', oParent)
    for (let i = 0; i < aElem.length; i++) {
      reClass.test(aElem[i].className) && aClass.push(aElem[i])
    }
    return aClass
  },
  byTagName(elem, obj) {
    return (obj || document).getElementsByTagName(elem)
  },
  /**
   * Drag and drop function
   * @param{oDrag} Dragged elements
   * @param{handle} Target element
   */
  drag(oDrag, handle, dragMinWidth, dragMinHeight) {
    let self = this
    handle.onselectstart = function () {
      return false
    }
    // Offset
    let disX = 0
    let disY = 0
    handle = handle || oDrag
    handle.style.cursor = 'move'
    handle.onmousedown = function (event) {
      event = event || window.event
      disX = event.clientX - oDrag.offsetLeft
      disY = event.clientY - oDrag.offsetTop
      document.onmousemove = function (event) {
        event = event || window.event
        let iL = event.clientX - disX // X-axis moving distance
        let iT = event.clientY - disY // Y-axis moving distance
        let maxL = document.documentElement.clientWidth - oDrag.offsetWidth // Maximum movement distance of X axis
        let maxT = document.documentElement.clientHeight - oDrag.offsetHeight // Maximum moving distance of Y axis

        iL = Math.min(maxL, Math.max(0, iL))
        iT = Math.min(maxT, Math.max(0, iT))

        oDrag.style.left = iL + 'px'
        oDrag.style.top = iT + 'px'
        return false
      }
      document.onmouseup = function () {
        document.onmousemove = null
        document.onmouseup = null
      }
      return false
    }
  },
  /**
   * Function to change panel size
   * 
   * @param {Object} oParent Dragged elements
   * @param {Object} handle Target elements selected when clicking
   * @param {Boolean} isLeft Whether to stretch div in the left direction
   * @param {Boolean} isTop Is the top stretch div
   * @param {Boolean} lockX Stretch in X direction or not
   * @param {Boolean} lockY Stretch in Y direction or not
   * @param {Number} dragMinWidth Minimum panel width
   * @param {Number} dragMinHeight Minimum height of panel
   */
  resize(oParent, handle, isLeft, isTop, lockX, lockY, dragMinWidth, dragMinHeight) {
    handle.onmousedown = function (event) {
      event = event || window.event
      let disX = event.clientX - handle.offsetLeft
      let disY = event.clientY - handle.offsetTop
      let iParentTop = oParent.offsetTop
      let iParentLeft = oParent.offsetLeft
      let iParentWidth = oParent.offsetWidth
      let iParentHeight = oParent.offsetHeight

      document.onmousemove = function (event) {
        event = event || window.event

        let iL = event.clientX - disX
        let iT = event.clientY - disY
        let maxW = document.documentElement.clientWidth - oParent.offsetLeft - 2
        let maxH = document.documentElement.clientHeight - oParent.offsetTop - 2
        let iW = isLeft ? iParentWidth - iL : handle.offsetWidth + iL
        let iH = isTop ? iParentHeight - iT : handle.offsetHeight + iT

        isLeft && (oParent.style.left = iParentLeft + iL + 'px')
        isTop && (oParent.style.top = iParentTop + iT + 'px')

        iW < dragMinWidth && (iW = dragMinWidth)
        iW > maxW && (iW = maxW)
        lockX || (oParent.style.width = iW + 'px')

        iH < dragMinHeight && (iH = dragMinHeight)
        iH > maxH && (iH = maxH)
        lockY || (oParent.style.height = iH + 'px')

        if ((isLeft && iW === dragMinWidth) || (isTop && iH === dragMinHeight)) document.onmousemove = null

        return false
      }
      document.onmouseup = function () {
        document.onmousemove = null
        document.onmouseup = null
      }
      return false
    }
  },
  /**
   * Panel zooming in and out -- (general purpose not supported)
   * 
   * @param {Object} el Panel elements
   * @param {Number} minWidth Minimum panel width
   * @param {Number} minHeight Minimum height of panel
   */
  vpanelResize(el, minWidth, minHeight) {
    // Class names of four corners and four sides
    let classNames = ['panel_resizeL', 'panel_resizeT', 'panel_resizeR', 'panel_resizeB', 'panel_resizeLT', 'panel_resizeTR', 'panel_resizeBR', 'panel_resizeLB']
    let div = null
    for (let i = 0; i < 8; i++) {
      div = document.createElement('div')
      div.className = classNames[i]
      el.appendChild(div)
    }
    var oL = this.byClass('panel_resizeL', el)[0]
    var oT = this.byClass('panel_resizeT', el)[0]
    var oR = this.byClass('panel_resizeR', el)[0]
    var oB = this.byClass('panel_resizeB', el)[0]
    var oLT = this.byClass('panel_resizeLT', el)[0]
    var oTR = this.byClass('panel_resizeTR', el)[0]
    var oBR = this.byClass('panel_resizeBR', el)[0]
    var oLB = this.byClass('panel_resizeLB', el)[0]
    // Four corners
    this.resize(el, oLT, true, true, false, false, minWidth, minHeight)
    this.resize(el, oTR, false, true, false, false, minWidth, minHeight)
    this.resize(el, oBR, false, false, false, false, minWidth, minHeight)
    this.resize(el, oLB, true, false, false, false, minWidth, minHeight)
    // Four sides
    this.resize(el, oL, true, false, false, true, minWidth, minHeight)
    this.resize(el, oT, false, true, true, false, minWidth, minHeight)
    this.resize(el, oR, false, false, false, true, minWidth, minHeight)
    this.resize(el, oB, false, false, true, false, minWidth, minHeight)
  }
}

3. Set utils path

Set path alias of JS general function in webpack.base.conf.js

4. Introduce utils general function

5. Define the instruction v-panel in main.js

/** 
 * Pop up panel can drag and change size command
 * Currently, the instruction attribute drag drag resize change size is supported
 * Usage: v-panel.drag.resize
 * Parameter passing method: v-panel:{minWidth:500,minHeight:260} note: parameters cannot be passed with spaces, otherwise an error is reported!!!!!
 * @param{Object} el Panel elements
 * @param{Object} binding 
 * @param{Object}
 */
Vue.directive('panel', {
    bind: function (el, binding, vnode) {
        var sports = binding.modifiers  // Object of instruction modifier
        var params = binding.arg        // Instruction parameter {minWidth:500,minHeight:260} panel width and height
        var targetElem = vnode.children.length && vnode.children[0].elm  // Target element
        window.onresize = function () {
            utils.ElementUtils.autoCenter(el)  // Centered
        }
        if (!targetElem) {      // Turn off drag and resize if the target element does not exist
            return
        }
        var minWidth = 500      // Panel default minimum width
        var minHeight = 260 // Panel default minimum height
        if (params) {
            minWidth = +params.minWidth || minWidth
            minHeight = +params.minHeight || minHeight
        }
        // 2. Add v-panel.drag.resize panel to support dragging and resizing
        if (JSON.stringify(sports) !== '{}') {
            if (sports.drag) {      // Drag and drop
                utils.ElementUtils.drag(el, targetElem, minWidth, minHeight)
            }
            if (sports.resize) {    // Resize
                utils.ElementUtils.vpanelResize(el, minWidth, minHeight)
            }
        } else {
            // 1. Add the v-panel command. The panel supports dragging by default
            utils.ElementUtils.drag(el, targetElem, minWidth, minHeight)
        }
    },
    // Called when the VNode of the component is updated
    update: function (el) {
        utils.ElementUtils.autoCenter(el)  // Centered
    }
})

6. Panel Demo, the most important is to add the v-panel command!

<!--
    path: src/components/panel/panelDmeo.vue
    author: wujiang
    time: 
    desc: Panel command function demonstration Demo
-->
<template>
    <section>
        <section class="panel-mask" v-show="show"></section>
        <section class="panel-dialog" v-show="show" v-panel.drag.resize>
            <section class="panel-dialog-title">
                //panel
                <a class="panel-dialog-closebutton" @click="onClose"></a>
            </section>
            <section class="panel-dialog-content">
            </section>
        </section>
    </section>
</template>

<script>
    export default {
        components: {
        },
        data () {
            return {
                // Display panel or not
                show: false
            }
        },
        computed: {
        },
        mounted () {
        },
        methods: {
            // Open panel
            onShow () {
                this.show = true
            },
            // Closing panel
            onClose () {
                this.show = false
            }
        }
    }
</script>

7. The effect is as follows

Keywords: Vue IE Webpack Attribute

Added by mudi on Thu, 02 Apr 2020 13:40:58 +0300