在 jQuery 中有 show(), hide(), slideDown(), slideUp() 等方法,能够以动画的形式显示或隐藏 DOM 元素。这一类的动画在页面交互中比较常用,这也是 jQuery 方便开发的地方之一,但如果只想使用这些动画效果而加载整个 jQuery 库那就有点浪费资源了,于是最近在折腾 JavaScript 的 Kayo 便尝试用原生的 JavaScript 实现这一类 jQuery 动画。
在介绍原生 JavaScript 代码前 Kayo 先想提出一个问题,也就是 jQuery 相对 JavaScript 的优势是什么?若开发者是先了解 jQuery 再学习原生 JavaScript ,那么以下这些优势将会让你很容易发现:
- 强大而且灵活的选择器, 正如很多 JavaScript 类库一样,jQuery 使用 $() 函数来作为选择器,支持 CSS1 到 CSS3 的选择器,比起 JavaScript 中的 document.getElementById(), document.getElementsByTagName() ,这样的选择器无疑方便很多。
- 带有常用的事件、方法,包括一些动画方法。
- 完善的封装, jQuery 中的对象处理,传递,操作都有着完善的封装和处理机制,并且做好了针对不同浏览器的兼容,这些若使用原生 JavaScript 重写将是一项非常繁重的工作。
当然, jQuery 的劣势也非常明显——即使你的整个网站只是使用 jQuery 的几个动画方法,也要加载一个近 100K 的库文件。下面大家不妨带着上面几点思考去阅读下文,这样就会感觉到 jQuery 在使用上的方便。
回到一开始讨论的问题——使用原生的 JavaScript 实现 jQuery 动画,下面会放出代码,但由于代码已经封装好了,具体的过程通过代码比较难理解,这里再简要说明一下:
1.建立一个动画对象—— Transform ,增加一些方法:
- 动画形式隐藏 DOM 元素
- 动画形式显示 DOM 元素
2.建立一个 DOM 元素对象—— $ ,增加一些方法:
- 获取某 id 的 DOM 元素
- 获取该元素的某项 CSS
- 动画形式隐藏元素(实例化 Transform 对象并调用其中的方法)
- 动画形式显示元素(实例化 Transform 对象并调用其中的方法)
3.根据实际需要操作的 DOM 元素 id 实例化 $ 对象并调用相应的方法
可以看出,上面的方法有点累赘,为什么不直接把动画方法写到 $ 对象里呢?
之所以会这样写,完全是为了方便维护和提高对象的独立性,例如给动画对象添加更多的动画方法或是给 Dom 元素对象添加更多的操作,封装为两个不同的对象将会更加方便维护。如果只是希望使用简单的动画效果,完全可以不同封装,毕竟封装后效率会降低很多,当然这种效率的差别你很难在 PC 上直接看出。
下面给出具体方法和代码:
实现动画的原理很简单——按特定的单位时间连续播放一组静态画面,在 JavaScript 中,我们可以利用 window.setTimeout 或 window.setInterval 来实现此效果,这里 Kayo 采用 window.setTimeout 递归调用一个减少元素宽度和高度的方法来实现。
需要注意的是:
- 在实现动画的方法中应该直接传递需要操作的 DOM 对象而不是传递 DOM 对象的 id ,因此我们最好写一个方法来获取 DOM 。
- 动画应该是能同时作用于网页上的多个元素,因此避免使用全局变量。
- 封装函数时应该使用 .prototype 添加方法,节省内存。
- 这些 JavaScript 写好后应该放在 footer 而不是 header ,因为原生 JavaScript 中没有自带的函数检查页面中每一个 DOM 是否都加载完毕,因此应该把 JavaScript 写在最后,当然开发者也可以另外写出一个判断页面的 DOM 是否加载完毕的函数。
这里以隐藏 DOM 元素为例,创建一个动画对象,包含以动画形式隐藏 DOM 元素的方法。在动画对象的接口中, obj 是需要操作的 DOM 对象, speed 是动画速度,数值越小动画越快, mode 是动画方式,有 “zoom” , “slide” 两种方式,分别模拟 jQuery 中 hide() 和 slideUp() 的效果, fn 为回调函数。另外 hide() 中的 width 和 height 两个参数为 DOM 元素的宽度和高度,会在 DOM 元素对象中调用 hide() 时赋值。
// 动画对象模板 var Transform = function(obj, speed, mode, fn){ this.obj = obj; this.speed = speed; // 动画速度 this.mode = mode; // 动画形式 this.heightChange = 10; this.fn = fn; if( speed === 'fast') this.speed = 10; else if( speed === 'normal' ) this.speed = 20; else if( speed === 'slow' ) this.speed = 30; } Transform.prototype = { // 处理隐藏 hide: function( width, height ){ var self = this; if ( !this.speed ) { this.obj.style.display = 'none'; return; } width = width - this.widthChange > 0 ? width - this.widthChange : 0; height = height - this.heightChange > 0 ? width - this.heightChange : 0; // if( width !== 0 || height !== 0 ) { // 判断采用何种动画形式 if( this.mode === 'zoom' ) this.obj.style.width = width + 'px'; this.obj.style.height = height + 'px'; // 递归调用自身 setTimeout(function(){self.hide(width,height)},this.speed); } else { // 完成后清除所有 style 属性 this.obj.style.cssText = ""; // 设置 display: none this.obj.style.display = 'none'; if(this.fn) this.fn.call(this.obj); } }
下面是创建一个 DOM 对象模板
// DOM 元素对象模板 var $ = function(id){ this.id = id; this.obj = document.getElementById(this.id); } $.prototype = { // 获取元素的某项 CSS getClass: function(name){ // IE8及以下版本 if(this.obj.currentStyle) { return this.obj.currentStyle[name]; } // Firefox, Chrome, IE9+ else { var style = document.defaultView.getComputedStyle(this.obj, null); return style[name]; } }, // 以元素高宽生成动画对象 cal: function(speed, mode, fn){ // 创建动画对象 this.theTransform = new Transform(this.obj, speed, mode, fn); this.theTransform.theWidth = this.getClass('width').replace('px',''); this.theTransform.theHeight = this.getClass('height').replace('px',''); // 按长宽比例计算单位时间内元素宽带减少值 this.theTransform.widthChange = this.theTransform.heightChange*(this.theTransform.theWidth / this.theTransform.theHeight); }, // 隐藏元素 hide: function(speed, mode, fn){ this.cal(speed, mode, fn); this.theTransform.hide(this.theTransform.theWidth, this.theTransform.theHeight); }, // 显示元素 show: function(speed, mode, fn){ this.cal(speed, mode, fn); this.theTransform.show(0, 0); } }
这里使用一个 getCss 方法获取 DOM 元素的宽和高,注意在不同的浏览器中获取方式是不同的,所以要作出判断(感受到 jQuery 的优势了吧),另外每次减少的宽度 widthChange 是按元素宽高比例算出的,不是直接指定的,这样是为了模拟 jQuery 中的动画效果。
下面给出完整的 Demo
需要使用这类动画而不需要加载 jQuery 库的童鞋可以下载完整 Demo ,连接 Demo 中的 js 文件到你的网页中就可以使用动画,比如网面中有一 id="box" 的 div ,那么可以使用以下这段 JavaScript 和 HTML 来隐藏和显示该 div 。
以需要操作的 DOM 元素的 id 实例化一个 DOM 元素对象
// 创建 DOM 元素对象 var theDom = new $('box');
相应的 HTML ,其中 'fast' 为动画速度,还可以选择 'normal', 'slow' ,代表三种不同速度,也可以直接填数值(建议 50 以内,数值越小动画速度越快),不填(即参数为'')则取消动画,直接隐藏或显示元素,'zoom' 为动画形式,还可以选择 'slide' ,还有一个选填的回调函数,如theDom.hide('fast', 'zoom', function(){alert('succeed');})。这些用法可以参考 Demo 。
<a href="#" onclick="theDom.hide('fast', 'zoom')">点击隐藏</a> <a href="#" onclick="theDom.show('fast', 'zoom')">点击显示</a>
本文由 Kayo Lee 发表,本文链接:https://kayosite.com/achieve-jquery-animate-by-javascript.html
Pingback
评论列表
代码那里溢出了哦。。。沙发
@Demon 估计刚才高亮插件还没有加载好,貌似最近这个空间不大稳定!
汗。难道刚刚还没加载完成就停止 刷新了。
@Demon 空间不稳定时那个高亮代码插件加载会慢点,不过还没有加载好就停止应该不会吧 :arrow:
还是挺复杂的啊 :-x
闲着过来打酱油。
@Demon 没事,这里是欢迎打酱油的~
一个微型的动画框架出来了
@万戈 哈哈,小小的动画操作,框架的话倒是想做一个用于表单UI美化的~