我用的是Packery &在Angular.js应用中拖拽,创建一个类似仪表板的设置,用户可以动态地创建添加到Packery布局中的窗口。我认为,我遇到的问题与将Packery和Angular.js正确地组合在一起有关。
总的来说,布局工作得很好:div的添加是正确的,它们的顺序可以通过在画布上拖动来改变,它们可以被删除。问题是,如果改变了div的顺序并向布局中添加了一个新的div,那么div将被重新定位到旧位置。例如:
- 添加div A, B和c。A现在是最左边的画布。
- 将A拖到C后面,新顺序为B, C, A。
- 添加新的div, d
- 由于某种原因,新的订单现在是A, B, C, D为div。我所期望的是,A的拖动位置将在布局的新div之后得到尊重。
包装说明:
win.controller('PackeryController', ['$scope', '$rootScope', '$timeout',
function($scope, $rootScope, $timeout) {
console.log("packery controller");
$scope.$onRootScope('packery.add', function(event, selection, type) {
$scope.add(selection, type);
});
$scope.windows = [];
$scope.windowRunningNumber = 0;
// remove from grid
$scope.remove = function(number, element) {
$scope.windows = _.reject($scope.windows, function(obj) {
return obj.number === number;
});
$scope.packery.remove(element[0]);
$scope.packery.layout();
};
// adds window to grid
$scope.add = function(selection, type) {
$scope.windows.push({
number: (++$scope.windowRunningNumber),
type: type,
variables: selection
});
};
}
]);
win.directive('packery', [
function() {
return {
restrict: 'C',
templateUrl: 'vis/windowing/packery.tpl.html',
replace: true,
controller: 'PackeryController',
scope: {},
link: function(scope, elm, attrs, controller) {
scope.packery = new Packery(elm[0], {
isResizeBound: true,
// see https://github.com/metafizzy/packery/issues/7
rowHeight: 410,
itemSelector: '.window',
gutter: '.gutter-sizer',
columnWidth: 500
});
}
};
}
]);
包装画布上单个div/window的指令:
win.directive('window', ['$compile', '$injector',
function($compile, $injector) {
return {
scope: false,
require: '^packery',
restrict: 'C',
templateUrl: 'vis/windowing/window.tpl.html',
replace: true,
link: function($scope, ele, iAttrs, controller) {
$scope.element = ele;
var draggable = new Draggabilly($scope.element[0], {
handle: '.handle'
});
$scope.$parent.packery.bindDraggabillyEvents(draggable);
$scope.packery.reloadItems();
$scope.packery.layout();
// catch dragging operations
$scope.element.find('.handle').mousedown(function() {
$(window).mousemove(function() {
$scope.isDragging = true;
$(window).unbind("mousemove");
});
})
.mouseup(function() {
var wasDragging = $scope.isDragging;
$scope.isDragging = false;
$(window).unbind("mousemove");
if (!wasDragging) { //was clicking
return;
}
console.log("was dragging");
setTimeout(function() {
$scope.packery.reloadItems();
// $scope.packery.layout();
}, 900);
});
// catch window destroys
$scope.$on('$destroy', function() {
$scope.packery.reloadItems();
// $scope.packery.layout();
});
}
};
}
]);
我怀疑
a)我没有捕捉到所有必要的DOM操作(除了添加,删除和通过拖动更改顺序之外还有其他操作吗?)这会导致Packery实例不同步,或者
b)需要在这些DOM操作上调用其他Packery方法。
任何想法?我做错了什么?
在Github中Packery开发人员的帮助下解决了这个问题。
看这个Codepen的要点。基本上你想要避免.reloadItems()
,并且没有必要在拖动事件之后进行布局(无论如何,这些都可以处理得更好,参见Draggabilly文档中的事件)。