上一篇说了瀑布流,今天说一下小小幻灯片的故事。

幻灯片学名又叫 轮播。应该算是一种最常用的页面展示信息。以前由于ie6/7的拖累,导致我们只能使用,很古老的方式去兼容。(我最爱的css3啊~~~)。不过今年真的是前端的幸福年,各种 polyfill 和 shim,而且现在各大公司已经对ie6/7不予理睬,直接给他一个提醒页面(老子让你用ie6/7)。而且IE的爸爸,ms已经表态了,我当初是怎么生下你来的,太tm丑了,由于开放二胎,ms已经孵化了edge(原名斯巴达),现在基本上是前端的黄金时代了。这里我主要介绍一种比较实用的轮播效果。

简单轮播

轮播,在各大网站都是使用,比如在淘宝首页(兼容性比较好), 网易云音乐首页等等。 可以说,写轮播应该算是前端的一个必修课程吧。 我这里就挑一个最简单的实现。

这里实现轮播的技术,主要依赖与css3,js只是作为一个切换class名的作用(只要不写js都简单)。

轮播原理

这里先说一下基本原理吧, 就是将图片 向左或向右移,然后接着显示下一张,或者上一张。

特么,逗我呢。你不说我也知道哎喂。

咳咳~
我们来看一下,html部分吧。

<div class="sliderCon">
        <ul>
            <li class="current"><img src="http://www.w2bc.com/demo/201510/2015-10-20-html5-css3-focus-change/img/1.jpg" alt=""></li>
            <li><img src="http://www.w2bc.com/demo/201510/2015-10-20-html5-css3-focus-change/img/2.jpg" alt=""></li>
            <li><img src="http://www.w2bc.com/demo/201510/2015-10-20-html5-css3-focus-change/img/3.jpg" alt=""></li>
            <li><img src="http://www.w2bc.com/demo/201510/2015-10-20-html5-css3-focus-change/img/4.jpg" alt=""></li>
            <li><img src="http://www.w2bc.com/demo/201510/2015-10-20-html5-css3-focus-change/img/5.jpg" alt=""></li>
        </ul>
    </div>

这里就是通过ul包裹多个li实现的轮播。(这里需要感谢一下爱编程提供的图片)

接着重头戏就是css3。
看~

.sliderCon {
    width: 100%;
    max-width: 100%;
    height: 100%;
    position: relative;
    text-align: center;
    ul {
        display: inline-block;
        position: relative;
        width: 450px;
        padding: 0;
        perspective: 1400px;
        li {
            width: 450px;
            height: 290px;
            position: absolute;
            list-style: none;
            top: 0;
            left: 0;
            opacity: 0;
            pointer-events: none;
            z-index: 1000;
            text-align: center;
            &.navOutNext {
                animation: rotate3DSlideOutLeft 0.3s forwards;
            }
            &.navInNext {
                animation: rotate3DSlideInRight 0.3s 0.1s forwards;
            }
            &.navOutPre{
                 animation: rotate3DSlideOutLeft 0.3s forwards;
            }
            &.navInPre{
                 animation: rotate3DSlideInRight 0.3s forwards;
            }
            &.current {  
                opacity: 1;
                pointer-events: auto;
                z-index: 1000;
            }
        }
    }
}

我这里只贴出主要部分的。 其实,贴出来根本没用,需要结合js来看。

js原理解析

好吧,我继续贴哈。

js部分:

var slider = (function() {
    var order = 0,
        lis = $('.sliderCon li');
    var toggle = (function() { //通过flag来进行切换
        var current,
            next,
            isAnimated = false, //标识是否正在执行动画
            mark = 0, //用来表示多个动画是否都结束
            len = lis.length - 1; //获得总的图片框
        var changeState = function() {
            mark++;
            if (mark === 2) {
                isAnimated = false;
                mark = 0;
            }
        }
        var nextExe = (function() {
            var setCurrentAnimate = function() {
                this.removeEventListener(transitionName, setCurrentAnimate);
                this.classList.remove("current");
                this.classList.remove("navOutNext");
                changeState(); //检测是否动画都执行完整
            }
            var setNextAnimate = function() {
                this.removeEventListener(transitionName, setNextAnimate);
                this.classList.add("current");
                this.classList.remove('navInNext');
                changeState();
            }
            return function() {
                var current = lis[order];
                order = order + 1 > len ? 0 : order + 1;
                var next = lis[order]; //获取下一个元素
                if (!transitionName) {
                    alert("你浏览器怎么这么垃圾,赶紧换一个吧");
                } else {
                    current.addEventListener(transitionName, setCurrentAnimate);
                    next.addEventListener(transitionName, setNextAnimate);
                }
                current.classList.add('navOutNext'); //开始执行动画
                next.classList.add('navInNext');
            }
        })();
        var preExe = (function(){
            var setCurrentAnimate = function() {
                this.removeEventListener(transitionName, setCurrentAnimate);
                this.classList.remove("current");
                this.classList.remove("navOutPre");
                changeState(); //检测是否动画都执行完整
            }
            var setPreAnimate = function(){
                this.removeEventListener(transitionName, setPreAnimate);
                this.classList.add("current");
                this.classList.remove("navInPre");
                changeState(); //检测是否动画都执行完整
            }
            return function(){
                var current = lis[order];
                order = order-1<0 ? len: order-1;
                 var pre = lis[order];  //获得下一个切换的元素
                if (!transitionName) {
                    alert("你浏览器怎么这么垃圾,赶紧换一个吧");
                } else {
                    current.addEventListener(transitionName, setCurrentAnimate);
                    pre.addEventListener(transitionName, setPreAnimate);
                }
                current.classList.add('navOutPre'); //开始执行动画
                pre.classList.add('navInPre');
            }
        })();
        return function(flag) { //入口函数
            if (isAnimated) return; //如果正在执行动画则退出
            isAnimated = true; //标识正在执行动画
            if (flag === "next") {
                nextExe();
            }else if(flag==="pre"){
                preExe();
            }
        }
    })();
    setInterval(function() {
        toggle("pre");
    }, 1000);
})();

