impress.js源码阅读

最近有点忙了呀,又过上宿舍-公司-食堂-宿舍的生活了,之前闲的慌,现在发现早上7点起床到晚上吃完饭回宿舍8点多了,都几乎没有能完全自己支配的时间了,不过还好啦,公司下班到挺准时的~~
然后还是想找些其他提升自己的事做做啦,正好前些时候用了impress写了个demo,那么这次就看看impress.js的源码啦

impress.js源码阅读

CSS前缀的兼容处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
var pfx = ( function() {

var style = document.createElement( "dummy" ).style,
prefixes = "Webkit Moz O ms Khtml".split( " " ),
// 此处算是个闭包,做记忆
memory = {};

// prop为css属性
return function( prop ) {
// 如果memoory对象中为存储该属性时
if ( typeof memory[ prop ] === "undefined" ) {
// 首字母大写
var ucProp = prop.charAt( 0 ).toUpperCase() + prop.substr( 1 ),
// 此处处理为如下: transition webkitTransition MozTransition
props = ( prop + " " + prefixes.join( ucProp + " " ) + ucProp ).split( " " );
// 创建该属性对象
memory[ prop ] = null;
for ( var i in props ) {
// 判断该属性是否存在
if ( style[ props[ i ] ] !== undefined ) {
// 给上一个可用前缀的属性名并且break出去
memory[ prop ] = props[ i ];
break;
}
}

}
// 返回这个可用的属性
return memory[ prop ];
};

} )();

处理类数组

1
2
3
4
// 将类数组转换为数组也可用于数组的克隆
var arrayify = function( a ) {
return [].slice.call( a );
};

设置css的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 传入DOM元素以及包含CSS属性的对象,并且通过pfx设置浏览器兼容属性
// 传入的对象如: {width:'10px';height: '10px'}
var css = function( el, props ) {
var key, pkey;
for ( key in props ) {
if ( props.hasOwnProperty( key ) ) {
// 做css的兼容处理
pkey = pfx( key );
if ( pkey !== null ) {
el.style[ pkey ] = props[ key ];
}
}
}
return el;
};

处理数字

1
2
3
4
// 判断是否为数字,若不是数字则执行fallback,若未传入fallback则返回0,如果是数字,则处理为数字
var toNumber = function( numeric, fallback ) {
return isNaN( numeric ) ? ( fallback || 0 ) : Number( numeric );
};

元素选择器

1
2
3
4
5
// 传入上下文和CSS选择器,若未传入上下文则使用document,返回匹配的第一个元素
var $ = function( selector, context ) {
context = context || document;
return context.querySelector( selector );
};
1
2
3
4
5
// 传入部分同上,返回匹配的所有元素,并且数组化
var $$ = function( selector, context ) {
context = context || document;
return arrayify( context.querySelectorAll( selector ) );
};

事件触发器

1
2
3
4
5
6
7
// 事件的触发器
// 传入触发元素,事件名
var triggerEvent = function( el, eventName, detail ) {
var event = document.createEvent( "CustomEvent" );
event.initCustomEvent( eventName, true, true, detail );
el.dispatchEvent( event );
};

根据网址的hash获取dom元素

1
2
3
4
5
6
var getElementFromHash = function() {

// Get id from url # by removing `#` or `#/` from the beginning,
// so both "fallback" `#slide-id` and "enhanced" `#/slide-id` will work
return byId( window.location.hash.replace( /^#\/?/, "" ) );
};

设备兼容性的判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var ua = navigator.userAgent.toLowerCase();
var impressSupported =

// Browser should support CSS 3D transtorms
// 是否包含透视属性
( pfx( "perspective" ) !== null ) &&

// Browser should support `classList` and `dataset` APIs
// 是否支持Data属性
( body.classList ) &&
( body.dataset ) &&

// But some mobile devices need to be blacklisted,
// because their CSS 3D support or hardware is not
// good enough to run impress.js properly, sorry...
// 去除对移动设备的支持
( ua.search( /(iphone)|(ipod)|(android)/ ) === -1 );

if ( !impressSupported ) {
// We can't be sure that `classList` is supported
body.className += " impress-not-supported ";
} else {
body.classList.remove( "impress-not-supported" );
body.classList.add( "impress-supported" );
}

移动端添加meta信息

1
2
3
4
5
6
7
var meta = $( "meta[name='viewport']" ) || document.createElement( "meta" );
meta.content = "width=device-width, minimum-scale=1, maximum-scale=1, user-scalable=no";
// 此处用于没有viewport的情况,设置好name并且将该元素放入head中
if ( meta.parentNode !== document.head ) {
meta.name = "viewport";
document.head.appendChild( meta );
}

函数防抖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var throttle = function( fn, delay ) {
var timer = null;
return function() {
var context = this, args = arguments;
clearTimeout( timer );
timer = setTimeout( function() {
fn.apply( context, args );
}, delay );
};
};

// 这样写可以得到正确的this
var throttle = function( fn, delay ) {
var timer = null;
// 这里使用箭头函数可以获得正确的this,调用的时候应该使用普通的函数定义方式,否则无法绑定正确的this
return () => {
var context = this, args = arguments;
clearTimeout( timer );
timer = setTimeout( function() {
fn.apply( context, args );
}, delay );
};
};