拖动指令
指令方法
说明bind
只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。
inserted
被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。
update
被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新。
componentUpdated
被绑定元素所在模板完成一次更新周期时调用。
unbind
只调用一次, 指令与元素解绑时调用。
指令属性
说明el
指令所绑定的元素,可以用来直接操作 DOM 。
binding
一个对象,包含以下属性
vnode
Vue 编译生成的虚拟节点, context指向Vue实例
指令逻辑
@/directive/drag,js
基本架子
export default {
bind: (el, binding, vnode) => {
},
inserted: (el, binding, vnode) => {
},
update: (el, binding, vnode) => {
},
componentUpdated: (el, binding, vnode) => {
},
unbind: (el, binding, vnode) => {
}
}
实现拖动
**********************************
import $ from 'jquery'
**********************************
export default {
bind: (el, binding, vnode) => {
},
inserted: (el, binding, vnode) => {
******************************************
// 绑定按下事件
el.onmousedown = function (e) { // DOM绑定点击事件
let left = e.clientX - el.offsetLeft
let top = e.clientY - el.offsetTop
document.onmousemove = function (e) { // 绑定在DOM上移动的事件
el.style.left = e.clientX - left + 'px'
el.style.top = e.clientY - top + 'px'
}
el.onmouseup = function (e) { // DOM绑定抬起事件
document.onmousemove = null
el.onmouseup = null
}
}
*********************************************
},
update: (el, binding, vnode) => {
},
componentUpdated: (el, binding, vnode) => {
},
unbind: (el, binding, vnode) => {
}
}
此时已经实现了拖动效果,注意:绑定指令的DOM需要时绝对定位
划出屏幕
后DOM跟随鼠标的BUGimport $ from 'jquery'
export default {
bind: (el, binding, vnode) => {},
inserted: (el, binding, vnode) => {
// 绑定按下事件
el.onmousedown = function (e) { // DOM绑定点击事件
let left = e.clientX - el.offsetLeft
let top = e.clientY - el.offsetTop
document.onmousemove = function (e) { // 绑定在DOM上移动的事件
el.style.left = e.clientX - left + 'px'
el.style.top = e.clientY - top + 'px'
}
el.onmouseup = function (e) { // DOM绑定抬起事件
document.onmousemove = null
el.onmouseup = null
}
}
*********************
el.onmouseout = function (e) { // 绑定在DOM上移开鼠标的事件
$(el).animate({}, 100, function () {
$(el).css('padding', '0')
})
document.onmousemove = null
el.onmouseup = null
el.onmouseout = null
}
***************************
},
update: (el, binding, vnode) => {},
componentUpdated: (el, binding, vnode) => {},
unbind: (el, binding, vnode) => {}
}
至此,已经可以通过指令绑定到DOM实现拖动,接下来我们来实现父组件控制指令状态
指令状态
import $ from 'jquery'
export default {
bind: (el, binding, vnode) => {},
inserted: (el, binding, vnode) => {
********************************
let value = binding.value
let isAllow = typeof value.isAllow !== 'undefined' ? value.isAllow : value
if (!isAllow) return
*******************************
// 绑定按下事件
el.onmousedown = function (e) { // DOM绑定点击事件
let left = e.clientX - el.offsetLeft
let top = e.clientY - el.offsetTop
document.onmousemove = function (e) { // 绑定在DOM上移动的事件
el.style.left = e.clientX - left + 'px'
el.style.top = e.clientY - top + 'px'
}
el.onmouseup = function (e) { // DOM绑定抬起事件
document.onmousemove = null
el.onmouseup = null
}
}
el.onmouseout = function (e) { // 绑定在DOM上移开鼠标的事件
$(el).animate({}, 100, function () {
$(el).css('padding', '0')
})
document.onmousemove = null
el.onmouseup = null
el.onmouseout = null
}
},
update: (el, binding, vnode) => {},
componentUpdated: (el, binding, vnode) => {},
unbind: (el, binding, vnode) => {}
}
此时如果调用时
value
传递为false
则不会绑定指令
指令状态
import $ from 'jquery'
export default {
bind: (el, binding, vnode) => {},
inserted: (el, binding, vnode) => {
let value = binding.value
let isAllow = typeof value.isAllow !== 'undefined' ? value.isAllow : value
if (!isAllow) return
// 绑定按下事件
el.onmousedown = function (e) { // DOM绑定点击事件
let left = e.clientX - el.offsetLeft
let top = e.clientY - el.offsetTop
document.onmousemove = function (e) { // 绑定在DOM上移动的事件
el.style.left = e.clientX - left + 'px'
el.style.top = e.clientY - top + 'px'
}
el.onmouseup = function (e) { // DOM绑定抬起事件
document.onmousemove = null
el.onmouseup = null
}
}
el.onmouseout = function (e) { // 绑定在DOM上移开鼠标的事件
$(el).animate({}, 100, function () {
$(el).css('padding', '0')
})
document.onmousemove = null
el.onmouseup = null
el.onmouseout = null
}
},
*****************************************
update: (el, binding, vnode) => {
let value = binding.value
let isAllow = typeof value.isAllow !== 'undefined' ? value.isAllow : value
if (!isAllow) {
document.onmousemove = null
el.onmousedown = null
el.onmouseup = null
el.onmouseout = null
} else {
// 绑定按下事件
el.onmousedown = function (e) { // DOM绑定点击事件
let left = e.clientX - el.offsetLeft
let top = e.clientY - el.offsetTop
$(el).animate({}, 100, function () {
$(el).css('padding', '2px 5px')
})
document.onmousemove = function (e) { // 绑定在DOM上移动的事件
el.style.left = e.clientX - left + 'px'
el.style.top = e.clientY - top + 'px'
}
el.onmouseup = function (e) { // DOM绑定抬起事件
$(el).animate({}, 100, function () {
$(el).css('padding', '0')
})
document.onmousemove = null
el.onmouseup = null
}
}
el.onmouseout = function (e) { // 绑定在DOM上移开鼠标的事件
$(el).animate({}, 100, function () {
$(el).css('padding', '0')
})
document.onmousemove = null
el.onmouseup = null
el.onmouseout = null
}
}
},
**************************************************
componentUpdated: (el, binding, vnode) => {},
unbind: (el, binding, vnode) => {}
}
此时在使用指令时,就可以达到动态控制指令的目的了
统一出口
@/directive/index.js
import drag from './drag'
export { drag }
main.js
引入并挂载指令import * as directive from '@/directive'
Vue.directive('drag', directive.drag)
使用
Html
<div class="drags" v-drag="true"> // 自定义的指令统一通过 v-xxx 调用,接受传参
<span>按住可以拖动我span>
div>
CSS
.drags {
position: absolute; // 使用v-drag的DOM需要绝对定位
z-index: 11;
top: -50px;
width: 120px;
height: 30px;
cursor: pointer;
border: 1px solid #b50136;
}