js 实现动画功能,完整解析插件版 可更改配置参数[animate.js]
前言:
本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽。
本篇文章为您分析一下原生JS写一个运动插件
基本功能:
补充: 本插件需要依赖heplers.js插件的(对象混合与克隆) https://www.cnblogs.com/qq4297751/p/12630364.html
补充中......
HTML结构
<div class="container"></div>
<p>
<button id="start">开始</button>
<button id="stop">结束</button>
</p>
CSS样式
<style>
.container {
width: 100px;
height: 100px;
background-color: aqua;
position: absolute;
left: 0;
top: 0;
}
p{
position: absolute;
top: 50px;
left: 100px;
}
</style>
JS行为
需求分析:
动画: 某些元素的某些CSS属性,在一段时间内,从一个值变化到另一个值
动画插件: 某些数据(数字),在一段时间内,从一个值变化到另一个值
不考虑DOM元素,DOM元素由用户传入
创建一个构造函数,让用户传入一些必须的参数(值、函数)
引入helper.js插件(自己封装的),使用对象混合
计算运动的总次数
获取当前的运动状态
计算所有属性每次运动的距离
为Animate函数添加方法
在原型上添加动画的开始函数
判断当前动画是否存在
开启一个定时器 ( 清空)
设置当前动画的状态(每次改变的距离)
页面JS:
var div = document.querySelector(".container");
var animate = new this.myPlugin.Animate({
duration: 30,
tatal: 1000,
begin: {
left: 0,
top: 0
},
end: {
left: 1000,
top: 600
},
});
/**
* 动画: 某些元素的某些CSS属性,在一段时间内,从一个值变化到另一个值
* 动画插件: 某些数据,在一段时间内,从一个值变化到另一个值
* 构造函数
* @param {Object} option 配置对象
*/
this.myPlugin.Animate = function (option) {
// 第一步: 默认配置
var defalutOption = {
duration: 16, // 默认间隔时间,单位毫秒
total: 1000, // 默认总时间,单位毫秒
begin: {}, // 需要变化的初始值
end: {} // 需要变化的结束值
}
// 第二步: 对象混合 参考helper.js中的对象混合插件
this.option = myPlugin.mixin(defalutOption, option);
// 计时器的id
var timer = null;
// 第三步: 运行总次数 变化的次数
this.number = Math.ceil(this.option.total / this.option.duration);
// 3.1 当前运动的次数
this.curNumber = 0;
// 第四步: 得到当前的运动状态 参考helper.js中的对象克隆插件 因为当前的运动属性肯定和你的初始值运动属性是一样的,所有我们要克隆他
this.curData = myPlugin.clone(this.option.begin);
// 第五步: 所有属性运动的总距离
this.distance = {};
// 5.1 所有属性每次运动的距离
this.everyDistance = {};
// 循环begin和end的所有属性
for (var prop in this.option.begin) {
// 5.2 所有属性运动的距离 = 结束值 - 初始值
this.distance[prop] = this.option.end[prop] - this.option.begin[prop];
// 5.3 所有属性每次运动的距离 = 运动总距离 / 运动次数
this.everyDistance[prop] = this.distance[prop] / this.number;
}
}
/**
* 在原型上添加动画方法,因为每创建一个Animate函数时都会创建一个start方法,这样代码比较冗余
* 第七步: 7.1 开始动画
*/
this.myPlugin.Animate.prototype.start = function () {
// 第八步: 如果这个定时器已经有动画了或者当前运动的次数达到了运动的总次数
if (this.timer || this.curNumber === this.number) {
// 不做任何处理 此处并非清空定时器
return;
}
// 8.1 保存this
var self = this;
// 第九步: 开启一个定时器
this.timer = setInterval(function () {
// 9.1 每次运动次数加一
self.curNumber++;
// 9.2 如果当前运动的次数等于总次数
if (self.curNumber === self.number) {
// 9.3 停止动画
self.stop();
}
}, this.option.duration)
}
/**
* 第七步: 7.2 停止动画
*/
this.myPlugin.Animate.prototype.stop = function () {
// 清空定时器
clearInterval(this.timer);
// 将定时器设置为null
this.timer = null;
}
/**
* 在原型上添加动画方法,因为每创建一个Animate函数时都会创建一个start方法,这样代码比较冗余
* 第七步: 7.1 开始动画
*/
this.myPlugin.Animate.prototype.start = function () {
// 第八步: 如果这个定时器已经有动画了或者当前运动的次数达到了运动的总次数
if (this.timer || this.curNumber === this.number) {
// 不做任何处理 此处并非清空定时器
return;
}
// 8.1 保存this
var self = this;
// 第九步: 开启一个定时器
this.timer = setInterval(function () {
// 9.1 每次运动次数加一
self.curNumber++;
// 第十步: 改变self.curData的每一项属性
for (var prop in self.curData) {
// 10.1 这里进行的是小数的运算。
if (self.curNumber === self.number) {
// 10.2 处理小数不精确 最后一次运动
self.curData[prop] = self.option.end[prop];
} else {
// 10.3 每次运动都加上当前的距离
self.curData[prop] += self.everyDistance[prop];
}
}
// 9.2 如果当前运动的次数等于总次数
if (self.curNumber === self.number) {
// 9.3 停止动画
self.stop();
}
}, this.option.duration)
}
/**
* 第七步: 7.2 停止动画
*/
this.myPlugin.Animate.prototype.stop = function () {
// 清空定时器
clearInterval(this.timer);
// 将定时器设置为null
this.timer = null;
}
在页面的JS中添加:
var div = document.querySelector(".container");
var animate = new this.myPlugin.Animate({
duration: 30,
tatal: 1000,
begin: {
left: 0,
top: 0
},
end: {
left: 1000,
top: 600
},
onstart: function () {
console.log("开始");
},
});
start.onclick = function () {
animate.start();
}
// 第八步: 如果这个定时器已经有动画了或者当前运动的次数达到了运动的总次数
if (this.timer || this.curNumber === this.number) {
// 不做任何处理 此处并非清空定时器
return;
}
// 保存this。
var self = this;
// 第十一步: 如果在配置里有这个函数,我们就在开始的时候调用
if (this.option.onstart) {
// 调用函数,通过call来传入他的this指向
this.option.onstart.call(self)
}
// 第九步: 开启一个定时器
this.timer = setInterval(function () {
// console.log(self.curData);
// 9.1 每次运动次数加一
self.curNumber++;
// 第十步: 改变self.curData的每一项属性
for (var prop in self.curData) {
// 10.1 这里进行的是小数的运算。
if (self.curNumber === self.number) {
// 10.2 处理小数不精确 最后一次运动
self.curData[prop] = self.option.end[prop];
} else {
// 10.3 每次运动都加上当前的距离
self.curData[prop] += self.everyDistance[prop];
}
}
// 第十一步: 如果在配置里有这个函数,我们就在开始的时候调用
if (self.option.onmove) {
// 调用函数,通过call来传入他的this指向
self.option.onmove.call(self);
}
// 9.2 如果当前运动的次数等于总次数
if (self.curNumber === self.number) {
self.stop();
// 第十一步: 如果在配置里有这个函数,我们就在开始的时候调用
if (self.option.onover) {
// 调用函数,通过call来传入他的this指向
self.option.onover.call(self);
}
}
}, this.option.duration)
// 当每次发生变化时
onmove: function () {
// console.log(this.curData);
div.style.left = this.curData.left + "px";
div.style.top = this.curData.top + "px";
div.style.background = `rgb(${this.curData.r},${this.curData.g},${this.curData.b})`;
},
// 第八步: 如果这个定时器已经有动画了或者当前运动的次数达到了运动的总次数
if (this.timer || this.curNumber === this.number) {
// 不做任何处理 此处并非清空定时器
return;
}
// 保存this。
var self = this;
// 第十一步: 如果在配置里有这个函数,我们就在开始的时候调用
if (this.option.onstart) {
// 调用函数,通过call来传入他的this指向
this.option.onstart.call(self)
}
// 第九步: 开启一个定时器
this.timer = setInterval(function () {
// console.log(self.curData);
// 9.1 每次运动次数加一
self.curNumber++;
// 第十步: 改变self.curData的每一项属性
for (var prop in self.curData) {
// 10.1 这里进行的是小数的运算。
if (self.curNumber === self.number) {
// 10.2 处理小数不精确 最后一次运动
self.curData[prop] = self.option.end[prop];
} else {
// 10.3 每次运动都加上当前的距离
self.curData[prop] += self.everyDistance[prop];
}
}
// 第十二步: 如果在配置里有这个函数,我们就在开始的时候调用
if (self.option.onmove) {
// 调用函数,通过call来传入他的this指向
self.option.onmove.call(self);
}
// 9.2 如果当前运动的次数等于总次数
if (self.curNumber === self.number) {
self.stop();
}
}, this.option.duration)
btnStop.onclick = function () {
animate.stop();
}
// 第八步: 如果这个定时器已经有动画了或者当前运动的次数达到了运动的总次数
if (this.timer || this.curNumber === this.number) {
// 不做任何处理 此处并非清空定时器
return;
}
// 保存this。
var self = this;
// 第十一步: 如果在配置里有这个函数,我们就在开始的时候调用
if (this.option.onstart) {
// 调用函数,通过call来传入他的this指向
this.option.onstart.call(self)
}
// 第九步: 开启一个定时器
this.timer = setInterval(function () {
// console.log(self.curData);
// 9.1 每次运动次数加一
self.curNumber++;
// 第十步: 改变self.curData的每一项属性
for (var prop in self.curData) {
// 10.1 这里进行的是小数的运算。
if (self.curNumber === self.number) {
// 10.2 处理小数不精确 最后一次运动
self.curData[prop] = self.option.end[prop];
} else {
// 10.3 每次运动都加上当前的距离
self.curData[prop] += self.everyDistance[prop];
}
}
// 第十二步: 如果在配置里有这个函数,我们就在开始的时候调用
if (self.option.onmove) {
// 调用函数,通过call来传入他的this指向
self.option.onmove.call(self);
}
// 9.2 如果当前运动的次数等于总次数
if (self.curNumber === self.number) {
self.stop();
// 第十三步: 如果在配置里有这个函数,我们就在开始的时候调用
if (self.option.onover) {
// 调用函数,通过call来传入他的this指向
self.option.onover.call(self);
}
}
}, this.option.duration)
HTML结构
<div class="container">
</div>
<p>
<button id="btnBegin">开始</button>
<button id="btnStop">停止</button>
</p>
CSS样式
<style>
.container {
position: absolute;
left: 0;
top: 0;
width: 100px;
height: 100px;
background-color: aqua;
}
p {
position: absolute;
left: 200px;
top: 100px;
width: 100px;
height: 100px;
}
</style>
JS行为
页面JS行为
<script src="./plugin/helpers.js"></script> <!--引入插件-->
<script src="./anmate.js"></script> <!--引入插件-->
<script>
var div = document.querySelector(".container");
var animate = new this.myPlugin.Animate({
duration: 30,
tatal: 1000,
begin: {
left: 0,
top: 0
},
end: {
left: 1000,
top: 400
},
onstart: function () {
console.log("开始");
},
// 当每次发生变化时
onmove: function () {
console.log(this.curData);
div.style.left = this.curData.left + "px";
div.style.top = this.curData.top + "px";
div.style.background = `rgb(${this.curData.r},${this.curData.g},${this.curData.b})`;
},
onover: function() {
console.log("结束");
}
});
btnBegin.onclick = function () {
animate.start();
}
btnStop.onclick = function () {
animate.stop();
}
// console.log(animate);
</script>
插件JS行为
if (!this.myPlugin) {
this.myPlugin = {};
}
/**
* 动画: 某些元素的某些CSS属性,在一段时间内,从一个值变化到另一个值
* 动画插件: 某些数据,在一段时间内,从一个值变化到另一个值
* 构造函数
* @param {Object} option 配置对象
*/
this.myPlugin.Animate = function (option) {
// 第一步: 默认配置
var defalutOption = {
duration: 16, // 默认间隔时间,单位毫秒
total: 1000, // 默认总时间,单位毫秒
begin: {}, // 需要变化的初始值
end: {} // 需要变化的结束值
}
// 第二步: 对象混合 参考helper.js中的对象混合插件
this.option = myPlugin.mixin(defalutOption, option);
// 第三步: 计时器的id
var timer = null;
// 3.1 运行总次数 变化的次数
this.number = Math.ceil(this.option.total / this.option.duration);
// 3.2 当前运动的次数
this.curNumber = 0;
// 第四步: 得到当前的运动状态 参考helper.js中的对象克隆插件 因为当前的运动属性肯定和你的初始值运动属性是一样的,所有我们要克隆他
this.curData = myPlugin.clone(this.option.begin);
// 第五步: 所有属性运动的总距离
this.distance = {};
// 5.1 所有属性每次运动的距离
this.everyDistance = {};
// 第六步: 循环begin和end的所有属性
for (var prop in this.option.begin) {
// 6.1 所有属性运动的距离 = 结束值 - 初始值
this.distance[prop] = this.option.end[prop] - this.option.begin[prop];
// 6.2 所有属性每次运动的距离 = 运动总距离 / 运动次数
this.everyDistance[prop] = this.distance[prop] / this.number;
}
}
/**
* 在原型上添加动画方法,因为每创建一个Animate函数时都会创建一个start方法,这样代码比较冗余
* 第七步: 7.1 开始动画
*/
this.myPlugin.Animate.prototype.start = function () {
// 第八步: 如果这个定时器已经有动画了或者当前运动的次数达到了运动的总次数
if (this.timer || this.curNumber === this.number) {
// 不做任何处理 此处并非清空定时器
return;
}
// 保存this。
var self = this;
// 第十一步: 如果在配置里有这个函数,我们就在开始的时候调用
if (this.option.onstart) {
// 调用函数,通过call来传入他的this指向
this.option.onstart.call(self)
}
// 第九步: 开启一个定时器
this.timer = setInterval(function () {
// console.log(self.curData);
// 9.1 每次运动次数加一
self.curNumber++;
// 第十步: 改变self.curData的每一项属性
for (var prop in self.curData) {
// 10.1 这里进行的是小数的运算。
if (self.curNumber === self.number) {
// 10.2 处理小数不精确 最后一次运动
self.curData[prop] = self.option.end[prop];
} else {
// 10.3 每次运动都加上当前的距离
self.curData[prop] += self.everyDistance[prop];
}
}
// 第十二步: 如果在配置里有这个函数,我们就在开始的时候调用
if (self.option.onmove) {
// 调用函数,通过call来传入他的this指向
self.option.onmove.call(self);
}
// 9.2 如果当前运动的次数等于总次数
if (self.curNumber === self.number) {
self.stop();
// 第十三步: 如果在配置里有这个函数,我们就在开始的时候调用
if (self.option.onover) {
// 调用函数,通过call来传入他的this指向
self.option.onover.call(self);
}
}
}, this.option.duration)
}
/**
* 第七步: 7.2 停止动画
*/
this.myPlugin.Animate.prototype.stop = function () {
// 清空定时器
clearInterval(this.timer);
// 将定时器设置为null
this.timer = null;
}
结语
整完!!!
js 实现动画功能,完整解析插件版 可更改配置参数[animate.js]的更多相关文章
- js 控制Div循环显示 非插件版
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- js 实现文字滚动功能,可更改配置参数 带完整版解析代码。
前言: 本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽. 本篇文章为您分析一下原生JS写文字滚动效果 需求分析: 需要 ...
- js 实现淘宝放大镜功能,可更改配置参数 带完整版解析代码[magnifier.js]
前言: 本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽. 本篇文章为您分析一下原生JS写淘宝放大镜效果 基本功能: 运 ...
- js 实现图片瀑布流效果,可更改配置参数 带完整版解析代码[waterFall.js]
前言: 本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽. 本篇文章为您分析一下原生JS实现图片瀑布流效果 页面需求 1 ...
- js 实现淘宝无缝轮播图效果,可更改配置参数 带完整版解析代码[slider.js]
前言: 本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽. 本篇文章为您分析一下原生JS写淘宝无缝轮播图效果 需求分析: ...
- js 函数的防抖(debounce)与节流(throttle) 带 插件完整解析版 [helpers.js]
前言: 本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽. 函数防抖与节流是做什么的?下面进行通俗的讲解. 本文借鉴:h ...
- js 函数的多图片懒加载(lazy) 带插件版完整解析
前言: 本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽. 本篇文章为您分析一下原生JS实现图片懒加载效果 页面需求 1 ...
- 好用的jquery.animateNumber.js数字动画插件
在做公司的运营报告页面时,有一个数字累计增加的动画效果,一开始,毫无头绪,不知如何下手,于是上网查资料,发现大多都是用的插件来实现的,那么今天,我也来用插件jquery.animateNumber.j ...
- Knockout.js 数据验证之插件版和无插件版
本文我们将介绍使用 Knockout.js 实现一些基本的数据验证.就如我们在标题里提到的,我们会使用两种方法来创建数据验证方法. 使用自定义方法,不需要任何插件 最简单的方法是使用已有的插件 如果你 ...
随机推荐
- ensp,acl访问控制列表
ACL分类: 基本ACL 编号范围: 2000-2999 参数:源ip地址 高级ACL 编号范围: 3000-3999 参数:源ip地址,目的ip地址,源端口,目的端口等 二层ACL ...
- bootstraptable 必备知识点
1.如何动态刷新表中数据? (1).无参刷新: $("#table").bootstrapTable('refresh'); (2).带参刷新: var opt = { url: ...
- MySQL学习之路1-Mac下启动连接MySQL服务
MySQL简介 (MySQL是目前最流行的关系型数据库管理系统,现属于Oracle公司.) MySQL主要特点: 支持大型数据库,支持5000万条记录的数据仓库,32位系统表文件最大可支持4GB,64 ...
- java的套接字实现远程连接
package jnet;//客户端程序,使用套接字连接服务器import java.net.*;import java.io.*;import javax.swing.*; public class ...
- AJ学IOS 之微博项目实战(7)程序启动新特性用UICollectionViewController实现
AJ分享,必须精品 一:效果 这里实现了大多数app都会有的软件新特性的功能,用的是UICollectionViewController实现的 二:思路 这里用了UICollectionViewCon ...
- AJ学IOS(28)UI之Quartz2D简单介绍
AJ分享,必须精品 iOS开发UI篇—Quartz2D简单介绍 什么是Quartz2D Quartz 2D是⼀个二维绘图引擎,同时支持iOS和Mac系统 Quartz 2D能完成的工作: 绘制图形 : ...
- Python 控制流代码混淆简介,加大别人分析你代码逻辑和流程难度
前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: 王平 PS:如有需要Python学习资料的小伙伴可以加点击下方链接自 ...
- 资料整理:python自动化测试——操作测试对象
文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:爱吃米饭的猪 PS:如有需要Python学习资料的小伙伴可以加点击下方链接自 ...
- PDF各种骚操作如何用python实现
前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: wLsq PS:如有需要Python学习资料的小伙伴可以加点击下方链 ...
- sqli-labs通关教程----21~30关
第二十一关 第二十一关我们正常登陆后看到,uname后面变成了一堆字母 这是经过base64编码之后的样子,所以就照葫芦画瓢,将我payload的uname后面的部分转码成base64,这里可以用正常 ...