今天给大家带来一个很有用原生angularjs的拖拽布局功能,可以说是相当丝滑。
先来个效果动态图:
具体实现:
HTML模板:
<div>
<bg-splitter orientation="horizontal">
<bg-pane min-size="101" style="max-width:400">
<div class="pane-container" ng-init="h=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27]">
<p ng-repeat="i in h">Left{{i}}</p>
</div>
</bg-pane>
<bg-pane min-size="150">
<bg-splitter orientation="vertical">
<bg-pane min-size="100" class="pane-container">
<div ng-init="h=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]">
<p ng-repeat="i in h">RightTop{{i}}</p>
</div>
</bg-pane>
<bg-pane min-size="150" class="pane-container">
<div ng-init="h=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]">
<p ng-repeat="i in h">RightBottom{{i}}</p>
</div>
</bg-pane>
</bg-splitter>
</bg-pane>
</bg-splitter>
</div>
指令定义:
'use strict';
app.directive('bgSplitter', function() {
return {
restrict: 'E',
replace: true,
transclude: true,
scope: {
orientation: '='
},
template: '<div class="split-panes {{orientation}}" ng-transclude></div>',
controller: ['$scope', function ($scope) {
$scope.panes = [];
this.addPane = function(pane){
if ($scope.panes.length > 1)
throw 'splitters can only have two panes';
$scope.panes.push(pane);
return $scope.panes.length;
};
}],
link: function(scope, element, attrs) {
var handler = angular.element('<div class="split-handler"></div>');
var pane1 = scope.panes[0];
var pane2 = scope.panes[1];
var vertical = scope.orientation == 'vertical';
var pane1Min = pane1.minSize || 0;
var pane2Min = pane2.minSize || 0;
var drag = false;
pane1.elem.after(handler);
element.bind('mousemove', function (ev) {
if (!drag) return;
var bounds = element[0].getBoundingClientRect();
var pos = 0;
if (vertical) {
var height = bounds.bottom - bounds.top;
pos = ev.clientY - bounds.top;
if (pos < pane1Min) return;
if (height - pos < pane2Min) return;
handler.css('top', pos + 'px');
pane1.elem.css('height', pos + 'px');
pane2.elem.css('top', pos + 'px');
scope.verPos = pos;
} else {
var width = bounds.right - bounds.left;
pos = ev.clientX - bounds.left;
if (pos < pane1Min) return;
if (width - pos < pane2Min) return;
handler.css('left', pos + 'px');
pane1.elem.css('width', pos + 'px');
pane2.elem.css('left', pos + 'px');
scope.horPos = pos;
}
scope.$emit('bgSplitterChanged', {
orientation:vertical?"vertical":"horizontal",
bounds:bounds,
pos:pos
});
});
handler.bind('mousedown', function (ev) {
ev.preventDefault();
drag = true;
});
angular.element(document).bind('mouseup', function (ev) {
drag = false;
});
}
};
})
.directive('bgPane', function () {
return {
restrict: 'E',
require: '^bgSplitter',
replace: true,
transclude: true,
scope: {
minSize: '='
},
template: '<div class="split-pane{{index}}" ng-transclude></div>',
link: function(scope, element, attrs, bgSplitterCtrl) {
scope.elem = element;
scope.index = bgSplitterCtrl.addPane(scope);
}
};
});
CSS样式:
<style>
.split-panes
{
overflow: hidden;
left: 0px;
right: 0px;
top: 0px;
bottom: 0px;
position: absolute;
}
.split-panes > .split-handler
{
position: absolute;
z-index: 999;
}
/* Horizontal */
.split-panes.horizontal > .split-handler
{
width: 6px;
top: 0px;
left: 232px;
bottom: 0px;
border-left: solid 1px #B3B3B3;
border-right: solid 1px #B3B3B3;
cursor: ew-resize;
background: #B3B3B3 0 50%;
}
.split-panes.horizontal > .split-pane1,
.split-panes.horizontal > .split-pane2
{
position: absolute;
height: 100%;
}
.split-panes.horizontal > .split-pane1
{
width: 232px;
}
.split-panes.horizontal > .split-pane2
{
left: 230px;
right: 0px;
}
/* Vertical */
.split-panes.vertical > .split-handler
{
height: 6px;
top: 50%;
left: 0px;
right: 0px;
border-top: solid 1px #B3B3B3;
border-bottom: solid 1px #B3B3B3;
cursor: ns-resize;
background: #B3B3B3 50% 0;
}
.split-panes.vertical > .split-pane1,
.split-panes.vertical > .split-pane2
{
position: absolute;
width: 100%;
}
.split-panes.vertical > .split-pane1
{
height: 50%;
}
.split-panes.vertical > .split-pane2
{
top: 50%;
bottom: 0px;
margin-top: 8px;
}
.split-pane1,.split-pane2{
overflow:auto;
}
.split-panes.vertical{
left:8px;
}
</style>
效果图: