实现一个JS弹性势能动画效果代码:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>弹性势能动画</title> <style type="text/css"> * { margin: 0; padding: 0; } html, body { width: 100%; height: 100%; background: #e1e1e1; overflow: hidden; } #mark { position: absolute; top: 20px; left: 10px; width: 100px; height: 100px; cursor: move; background: green; } </style> </head> <body> <div id="mark"></div> <script charset="utf-8" type="text/javascript" src="jss/event.js"></script> <script type="text/javascript"> var mark = document.getElementById("mark"); var winW = document.documentElement.clientWidth || document.body.clientWidth, winH = document.documentElement.clientHeight || document.body.clientHeight; var markW = mark.offsetWidth, markH = mark.offsetHeight; on(mark, "mousedown", dragDown); function dragDown(e) { this["strX"] = e.clientX;//this["strX"]存的自定义属性 this["strY"] = e.clientY; this["strL"] = this.offsetLeft; this["strT"] = this.offsetTop; if (this.setCapture) {//->IE和火狐 this.setCapture(); zhufengEvent.on(this, "mousemove", dragMove); zhufengEvent.on(this, "mouseup", dragUp); } else { var _this = this; this.MOVE = function (e) { dragMove.call(_this, e); }; this.UP = function (e) { dragUp.call(_this, e); }; on(document, "mousemove", this.MOVE); on(document, "mouseup", this.UP); //->清除正在运行的动画 window.clearInterval(this.flyTimer); window.clearInterval(this.dropTimer); } } function dragMove(e) { var curL = e.clientX - this["strX"] + this["strL"]; var curT = e.clientY - this["strY"] + this["strT"]; var minL = 0, minT = 0, maxL = winW - markW, maxT = winH - markH; curL = curL <= minL ? minL : (curL >= maxL ? maxL : curL); curT = curT <= minT ? minT : (curT >= maxT ? maxT : curT); mark.style.left = curL + "px"; mark.style.top = curT + "px"; //->动画 //浏览器中每一个事件行为都有一个最短的反应时间minTime,在minTime以内,不会重复触发这个行为,只有超过了这个最短时间才会触发下一次的行为 //我们水平方向运动的速度取决于拖拽结束的那一瞬间,鼠标移动的距离; //console.log("ok"); if (!this["flyPre"]) { this["flyPre"] = this.offsetLeft; } else { this["flySpeed"] = this.offsetLeft - this["flyPre"]; this["flyPre"] = this.offsetLeft; } } function dragUp(e) { if (this.releaseCapture) { this.releaseCapture(); off(this, "mousemove", dragMove); off(this, "mouseup", dragUp); } else { off(document, "mousemove", this.MOVE); off(document, "mouseup", this.UP); } //->拖拽结束执行动画 fly.call(this);//让this变为当前元素 drop.call(this); } //->水平方向的动画 function fly() { //->this->mark var _this = this, speed = this["flySpeed"]; _this.flyTimer = window.setInterval(function () { //->由于我们的offsetLeft每一次获取的值都会出现四舍五入,这样如果本次增加一个小于0.5的速度值的话,下一次获取的值还是上次的值,加的速度起不到作用,我们结束动画即可 if (Math.abs(speed) < 0.5) {//可能是负值 window.clearInterval(_this.flyTimer); return; } //console.log("ok");//动画结束了,定时器还没有结束 speed *= 0.98;//每一次都让速度乘以一个小于1的值,这样我们的速度就在衰减 var curL = _this.offsetLeft + speed;// _this.offsetLeft获取的是整数(四舍五入了)?????? var minL = 0, minT = 0, maxL = winW - markW, maxT = winH - markH; if (curL >= maxL) {//到达右边界 curL = maxL; speed *= -1; } else if (curL <= minL) {//到达左边界 curL = minL; speed *= -1; } //console.log(curL); _this.style.left = curL + "px"; }, 10); } //->垂直方向 function drop() { var _this = this, speed = 9.8; _this["dropFlag"] = 0; _this.dropTimer = window.setInterval(function () { if (_this["dropFlag"] > 1) { window.clearInterval(_this.dropTimer); return; } speed += 10; speed *= 0.98; var curT = _this.offsetTop + speed; if (curT >= winH - markH) {//到底了 curT = winH - markH; //return; speed *= -1; _this["dropFlag"]++; } else {//不在底 _this["dropFlag"] = 0; } _this.style.top = curT + "px"; }, 10); } </script> </body> </html>
以上代码是页面HTML和实现动画的JS,下面是里面引用的jss里面的event.js文件:
//->基于内置类的原型扩展一个等价于bind的方法,预先把某一个函数中的this进行处理,把一些参数值预先传递进来(事件对象也可以获取到) Function.prototype.myBind = function myBind(context) { //this->我要操作的那个函数 var _this = this; var outerArg = Array.prototype.slice.call(arguments, 1); return function () { var innerArg = Array.prototype.slice.call(arguments, 0); _this.apply(context, outerArg.concat(innerArg)); } }; //->清除正在运行的动画 function bind(curEle, type, fn) { if (curEle.addEventListener) { curEle.addEventListener(type, fn, false); return; } var tempFn = fn.myBind(curEle); tempFn.photo = fn; !curEle["myBind" + type] ? curEle["myBind" + type] = [] : null; var ary = curEle["myBind" + type]; for (var i = 0; i < ary.length; i++) { if (ary[i].photo === fn) { return; } } ary.push(tempFn); //curEle["myBind" + type].push(tempFn); curEle.attachEvent("on" + type, tempFn); //curEle.attachEvent("on"+type,fn.myBind(curEle)); } function unbind(curEle, type, fn) { if (curEle.removeEventListener) { curEle.removeEventListener(type, fn, false); return; } var ary = curEle["myBind" + type]; if (ary) { for (var i = 0; i < ary.length; i++) { var tempFn = ary[i]; if (tempFn.photo === fn) { curEle.detachEvent("on" + type, tempFn); ary.splice(i, 1); break; //curEle.detachEvent("on" + type, fn.myBind(curEle)); } } } } //->自己模拟内置的事件池创建一个临时的容器,把所有需要绑定的方法先放在自己的容器中,然后值给元素的某个行为绑定一个方法run,(把这个方法需要增加到内置的事件池中)当行为触发的时候执行run方法,在run执行的过程中,我们在把通过on绑定的方法依次的按顺序执行即可; function on(curEle, type, fn) { !curEle["myEvent" + type] ? curEle["myEvent" + type] = [] : null; var ary = curEle["myEvent" + type]; for (var i = 0; i < ary.length; i++) { if (ary[i] === fn) { return;//重复了就不追加了,直接return } } ary.push(fn); bind(curEle, type, run); } function off(curEle, type, fn) { var ary = curEle["myEvent" + type]; if (ary) { for (var i = 0; i < ary.length; i++) { var curFn = ary[i]; if (curFn === fn) { ary[i] = null; break; } } } } function run(e) { if (window.event) { e.target = e.srcElement; e.pageX = e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft); e.pageY = e.clientY + (document.documentElement.scrollTop || document.body.scrollTop); e.preventDefault = function () { e.returnValue = false; }; e.stopPropagation = function () { e.cancelBubble = true; }; } var ary = this["myEvent" + e.type]; if (ary) { for (var i = 0; i < ary.length; i++) { var curFn = ary[i]; if (typeof curFn === "function") { curFn.call(this, e); continue; } ary.splice(i, 1); i--; } } }
通过以上的详细代码,就实现了我们的弹性势能动画