var slidingTabsDirective = angular.module("ionic").directive('ionSlideTabs', ['$timeout', '$compile', '$interval', '$ionicSlideBoxDelegate', '$ionicScrollDelegate', '$ionicGesture', function($timeout, $compile, $interval, $ionicSlideBoxDelegate, $ionicScrollDelegate, $ionicGesture) {
return {
require: "^ionSlideBox",
restrict: 'A',
link: function(scope, element, attrs, parent) {
var ionicSlideBoxDelegate;
var ionicScrollDelegate;
var ionicScrollDelegateID;
var slideTabs;
var indicator;
var slider;
var tabsBar;
var options = {
"slideTabsScrollable": true
}
var init = function () {
if(angular.isDefined( attrs.slideTabsScrollable ) && attrs.slideTabsScrollable === "false" ) {
options.slideTabsScrollable = false;
}
var tabItems = '<li ng-repeat="(key, value) in tabs" ng-click="onTabTabbed($event, {{key}})" class="slider-slide-tab" ng-bind-html="value"></li>';
if(options.slideTabsScrollable) {
ionicScrollDelegateID = "ion-slide-tabs-handle-" + Math.floor((Math.random() * 10000) + 1);
tabsBar = angular.element('<ion-scroll delegate-handle="' + ionicScrollDelegateID + '" class="slidingTabs" direction="x" scrollbar-x="false"><ul>' + tabItems + '</ul> <div class="tab-indicator-wrapper"><div class="tab-indicator"></div></div> </ion-scroll>');
}
else {
tabsBar = angular.element('<div class="slidingTabs"><ul>' + tabItems + '</ul> <div class="tab-indicator-wrapper"><div class="tab-indicator"></div></div> </div>');
}
slider = angular.element(element);
var compiled = $compile(tabsBar);
slider.parent().prepend(tabsBar);
compiled(scope);
//get Tabs DOM Elements
indicator = angular.element(tabsBar[0].querySelector(".tab-indicator"));
//get the slideBoxHandle
var slideHandle = slider.attr('delegate-handle');
var scrollHandle = tabsBar.attr('delegate-handle');
ionicSlideBoxDelegate = $ionicSlideBoxDelegate;
if (slideHandle) {
ionicSlideBoxDelegate = ionicSlideBoxDelegate.$getByHandle(slideHandle);
}
if(options.slideTabsScrollable) {
ionicScrollDelegate = $ionicScrollDelegate;
if (scrollHandle) {
ionicScrollDelegate = ionicScrollDelegate.$getByHandle(scrollHandle);
}
}
addEvents();
setTabBarWidth();
slideToCurrentPosition();
};
var addEvents = function() {
ionic.onGesture("dragleft", scope.onSlideMove ,slider[0]);
ionic.onGesture("dragright", scope.onSlideMove ,slider[0]);
ionic.onGesture("release", scope.onSlideChange ,slider[0]);
}
var setTabBarWidth = function() {
if( !angular.isDefined(slideTabs) || slideTabs.length == 0 ) {
return false;
}
tabsList = tabsBar.find("ul");
var tabsWidth = 0;
angular.forEach(slideTabs, function (currentElement,index) {
var currentLi = angular.element(currentElement);
tabsWidth += currentLi[0].offsetWidth;
});
if(options.slideTabsScrollable) {
angular.element(tabsBar[0].querySelector(".scroll")).css("width", tabsWidth + 1 + "px");
}
else {
slideTabs.css("width",tabsList[0].offsetWidth / slideTabs.length + "px");
}
slideToCurrentPosition();
};
var addTabTouchAnimation = function(event,currentElement) {
var ink = angular.element(currentElement[0].querySelector(".ink"));
if( !angular.isDefined(ink) || ink.length == 0 ) {
ink = angular.element("<span class='ink'></span>");
currentElement.prepend(ink);
}
ink.removeClass("animate");
if(!ink.offsetHeight && !ink.offsetWidth)
{
d = Math.max(currentElement[0].offsetWidth, currentElement[0].offsetHeight);
ink.css("height", d + "px");
ink.css("width", d + "px");
}
x = event.offsetX - ink[0].offsetWidth / 2;
y = event.offsetY - ink[0].offsetHeight / 2;
ink.css("top", y +'px');
ink.css("left", x +'px');
ink.addClass("animate");
}
var slideToCurrentPosition = function() {
if( !angular.isDefined(slideTabs) || slideTabs.length == 0 ) {
return false;
}
var targetSlideIndex = ionicSlideBoxDelegate.currentIndex();
var targetTab = angular.element(slideTabs[targetSlideIndex]);
var targetLeftOffset = targetTab.prop("offsetLeft");
var targetWidth = targetTab[0].offsetWidth;
indicator.css({
"-webkit-transition-duration": "300ms",
"-webkit-transform":"translate(" + targetLeftOffset + "px,0px)",
"width": targetWidth + "px"
});
if (options.slideTabsScrollable && ionicScrollDelegate) {
var scrollOffset = 40;
ionicScrollDelegate.scrollTo(targetLeftOffset - scrollOffset,0,true);
}
slideTabs.removeClass("tab-active");
targetTab.addClass("tab-active");
}
var setIndicatorPosition = function (currentSlideIndex, targetSlideIndex, position, slideDirection) {
var targetTab = angular.element(slideTabs[targetSlideIndex]);
var currentTab = angular.element(slideTabs[currentSlideIndex]);
var targetLeftOffset = targetTab.prop("offsetLeft");
var currentLeftOffset = currentTab.prop("offsetLeft");
var offsetLeftDiff = Math.abs(targetLeftOffset - currentLeftOffset);
if( currentSlideIndex == 0 && targetSlideIndex == ionicSlideBoxDelegate.slidesCount() - 1 && slideDirection == "right" ||
targetSlideIndex == 0 && currentSlideIndex == ionicSlideBoxDelegate.slidesCount() - 1 && slideDirection == "left" ) {
return;
}
var targetWidth = targetTab[0].offsetWidth;
var currentWidth = currentTab[0].offsetWidth;
var widthDiff = targetWidth - currentWidth;
var indicatorPos = 0;
var indicatorWidth = 0;
if (currentSlideIndex > targetSlideIndex) {
indicatorPos = targetLeftOffset - (offsetLeftDiff * (position - 1));
indicatorWidth = targetWidth - ((widthDiff * (1 - position)));
}
else if (targetSlideIndex > currentSlideIndex) {
indicatorPos = targetLeftOffset + (offsetLeftDiff * (position - 1));
indicatorWidth = targetWidth + ((widthDiff * (position - 1)));
}
indicator.css({
"-webkit-transition-duration":"0ms",
"-webkit-transform":"translate(" + indicatorPos + "px,0px)",
"width": indicatorWidth + "px"
});
if (options.slideTabsScrollable && ionicScrollDelegate) {
var scrollOffset = 40;
ionicScrollDelegate.scrollTo(indicatorPos - scrollOffset,0,false);
}
}
scope.onTabTabbed = function(event, index) {
addTabTouchAnimation(event, angular.element(event.currentTarget) );
ionicSlideBoxDelegate.slide(index);
slideToCurrentPosition();
}
scope.tabs = [];
scope.addTabContent = function ($content) {
scope.tabs.push($content);
scope.$apply();
$timeout(function() {
slideTabs = angular.element(tabsBar[0].querySelector("ul").querySelectorAll(".slider-slide-tab"));
slideToCurrentPosition();
setTabBarWidth()
})
}
scope.onSlideChange = function (slideIndex) {
slideToCurrentPosition();
};
scope.onSlideMove = function () {
var scrollDiv = slider[0].getElementsByClassName("slider-slide");
var currentSlideIndex = ionicSlideBoxDelegate.currentIndex();
var currentSlide = angular.element(scrollDiv[currentSlideIndex]);
var currentSlideLeftOffset = currentSlide.css('-webkit-transform').replace(/[^0-9\-.,]/g, '').split(',')[0];
var targetSlideIndex = (currentSlideIndex + 1) % scrollDiv.length;
if (currentSlideLeftOffset > slider.prop("offsetLeft")) {
targetSlideIndex = currentSlideIndex - 1;
if (targetSlideIndex < 0) {
targetSlideIndex = scrollDiv.length - 1;
}
}
var targetSlide = angular.element(scrollDiv[targetSlideIndex]);
var position = currentSlideLeftOffset / slider[0].offsetWidth;
var slideDirection = position > 0 ? "right":"left";
position = Math.abs(position);
setIndicatorPosition(currentSlideIndex, targetSlideIndex, position, slideDirection);
};
init();
},
controller: ['$scope',function($scope) {
this.addTab = function($content) {
$timeout(function() {
if($scope.addTabContent) {
$scope.addTabContent($content);
}
});
}
}]
};
}]);
slidingTabsDirective.directive('ionSlideTabLabel', [ function() {
return {
require: "^ionSlideTabs",
link: function ($scope, $element, $attrs, $parent) {
$parent.addTab($attrs.ionSlideTabLabel);
}
}
}]);
1.根据需求来直接实战,不要只看不写;
2.最简单的,把你手里现在目前的小型组件全部转成AngularJS版本,只重写代码,而不是套一个AngularJS的壳子~~
3.在重构代码的时候仔细学习自己忽略的知识点
4.重构都没问题了,然后再开始根据Angular的一些特定来进行组件的优化
上面其实每个步骤都能积攒一些经验~~
对于Angular我觉得最重要的是深入理解和学习 如果使用数据来操作页面,而不是DOM~
当你发现你要重复写很多次某种功能组件,或者一切组件不适合项目,你就想自己写了。其实真的很简单。并不是很难
directive,scope,controller先学好吧,先试着写些简单的,慢慢不就好了
只是代码量多一些而已,仔细看来难度并不是很大。
涉及到只是点主要是看指令注入了那些service,比如$compile指令需要加深理解。其他service都比较简单,
再则重点关注 link函数中的几个参数(scope,element,attr,ctrl,transclude)在指令中的作用。
还需要重点理解 controller函数在指令间通信的作用。
总体来说,指令的东西需要持续学习,也需要小步快走,切不可想一下子都学会。 指令是angular的非常重要的一部分,也是angular实现组件化的重要一步。深入学习指令系统,对整个angular的学习都非常有好处。