写在前面:感谢腾讯课堂与妙味课堂的移动端公开课

  对于需要设置动画的元素需要提前设置css()样式,这样数据才会被记录起来。

function css(ele, attr, val) {
if (/rotate/.test(attr) || /scale/.test(attr) || /skew/.test(attr) || /translate/.test(attr)) {
return cssTransform(ele, attr, val);
}
if (arguments.length == 2) {
var val = getComputedStyle(ele)[attr];
if (attr == 'opacity') {
val = Math.round(val * 100);
}
return parseFloat(val)
}
if (attr == 'opacity') {
ele.style.opacity = val / 100;
} else {
ele.style[attr] = val + 'px'
}
}

这里需要判断属于transform的值

/*
* 设置transform 只能在这里设置 不能在css设置
* ele.transform ={
* rotate: 40,
* scale: 100,
* skew:
* translate
* }
* */
function cssTransform(ele, attr, val) {
ele.transform = ele.transform || {}
if (typeof val == "undefined") {
//get
if (typeof ele.transform[attr] == 'undefined') { //代表没有设置transform 返回默认值
switch (attr) {
case 'scale':
case 'scaleX':
case 'scaleY':
case 'scaleZ':
ele.transform[attr] = 100;
break;
default:
ele.transform[attr] = 0;
break;
}
}
return ele.transform[attr];
} else {
//set
var transformVal = '';
ele.transform[attr] = val; for (s in ele.transform) {
switch (s) {
case 'scale':
case 'scaleX':
case 'scaleY':
case 'scaleZ':
transformVal += " " + s + "(" + ele.transform[s]/100 + ")";
break;
case 'rotate':
case 'rotateX':
case 'rotateY':
case 'rotateZ':
case 'skew':
case 'skewX':
case 'skewY':
transformVal += " " + s + "(" + ele.transform[s] + "deg)";
break;
default:
transformVal += " " + s + "(" + ele.transform[s] + "px)";
break;
}
} ele.style.WebkitTransform = ele.style.transform = transformVal;
}
}

通过检测,在合适位置调用MTwen函数

/*
* @param el:控制元素 (element)
* @param target:想要达成效果的数据 例如:translateY (string)
* @param time:历时 (number)
* @param type:运动效果 (string)
* @param callIn:运动中执行的函数 (fn)
* @param callBack:运动结束执行的函数 (fn)
* */
function MTween(init) {
var t = 0;
var b = {};
var c = {};
var d = init.time / 20;
for (var s in init.target) {
b[s] = css(init.el, s);
c[s] = init.target[s] - b[s];
}
clearInterval(init.el.timer);
init.el.timer = setInterval(function () {
t++;
if (t > d) {
clearInterval(init.el.timer);
init.callBack && init.callBack.call(init.el);
} else {
init.callIn && init.callIn.call(init.el);
for (var s in b) {
var val = Number((Tween[init.type](t, b[s], c[s], d)).toFixed(2));
css(init.el, s, val)
}
}
},20)
}

先上完整的代码

