基于AngularJS指令与动画模块实现轮播图
本文介绍利用AngularJS实现首页轮播图的两种主要方案。第一种方案仅使用指令操作DOM元素,通过jQuery封装函数切换样式;第二种方案结合AngularJS动画模块与$deferred机制,利用CSS3过渡效果实现平滑切换。文章对比了直接修改src属性的低效做法,推荐前两种体验更优的实现方式,并提供了相关代码示例与注意事项。
首先展示最终的运行效果。

轮播图实现方案概述
实现一个轮播图功能实际上并不复杂。本文探讨了两种主要的实现路径(若细分则涉及五种具体手法,其中两种依赖原生DOM操作,另外三种基于AngularJS的动画机制,因此归纳为两大类)。后续将详细展开这两种方法,供读者深入理解。
基于指令的DOM操作方案
首先介绍第一种方法:不使用AngularJS的动画模块,仅依靠指令来完成动画切换。该方法的核心在于指令内部直接操作DOM元素,实现起来相对简单。
具体示例代码如下。
<!DOCTYPE html>
<html lang="en" ng-app="lunbo">
<head>
<meta charset="UTF-8">
<script src="lib/angular.min.js" type="text/javascript"></script>
<script src="lib/angular-animate.js" type="text/javascript"></script>
<title></title>
<style>
.hidden{
display: none;
}
.active{
display: block;
}
</style>
</head>
<body ng-controller="lunboController">
<div lunbo ></div>
<script type="text/ng-template" id="lunbo.html">
<ul>
<li ng-repeat="img in images"
class="fade-in style hidden" >
<a href="{{img.href}}"><img src="{{img.src}}" alt=""/></a></li>
</ul>
</script>
</body>
<script>
var app=angular.module('lunbo',['ngAnimate']);
app.controller('lunboController',['$scope','readJSON', function ($scope,readJSON) {
}]);
app.factory('readJSON',['$http','$q', function ($http,$q) {
return {
query: function () {
var deferred=$q.defer();
$http({
method:'GET',
url:'img.json'
}).success(function (data, status, header, config) {
deferred.resolve(data);
}).error(function (data, status, header, config) {
deferred.reject(data);
});
return deferred.promise;
}
}
}]);
app.directive('lunbo',['readJSON', function (readJSON) {
return{
restrict:'EA',
templateUrl:'lunbo.html',
scope:{},
link: function (scope, element, attr) {
var promise=readJSON.query();
var step=0;
scope.flag=false;
promise.then(function (data) {
console.log(data);
scope.images=data;
});
setInterval(function () {
element.find("li").css({"display":"none","opacity":0});
step++;
step=step%5;
element.find("li").eq(step).css({"display":"block","opacity":1});
},1000)
}
}
}]);
/*app.animation('.fade-in', function () {
return{
enter: function (element, done) {
}
}
})*/
</script>
</html>
[
{
"href":"http://www.google.com",
"src":"img/5.jpg",
"alt":"5"
},
{
"href":"http://www.google.com",
"src":"img/6.jpg",
"alt":"6"
},
{
"href":"http://www.google.com",
"src":"img/7.jpg",
"alt":"7"
},
{
"href":"http://www.google.com",
"src":"img/8.jpg",
"alt":"8"
},
{
"href":"http://www.google.com",
"src":"img/9.jpg",
"alt":"9"
}
]
观察指令代码的最后部分,实现逻辑非常简洁。它通过指令的link函数中的element对象,调用了AngularJS封装的jQuery相关函数来执行DOM操作。
基于动画模块与异步数据的方案
接下来介绍第二种方法。
link: function (scope, element, attr) {
var promise=readJSON.query();
var step=0;
scope.flag=false;
promise.then(function (data) {
console.log(data);
scope.images=data;
});
setInterval(function () {
element.find("li").removeclass("acitve");
step++;
step=step%5;
element.find("li").eq(step).addclass("active");
},1000)
}
}
如果需要更平滑的过渡效果,可以在acive类定义中加入CSS3的过渡动画属性。
在此方案中,使用了$http和$q来组合实现延迟异步获取数据。这种函数组合方式不仅增强了功能的健壮性,也便于对函数进行监控。未来将专门深入解析AngularJS的$q与jQuery的$Deferred,尽管两者原理相似,但都实现了promise的核心操作。
其他实现方式及局限性分析
使用JavaScript原生方法实现的难点在于如何动态增加和减少DOM元素,以触发AngularJS的动画效果。本文尝试了相关实现,但在初始运行时存在一个小瑕疵:导航按钮的步长必须加1才能与图片显示同步。具体原因待后续排查,如有不当之处,欢迎指正。
此外还存在另一种写法,虽然编码简单,但本文不推荐。其思路是建立一个数组存储图片的src等属性,每次从中取出一个值通过双向绑定更新img标签的src。当切换到下一张时,先清空当前img的src再赋值新值,如此循环。这种方式虽然能实现轮播,但会显著增加HTTP请求数量,在网速较慢时用户体验较差。
因此,本文更推荐前述两种写法,尽管代码可能稍显繁琐,但能提供更好的用户体验。
<!DOCTYPE html>
<html lang="en" ng-app="lunbo">
<head>
<meta charset="UTF-8">
<script src="lib/angular.min.js" type="text/javascript"></script>
<script src="lib/angular-animate.js" type="text/javascript"></script>
<title></title>
<style>
*{
padding: 0px;
margin: 0px;
}
div {
position: relative;
}
div ul {
position: absolute;
}
div ul li {
list-style-type: none;
position: absolute;
}
div ul li a img {
display: block;
width: 730px;
height: 454px;
}
div ul.listContent{
position: absolute;
left: 500px;
top: 410px;
width: 200px;
height: 25px;
}
div ul.listContent li.list{
position: relative;
display: block;
width: 25px;
height: 25px;
float: left;
margin: 0 5px;
border: 1px solid blue;
text-align: center;
line-height: 25px;
cursor: pointer;
}
.active{
background: #161616;
color: #ffffff;
}
</style>
</head>
<body ng-controller="lunboController">
<div lunbo ></div>
<script type="text/ng-template" id="lunbo.html">
<div ng-mouseleave="start()">
<ul ng-switch="pic">
<li ng-switch-when="0" class="fade-in "><a href="{{img1.href}}"><img src="{{img1.src}}" alt=""/></a></li>
<li ng-switch-when="1" class="fade-in "><a href="{{img2.href}}"><img src="{{img2.src}}" alt=""/></a></li>
<li ng-switch-when="2" class="fade-in "><a href="{{img3.href}}"><img src="{{img3.src}}" alt=""/></a></li>
<li ng-switch-when="3" class="fade-in "><a href="{{img4.href}}"><img src="{{img4.src}}" alt=""/></a></li>
<li ng-switch-when="4" class="fade-in "><a href="{{img5.href}}"><img src="{{img5.src}}" alt=""/></a></li>
</ul>
<ul class="listContent" >
<li class="list" ng-click="clickEvent(0)" >1</li>
<li class="list" ng-click="clickEvent(1)" >2</li>
<li class="list" ng-click="clickEvent(2)" >3</li>
<li class="list" ng-click="clickEvent(3)" >4</li>
<li class="list" ng-click="clickEvent(4)" >5</li>
</ul>
</div>
</script>
</body>
<script>
var app=angular.module('lunbo',['ngAnimate']);
app.controller('lunboController',['$scope','readJSON','mouseEvent' ,function ($scope,readJSON,mouseEvent) {
}]);
app.factory('readJSON',['$http','$q', function ($http,$q) {
return {
query: function (){
var deferred=$q.defer();
$http({
method:'GET',
url:'img.json'
}).success(function (data, status, header, config) {
deferred.resolve(data);
}).error(function (data, status, header, config) {
deferred.reject(data);
});
return deferred.promise;
}
}
}]);
/*这个服务有问题,需改进,暂时没想到解决办法*/
app.factory('mouseEvent', function () {
return{
mouseevent: function (ele1,ele2 ,event, done) {
}
}
});
app.directive('lunbo',['readJSON','$timeout','mouseEvent' ,function (readJSON,$timeout,mouseEvent) {
return{
restrict:'EA',
templateUrl:'lunbo.html',
scope:{},
link: function (scope, element, attr) {
var promise=readJSON.query();
var step=0;
var time=null;
promise.then(function (data) {
scope.img1=data[0];
scope.img2=data[1];
scope.img3=data[2];
scope.img4=data[3];
scope.img5=data[4];
});
var stepFun= function () {
element.find("li").removeClass("active");
element.find("li").eq(step+1).addClass("active");
scope.pic=step;
step++;
step=step%5;
time=$timeout(function () {
stepFun();
},5000);
};
stepFun();
/*点击事件*/
scope.clickEvent= function (number) {
scope.pic=number;
element.find("li").removeClass("active");
element.find("li").eq(number+1).addClass("active");
$timeout.cancel(time);
step=number;
};
/*鼠标移除动画重新开始*/
scope.start= function () {
$timeout.cancel(time);
stepFun();
}
}
}
}]);
app.animation('.fade-in', function () {
return{
enter: function (element, done) {
var step=0;
var time=null;//计时器
var animationFunc= function () {
step+=20;
if(step>100){
done();
clearInterval(time);
}else{
element.css("opacity",step/100);
}
};
element.css("opacity",0);
time=setInterval(animationFunc,50);
},
leave: function (element,done) {
var step=100;
var time=null;
var animationFun= function () {
step-=20;
if(step<0){
done();
clearInterval(time);
}else{
element.css("opacity",step/100)
}
};
element.css("opacity",1);
time=setInterval(animationFun,40);
}
}
})
</script>
</html>
总结。
以上内容为本文的全部讲解,希望能为读者的学习与工作提供一定帮助。如有任何疑问,欢迎留言交流。
anime.js 快速入门:怎么引入库并编写第一个 DOM 动画
2026-11-05 14:22:43
在线JS解密后变量名仍乱码?结合浏览器DevTools调试还原
2026-11-04 20:26:01
怎么在浏览器中运行JavaScript代码并查看输出结果
2026-11-04 09:07:33
JS 获取屏幕分辨率:window.screen.width 与 height 用法
2026-11-04 08:52:48
为什么推荐用DOMContentLoaded代替window.onload初始化JS
2026-11-04 08:42:33
