首页 > 其他 > 详细

图片切换特效的分析和学习

时间:2014-03-17 04:49:16      阅读:528      评论:0      收藏:0      [点我收藏+]

效果

bubuko.com,布布扣

实现功能1 自动切换

               2鼠标移动到图片上暂停

               3鼠标移动到数字上切换到指定图片

                4图片切换动画平滑

bubuko.com,布布扣

基本布局

通过查看元素分布可以发现

每个图片占据1个TD单元格,横向平铺

2 表格table 决定定位---------------------------》动画内容独立于当前文档流,避免dom 的重绘和重排

几个基本的辅助js代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var $ = function (id) {
           return "string" == typeof id ? document.getElementById(id) : id;
       };
       var Extend = function(destination, source) {
           for (var property in source) {
               destination[property] = source[property];
           }
           return destination;
       }
       var CurrentStyle = function(element){
           return element.currentStyle || document.defaultView.getComputedStyle(element, null);
       }
       var Bind = function(object, fun) {
           var args = Array.prototype.slice.call(arguments).slice(2);
           return function() {
               return fun.apply(object, args.concat(Array.prototype.slice.call(arguments)));
           }
       }

1:$根据ID获取元素

2:Extend 通过拷贝属性世面自定义值覆盖默认值

3:CurrentStyle 获取dom中实际展示的样式  ps:这里的方式我第一次见以前还不知道呢bubuko.com,布布扣

4:函数绑定     以前始终找不见闭包最基本的使用场景,这不是闭包这是啥?

Tween 算子,   以前一直不知道 其妙的动画是怎么实现,这次终于找到了,不过这里的源代码并没有解释这些参数 是啥意思

这里是详细介绍:http://blog.csdn.net/pointerfree/article/details/6777693

                              http://www.cnblogs.com/NNUF/archive/2013/01/16/2857784.html

Tween中的方法接受4个参数t,b,c,d 。返回值为计算后的当前位置.

t => time(初始记步次数)   b => begin(初始位置)   c => change(变化量)   d => duration(持续次数)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var Tween = {
    Quart: {
        easeOut: function(t,b,c,d){
            return -c * ((t=t/d-1)*t*t*t - 1) + b;
        }
    },
    Back: {
        easeOut: function(t,b,c,d,s){
            if (s == undefined) s = 1.70158;
            return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
        }
    },
    Bounce: {
        easeOut: function(t,b,c,d){
            if ((t/=d) < (1/2.75)) {
                return c*(7.5625*t*t) + b;
            } else if (t < (2/2.75)) {
                return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
            } else if (t < (2.5/2.75)) {
                return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
            } else {
                return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
            }
        }
    }
}
1
  
