拖动指令
指令方法
说明
bind
只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。
inserted
被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。
update
被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新。
componentUpdated
被绑定元素所在模板完成一次更新周期时调用。
unbind
只调用一次, 指令与元素解绑时调用。
指令属性
说明
el
指令所绑定的元素,可以用来直接操作 DOM 。
binding
一个对象,包含以下属性
- [ ] name: 指令名,不包括 v- 前缀。
- [ ] value: 指令的绑定值, 例如: v-xxx=”1 + 1”, value 的值是 2。 相当于{{}}
- [ ] oldValue: 指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
- [ ] expression: 绑定值的字符串形式。 例如 v-xxx=”1 + 1” , expression 的值是 “1 + 1”。String类型
- [ ] arg: 传给指令的参数。例如 v-xxx:foo, arg 的值是 “foo”。 String类型
- [ ] modifiers: 一个包含修饰符的对象。 例如: v-xxx.foo.bar, 修饰符对象 modifiers 的值是 { foo: true, bar: true }。
- [ ] oldVnode: 上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
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跟随鼠标的BUG
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
}
}
*********************
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;
}