function css(ele, attr, val) {

    if (/rotate/.test(attr) || /scale/.test(attr) || /skew/.test(attr) || /translate/.test(attr)) {
return cssTransform(ele, attr, val);
}
if (arguments.length == 2) {
var val = getComputedStyle(ele)[attr];
if (attr == 'opacity') {
val = Math.round(val * 100);
}
return parseFloat(val)
}
if (attr == 'opacity') {
ele.style.opacity = val / 100;
} else {
ele.style[attr] = val + 'px'
}
}
/*
* @param el:控制元素 (element)
* @param target:想要达成效果的数据 例如:translateY (string)
* @param time:历时 (number)
* @param type:运动效果 (string)
* @param callIn:运动中执行的函数 (fn)
* @param callBack:运动结束执行的函数 (fn)
* */
function MTween(init) {
var t = 0;
var b = {};
var c = {};
var d = init.time / 20;
for (var s in init.target) {
b[s] = css(init.el, s);
c[s] = init.target[s] - b[s];
}
clearInterval(init.el.timer);
init.el.timer = setInterval(function () {
t++;
if (t > d) {
clearInterval(init.el.timer);
init.callBack && init.callBack.call(init.el);
} else {
init.callIn && init.callIn.call(init.el);
for (var s in b) {
var val = Number((Tween[init.type](t, b[s], c[s], d)).toFixed(2));
css(init.el, s, val)
}
}
},20)
} /*
* 设置transform 只能在这里设置 不能在css设置
* ele.transform ={
* rotate: 40,
* scale: 100,
* skew:
* translate
* }
* */
function cssTransform(ele, attr, val) {
ele.transform = ele.transform || {}
if (typeof val == "undefined") {
//get
if (typeof ele.transform[attr] == 'undefined') { //代表没有设置transform 返回默认值
switch (attr) {
case 'scale':
case 'scaleX':
case 'scaleY':
case 'scaleZ':
ele.transform[attr] = 100;
break;
default:
ele.transform[attr] = 0;
break;
}
} return ele.transform[attr];
} else {
//set
var transformVal = '';
ele.transform[attr] = val; for (s in ele.transform) {
switch (s) {
case 'scale':
case 'scaleX':
case 'scaleY':
case 'scaleZ':
transformVal += " " + s + "(" + ele.transform[s]/100 + ")";
break;
case 'rotate':
case 'rotateX':
case 'rotateY':
case 'rotateZ':
case 'skew':
case 'skewX':
case 'skewY':
transformVal += " " + s + "(" + ele.transform[s] + "deg)";
break;
default:
transformVal += " " + s + "(" + ele.transform[s] + "px)";
break;
}
} ele.style.WebkitTransform = ele.style.transform = transformVal;
}
} /*
* t : time 已过时间
* b : begin 起始值
* c : count 总的运动值
* d : duration 持续时间
* */ //Tween.linear(); var Tween = {
linear: function (t, b, c, d) { //匀速
return c * t / d + b;
},
easeIn: function (t, b, c, d) { //加速曲线
return c * (t /= d) * t + b;
},
easeOut: function (t, b, c, d) { //减速曲线
return -c * (t /= d) * (t - 2) + b;
},
easeBoth: function (t, b, c, d) { //加速减速曲线
if ((t /= d / 2) < 1) {
return c / 2 * t * t + b;
}
return -c / 2 * ((--t) * (t - 2) - 1) + b;
},
easeInStrong: function (t, b, c, d) { //加加速曲线
return c * (t /= d) * t * t * t + b;
},
easeOutStrong: function (t, b, c, d) { //减减速曲线
return -c * ((t = t / d - 1) * t * t * t - 1) + b;
},
easeBothStrong: function (t, b, c, d) { //加加速减减速曲线
if ((t /= d / 2) < 1) {
return c / 2 * t * t * t * t + b;
}
return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
},
elasticIn: function (t, b, c, d, a, p) { //正弦衰减曲线(弹动渐入)
if (t === 0) {
return b;
}
if ((t /= d) == 1) {
return b + c;
}
if (!p) {
p = d * 0.3;
}
if (!a || a < Math.abs(c)) {
a = c;
var s = p / 4;
} else {
var s = p / (2 * Math.PI) * Math.asin(c / a);
}
return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
},
elasticOut: function (t, b, c, d, a, p) { //正弦增强曲线(弹动渐出)
if (t === 0) {
return b;
}
if ((t /= d) == 1) {
return b + c;
}
if (!p) {
p = d * 0.3;
}
if (!a || a < Math.abs(c)) {
a = c;
var s = p / 4;
} else {
var s = p / (2 * Math.PI) * Math.asin(c / a);
}
return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
},
elasticBoth: function (t, b, c, d, a, p) {
if (t === 0) {
return b;
}
if ((t /= d / 2) == 2) {
return b + c;
}
if (!p) {
p = d * (0.3 * 1.5);
}
if (!a || a < Math.abs(c)) {
a = c;
var s = p / 4;
}
else {
var s = p / (2 * Math.PI) * Math.asin(c / a);
}
if (t < 1) {
return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) *
Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
}
return a * Math.pow(2, -10 * (t -= 1)) *
Math.sin((t * d - s) * (2 * Math.PI) / p) * 0.5 + c + b;
},
backIn: function (t, b, c, d, s) { //回退加速(回退渐入)
if (typeof s == 'undefined') {
s = 1.70158;
}
return c * (t /= d) * t * ((s + 1) * t - s) + b;
},
backOut: function (t, b, c, d, s) {
if (typeof s == 'undefined') {
s = 3.70158; //回缩的距离
}
return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
},
backBoth: function (t, b, c, d, s) {
if (typeof s == 'undefined') {
s = 1.70158;
}
if ((t /= d / 2 ) < 1) {
return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
}
return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
},
bounceIn: function (t, b, c, d) { //弹球减振(弹球渐出)
return c - Tween['bounceOut'](d - t, 0, c, d) + b;
},
bounceOut: 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 + 0.75) + b;
} else if (t < (2.5 / 2.75)) {
return c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375) + b;
}
return c * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375) + b;
},
bounceBoth: function (t, b, c, d) {
if (t < d / 2) {
return Tween['bounceIn'](t * 2, 0, c, d) * 0.5 + b;
}
return Tween['bounceOut'](t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b;
}
}

