angular的splitter案例学习,都有注释了,作为自己的备忘。
<!DOCTYPE html> <html ng-app="APP"> <head> <meta charset="UTF-8"> <title>Angular pane splitter example</title> <link type="text/css" rel="stylesheet" href="split.css" /> </head> <body> <!-- //主要流程是根据dom的包裹节点从外部到内部 //先是界面的渲染是先把指令转换成template, 然后为每一个指令定义controller控制器, 然后进行link; --> <bg-splitter orientation="horizontal"> <bg-pane min-size="100">Pane 1</bg-pane> <bg-pane min-size="150"> <bg-splitter orientation="vertical"> <bg-pane min-size="50">Pane 2</bg-pane> <bg-pane min-size="50">Pane 3</bg-pane> </bg-splitter> </bg-pane> </bg-splitter> <script src="http://cdn.bootcss.com/angular.js/1.3.0-beta.12/angular.min.js"></script> <script> //依赖模块; angular.module("APP",["bgDirectives"]) </script> </body> <script> //新建模块; angular.module('bgDirectives', []) .directive('bgSplitter', function() { return { //使用 标签(tag)的方式 restrict: 'E', //替换节点 replace: true, //替换内容 transclude: true, //独立作用域, 并引用属性 scope: { orientation: '@' }, //包裹的节点; template: '<div class="split-panes {{orientation}}" ng-transclude></div>', controller: 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) { //因为这个组件没有进行双向绑定, 链接阶段就对dom进行更改, 也都没什么事情; //把分隔线添加进来; 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); //为这个元素添加事件(不给document添加事件吗?); 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是这个事件的; 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'); } 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'); } }); //为分割线添加事件; handler.bind('mousedown', function (ev) { ev.preventDefault(); //添加了拖拽的标志; drag = true; }); angular.element(document).bind('mouseup', function (ev) { //删除拖拽的标志; drag = false; }); } }; }) /* 就是说指令的顺序是外部包裹节点到内部子节点; // */ .directive('bgPane', function () { return { restrict: 'E', //依赖bgSplitter这个controller; require: '^bgSplitter', replace: true, transclude: true, scope: { minSize: '=' }, //主要流程是根据dom的包裹节点从外部到内部 //先是界面的渲染是先把指令转换成template, 然后为每一个指令定义controller控制器, 然后进行link; template: '<div class="split-pane{{index}}" ng-transclude></div>', link: function(scope, element, attrs, bgSplitterCtrl) { scope.elem = element; scope.index = bgSplitterCtrl.addPane(scope); } }; }); </script>
<style>
.split-panes
{
left: 0px;
right: 0px;
top: 0px;
bottom: 0px;
position: absolute;
}
.split-panes > .split-handler
{
background: transparent;
position: absolute;
z-index: 999;
}
/* Horizontal */
.split-panes.horizontal > .split-handler
{
width: 4px;
top: 0px;
left: 50%;
bottom: 0px;
cursor: ew-resize;
}
.split-panes.horizontal > .split-pane1,
.split-panes.horizontal > .split-pane2
{
position: absolute;
height: 100%;
}
.split-panes.horizontal > .split-pane1
{
width: 50%;
}
.split-panes.horizontal > .split-pane2
{
left: 50%;
right: 0px;
border-left: 1px solid #aaa;
}
/* Vertical */
.split-panes.vertical > .split-handler
{
height: 4px;
top: 50%;
left: 0px;
right: 0px;
cursor: ns-resize;
}
.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;
border-top: 1px solid #aaa;
}
</style>
</html>