angular的splitter案例学习

  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>