AngularJS实现一个简单的Carousel
来源:互联网 发布:世界销售网络分布图 编辑:程序博客网 时间:2024/05/17 03:10
利用AngularJS实现了一个简单版的Bootstrap Carousel,即单击Next或Prev按钮时能翻看后一张或前一张图片。 在这里总结一下,有些地方我自己也存在疑惑,望各位不吝赐教。
Bootstrap Carousel实现步骤
1、这个方法很方便,不需要再额外编写js代码按照此方法即可实现此效果,看相关代码:
点滴积累:
通过 data 属性:使用 data 属性可以很容易控制轮播(Carousel)的位置。
属性 data-slide 接受关键字 prev 或 next,用来改变幻灯片相对于当前位置的位置。
使用 data-slide-to 来向轮播床底一个原始滑动索引,data-slide-to="2" 将把滑块移动到一个特定的索引,索引从 0 开始计数。
2、先看一下相关的HTML片段,div.item的id是为了方便说明添加的,与实现无关。
<div class="carousel"> <div class="carousel-inner"> <div class="item" id="item1"> <img src="img1" alt=""/> </div> <div class="item active" id="item2"> <img src="img2" alt=""/> </div> <div class="item" id="item3"> <img src="img3" alt=""/> </div> </div></div>
在上面的示例代码中,我们要轮流播放img1、img2和img3三张图片。当前显示的是img2(因为item2属于active类),下一张要显示的图片假设是img3。 具体步骤如下(利用jQuery代码说明):
- $('#item3').addClass('next');(将#item3放在#item2的右侧,但是被浏览器隐藏起来)
- var reflow = $('#item3')[0].offsetWidth;( 这一步非得做吗?我自己实验了一下,如果不重绘UI,好像效果也一样 )
- $('#item2 #item3').addClass('left');(这会导致#item2和#item3同时向左平移, bootstrap的css文件中注册了item类元素针对translate属性的transition)
- 当平移结束时,$('#item2').removeClass('active left'); $('#item3').removeClass('next left').addClass('active');
AngularJS实现
先看index.html中的代码片段
<body><div ng-app="app"> <div class="row"> <div class="col-md-2"> <div ng-controller="CarouselController"> <carousel current-slide="currentSlide" forward="forward"> <slide ng-repeat="img in images"> <img ng-src="{{img}}" alt=""/> </slide> </carousel> <button ng-click="prev()" class="btn btn-primary">Prev</button> <button ng-click="next()" class="btn btn-primary">Next</button> </div> </div> </div></div><script src="angular.js"></script><script src="ui-bootstrap.js"></script><script src="carousel.js"></script><script src="app.js"></script></body>
下面一个个地解释涉及到的directive:
CarouselController
angular.module('app', ['carousel']). controller('CarouselController', function($scope, $element){ $scope.images = [ './imgs/img1-large.jpg', './imgs/img2-large.jpg', './imgs/img3-large.jpg', './imgs/img4-large.jpg', './imgs/img5-large.jpg' ]; $scope.currentSlide = 1; $scope.prev = function(){ $scope.forward = false; $scope.currentSlide = ($scope.currentSlide + $scope.images.length - 1) % $scope.images.length; }; $scope.next = function(){ $scope.forward = true; $scope.currentSlide = ($scope.currentSlide + 1) % $scope.images.length; }; });
各变量说明如下:
- images是待显示的图片集合
- currentSlide表示当前显示的图片在images中的索引
- forward表示图片显示顺序。为true表示按照images中的索引从小到大显示;为false表示按照索引从大到小显示
- prev()和next()是单击Prev和Next按钮时执行的代码,它们只是更新了currentSlide和forward
carousel directive
angular.module('carousel', ['ui.bootstrap.transition']). directive('carousel', function($transition, $timeout){ return { restrict: 'E', replace: true, transclude: true, scope: { forward: '=', currentSlide: '=' }, controller: function($scope, $element) { $scope.slides = []; this.addSlide = function (slide) { if($scope.currentSlide === $scope.slides.length){ slide.active = true; } $scope.slides.push(slide); }; this.removeSlide = function(slide){ var idx = $scope.slides.indexOf(slide); $scope.slides.splice(idx, 1); }; var oldSlide = $scope.currentSlide; var transition; function go(from, to, forward){ if(from === to) return; var lor = forward ? 'left' : 'right'; var pon = forward ? 'next' : 'prev'; var fromSlide = $scope.slides[from]; var toSlide = $scope.slides[to]; toSlide[pon] = true; //var reflow = toSlide.$element.offsetWidth; $timeout(function(){ fromSlide[lor] = toSlide[lor] = true; }); transition = $transition(toSlide.$element, {}). then(function(){ angular.extend(fromSlide, {active: false, left: false, right: false}); angular.extend(toSlide, {active: true, left: false, right: false, prev: false, next: false}); oldSlide = to; transition = null; }); } $scope.$watch('currentSlide', function(newSlide){ if(newSlide === oldSlide) return; var forward = $scope.forward; if(!transition){ go(oldSlide, newSlide, forward); } }); }, templateUrl: 'kits/carousel/carousel.tmpl.html' }; });
其$scope中有两个属性forward和currentSlide,它们是与CarouselController中的forward以及currentSlide绑定在一起的,而且通过$scope.$watch('currentSlide', ...)来监听currentSlide的变化。于是,当用户通过单击Prev或Next按钮来改变CarouselController中的currentSlide和forward时,carousel directive能及时地发现,并通过go(oldSlide, newSlide, forward)来执行图片切换。
carousel directive的HTML模版
<div class="carousel slide"> <div class="carousel-inner" ng-transclude> </div></div>
这没什么好说,只不过其中有个data-ng-transclude来指定子元素的位置
slide directive
angular.module('carousel', ['ui.bootstrap.transition']). directive('slide', function(){ return { scope: {}, restrict: 'E', require: '^carousel', replace: true, transclude: true, templateUrl: 'kits/carousel/slide.tmpl.html', link: function(scope, element, attrs, carousel){ scope.$element = element; carousel.addSlide(scope); scope.$on('destroy', function(){ carousel.removeSlide(scope); }) } } });
通过require: '^carousel',link函数中能获取到carousel的controller。通过carousel controller 的addSlide(scope)方法,每个slide都会将自身的scope添加到carousel scope的slides数组中。为什么要这样做呢?carousel中定义的go函数在实现transition时需要改变当前slide element和下一个slide element的class属性(参见前面的“Bootstrap Carousel实现步骤”小节),而这些class属性是和slide scope中相应的变量绑定在一起的。比如,当slide scope中active为true时,相应的slide element就会拥有active类。这是通过ng-class实现的,具体参见下面的slide directive模版。
<div class="item" data-ng-class="{'active': active, 'prev': prev, 'next': next, 'left': left, 'right': right}" ng-transclude></div>
carousel directive中go(oldSlide, newSlide, forward)的实现
为方便查看,代码再次贴到此处
function go(from, to, forward){ if(from === to) return; var lor = forward ? 'left' : 'right'; var pon = forward ? 'next' : 'prev'; var fromSlide = $scope.slides[from]; var toSlide = $scope.slides[to]; toSlide[pon] = true; var reflow = toSlide.$element[0].offsetWidth; $timeout(function(){ fromSlide[lor] = toSlide[lor] = true; }); transition = $transition(toSlide.$element, {}). then(function(){ angular.extend(fromSlide, {active: false, left: false, right: false}); angular.extend(toSlide, {active: true, left: false, right: false, prev: false, next: false}); oldSlide = to; transition = null; }); }
假设forward === true,我将这里执行的步骤与'Bootstrap Carousel实现步骤'进行对比
- toSlide[pon] = true; ===> $('#item3').addClass('next');
- var reflow = toSlide.$element[0].offsetWidth; ===> var reflow = $('#item3')[0].offsetWidth;
- $timeout(function(){ fromSlide[lor] = toSlide[lor] = true; }); ===> $('#item2 #item3').addClass('left');
- 平移完成后
angular.extend(fromSlide, {active: false, left: false, right: false});
angular.extend(toSlide, {active: true, left: false, right: false, prev: false, next: false});
===>
当平移结束时
$('#item2').removeClass('active left'); $('#item3').removeClass('next left').addClass('active');
可以看出没有本质区别。上面步骤3中,我用到了$timeout,这是我通过多次实验想到的。因为如果直接在$timeout外面写fromSlide[lor] = toSlide[lor] = true;下一张图片会立即显示出来,而不是缓慢地从右侧平移过来, 关于这一点我暂时还没有想明白为什么,希望清楚的小伙伴告诉我一下,谢谢啦^-^!
- AngularJS实现一个简单的Carousel
- 一个简单的AngularJS实例
- 使用AngularJS实现一个简单页面
- AngularJS系列:1、一个简单的AngularJS实例
- 使用angularJS做一个简单的拼图游戏
- 使用AngularJS完成一个简单的todoList
- ngDialog 一个简单的AngularJS模态框模板
- OWL Carousel integration with AngularJS
- AngularJS+RestfulAPI+BasicAuth+Python/PHP/Node.JS来实现一个最简单的新闻管理后台
- 基于AngularJS前端路由,实现一个最简单的图片翻页查看器
- 【angularjs指令】简单的搜索框实现
- 简单的下拉多选angularjs 实现
- AngularJs实现简单的购物车
- Angularjs实现简单的购物车
- angularjs 实现简单的快递页面
- AngularJs简单购物车的实现
- AngularJs 技术实现简单的表格管理
- 一个 AngularJS 的自动完成 UI 实现
- 进程与线程
- FZU 2098 刻苦的小芳(卡特兰数,动态规划)
- android-TextureView参考例子
- [leetcode] 159. Longest Substring with At Most Two Distinct Characters 解题报告
- 大数据处理
- AngularJS实现一个简单的Carousel
- amoeba与J2EE工程的对接
- php 学习笔记 -- 文件(五)
- Java中 “this” 关键字的使用
- 编写打印出一个单链表的所有元素的程序
- facebook Fresco框架库源使用基础
- AIDL及IPC浅谈
- 网络编程需要考虑的问题
- java POI操作excel