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>