接下来说一下使用方式

1.设置css(el,'translateY',) //获取translateY的值

2.处理后 css(el, 'translateY', -translateY*scale)//获设置translateY的值

3.运行动画

 MTween({
el: el,
target: {
translateY: target
},
time:3,
type: 'backOut',
callBack: function () {
(init.offBar)|| (scrollBar.style.opacity = 0);
},
callIn: function () {
var translateY = css(inner, 'translateY');
(init.offBar)|| css(scrollBar, 'translateY', -translateY*scale);
}
})

接下来的完整的代码

可以自己去尝试下

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width,user-scalable=no,initial-scale=1.0">
<title>Title</title>
<style>
body {
margin: 0;
} body, html {
height: 100%;
overflow: hidden;
position: relative;
} header {
height: 40px;
font-size: 20px;
line-height: 40px;
text-align: center;
background: #000;
color: #fff;
width: 100%;
} footer {
height: 40px;
line-height: 40px;
text-align: center;
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: #000;
color: white;
} #wrap {
position: absolute;
left: 0;
right: 0;
bottom: 40px;
top: 40px;
overflow: hidden;
} #list {
margin: 0;
padding: 0;
list-style: none;
} #list li {
height: 30px;
border-bottom: 1px solid #000;
line-height: 30px;
text-indent: 20px;
font-size: 16px;
}
</style>
</head>
<body>
<header id="header">测试滑屏动画</header>
<section id="wrap">
<ul id="list"></ul>
</section>
<footer id="footer">慢慢的干活,还是很不错</footer>
<script src="m.Tween.js"></script>
<script>
/*
* 缓冲动画
* 获取最后一次速度=位移/时间
*
* */
document.addEventListener('touchstart', function (ev) {
ev.preventDefault();
})
function setListInner() {
var list = document.querySelector('#list');
var inner = '';
for (var i = 0; i < 100; i++) {
inner += '<li>这是第' + i + '个li</li>'
}
list.innerHTML = inner
}
window.onload = function () {
setListInner();
var wrap = document.querySelector('#wrap');
mScroll({
el: wrap,
offBar : false,
start : function(e){ },
move : function(e){ },
end:function(e){ },
over:function(e){ }
})
}; //添加父级
function mScroll(init){
if(!init.el){
return;
} var inner = init.el.children[0];
var scrollBar = document.createElement('div'); var startPoint = 0;
var startEl = 0;
var lastDis = 0; //最后一次距离
var lastY = 0; //上一次距离
var lastTime = 0;
var lastTimeDis = 0;
var maxTranslate = init.el.clientHeight - inner.offsetHeight;
var scale = init.el.clientHeight / inner.offsetHeight; inner.style.minHeight = '100%'; if(!init.offBar){
scrollBar.style.cssText = 'width:6px;background:rgba(0,0,0,.5);' +
'position:absolute;right:0;top:0;border-radius:3px;opacity:0;transition:opacity .3s';
init.el.appendChild(scrollBar);
} //设置动画
css(inner, 'translateZ', 0.01); inner.addEventListener('touchstart', function (e) {
clearInterval(inner.time);
//预留后面高度被改变
maxTranslate = init.el.clientHeight - inner.offsetHeight;
//内容太少
if(!init.offBar){
if(maxTranslate >= 0){
scrollBar.style.display = 'none'
}else{
scrollBar.style.display = 'block' }
scale = init.el.clientHeight / inner.offsetHeight;
scrollBar.style.height = init.el.clientHeight * scale+'px';
} startPoint = e.changedTouches[0].pageY;
startEl = css(inner, 'translateY'); //获得点击下去的translateY 的值
lastY = startEl; //赋值每一次开始的位置
lastTimeDis = lastDis = 0;
lastTime = new Date().getTime(); (init.offBar)||(scrollBar.style.opacity = 1);
});
inner.addEventListener('touchmove', function (e) { var nowPoint = e.changedTouches[0].pageY;
var dis = nowPoint - startPoint;
var translateY = dis + startEl;
var nowTime = new Date().getTime();
css(inner, 'translateY', translateY);
(init.offBar)||css(scrollBar, 'translateY', -translateY*scale); lastDis = translateY - lastY;
lastY = translateY;
lastTimeDis = nowTime - lastTime;
lastTime = nowTime; });
inner.addEventListener('touchend', function (e) {
var type = 'easeOut';
var speed = Math.round(lastDis / lastTimeDis * 10);
speed = lastTimeDis <= 0 ? 0 : speed;
var target = Math.round(speed * 30 + css(inner, 'translateY'));//缓冲距离 if (target > 0) {
target = 0;
type = 'backOut'
} else if (target < maxTranslate) {
target = maxTranslate;
type = 'backOut'
} MTween({
el: inner,
target: {
translateY: target
},
time: Math.round(Math.abs(target - css(inner, 'translateY')) * 1.5),
type: type,
callBack: function () {
(init.offBar)|| (scrollBar.style.opacity = 0);
},
callIn: function () {
var translateY = css(inner, 'translateY');
(init.offBar)|| css(scrollBar, 'translateY', -translateY*scale);
}
}) }) } </script>
</body>
</html>