1
现在来看看 初始化构造函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
//容器对象,滑动对象,切换数量
     var SlideTrans = function(container, slider, count, options) {
         this._slider = $(slider);
         this._container = $(container);//容器对象
         this._timer = null;//定时器
         this._count = Math.abs(count);//切换数量
         this._target = 0;//目标值
         this._t = this._b = this._c = 0;//tween参数
 
         this.Index = 0;//当前索引
 
         this.SetOptions(options);
 
         this.Auto = !!this.options.Auto;                          PS:!!能够将任何值转化为布尔值
         this.Duration = Math.abs(this.options.Duration);
         this.Time = Math.abs(this.options.Time);
         this.Pause = Math.abs(this.options.Pause);
         this.Tween = this.options.Tween;
         this.onStart = this.options.onStart;
         this.onFinish = this.options.onFinish;
 
         var bVertical = !!this.options.Vertical;
         this._css = bVertical ? "top" : "left";//方向
 
         //样式设置
         var p = CurrentStyle(this._container).position;
         p == "relative" || p == "absolute" || (this._container.style.position = "relative");
         this._container.style.overflow = "hidden";
         this._slider.style.position = "absolute";
 
         this.Change = this.options.Change ? this.options.Change :
                 this._slider[bVertical ? "offsetHeight" : "offsetWidth"] / this._count;
     };
     SlideTrans.prototype = {
         //设置默认属性
         SetOptions: function(options) {
             this.options = {//默认值
                 Vertical: true,//是否垂直方向(方向不能改)
                 Auto:  true,//是否自动
                 Change:  0,//改变量
                 Duration: 50,//滑动持续时间
                 Time:  10,//滑动延时
                 Pause:  4000,//停顿时间(Auto为true时有效)
                 onStart: function(){},//开始转换时执行
                 onFinish: function(){},//完成转换时执行
                 Tween:  Tween.Quart.easeOut//tween算子
             };
             Extend(this.options, options || {});
         },
         //开始切换
         Run: function(index) {
             //修正index
             index == undefined && (index = this.Index);
             index < 0 && (index = this._count - 1) || index >= this._count && (index = 0);
             //设置参数
             this._target = -Math.abs(this.Change) * (this.Index = index);
             this._t = 0;
             this._b = parseInt(CurrentStyle(this._slider)[this.options.Vertical ? "top" : "left"]);
             this._c = this._target - this._b;
 
             this.onStart();
             this.Move();
         },
         //移动
         Move: function() {
             clearTimeout(this._timer);
             //未到达目标继续移动否则进行下一次滑动
             if (this._c && this._t < this.Duration) {
                 this.MoveTo(Math.round(this.Tween(this._t++, this._b, this._c, this.Duration)));
                 this._timer = setTimeout(Bind(this, this.Move), this.Time);
             }else{
                 this.MoveTo(this._target);
                 this.Auto && (this._timer = setTimeout(Bind(this, this.Next), this.Pause));
             }
         },
         //移动到
         MoveTo: function(i) {
             this._slider.style[this._css] = i + "px";
             console.log(i)
         },
         //下一个
         Next: function() {
             this.Run(++this.Index);
         },
         //上一个
         Previous: function() {
             this.Run(--this.Index);
         },
         //停止
         Stop: function() {
             clearTimeout(this._timer); this.MoveTo(this._target);
         }
     };

 

相关方法说明

ps:我以前一直不清楚 定义的默认对象有好多属性,传入的自定义参数如何赋值,原来通过浅层拷贝就可以了

Run 启动方法

Move 移动方法

MoveTo 移动到指定位置方法

Next 切换到下一个图片

Previous 切换到上一张图片

Stop 停止

在细看这几个方法前 先看一下默认值

1
2
3
4
5
6
7
8
9
10
11
this.options = {//默认值
           Vertical: true,//是否垂直方向(方向不能改)
           Auto:  true,//是否自动
           Change:  0,//改变量
           Duration: 50,//滑动持续时间
           Time:  10,//滑动延时
           Pause:  4000,//停顿时间(Auto为true时有效)
         onStart: function(){},//开始转换时执行
           onFinish: function(){},//完成转换时执行
           Tween:  Tween.Quart.easeOut//tween算子
       };

 

动画到底是什么原理呢????这个还得在看看源代码dom树动态运行结果

bubuko.com,布布扣

通过不断的变化可以发现是通过决定定位+控制left 定位来实现 所有图片的滚动切换,其实就是图片在反复按照算法移动

先从run 方法看看

看看运行时 点击4 时候参数run,这些值的变化

bubuko.com,布布扣

看到change 值是610 在那进行赋值的???

bubuko.com,布布扣

搜索发现  在这里进行的赋值 

也就是可见 offsetwidth在JS中是获区元素的宽. 除以 图片的数量

什么是 offsetwidth ?==> http://blog.csdn.net/xuantian868/article/details/3116442

也就是 初始化后change  是不变的

this._b = parseInt(CurrentStyle(this._slider)[this.options.Vertical ? "top" : "left"]);

可见_b 的值是读取执行动画前的left的值 是会

this._target = -Math.abs(this.Change) * (this.Index = index);

_target 是执行动画要移动的距离 是变化量*图片的位置[]

this._c = this._target - this._b;

_c  就是当前位置和目标位置的差距也就是移动的真实距离

RUN 方法最后调用 this.onStart();   和      this.Move();

