怎么在vue中利用自定义指令实现一个拖拽功能-创新互联
怎么在vue中利用自定义指令实现一个拖拽功能?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。
海城ssl适用于网站、小程序/APP、API接口等需要进行数据传输应用场景,ssl证书未来市场广阔!成为创新互联的ssl证书销售渠道,可以享受市场价格4-6折优惠!如果有意向欢迎电话联系或者加微信:18980820575(备注:SSL证书合作)期待与您的合作!1.vue自定义指令
Vue.directive('dragx', (el, binding, vnode) => {
// 默认参数
let defaultOpts = {
dragDirection: 'n, e, s, w, ne, se, sw, nw, all',
dragContainerId: '', //
dragBarClass: '', // 类选择器
canDrag: true,
canResize: true,
multiSelect: false
}
let isMove = false
let isResize = false
let constraintDom
let constraintRect
let constraintRectHeight
let constraintRectWidth
binding.value = binding.value || {}
let cfg = Object.assign({}, defaultOpts, binding.value)
if (cfg.dragContainerId) {
constraintDom = document.querySelector('#' + cfg.dragContainerId)
constraintRect = constraintDom.getBoundingClientRect()
constraintRectHeight = constraintRect.height
constraintRectWidth = constraintRect.width
}
let getStyleNumValue = (style, key) => parseInt(style.getPropertyValue(key), 10)
// 设置约束范围
function setConstraint (data) {
if (cfg.dragContainerId) {
if (data.left <= 0) data.left = 0
if (data.top <= 0) data.top = 0
if (data.top + data.height + data.borderTop + data.borderBottom >= constraintRectHeight) data.top = constraintRectHeight - data.height - data.borderTop - data.borderBottom
if (data.left + data.width + data.borderLeft + data.borderRight > constraintRectWidth) data.left = constraintRectWidth - data.width - data.borderLeft - data.borderRight
}
}
el.onmousemove = e => {
if (cfg.dragBarClass.length > 0 && e.target.classList.contains(cfg.dragBarClass) && cfg.canDrag) {
el.style.cursor = 'move'
return
}
el.style.cursor = ''
}
el.onmouseleave = e => {
el.style.cursor = ''
}
el.onmousedown = e => {
let clickId = (e.target || e.srcElement).id
let posData = {
x: e.pageX, y: e.pageY
}
el.onmouseup = e => {
// dom元素选中时发送active事件
if (!cfg.active) el.dispatchEvent(new CustomEvent('bindActive', { 'detail': { ...posData } }))
}
isMove = false
if (cfg.dragBarClass.length > 0 && !e.target.classList.contains('icon-icon-resize')) {
isMove = true
isResize = false
document.body.style.cursor = 'move'
} else if (e.target.classList.contains('icon-icon-resize')) {
isMove = false
isResize = true
}
let style
let rect
let data
let tableStyle
style = window.getComputedStyle(el)
rect = el.getBoundingClientRect()
data = {
width: getStyleNumValue(style, 'width'),
height: getStyleNumValue(style, 'height'),
left: getStyleNumValue(style, 'left'),
top: getStyleNumValue(style, 'top'),
borderLeft: getStyleNumValue(style, 'border-left-width'),
borderTop: getStyleNumValue(style, 'border-top-width'),
borderRight: getStyleNumValue(style, 'border-right-width'),
borderBottom: getStyleNumValue(style, 'border-bottom-width'),
deltX: e.pageX - rect.left,
deltY: e.pageY - rect.top,
startX: rect.left,
startY: rect.top
}
if (el.id.indexOf(THSIGN) > -1 || el.id.indexOf(TDSIGN) > -1) {
let table = document.getElementById(el.id.split(SEPARATOR)[0])
tableStyle = window.getComputedStyle(table)
data.left = getStyleNumValue(tableStyle, 'left')
data.top = getStyleNumValue(tableStyle, 'top')
}
document.onmousemove = edom => {
if (edom.ctrlKey) return
if (isResize) {
data.width = Math.round(edom.pageX - data.startX + data.borderLeft + data.borderRight)
data.height = Math.round(edom.pageY - data.startY + data.borderBottom + data.borderTop)
}
// 处理组件 移动
if (isMove && cfg.canDrag && (cfg.active || cfg.multiSelect)) {
let targetPageX = edom.pageX
let targetPageY = edom.pageY
let deltX = targetPageX - data.startX - data.deltX
let deltY = targetPageY - data.startY - data.deltY
let newLeft = Math.round(getStyleNumValue(style, 'left') || '0', 10) + deltX
let newTop = Math.round(getStyleNumValue(style, 'top') || '0', 10) + deltY
data.left = Math.round(newLeft)
data.top = Math.round(newTop)
data.startX = data.startX + deltX
data.startY = data.startY + deltY
setConstraint(data)
if (el.id.indexOf(THSIGN) > -1 || el.id.indexOf(TDSIGN) > -1) {
let newLeft = Math.round(getStyleNumValue(tableStyle, 'left') || '0', 10) + deltX
let newTop = Math.round(getStyleNumValue(tableStyle, 'top') || '0', 10) + deltY
data.left = Math.round(newLeft)
data.top = Math.round(newTop)
}
}
if (cfg.multiSelect) {
let domData = {
el: clickId,
x: edom.pageX,
y: edom.pageY
}
// 移动多个元素时发送事件 bindUpdateDoms
el.dispatchEvent(new CustomEvent('bindUpdateDoms', { detail: domData }))
} else {
// 移动单个元素移动时发送事件 bindUpdate
el.dispatchEvent(new CustomEvent('bindUpdate', { detail: data }))
}
document.onmouseup = edom => {
if (cfg.multiSelect && posData.x != edom.pageX && posData.y != edom.pageY) {
let domData = {
x: edom.pageX,
y: edom.pageY
}
// 发送下面2个事件主要是为了实现操作的撤销和恢复功能,浏览器保存一个执行栈,一个移动表示一个事件
// 多个元素同时移动时发送事件 bindFinishMoveDoms
el.dispatchEvent(new CustomEvent('bindFinishMoveDoms', { detail: domData }))
} else if (posData.x != edom.pageX && posData.y != edom.pageY) {
// 单个元素同时移动时发送事件 bindFinishMove
el.dispatchEvent(new CustomEvent('bindFinishMove', { detail: data }))
}
document.body.style.cursor = ''
document.onmousemove = null
document.onmouseup = null
isMove = false
}
}
document.onmouseup = edom => {
document.body.style.cursor = ''
document.onmousemove = null
document.onmouseup = null
isMove = false
}
}
})2.自定义事件
在vue组件使用自定义指令并添加事件监听器
如果指令需要多个值,可以传入一个 JavaScript 对象字面量。记住,指令函数能够接受所有合法的 JavaScript 表达式。
// 添加一个适当的事件监听器
// 创建并分发事件
el.dispatchEvent(new CustomEvent('bindUpdate', { detail: data }))字段说明

3.vuex实现状态管理
因为涉及到多个组件的通信,因此使用vuex,把模板信息和执行栈全部保存在vuex中
最终实现的效果如下图所示

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注创新互联行业资讯频道,感谢您对创新互联的支持。
本文名称:怎么在vue中利用自定义指令实现一个拖拽功能-创新互联
当前链接:http://www.jxjierui.cn/article/cchihh.html


咨询
建站咨询