封装CSS动画的更多相关文章

  1. amazeui学习笔记--css(常用组件15)--CSS动画Animation

    amazeui学习笔记--css(常用组件15)--CSS动画Animation 一.总结 1.css3动画封装:CSS3 动画封装,浏览器需支持 CSS3 动画. Class 描述 .am-anim ...

  2. 原生Js封装的动画类

    算法用的是Tween类,需要研究的参考这篇文章: http://www.cnblogs.com/cloudgamer/archive/2009/01/06/Tween.html 网页里常用的动画 放大 ...

  3. CSS 动画一站式指南

    CSS 动画一站式指南 目录 CSS 动画一站式指南 1. CSS 动画 1.1 变换 1.1.1 变换属性介绍 1.1.2 变换动画实践 1.2 过渡 1.2.1 过渡属性介绍 1.2.2 过渡动画 ...

  4. 梅须逊雪三分白,雪却输梅一段香——CSS动画与JavaScript动画

    CSS动画并不是绝对比JavaScript动画性能更优越,开源动画库Velocity.js等就展现了强劲的性能. 一.两者的主要区别 先开门见山的说说两者之间的区别. 1)CSS动画: 基于CSS的动 ...

  5. Css 动画的回调

    在做项目中经常会遇到使用动画的情况.以前的情况是用js写动画,利用setTimeout函数或者window.requestAnimationFrame()实现目标元素的动画效果.虽然后者解决了刷新频率 ...

  6. 【译】css动画里的steps()用法详解

    原文地址:http://designmodo.com/steps-c... 原文作者:Joni Trythall 我想你在css 动画里使用steps()会和我一样有很多困惑.一开始我不清楚怎样使用它 ...

  7. css动画属性性能

    性能主要表现:流量.功耗与流畅度 在现有的前端动画体系中,通常有两种模式:JS动画与CSS3动画. JS动画是通过JS动态改写样式实现动画能力的一种方案,在PC端兼容低端浏览器中不失为一种推荐方案. ...

  8. Css动画形式弹出遮罩层,内容区上下左右居中于不定宽高的容器中

    <!DOCTYPE html> <html> <head> </head> <body id="body"> <! ...

  9. css动画与js动画的区别

    CSS动画 优点: (1)浏览器可以对动画进行优化.   1. 浏览器使用与 requestAnimationFrame 类似的机制,requestAnimationFrame比起setTimeout ...