onStart 主要用户控制下面1,2,3,4的现实情况
        this.Move()  则负责具体的图片移动

下面看看move 方法

1
2
3
4
5
6
7
8
9
10
11
Move: function() {
                clearTimeout(this._timer);
                //未到达目标继续移动否则进行下一次滑动
                if (this._c && this._t < this.Duration) {
                    this.MoveTo(Math.round(this.Tween(this._t++, this._b, this._c, this.Duration)));
                    this._timer = setTimeout(Bind(this, this.Move), this.Time);
                }else{
                    this.MoveTo(this._target);
                    this.Auto && (this._timer = setTimeout(Bind(this, this.Next), this.Pause));
                }
            }


Move 方法第一步是清除 Timeout,然后判断当前位置是否移动完成

this._c && this._t < this.Duration  通过这个条件来判断

_c  是要移动距离

this._t  是初始化的时间,每次移动结束应该会变为0  每次run开始的时候 _t归为0

!_c 为负值也是true 因为  if(-1){}  bubuko.com,布布扣    !!-1==true

bubuko.com,布布扣

如果没有移动完毕,就调用MoveTo修改一次left,谈后setTimeout 调用下一次移动

this.MoveTo(Math.round(this.Tween(this._t++, this._b, this._c, this.Duration)));
                   this._timer = setTimeout(Bind(this, this.Move), this.Time);

如果移动完毕

就就调用

this.MoveTo(this._target);   准确的移动到指定位置
                 this.Auto && (this._timer = setTimeout(Bind(this, this.Next), this.Pause));  绑定下一次移动

到这里 和动画相关的基本方法和原理就分析差不多

下面还有一些js工具

forEach 工具 如果浏览器不支持forEach就自己遍历一遍

