通过队列保证JQuery动画animate的顺序

通过队列保证JQuery动画animate的顺序

问题来源

因为项目需要需要在前端进行实时模拟设备运行状态,暂时用的是2D,所以就要用到了JQuery的animate,但是只是animate还不能满足需求,因为可能存在这样的一个场景,当这个动画还没执行完,下一个就来了,那么就需要保证前后动画的有序执行,如果不能保证运动的有序执行,那么节点会出现紊乱,特别是css类似{height:'+=10px'}这样的情况,那么就会出现很严重的bug。

解决办法

在动画的基础上添加一个队列来保证动画的执行有序性,队列保存还未运动的动画,这样就不会出现上一个动画还没完成,下一个动画就实现了,好,思路清晰了,那就甩开膀子干吧。

原始版本

//队列Queue.js
var ArrayQueue = function() {
  this.arr = [];
  //入队操作  
  this.push = function(element) {
    this.arr.push(element);
    return true;
  }
  //出队操作  
  this.pop = function() {
    return this.arr.shift();
  }
  //获取队首  
  this.getFront = function() {
    return this.arr[0];
  }
  //获取队尾  
  this.getRear = function() {
    return this.arr[this.arr.length - 1]
  }
  //清空队列  
  this.clear = function() {
    this.arr = [];
  }
  //获取队长  
  this.size = function() {
    return this.arr.length;
  }
  this.isEmpty = function() {
    return this.arr.length == 0;
  }
};
export default new ArrayQueue();

//index.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="https://libs.baidu.com/jquery/1.10.2/jquery.min.js"></script>
	</head>
	<body>
		<div class="text" style="width: 6.25rem;height: 12.5rem;border: bisque solid 0.0625rem;overflow-x: hidden;overflow-y: scroll;">
			
		</div>
		<div class="content" style="width: 37.5rem;height: 3.125rem;border: #000000 solid 0.0625rem;">
			<div class="tr" style="width: 1.25rem; height: 1.25rem; margin-top: 1.25rem;background-color: aqua;"></div>
		</div>
		<button class="send">发送</button>
		<script type="module">//type="module" 必须要有,因为import 是导入模块,如果其他script标签也用到了,那么同样需要加
			import ArrayQueue from './js/Queue.js';
			$(function(){
				var isrunning = false;
				function animate(){
					let msg = ArrayQueue.pop();
					isrunning = true;
					$(".tr").animate({marginLeft:msg+'px'},3000,null,function(){
						$('.text').append('<li>'+$('.tr').css('marginLeft')+'</li>');
						if(ArrayQueue.isEmpty()){
							isrunning = false;
						}else{
							animate();
						}
					});
				};
				function onMessage(msg){
					ArrayQueue.push(msg);
					console.log(msg);
					if(!isrunning){
						animate();
					}
				}
				//模拟发送
				$(".send").click(function(){
					let location = (578*Math.random()).toFixed(0);
					onMessage(location);
				});
			});
		</script>
	</body>
</html>


效果

在这里插入图片描述

优化

作为一个后端java开发工程师,这样写真的是太难受了,既然队列封装了,那么动画何不封装一下呢?继续干~~

//Animate.js Queue.js没变化,就没重复写出来了。
/**
 * 
 * 基于jq的包含队列的逐帧动画,为啥要加入队列呢?如果在同时产生了多个动画的情况下,
 * 如果不能保证运动的有序执行,那么节点会出现紊乱,特别是css类似{height:'+=10px'}
 * 这样的情况,那么就会出现很严重的bug。
 * 
 * */
import ArrayQueue from './Queue.js'
var Animate = function() {
	//运动的节点
	this.$el = null;
	//当前是否在运动
	this.isRunning = false;
	//默认速度
	this.defaultSpeed = 3000;
	//默认回调函数
	this.defaultCallback = function(callback) {
		try{
			callback();
		}catch(e){
			throw Error(e);
		}finally{
			if (ArrayQueue.isEmpty()) {
				this.isRunning = false;
			} else {
				this.animate();
			}
		}
	};
	//初始化
	this.init = function(el) {
		if (!this.isElement(el)) {
			throw Error("init: The type of variable el is not an Element")
		} else {
			this.$el = el;
		}

	};
	//设置参数
	this.setoptions = function(options) {
		if(!options.css){
			throw Error("setoptions: options.css cannot be empty");
		}else{
			let ins = {
				css: options.css || {},
				speed: options.speed || this.defaultSpeed,
				easing: options.easing || null,
				startBefore : options.startBefore(options) || function(options){},
				callback: options.callback,
			}
			return ins;
		}
	};
	//开始运行,加入队列,保证顺序。
	this.start = function(options){
		ArrayQueue.push(this.setoptions(options));
		if(!this.isRunning){
			this.Animate();
		}
	};
	//动画
	this.Animate = function() {
		if (!this.isElement(this.$el)) {
			throw Error("Animate: The type of variable el is not an Element")
		} else {
			try{
				if(!ArrayQueue.isEmpty()){
					let options = ArrayQueue.pop();
					options.startBefore();
					$(this.$el).animate(options.css,options.speed,options.easing,()=>{
						this.defaultCallback(options.callback);
					});
				}
			}catch(e){
				throw Error(e);
			}
			
		}
	};
	//判断对象类型是否为节点
	this.isElement = function(obj) {
		return (typeof HTMLElement === 'object') ?
			(obj instanceof HTMLElement) :
			!!(obj && typeof obj === 'object' && (obj.nodeType === 1 || obj.nodeType === 9) && typeof obj.nodeName ===
				'string');
	}
}
export default new Animate();


//index.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="https://libs.baidu.com/jquery/1.10.2/jquery.min.js"></script>
	</head>
	<body>
		<div class="text" style="width: 6.25rem;height: 12.5rem;border: bisque solid 0.0625rem;overflow-x: hidden;overflow-y: scroll;">
			
		</div>
		<div class="content" style="width: 37.5rem;height: 3.125rem;border: #000000 solid 0.0625rem;">
			<div id="tr" style="width: 1.25rem; height: 1.25rem; margin-top: 1.25rem;background-color: aqua;"></div>
		</div>
		<button class="send">发送</button>
		<script type="module">//type="module" 必须要有,因为import 是导入模块,如果其他script标签也用到了,那么同样需要加
			import Animate from './js/Animate.js';
			$(function(){
				Animate.init(document.getElementById('tr'));
				//模拟发送
				$(".send").click(function(){
					let location = (578*Math.random()).toFixed(0);
					let option = {
						css:{marginLeft:location+'px'},
						speed:3000,
						startBefore:function(options){
							console.log(options);
						},
						callback:function(){
							$('.text').append('<li>'+$('#tr').css('marginLeft')+'</li>');
						}
					};
					Animate.start(option);
				});
			});
		</script>
	</body>
</html>

效果

在这里插入图片描述

总结

总体来说还行,无论是原生html,还是vue,都可以使用(Vue需要npm install jquery,并且引入jquery,才可以使用哟),其实不用jquery也可以,利用css3的动画和js自己手写一个逐帧动画,既然有现成的,而且这么成熟的jquery,为啥不用呢,我们要提倡节约,代码丑陋是丑陋了点,别计较,如果有bug,麻烦偷偷告诉我,好了,散会!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值