随机推荐

  1. HDU2647 topsort

    Problem Description Dandelion's uncle is a boss of a factory. As the spring festival is coming , he ...

  2. Good Bye 2015 C

    C. New Year and Domino time limit per test 3 seconds memory limit per test 256 megabytes input stand ...

  3. 《A First Course in Abstract Algebra with Applications》-chaper1-数论-关于素数

    由于笔者在别的专栏多次介绍过数论,这里在<抽象代数基础教程>的专栏下,对于chaper1数论这一章节介绍的方式不那么“入门”. 首先来介绍一个代数中常用也是非常重要的证明方法:数学归纳法. ...

  4. C11性能之道:标准库优化

    1.emplace_back减少内存拷贝和移动 emplace_back能通过参数构造对象,不需要拷贝或者移动内存,相比pusk_back能更好的避免内存的拷贝和移动,使容器插入元素性能得到进一步提升 ...

  5. 【bzo1579】拆点+dijkstra优先队列优化+其他优化

    题意: n个点,m条边,问从1走到n的最短路,其中有K次机会可以让一条路的权值变成0.1≤N≤10000;1≤M≤500000;1≤K≤20 题解: 拆点,一个点拆成K个,分别表示到了这个点时还有多少 ...

  6. 【51NOD-0】1046 A^B Mod C

    [算法]快速幂运算 [题解]快速幂的原理是把幂用二进制表示,从最低位a,次低位a2,次次低位(a2)2. #include<cstdio> long long quick_pow(long ...

  7. 如果你也想写个完整的 Vue 组件项目

    1.一个完整的组件项目需要什么? 必要的: 组件构建方式 ( webpack / rollup 之类 ),并提供至少一个主流的输出格式 (ESModule) Demo 及 Demo 源码 文档,可以是 ...

  8. 深入理解javascript原型和闭包(2)——函数与对象的关系

    上文(理解javascript原型和作用域系列(1)——一切都是对象)已经提到,函数就是对象的一种,因为通过instanceof函数可以判断. var fn = function () { }; co ...

  9. 各浏览器的Hack写法【转】

    Hack是针对不同的浏览器去写不同的CSS样式,从而让各浏览器能达到一致的渲染效果,那么针对不同的浏览器写不同的CSS CODE的过程,就叫CSS HACK,同时也叫写CSS Hack.然后将Hack ...

  10. hdu 1863 畅通工程 (并查集+最小生成树)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1863 畅通工程 Time Limit: 1000/1000 MS (Java/Others)    M ...