实现无缝Carousel
标签:
最近一段时间我在重构访名医官网,多了很多动画,设计也更精美。 其中有一个就是实现无缝Carousel, 结合angularjs ,我想应该是很简单的吧。之前也看过不少这方面的资料,但总是不理解,一直压在心里,成了心结了。正好,借这次机会,彻底了解下。
淘宝网首页,就有这方面的完美例子,打开开发工具,仔细观察了布局和变化后,我写下了结论。 “帧布局是5-1-2-3-4-5-1,猜测是在跳转到最后一帧的时候,取消了transition,同时快速定位到第一幁,再加上transition属性,这样肉眼就看不出来。感觉无限滚动一样。”,我问了群里的朋友,一位朋友用例子证实了我的猜测,这大大增强了我的信心。
以前的项目,我用过angular-carousel,不是无缝实现,而且用起来也感觉不好,多了不可控的因素,但实现源码还是值得一看的,很有启发。
所以决定自己实现一个,花了大约一天的时间,反复测试后,终于OK了。
Directive simpleCarousel 的实现
//todo 参考angular-carousel 实现动态width
app.directive('simpleCarousel', function(fmyApi) {
return {
restrict: 'A',
scope : { slideIndex : "=" },
link: function($scope, element, attrs) {
//3-1-2-3-1 实现双向无缝滚动
// detect supported CSS property
var transformProperty = 'transform';
var transitionProperty = "transition";
var prefix = ['webkit', 'Moz', 'O', 'ms'];
for (var i = 0; i < prefix.length; i++) {
var e = prefix[i] + "Transform";
if (typeof document.body.style[e] !== 'undefined') {
transformProperty = e;
transitionProperty = prefix[i] + "Transition";
break;
}
};
var transV = "transform .25s ease";
if (fmyApi.isIe9 || fmyApi.isIe8) {
transV = "margin-left .25s ease";
}
var childrens = element.children(), l = childrens.length;
var l = element.children().length;
var firstC = angular.element(childrens[0]), lastC = angular.element(childrens[l - 1]);
var w = firstC[0].clientWidth;
element.append(firstC.clone()).prepend(lastC.clone());
$scope.$watch("slideIndex",function(nvalue,ovalue) {
element[0].style[transitionProperty] = transV;
if (fmyApi.isIe8 || fmyApi.isIe9) {
element[0].style["marginLeft"] = "-" + (nvalue + 1) * w + "px";
}else {
element[0].style[transformProperty] = "translate3d(-" + ( nvalue + 1 ) * w + "px,0,0)" ;
}
if (nvalue == l || nvalue == -1) {
element.on("transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd",function(e) {
element[0].style[transitionProperty] = "none";
if (nvalue == l) {
if (fmyApi.isIe8 || fmyApi.isIe9) {
element[0].style["marginLeft"] = "-" + w + "px";
}else {
element[0].style[transformProperty] = "translate3d(-" + w + "px,0,0)" ;
}
}else {
if (fmyApi.isIe8 || fmyApi.isIe9) {
element[0].style["marginLeft"] = "-" + l * w + "px";
}else {
element[0].style[transformProperty] = "translate3d(-" + l * w + "px,0,0)" ;
}
}
element.off("transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd");
});
}
});
}
};
});
页面布局
<div class='carousel-wrapper'>
<ul class="carousel-cnt" simple-carousel slide-index='car1' ng-class='[car1Active,"c" + car1]'>
...
</ul>
<img class='prev' src="images/v2/left.png" alt="left" ng-click='direct("car1",-1)'>
<img class='next' src="images/v2/right.png" alt="right" ng-click='direct("car1",1)'>
</div>
控制器
app.controller('indexCtrl', function($scope, $timeout, fmyApi) {
...
$scope.car1 = 0;
$scope.car2 = 0;
$scope.direct = function(car, step) {
var tt = $scope[car] + step;
if ( tt == -2 ) {
tt = 1;
}
if ( tt == 4 ) {
tt = 1;
}
$scope[car] = tt;
};
...
});