由于我过度的使用了闭包和高阶函数,所以看起来会有点累哈。不急,同样,一个程序我们先找入口函数。
可以看出。入口函数就是toggle(就是使用return 的那部分);

 return function(flag) { //入口函数
            if (isAnimated) return; //如果正在执行动画则退出
            isAnimated = true; //标识正在执行动画
            if (flag === "next") {
                nextExe();
            }else if(flag==="pre"){
                preExe();
            }
        }

isAnimated只是个标识符,用来表示是否正在执行动画。通过传入的flag来表示向前切换还是向后切换。如果向后接环则执行nextExe函数。好,我们来看一下nextExe函数。

切换动画函数

var nextExe = (function() {
            var setCurrentAnimate = function() {
                this.removeEventListener(transitionName, setCurrentAnimate);
                this.classList.remove("current");
                this.classList.remove("navOutNext");
                changeState(); //检测是否动画都执行完整
            }
            var setNextAnimate = function() {
                this.removeEventListener(transitionName, setNextAnimate);
                this.classList.add("current");
                this.classList.remove('navInNext');
                changeState();
            }
            return function() {
                var current = lis[order];
                order = order + 1 > len ? 0 : order + 1;
                var next = lis[order]; //获取下一个元素
                if (!transitionName) {
                    alert("你浏览器怎么这么垃圾,赶紧换一个吧");
                } else {
                    current.addEventListener(transitionName, setCurrentAnimate);
                    next.addEventListener(transitionName, setNextAnimate);
                }
                current.classList.add('navOutNext'); //开始执行动画
                next.classList.add('navInNext');
            }
        })();

对不起,吓到大家了,我这里又写了一个闭包。。。 当然,主要入口函数还是在return 后面。
order用来标识当前的元素的序号。 需要注意的是添加动画监听的那一部分。我这里使用了一个tricks(from moderniz),我贴出来吧。

动画支持检测

var transitionName = (function() {

    var t;

    var el = document.createElement('fakeelement');

    //其实使用animated完全可以取代transition
    var transitions = {
        //这里是aniamted事件
        'WebkitAnimation': 'webkitAnimationEnd',
        'OAnimation': 'oAnimationEnd',
        'msAnimation': 'MSAnimationEnd',
        'animation': 'animationend'
            //下面是transition事件
            // 'transition':'transitionend',

        // 'OTransition':'oTransitionEnd',

        // 'MozTransition':'transitionend',

        // 'WebkitTransition':'webkitTransitionEnd',

        // 'MsTransition':'msTransitionEnd'

    }


    for (t in transitions) {

        if (el.style[t] !== undefined) {

            return transitions[t];

        }

    }

})();

其实这个IIFE主要的功能就是检测,你的浏览器到底支持哪一个动画监听函数。 好,pass.
我们回到刚才的主函数nextExe. 接着,我们给current和next添加监听,监听函数先放着。 接着我们给current和next添加动画(就是添加class). 就这样。然后他会触发监听函数。 这里就不过多介绍了, 唯一需要提及的就是,需要在后面对监听进行解绑,避免重复绑定。

废话说完了。 直接看个实例吧。

slider实例
这应该算是最原始的轮播。 接着我们可以在上面加上一些我们想要的功能。这里我加上了一些比较常用的,比如,轮播标识符,左右翻页。

由于比较简单,我这里直接把实例贴出来。其实主要的干货就是最原始的轮播,其余的都是花花草草。

update slider

好了,大部分内容我也差不多介绍完了。

说说轮播

上面基本上把简单轮播的原理介绍一遍,虽说低版本的SB IE可能会不支持。 但这个主要取决于你产品leader的规范,如果他要求是ie9+那么你使用这个应该问题不大,就是需要处理一下动画结束事件的支持。如果甚者需要将ie8考虑进来,那么,这个应该使用css的基本属性,而不能使用css3,或者直接使用js进行改变。还是那句话,站在你的角度去造一个unique轮子,就是最好的学习。


villainhr
7.8k 声望2.2k 粉丝

下一篇 »
git入门讲解