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>