214 lines
7.7 KiB
JavaScript
214 lines
7.7 KiB
JavaScript
/**
|
|
*
|
|
* @authors yutent (yutent@doui.cc)
|
|
* @date 2017-03-29 18:39:35
|
|
*
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
define(['yua'], function(){
|
|
|
|
function getBindingCallback(elem, name, vmodels) {
|
|
var callback = elem.getAttribute(name)
|
|
if (callback) {
|
|
for (var i = 0, vm; vm = vmodels[i++]; ) {
|
|
if (vm.hasOwnProperty(callback) && typeof vm[callback] === "function") {
|
|
return vm[callback]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
yua.ui.drag = '0.0.1'
|
|
// 元素拖动
|
|
yua.directive('drag', {
|
|
priority: 1500,
|
|
init: function(binding){
|
|
binding.expr = '"' + binding.expr + '"'
|
|
yua(binding.element).css('cursor', 'move')
|
|
|
|
//取得拖动的3种状态回调
|
|
//按下,且拖拽之前
|
|
binding. beforedrag = getBindingCallback(binding.element, 'data-beforedrag', binding.vmodels)
|
|
//拖拽过程
|
|
binding.dragging = getBindingCallback(binding.element, 'data-dragging', binding.vmodels)
|
|
// 拖拽结束,且释放鼠标
|
|
binding.dragged = getBindingCallback(binding.element, 'data-dragged', binding.vmodels)
|
|
|
|
//默认允许溢出可视区
|
|
binding.overflow = true
|
|
|
|
//方向,x轴, y轴, xy轴
|
|
binding.axis = 'xy'
|
|
if(!!binding.element.dataset.axis){
|
|
binding.axis = binding.element.dataset.axis
|
|
delete binding.element.dataset.axis
|
|
}
|
|
|
|
//默认不限制拖拽区域
|
|
binding.limit = false
|
|
if(!!binding.element.dataset.limit) {
|
|
binding.limit = binding.element.dataset.limit
|
|
//这里,只要不为空,除parent外,其他值都默认为window, 故"可溢出"为false
|
|
binding.overflow = false
|
|
delete binding.element.dataset.limit
|
|
}
|
|
|
|
delete binding.element.dataset.beforedrag
|
|
delete binding.element.dataset.dragging
|
|
delete binding.element.dataset.dragged
|
|
},
|
|
update: function(val){
|
|
var _this = this,
|
|
target = val ? this.element.parentNode : this.element,
|
|
$drag = yua(this.element),
|
|
$doc = yua(document),
|
|
$target = null,
|
|
parentElem = null;
|
|
|
|
// val值不为空时, 获取真正的拖动元素
|
|
// 仅从父级上找
|
|
while(val && target){
|
|
if(target.classList.contains(val) || target.id === val){
|
|
break
|
|
}else{
|
|
target = target.parentNode
|
|
}
|
|
}
|
|
$target = yua(target);
|
|
// 限制范围为parent时,获取父级元素
|
|
if(this.limit === 'parent'){
|
|
parentElem = target.parentNode
|
|
}
|
|
|
|
|
|
var dx,dy,mx,my,ox,oy,tw,th,ww,wh,bst,bsl;
|
|
$drag.bind('mousedown', function(ev){
|
|
var gcs = getComputedStyle(target),
|
|
cst = gcs.transform.replace(/matrix\((.*)\)/, '$1'),
|
|
offset = $target.offset();
|
|
|
|
cst = cst !== 'none' ? cst.split(', ') : [1,0,0,1,0,0]
|
|
cst[4] -= 0
|
|
cst[5] -= 0
|
|
|
|
//记录初始的transform位移
|
|
dx = cst[4]
|
|
dy = cst[5]
|
|
|
|
//滚动条的偏移
|
|
bst = document.body.scrollTop
|
|
bsl = document.body.scrollLeft
|
|
|
|
// 计算元素的offset值, 需要修正
|
|
ox = offset.left - dx - bsl
|
|
oy = offset.top - dy - bst
|
|
|
|
mx = ev.pageX //按下鼠标的的坐标值
|
|
my = ev.pageY //按下鼠标的的坐标值
|
|
|
|
// 在按下时才获取窗口大小, 是为了防止人为的改变窗口大小,导致计算不准备
|
|
// 同时减少不必要的事件监听(页面上可能会很多可拖动元素)
|
|
ww = window.innerWidth;
|
|
wh = window.innerHeight;
|
|
|
|
// 同样,在点击之后获取元素的宽高,可保证获取到的是真实的值
|
|
tw = target.clientWidth;
|
|
th = target.clientHeight;
|
|
|
|
//拖拽前回调
|
|
if(_this.beforedrag){
|
|
_this.beforedrag.call(_this.vmodels, target, ox, oy)
|
|
}
|
|
|
|
//限制区域, 4个值依次是: 上, 下, 左, 右
|
|
var limit = [0, wh - th, 0, ww - tw]
|
|
|
|
if(_this.limit === 'parent') {
|
|
var pgcs = getComputedStyle(parentElem),
|
|
pcst = pgcs.transform.replace(/matrix\((.*)\)/, '$1'),
|
|
poffset = yua(parentElem).offset();
|
|
|
|
pcst = pcst !== 'none' ? pcst.split(', ') : [1,0,0,1,0,0]
|
|
|
|
var pox = poffset.left - pcst[4] - bsl,
|
|
poy = poffset.top - pcst[5] - bst;
|
|
|
|
limit = [poy, poy + parentElem.clientHeight - th, pox, pox + parentElem.clientWidth - tw]
|
|
}
|
|
|
|
var mvfn = $doc.bind('mousemove', function(ev){
|
|
|
|
//坐标轴限制
|
|
if(_this.axis !== 'y'){
|
|
cst[4] = ev.pageX - mx + dx
|
|
}
|
|
if(_this.axis !== 'x'){
|
|
cst[5] = ev.pageY - my + dy
|
|
}
|
|
|
|
|
|
var fox = ox + cst[4], //修正的offset
|
|
foy = oy + cst[5]; //修正的offset
|
|
|
|
|
|
//如果不允许溢出可视区
|
|
if(!_this.overflow){
|
|
if(_this.axis !== 'y'){
|
|
if(fox <= limit[2]) {
|
|
fox = limit[2]
|
|
//修正矩阵
|
|
cst[4] = fox - ox
|
|
}
|
|
if(fox >= limit[3]){
|
|
fox = limit[3]
|
|
//修正矩阵
|
|
cst[4] = fox - ox
|
|
}
|
|
}
|
|
|
|
if(_this.axis !== 'x'){
|
|
if(foy <= limit[0]) {
|
|
foy = limit[0]
|
|
//修正矩阵
|
|
cst[5] = foy - oy
|
|
}
|
|
if(foy >= limit[1]){
|
|
foy = limit[1]
|
|
//修正矩阵
|
|
cst[5] = foy - oy
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
$target.css({
|
|
transform: 'matrix(' + cst.join(', ') + ')'
|
|
})
|
|
|
|
//拖拽过程的回调
|
|
if(_this.dragging){
|
|
_this.dragging.call(_this.vmodels, target, fox, foy)
|
|
}
|
|
// 防止拖动到边缘时导致页面滚动
|
|
ev.preventDefault()
|
|
}),
|
|
upfn = $doc.bind('mouseup', function(ev){
|
|
$doc.unbind('mousemove', mvfn)
|
|
$doc.unbind('mouseup', upfn)
|
|
//结束回调
|
|
if(_this.dragged){
|
|
_this.dragged.call(_this.vmodels, target, fox, foy)
|
|
}
|
|
});
|
|
|
|
})
|
|
|
|
}
|
|
})
|
|
|
|
|
|
|
|
|
|
})
|
JavaScript
95.2%
CSS
4.8%