1
2
3
4
5
6
7
var forEach = function(array, callback, thisObject){
        if(array.forEach){
            array.forEach(callback, thisObject);
        }else{
            for (var i = 0, len = array.length; i < len; i++) { callback.call(thisObject, array[i], i, array); }
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var st = new SlideTrans("idContainer2", "idSlider2", 5, { Vertical: false });
  var nums = [];
  //插入数字
  for(var i = 0, n = st._count - 1; i <= n;){
      (nums[i] = $("idNum").appendChild(document.createElement("li"))).innerHTML = ++i;
  }
  forEach(nums, function(o, i){
      o.onmouseover = function(){ o.className = "on"; st.Auto = false; st.Run(i); }
      o.onmouseout = function(){ o.className = ""; st.Auto = true; st.Run(); }
  })
  //设置按钮样式
 
 
 
  st.onStart = function(){
      forEach(nums, function(o, i){ o.className = st.Index == i ? "on" : ""; })
  }

 

var st = new SlideTrans("idContainer2", "idSlider2", 5, { Vertical: false });

负责初始化

nums 主要用来处理下面的几个小图片数字并负责绑定 .onmouseover和onmouseout事件

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
<HTML>
<HEAD>
    <TITLE>腾讯软件-图片滑动效果,阿里西西整理收集。</TITLE>
    <style>
        BODY {
            PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px
        }
        UL {
            PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px
        }
        .container {
            WIDTH: 610px; HEIGHT: 205px
        }
        .container A IMG {
            WIDTH: 610px; HEIGHT: 205px
        }
        .container IMG {
            BORDER-BOTTOM-STYLE: none; BORDER-RIGHT-STYLE: none; BORDER-TOP-STYLE: none; BORDER-LEFT-STYLE: none
        }
        .td_f A IMG {
            PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px
        }
        .num {
            POSITION: absolute; WIDTH: 90px; FLOAT: right; TOP: 180px; LEFT: 520px
        }
        .num LI {
            TEXT-ALIGN: center; LINE-HEIGHT: 15px; LIST-STYLE-TYPE: none; MARGIN: 1px; WIDTH: 15px; FONT-FAMILY: Arial; BACKGROUND: url(http://pc.qq.com/pc/images/flashbutton.gif) no-repeat -15px 0px; FLOAT: left; HEIGHT: 15px; COLOR: #86a2b8; FONT-SIZE: 12px; CURSOR: pointer
        }
        .num LI.on {
            LINE-HEIGHT: 15px; WIDTH: 15px; BACKGROUND: url(http://pc.qq.com/pc/images/flashbutton.gif) no-repeat; HEIGHT: 15px; COLOR: #ffffff
        }
        .more {
            FLOAT: right
        }
        .more1 A {
            TEXT-ALIGN: left; LINE-HEIGHT: 25px; MARGIN: 0px 0px 0px 10px; COLOR: #3373a3
        }
    </style>
 
    <SCRIPT type=text/javascript>
        var $ = function (id) {
            return "string" == typeof id ? document.getElementById(id) : id;
        };
        var Extend = function(destination, source) {
            for (var property in source) {
                destination[property] = source[property];
            }
            return destination;
        }
        var CurrentStyle = function(element){
            return element.currentStyle || document.defaultView.getComputedStyle(element, null);
        }
        var Bind = function(object, fun) {
            var args = Array.prototype.slice.call(arguments).slice(2);
            return function() {
                return fun.apply(object, args.concat(Array.prototype.slice.call(arguments)));
            }
        }
        var Tween = {
            Quart: {
                easeOut: function(t,b,c,d){
                    return -c * ((t=t/d-1)*t*t*t - 1) + b;
                }
            },
            Back: {
                easeOut: function(t,b,c,d,s){
                    if (s == undefined) s = 1.70158;
                    return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
                }
            },
            Bounce: {
                easeOut: function(t,b,c,d){
                    if ((t/=d) < (1/2.75)) {
                        return c*(7.5625*t*t) + b;
                    } else if (t < (2/2.75)) {
                        return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
                    } else if (t < (2.5/2.75)) {
                        return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
                    } else {
                        return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
                    }
                }
            }
        }
        //容器对象,滑动对象,切换数量
        var SlideTrans = function(container, slider, count, options) {
            this._slider = $(slider);
            this._container = $(container);//容器对象
            this._timer = null;//定时器
            this._count = Math.abs(count);//切换数量
            this._target = 0;//目标值
            this._t = this._b = this._c = 0;//tween参数
 
            this.Index = 0;//当前索引
 
            this.SetOptions(options);
 
            this.Auto = !!this.options.Auto;
            this.Duration = Math.abs(this.options.Duration);
            this.Time = Math.abs(this.options.Time);
            this.Pause = Math.abs(this.options.Pause);
            this.Tween = this.options.Tween;
            this.onStart = this.options.onStart;
            this.onFinish = this.options.onFinish;
 
            var bVertical = !!this.options.Vertical;
            this._css = bVertical ? "top" : "left";//方向
 
            //样式设置
            var p = CurrentStyle(this._container).position;
            p == "relative" || p == "absolute" || (this._container.style.position = "relative");
            this._container.style.overflow = "hidden";
            this._slider.style.position = "absolute";
 
            this.Change = this.options.Change ? this.options.Change :
                    this._slider[bVertical ? "offsetHeight" : "offsetWidth"] / this._count;
        };
        SlideTrans.prototype = {
            //设置默认属性
            SetOptions: function(options) {
                this.options = {//默认值
                    Vertical: true,//是否垂直方向(方向不能改)
                    Auto:  true,//是否自动
                    Change:  0,//改变量
                    Duration: 50,//滑动持续时间
                    Time:  10,//滑动延时
                    Pause:  4000,//停顿时间(Auto为true时有效)
                    onStart: function(){},//开始转换时执行
                    onFinish: function(){},//完成转换时执行
                    Tween:  Tween.Quart.easeOut//tween算子
                };
                Extend(this.options, options || {});
            },
            //开始切换
            Run: function(index) {
                //修正index
                index == undefined && (index = this.Index);
                index < 0 && (index = this._count - 1) || index >= this._count && (index = 0);
                //设置参数
                this._target = -Math.abs(this.Change) * (this.Index = index);
                this._t = 0;
                this._b = parseInt(CurrentStyle(this._slider)[this.options.Vertical ? "top" : "left"]);
                this._c = this._target - this._b;
 
                this.onStart();
                this.Move();
            },
            //移动
            Move: function() {
                clearTimeout(this._timer);
                //未到达目标继续移动否则进行下一次滑动
                if (this._c && this._t < this.Duration) {
                    this.MoveTo(Math.round(this.Tween(this._t++, this._b, this._c, this.Duration)));
                    this._timer = setTimeout(Bind(this, this.Move), this.Time);
                }else{
                    this.MoveTo(this._target);
                    this.Auto && (this._timer = setTimeout(Bind(this, this.Next), this.Pause));
                }
            },
            //移动到
            MoveTo: function(i) {
                this._slider.style[this._css] = i + "px";
                console.log(i)
            },
            //下一个
            Next: function() {
                this.Run(++this.Index);
            },
            //上一个
            Previous: function() {
                this.Run(--this.Index);
            },
            //停止
            Stop: function() {
                clearTimeout(this._timer); this.MoveTo(this._target);
            }
        };
    </SCRIPT>
<BODY>
告诉你一个应有尽有的网页特效网址:<a href="http://js.alixixi.com">http://js.alixixi.com</a>
<hr />
<DIV id=idContainer2 class=container>
    <TABLE id=idSlider2 border=0 cellSpacing=0 cellPadding=0>
        <TBODY>
        <TR>
            <TD class=td_f><A onclick="pgvSendClick({hottag:‘ISD.SHOW.BANNER.SOFTMGR‘});" href="http://js.alixixi.com"><IMG src="http://pc.qq.com/pc/images/manage.jpg"></A></TD>
            <TD class=td_f><A onclick="pgvSendClick({hottag:‘ISD.SHOW.BANNER.PY‘});" href="http://js.alixixi.com"><IMG src="http://pc.qq.com/pc/images/py.jpg"></A></TD>
            <TD class=td_f><A onclick="pgvSendClick({hottag:‘ISD.SHOW.BANNER.PLAYER‘});" href="http://js.alixixi.com"><IMG src="http://pc.qq.com/pc/images/player.jpg"></A></TD>
            <TD class=td_f><A onclick="pgvSendClick({hottag:‘ISD.SHOW.BANNER.XF‘});"  href="http://js.alixixi.com"><IMG src="http://pc.qq.com/pc/images/xf.jpg"></A></TD>
            <TD class=td_f><A onclick="pgvSendClick({hottag:‘ISD.SHOW.BANNER.TT‘});"  href="http://js.alixixi.com"><IMG  src="http://pc.qq.com/pc/images/TT.jpg"></A></TD>
        </TR>
        </TBODY>
    </TABLE>
    <UL id=idNum class=num></UL>
</DIV>
<SCRIPT>
    //new SlideTrans("idContainer", "idSlider", 3).Run();
    ///////////////////////////////////////////////////////////
    var forEach = function(array, callback, thisObject){
        if(array.forEach){
            array.forEach(callback, thisObject);
        }else{
            for (var i = 0, len = array.length; i < len; i++) { callback.call(thisObject, array[i], i, array); }
        }
    }
    var st = new SlideTrans("idContainer2", "idSlider2", 5, { Vertical: false });
    var nums = [];
    //插入数字
    for(var i = 0, n = st._count - 1; i <= n;){
        (nums[i] = $("idNum").appendChild(document.createElement("li"))).innerHTML = ++i;
    }
    forEach(nums, function(o, i){
        o.onmouseover = function(){ o.className = "on"; st.Auto = false; st.Run(i); }
        o.onmouseout = function(){ o.className = ""; st.Auto = true; st.Run(); }
    })
    //设置按钮样式
 
 
 
    st.onStart = function(){
        forEach(nums, function(o, i){ o.className = st.Index == i ? "on" : ""; })
    }
 
  //   st.Run();
</SCRIPT>
</BODY></HTML>

  

图片切换特效的分析和学习,布布扣,bubuko.com

图片切换特效的分析和学习

原文:http://www.cnblogs.com/qqloving/p/3603873.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!