不熟悉vue自定義指令看這里: https://cn.vuejs.org/v2/guide/custom-directive.html
vue指令實現拖動方法很方便也挺簡單,但是網上大部分的教程代碼,一般都是把代碼全部寫一個方法里面,代碼不夠美觀,代碼邏輯也不太清晰,不推薦這種寫法,比如下面這樣:
Vue.directives: { drag: { // 使用bind會有可能沒有渲染完成 inserted: function(el, binding, vnode) { const _el = el; //獲取當前元素 const ref = vnode.context.$refs[binding.value]; // 判斷基於移動的是哪一個盒子 const masterNode = ref ? ref : document; // 用於綁定事件 const masterBody = ref ? ref : document.body; // 用於獲取高和寬 const mgl = _el.offsetLeft; const mgt = _el.offsetTop; const maxWidth = masterBody.clientWidth; const maxHeight = masterBody.clientHeight; const elWidth = _el.clientWidth; const elHeight = _el.clientHeight; let positionX = 0, positionY = 0; _el.onmousedown = e => { //算出鼠標相對元素的位置,加上的值是margin的值 let disX = e.clientX - _el.offsetLeft + mgl; let disY = e.clientY - _el.offsetTop + mgt; masterNode.onmousemove = e => { //用鼠標的位置減去鼠標相對元素的位置,得到元素的位置 let left = e.clientX - disX; let top = e.clientY - disY; // 綁定的值不能滑出基於盒子的范圍 left < 0 && (left = 0); left > (maxWidth - elWidth - mgl) && (left = maxWidth - elWidth - mgl); top < 0 && (top = 0); top > (maxHeight - elHeight - mgt) && (top = maxHeight - elHeight - mgt); //綁定元素位置到positionX和positionY上面 positionX = top; positionY = left; //移動當前元素 _el.style.left = left + "px"; _el.style.top = top + "px"; }; // 這里是鼠標超出基於盒子范圍之后再松開,會監聽不到 document.onmouseup = e => { masterNode.onmousemove = null; document.onmouseup = null; }; }; } } }
這里介紹一種比較方美觀,邏輯清晰的寫法,代碼如下:
Vue.directive('drag', { bind (el, binding) { el.style.cursor = 'move' el.style.position = 'fixed' el.mousedownPoint = { x: 0, y: 0 } // bind 改變函數內部 this 指向,讓 this 指向 el // el.handleMouseup, el.handleMousemove, el.handleMousedown 這三個可以是其他的全局變量 el.handleMouseup = handleMouseup.bind(el) el.handleMousemove = handleMousemove.bind(el) el.handleMousedown = handleMousedown.bind(el) el.addEventListener('mousedown', el.handleMousedown) document.body.addEventListener('mouseup', el.handleMouseup) document.body.addEventListener('mousemove', el.handleMousemove) }, unbind (el) { document.body.removeEventListener('mouseup', el.handleMouseup) document.body.removeEventListener('mousemove', el.handleMousemove) } });
const handleMousedown = function (e) {
// 這里的this被bind改變了,是el
// 這里的e是 MouseEvent 對象
const initialPosition = this.getBoundingClientRect() this.style.width = initialPosition.width + 'px' this.position = { left: initialPosition.left, top: initialPosition.top } this.readyToMove = true this.mousedownPoint.x = e.screenX this.mousedownPoint.y = e.screenY } const handleMousemove = function (e) { if (!this.readyToMove) return false const position = this.position position.left = position.left + e.screenX - this.mousedownPoint.x position.top = position.top + e.screenY - this.mousedownPoint.y this.mousedownPoint.x = e.screenX this.mousedownPoint.y = e.screenY this.style.left = position.left + 'px' this.style.transform = 'none' this.style.marginLeft = 0 this.style.marginTop = 0 this.style.top = position.top + 'px' this.style.bottom = 'auto' this.style.right = 'auto' } const handleMouseup = function (e) { this.readyToMove = false }
這種寫法主要利用了bind的特性,回一個新的函數,並且這個函數的 this 已經被改成我們想要的 this, 推薦這種寫法。