xml地图|网站地图|网站标签 [设为首页] [加入收藏]
js实现简洁的滑屏功能,开始使用Web
分类:web前端

利用轮播原理结合hammer.js实现简洁的滑屏功能

2016/02/02 · JavaScript · 滑屏

原文出处: 流云诸葛   

最近有个任务,做一个非常小的h5的应用,只有2屏,需要做横向的全屏滑动切换和一些简单的动画效果,之前做这种东西用的是fullpage.js和jquery,性能不是很好,于是就想自己动手弄一个简单的东西来实现。最后我用zepto

  • hammer.js 和轮播的方式解决了这个问题,效果还不错,整个页面不开启Gzip时所有资源请求的数据大小为200KB左右。这篇文章总结下这个方法的实现思路。

效果演示(代码下载):

图片 1

开始使用Web Workers

2012/11/28 · HTML5, JavaScript · 来源: 伯乐在线     · HTML5, Javascript

英文原文:tutsplus,编译:伯乐在线 – 胡蓉(@蓉Flora)

单线程(Single-threaded)运行是JavaScript语言的设计目标之一,进而言之是保持JavaScript的简单。但是我必须要说,尽管JavaScript具有如此语言特质,但它绝不简单!我们所说的“单线程”是指JavaScript只有一个线程控制。是的,这点令人沮丧,JavaScript引擎一次只能做一件事。

“web workers处在一个严格的无DOM访问的环境里,因为DOM是非线程安全的。”

现在,你是不是觉得要想利用下你机器闲置的多核处理器太受限制?不用担心,HTML5将改变这一切。

JavaScript的单线程模式

有学派认为JavaScript的单线程特质是一种简化,然而也有人认为这是一种限制。后者提出的是一个很好的观点,尤其是现在web应用程序大量的使用JavaScript来处理界面事件、轮询服务端接口、处理大量的数据以及基于服务端的响应操作DOM。

在维护响应式界面的同时,通过单线程控制处理如此多事件是项艰巨的任务。它迫使开发人员不得不依靠一些技巧或采用变通的方法(如使用setTimeout(),setInterval(),或调用XMLHttpRequest和DOM事件)来实现并发。然而,尽管这些技巧毫无疑问地提供了解决异步调用的方法,但非阻塞的并不意味着是并发的。John Resig在他的博客中解释了为什么不能并行运行。

限制

如果你已经和JavaScript打过一段时间的交道,那么你一定也遭遇过如下令人讨厌的对话框,提示你有脚本无响应。没错,几乎大多数的页面无响应都是由JavaScript代码引起的。

图片 2

以下是一些运行脚本时造成浏览器无响应的原因:

  • 过多的DOM操作:DOM操作也许是在JavaScript运行中代价最高的。所以,大批量的DOM操作无疑是你代码重构的最佳方向之一。
  • 无终止循环:审视你代码中复杂的嵌套循环永远不是坏事。复杂的嵌套循环所做的工作常常比实际需要做的多很多,也许你可以找到其他方法来实现同样的功能。
  • 同时包含以上两种:最坏的情况就是明明有更优雅的办法,却还是在循环中不断更新DOM元素,比如可以采用DocumentFragment。

 

JavaScript 中 this 的运行机制及爬坑指南

2018/03/14 · JavaScript · this

原文出处: [Dr. Axel

1. 实现要点

1)滑屏借鉴bootstrap的carousel插件,不过完全没有它那个复杂,只需要借鉴它的轮播实现思路即可;

2)滑屏切换的触发,跟PC不一样,PC通常都是通过元素的点击回调来触发,对于滑屏的页面,完全可以利用window的hashchange事件来处理,这样只要通过超链接设置锚点或者通过js改变location.hash就能触发切换;

3)考虑到移动还得支持手势操作,可以使用hammer.js这个手势库,API非常简单易用;

4)动画效果可以用animate.css,不过不用把它所有的代码都弄到代码里,只需要拷贝需要的动画效果相关的代码即可;

5)替代jquery,首选zepto;

6)滑屏效果使用transition动画,为了能够响应动画结束的回调,可以考虑使用transition.js,这个也是Bootstrap提供的工具,不过它默认只能跟jquery使用,要对它稍微改变一下才能跟zepto联合使用。

这些要点说的比较粗糙,后面的内容会一一详细介绍。

好帮手Web Workers

幸好有了HTML5和Web Workers,你可以真正生成一条异步的线程。当主线程处理界面事件时,新的worker可以在后台运行,它甚至可以有力的处理大量的数据。例如,一个worker可以处理大型的数据结构(如JSON),从中提取变量信息然后在界面中显示。好了,废话不多说,让我们看一些实际的代码吧。

 

创建一个Worker

通常,与web worker相关的代码都放在一个独立的JavaScript文件中。父线程通过在Worker构造函数中指定一个JavaScript文件的链接来创建一个新的worker,它会异步加载并执行这个JavaScript文件。

JavaScript

var primeWorker = new Worker('prime.js');

1
var primeWorker = new Worker('prime.js');

 

启动Worker

要启动一个Worker,则父线程向worker传递一个信息,如下所示:

JavaScript

var current = $('#prime').attr('value'); primeWorker.postMessage(current);

1
2
var current = $('#prime').attr('value');
primeWorker.postMessage(current);

父页面可以通过postMessage接口与worker进行通信,这也是跨源通信(cross-origin messaging)的一种方式。通过postMessage接口除了可以向worker传递私有数据类型,它还支持JSON数据结构。但是,你不能传递函数,因为函数也许会包含对潜在DOM的引用。

“父线程和worker线程有它们各自的独立空间,信息主要是来回交换而不是共享。”

信息在后台运行时,先在worker端序列化,然后在接收端反序列化。鉴于此,不推荐向worker发送大量的数据。

父线程同样可以声明一个回调函数,来侦听worker完成任务后发回的消息。这样,父线程就可以在worker完成任务后采取些必要的行动,比如更新DOM元素。如下代码所示:

JavaScript

primeWorker.addEventListener('message', function(event){ console.log('Receiving from Worker: '+event.data); $('#prime').html( event.data ); });

1
2
3
4
primeWorker.addEventListener('message', function(event){
    console.log('Receiving from Worker: '+event.data);
    $('#prime').html( event.data );
});

event对象包含两个重要属性:

  • target:用来指向发送信息的worker,在多元worker环境下比较有用。
  • data:由worker发回给父线程的数据。

worker本身是包含在prime.js文件中的,它同时侦听message事件,从父线程中接收信息。它同样通过postMessage接口与父线程进行通信。

JavaScript

self.addEventListener('message', function(event){ var currPrime = event.data, nextPrime; setInterval( function(){ nextPrime = getNextPrime(currPrime); postMessage(nextPrime); currPrime = nextPrime; }, 500); });

1
2
3
4
5
6
7
8
self.addEventListener('message',  function(event){
    var currPrime = event.data, nextPrime;
    setInterval( function(){
    nextPrime = getNextPrime(currPrime);
    postMessage(nextPrime);
    currPrime = nextPrime;
    }, 500);
});

在本文例子中,我们寻找下一个最大的质数,然后不断将结果发回至父线程,同时不断更新界面以显示新的值。在worker的代码中,字段self和this都是指向全局作用域。Worker既可以添加事件侦听器来侦听message事件,也可以定义一个onmessage处理器,来接收从父线程发回的消息。

寻找下一个质数的例子显然不是worker的理想用例,但是在此选用这个例子是为了说明消息传递的原理。之后,我们会挖掘些可以通过web worker获得益处的实际用例。

 

终止Workers

worker属于占用资源密集型,它们属于系统层面的线程。因此,你应该不希望创建太多的worker线程,所以你需要在它完成任务后终止它。Worker可以通过如下方式由自己终止:

JavaScript

self.close();

1
self.close();

或者,由父线程终止。

JavaScript

primeWorker.terminate();

1
primeWorker.terminate();

 

安全与限制

在worker的代码中,不要访问一些重要的JavaScript对象,如document、window、console、parent,更重要的是不要访问DOM对象。也许不用DOM元素以至不能更新页面元素听上去有点严格,但是这是一个重要的安全设计决定。

想象一下,如果众多线程都试着去更新同一个元素那就是个灾难。所以,web worker需要处在一个严格的并线程安全的环境中。

正如之前所说,你可以通过worker处理数据,并将结果返回主线程,进而更新DOM元素。尽管它们不能访问一些重要的JavaScript对象,但是它们可以调用一些函数,如setTimeout()/clearTimeout()、setInterval()/clearInterval()、navigator等等,也可以访问XMLHttpRequest和localStorge对象。

 

同源限制

为了能和服务器交互,worker必须遵守同源策略(same-origin policy)(译注:可参考国人文章同源策略)。比如,位于

 

Google Chrome与本地访问

Google Chrome对worker本地访问做了限制,因此你无法本地运行这些例子。如果你又想用Chrome,那么你可以将文件放到服务器上,或者在通过命令启动Chrome时加上–allow-file-access-from-files。例如,苹果系统下:

$ /Applications/Google Chrome.app/Contents/MacOS/Google Chrome –allow-file-access-from-files

然而,在实际产品生产过程中,此方法并不推荐。最好还是将你的文件上传至服务器中,同时进行跨浏览器测试。

 

Worker调试和错误处理

不能访问console似乎有点不方便,但幸亏有了Chrome开发者工具,你可以像调试其他JavaScript代码那样调试worker。

图片 3

为处理web worker抛出的异常,你可以侦听error事件,它属于ErrorEvent对象。检测该对象从中了解引起错误的详细信息。

JavaScript

primeWorker.addEventListener('error', function(error){ console.log(' Error Caused by worker: '+error.filename + ' at line number: '+error.lineno + ' Detailed Message: '+error.message); });

1
2
3
4
5
primeWorker.addEventListener('error', function(error){
    console.log(' Error Caused by worker: '+error.filename
        + ' at line number: '+error.lineno
        + ' Detailed Message: '+error.message);
});

多个Worker线程

尽管创建多个worker来协调任务分配也许很常见,但还是要提醒一下各位,官方规范指出worker属于相对重量级并能长期运行在后台的脚本。所以,由于Web worker的高启动性能成本和高进程内存成本,它们的数量不宜过多。

 

简单介绍共享workers

官方规范指出有两种worker:专用线程(dedicated worker)和共享线程(shared worker)。到目前为止,我们只列举了专用线程的例子。专用线程与创建线程的脚本或页面直接关联,即有着一对一的联系。而共享线程允许线程在同源中的多个页面间进行共享,例如:同源中所有页面或脚本可以与同一个共享线程通信。

“创建一个共享线程,直接将脚本的URL或worker的名字传入SharedWorker构造函数”

两者最主要的区别在于,共享worker与端口相关联,以保证父脚本或页面可以访问。如下代码创建了一个共享worker,并声明了一个回调函数以侦听worker发回的消息 ,同时向共享worker传输一条消息。

JavaScript

var sharedWorker = new SharedWorker('findPrime.js'); sharedWorker.port.onmessage = function(event){ ... } sharedWorker.port.postMessage('data you want to send');

1
2
3
4
5
var sharedWorker = new SharedWorker('findPrime.js');
sharedWorker.port.onmessage = function(event){
    ...
}
sharedWorker.port.postMessage('data you want to send');

同样,worker可以侦听connect事件,当有客户端想与worker进行连接时会相应地向其发送消息。

JavaScript

onconnect = function(event) { // event.source包含对客户端端口的引用 var clientPort = event.source; // 侦听该客户端发来的消息 clientPort.onmessage = function(event) { // event.data包含客户端发来的消息 var data = event.data; .... // 处理完成后发出消息 clientPort.postMessage('processed data'); } };

1
2
3
4
5
6
7
8
9
10
11
12
onconnect = function(event) {
    // event.source包含对客户端端口的引用
    var clientPort = event.source;
    // 侦听该客户端发来的消息
    clientPort.onmessage = function(event) {
        // event.data包含客户端发来的消息
        var data = event.data;
        ....
        // 处理完成后发出消息
        clientPort.postMessage('processed data');
    }
};

由于它们具有共享的属性,你可以保持一个应用程序在不同窗口内的相同状态,并且不同窗口的页面通过同一共享worker脚本保持和报告状态。想更多的了解共享worker,我建议你阅读官方文档。

 

实际应用场景

worker的实际发生场景可能是,你需要处理一个同步的第三方接口,于是主线程需要等待结果再进行下一步操作。这种情况下,你可以生成一个worker,由它代理,异步完成此任务。

Web worker在轮询情况下也非常适用,你可以在后台不断查询目标,并在有新数据时向主线程发送消息。

你也许遇到需要向服务端返回大量的数据的情况。通常,处理大量数据会消极影响程序的响应能力,然后导致不良用户体验。更优雅的办法是将处理工作分配给若干worker,由它们处理不重叠的数据。

还有应用场景会出现在通过多个web worker分析音频或视频的来源,每个worker针对专项问题。

 

结论

随着HTML5的展开,web worker规范也会持续加入。如果你打算使用web worker,看一看它的官方文档不是坏事。

专项线程的跨浏览器支持目前还不错,Chrome,Safari和Firefox目前的版本都支持,甚至IE这次都没有落后太多,IE10还是不错的。但是共享线程只有当前版本的Chrome和Safari支持。另外奇怪的一点是,Android 2.1的浏览器支持web worker,反而4.0版本不支持。苹果也从iOS 5.0开始支持web worker。

想象一下,在原本单线程环境下,多线程会带来无限可能哦~

 

译注:本人对此JavaScript技术领域并不是特别熟悉,如有误翻的地方,请大家及时批评指正,我将及时修改!!!最后,推荐两篇相关国人优秀文章

《HTML5 web worker的使用 》

《深入HTML5 Web Worker应用实践:多线程编程》

 

 

英文原文:tutsplus,编译:伯乐在线 – 胡蓉(@蓉Flora)

文章链接:

【如需转载,请在正文中标注并保留原文链接、译文链接和译者等信息,谢谢合作!】

 

赞 1 收藏 评论

Rauschmayer]()   译文出处:[众成翻译

woolll]()   

图片 4

在 JavaScript 中,this 这个特殊的变量是相对比较复杂的,因为 this 不仅仅用在面向对象环境中,在其他任何地方也是可用的。 本篇博文中会解释 this 是如何工作的以及使用中可能导致问题的地方,最后奉上最佳实践。

为了更好理解 this,将 this 使用的场景分成三类:

  • 在函数内部 this 一个额外的,通常是隐含的参数。
  • 在函数外部(顶级作用域中): 这指的是浏览器中的全局对象或者 Node.js 中一个模块的输出。
  • 在传递给eval()的字符串中: eval() 或者获取 this 当前值值,或者将其设置为全局对象,取决于 this 是直接调用还是间接调用。

我们来看看每个类别。

2. html结构

空的滑屏页的html结构是这样的:

XHTML

<div id="container" class="container"> <section id="page-1" class="page page--1"> </section> <section id="page-2" class="page page--2"> </section> <section id="page-3" class="page page--3"> </section> </div>

1
2
3
4
5
6
7
8
<div id="container" class="container">
    <section id="page-1" class="page page--1">
    </section>
    <section id="page-2" class="page page--2">
    </section>
    <section id="page-3" class="page page--3">
    </section>
</div>

html, body { height: 100%; -webkit-tap-highlight-color: transparent; } .container, .page { position: absolute; top: 0; left: 0; width: 100%; height: 100%; overflow: hidden; } .page { overflow: hidden; display: none; -webkit-transition: -webkit-transform .4s ease; transition: transform .4s ease; -webkit-backface-visibility: hidden; backface-visibility: hidden; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
html,
body {
    height: 100%;
    -webkit-tap-highlight-color: transparent;
}
 
.container,
.page {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    overflow: hidden;
}
 
.page {
    overflow: hidden;
    display: none;
    -webkit-transition: -webkit-transform .4s ease;
    transition: transform .4s ease;
    -webkit-backface-visibility: hidden;
    backface-visibility: hidden;
}

.container与.page初始化的时候采用绝对定位,全屏布局。每一个section.page代表一页,并且默认不显示,所有页的定位都相同,也就是说如果所有页都显示的话,这些页会重叠在一块。

demo页的html结构是:

XHTML

<div id="container" class="container"> <section id="page-1" class="page page--1"> <div class="page__jump"><a href="#page-2" title="">下一页</a></div> <p class="page__num animated">1</p> </section> <section id="page-2" class="page page--2"> <div class="page__jump"><a href="#page-1" title="">上一页</a><a href="#page-3" title="">下一页</a></div> <p class="page__num animated">2</p> </section> <section id="page-3" class="page page--3"> <div class="page__jump"><a href="#page-2" title="">上一页</a></div> <p class="page__num animated">3</p> </section> </div>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div id="container" class="container">
    <section id="page-1" class="page page--1">
        <div class="page__jump"><a href="#page-2" title="">下一页</a></div>
        <p class="page__num animated">1</p>
    </section>
    <section id="page-2" class="page page--2">
        <div class="page__jump"><a href="#page-1" title="">上一页</a><a href="#page-3" title="">下一页</a></div>
        <p class="page__num animated">2</p>
    </section>
    <section id="page-3" class="page page--3">
        <div class="page__jump"><a href="#page-2" title="">上一页</a></div>
        <p class="page__num animated">3</p>
    </section>
</div>

demo相关的css就不展示了。其中animated是应用animate.css需要的,animate.css是一个动画库,github上有。

关于作者:胡蓉

图片 5

胡蓉:某互联网公司交互设计师。在这么一个梦想者云集的互联网乐土中,用心培育着属于自己的那一片天地。做自己热爱的,然后一直坚持下去~(新浪微博:@蓉Flora) 个人主页 · 我的文章

图片 6

this 在函数中

这是最常用的 this 使用方式,函数通过扮演三种不同的角色来表示 JavaScript 中的所有可调用结构体:

  • 普通函数(this 在非严格模式下为全局对象,在严格模式下为undefined)
  • 构造函数(this 指向新创建的实例)
  • 方法(this 是指方法调用的接收者)

在函数中,this 通常被认为是一个额外的,隐含的参数。

3. 滑屏切换的实现思路

滑屏切换就是通过js控制2个要滑动的页增加和删除以下定义的这一些css类实现的:

.page.page--active, .page.page--prev, .page.page--next { display: block; } .page.page--next, .page.page--active.page--active-right { -webkit-transform: translate3d(100%, 0, 0); transform: translate3d(100%, 0, 0); } .page.page--prev, .page.page--active.page--active-left { -webkit-transform: translate3d(-100%, 0, 0); transform: translate3d(-100%, 0, 0); } .page.page--next.page--next-left, .page.page--prev.page--prev-right, .page.page--active { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.page.page--active,
.page.page--prev,
.page.page--next {
    display: block;
}
 
.page.page--next,
.page.page--active.page--active-right {
    -webkit-transform: translate3d(100%, 0, 0);
    transform: translate3d(100%, 0, 0);
}
 
.page.page--prev,
.page.page--active.page--active-left {
    -webkit-transform: translate3d(-100%, 0, 0);
    transform: translate3d(-100%, 0, 0);
}
 
.page.page--next.page--next-left,
.page.page--prev.page--prev-right,
.page.page--active {
    -webkit-transform: translate3d(0, 0, 0);
    transform: translate3d(0, 0, 0);
}

.page–active表示当前显示的页,页面初始化后,通过以下js调用,给第一页加上.page—active:

var $activePage; //初始化显示第一页 (function () { $activePage = $('#page-1'); $activePage.addClass('page--active'); })();

1
2
3
4
5
6
7
var $activePage;
 
//初始化显示第一页
(function () {
    $activePage = $('#page-1');
    $activePage.addClass('page--active');
})();

这样页面默认就显示了第一页。以向左滑屏说明这些css的使用原理:

第一步,找到下一页的section,添加page–next类,将它定位当前页的右边,为滑屏做准备;

第二步,找到当前页的section,给它添加page–active-left,由于这个类改变了translate3D属性的值,所以当前页会往左滑动一屏;

在第二步的同时,给下一页的section,添加page–next-left,由于这个类改变了translate3D属性的值,所以下一页会往左滑动一屏;

第三步,在当前页跟下一页滑屏动画结束后,找到原来的当前页,移除掉page–active和page–active-left类;

在第三步的同时,找到下一页,移除掉page–next和page–next-left类,添加page–active。

gif图说明如下

图片 7

向右滑屏原理类似

第一步,找到上一页的section,添加page–prev类,将它定位当前页的左边,为滑屏做准备;

第二步,找到当前页的section,给它添加page–active-right,由于这个类改变了translate3D属性的值,所以当前页会往右滑动一屏;

在第二步的同时,给上一页的section,添加page–prev-right,由于这个类改变了translate3D属性的值,所以上一页会往右滑动一屏;

第三步,在当前页跟上一页滑屏动画结束后,找到原来的当前页,移除掉page–active和page–active-right类;

在第三步的同时,找到上一页,移除掉page–prev和page–prev-right类,添加page–active。

综合以上实现原理,封装成JS函数如下:

JavaScript

var TRANSITION_DURATION = 400, sliding = false; function getSlideType($targetPage) { var activePageId = $activePage.attr('id'), targetPageId = $targetPage.attr('id'); return activePageId < targetPageId ? 'next' : activePageId == targetPageId ? '' : 'prev'; } function slide(targetPageId) { var $targetPage = $('#' + targetPageId); if (!$targetPage.length || sliding) return; var slideType = getSlideType($targetPage), direction = slideType == 'next' ? 'left' : 'right'; if (slideType == '') return; sliding = true; $targetPage.addClass('page--' + slideType); $targetPage[0].offsetWidth; $activePage.addClass('page--active-' + direction); $targetPage.addClass('page--' + slideType + '-' + direction); $activePage .one($.transitionEnd.end, function () { $targetPage.removeClass(['page--' + slideType, 'page--' + slideType + '-' + direction].join(' ')).addClass('page--active'); $activePage.removeClass(['page--active', 'page--active-' + direction].join(' ')); $activePage = $targetPage; sliding = false; }) .emulateTransitionEnd(TRANSITION_DURATION); }

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
var TRANSITION_DURATION = 400, sliding = false;
 
function getSlideType($targetPage) {
    var activePageId = $activePage.attr('id'),
            targetPageId = $targetPage.attr('id');
    return activePageId < targetPageId ? 'next' : activePageId == targetPageId ? '' : 'prev';
}
 
function slide(targetPageId) {
    var $targetPage = $('#' + targetPageId);
    if (!$targetPage.length || sliding) return;
 
    var slideType = getSlideType($targetPage),
            direction = slideType == 'next' ? 'left' : 'right';
    if (slideType == '') return;
 
    sliding = true;
    $targetPage.addClass('page--' + slideType);
    $targetPage[0].offsetWidth;
    $activePage.addClass('page--active-' + direction);
    $targetPage.addClass('page--' + slideType + '-' + direction);
 
    $activePage
            .one($.transitionEnd.end, function () {
                $targetPage.removeClass(['page--' + slideType, 'page--' + slideType + '-' + direction].join(' ')).addClass('page--active');
                $activePage.removeClass(['page--active', 'page--active-' + direction].join(' '));
                $activePage = $targetPage;
                sliding = false;
            })
            .emulateTransitionEnd(TRANSITION_DURATION);
}

由于$activePage在页面初始化的时候默认指定为第一页,在每次滑屏结束后都会更新成最新的当前页,所以调用的时候只要把目标页的ID传给slide函数即可。以上代码可能会有疑问的是:

1)$targetPage[0].offsetWidth的作用,这个代码用来触发浏览器的重绘,因为目标页原来是display: none的,如果不触发重绘的话,下一步添加css类后将看不到动画效果;

2)$.transitionEnd.end以及emulateTransitionEnd的作用,这个在下一部分说明。

this 在普通函数中

在普通函数中,this 的值取决于模式:

  • 非严格模式: this 是指向全局对象 (在浏览器中为window对象)。
function sloppyFunc() { console.log(this === window); // true }
sloppyFunc();

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f6bfd7bd4d414140440-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6bfd7bd4d414140440-2">
2
</div>
<div class="crayon-num" data-line="crayon-5b8f6bfd7bd4d414140440-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6bfd7bd4d414140440-4">
4
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f6bfd7bd4d414140440-1" class="crayon-line">
function sloppyFunc() {
</div>
<div id="crayon-5b8f6bfd7bd4d414140440-2" class="crayon-line crayon-striped-line">
    console.log(this === window); // true
</div>
<div id="crayon-5b8f6bfd7bd4d414140440-3" class="crayon-line">
  }
</div>
<div id="crayon-5b8f6bfd7bd4d414140440-4" class="crayon-line crayon-striped-line">
sloppyFunc();
</div>
</div></td>
</tr>
</tbody>
</table>
  • 严格模式: this 的值为 undefined。
function strictFunc() { 'use strict'; console.log(this ===
undefined); // true } strictFunc();

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f6bfd7bd58954780524-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6bfd7bd58954780524-2">
2
</div>
<div class="crayon-num" data-line="crayon-5b8f6bfd7bd58954780524-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f6bfd7bd58954780524-4">
4
</div>
<div class="crayon-num" data-line="crayon-5b8f6bfd7bd58954780524-5">
5
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f6bfd7bd58954780524-1" class="crayon-line">
function strictFunc() {
</div>
<div id="crayon-5b8f6bfd7bd58954780524-2" class="crayon-line crayon-striped-line">
   'use strict';
</div>
<div id="crayon-5b8f6bfd7bd58954780524-3" class="crayon-line">
   console.log(this === undefined); // true
</div>
<div id="crayon-5b8f6bfd7bd58954780524-4" class="crayon-line crayon-striped-line">
}
</div>
<div id="crayon-5b8f6bfd7bd58954780524-5" class="crayon-line">
strictFunc();
</div>
</div></td>
</tr>
</tbody>
</table>

也就是说,this 是一个设定了默认值(window或undefined)的隐式参数。 但是,可以通过 call() 或 apply() 进行函数调用,并明确指定this的值:``

function func(arg1, arg2) { console.log(this); // a console.log(arg1); // b console.log(arg2); // c } func.call('a', 'b', 'c'); // (this, arg1, arg2) func.apply('a', ['b', 'c']); // (this, arrayWithArgs)

1
2
3
4
5
6
7
function func(arg1, arg2) {
        console.log(this); // a
        console.log(arg1); // b
        console.log(arg2); // c
    }
func.call('a', 'b', 'c'); // (this, arg1, arg2)
func.apply('a', ['b', 'c']); // (this, arrayWithArgs)

4. 浏览器css动画结束的回调及模拟

bootstrap提供了一个工具,transition.js,用来判断浏览器是否支持css动画回调事件,以及在浏览器没有在动画结束后自动触发回调的特殊情况下通过模拟的方式来手动触发回调,原先这个工具只能配合jquery使用,为了在zepto中使用,必须稍微改变一下,下面就是改变之后的代码:

(function(){ var transition = $.transitionEnd = { end: (function () { var el = document.createElement('transitionEnd'), transEndEventNames = { WebkitTransition: 'webkitTransitionEnd', MozTransition: 'transitionend', OTransition: 'oTransitionEnd otransitionend', transition: 'transitionend' }; for (var name in transEndEventNames) { if (el.style[name] !== undefined) { return transEndEventNames[name]; } } return false; })() }; $.fn.emulateTransitionEnd = function (duration) { var called = false, _this = this, callback = function () { if (!called) $(_this).trigger(transition.end); }; $(this).one(transition.end, function () { called = true; }); setTimeout(callback, duration); return this; }; })();

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
33
34
35
(function(){
    var transition = $.transitionEnd =  {
        end: (function () {
            var el = document.createElement('transitionEnd'),
                transEndEventNames = {
                    WebkitTransition: 'webkitTransitionEnd',
                    MozTransition: 'transitionend',
                    OTransition: 'oTransitionEnd otransitionend',
                    transition: 'transitionend'
                };
 
            for (var name in transEndEventNames) {
                if (el.style[name] !== undefined) {
                    return transEndEventNames[name];
                }
            }
            return false;
        })()
    };
 
    $.fn.emulateTransitionEnd = function (duration) {
        var called = false,
            _this = this,
            callback = function () {
                if (!called) $(_this).trigger(transition.end);
            };
 
        $(this).one(transition.end, function () {
            called = true;
        });
 
        setTimeout(callback, duration);
        return this;
    };
})();

$.transitionEnd.end表示当前浏览器支持的动画结束事件的名称。$.fn.emulateTransitionEnd是一个扩展了Zepto原型的一个方法,传入一个动画的过渡时间,当这个时间段过完之后,如果浏览器没有自动触发回调事件,called就始终是false,setTimeout会导致callback被调用,然后callback内部就会手动触发动画结束的回调。为什么要通过这个方式来模拟动画结束,是因为浏览器即使支持动画结束事件的回调,但是有些时候并不会触发这个事件,或者在动画结束后不能立即触发,影响回调的准确性。传入的duration应该与执行动画的元素,在css上设置的transtion-duration相同,注意以下代码中标黄的部分:

JavaScript

var TRANSITION_DURATION = 400; $activePage .one($.transitionEnd.end, function () { $targetPage.removeClass(['page--' + slideType, 'page--' + slideType + '-' + direction].join(' ')).addClass('page--active'); $activePage.removeClass(['page--active', 'page--active-' + direction].join(' ')); $activePage = $targetPage; sliding = false; }) .emulateTransitionEnd(TRANSITION_DURATION);

1
2
3
4
5
6
7
8
9
var TRANSITION_DURATION = 400;
$activePage
            .one($.transitionEnd.end, function () {
                $targetPage.removeClass(['page--' + slideType, 'page--' + slideType + '-' + direction].join(' ')).addClass('page--active');
                $activePage.removeClass(['page--active', 'page--active-' + direction].join(' '));
                $activePage = $targetPage;
                sliding = false;
            })
            .emulateTransitionEnd(TRANSITION_DURATION);

.page { overflow: hidden; display: none; -webkit-transition: -webkit-transform .4s ease; transition: transform .4s ease; -webkit-backface-visibility: hidden; backface-visibility: hidden; }

1
2
3
4
5
6
7
8
.page {
    overflow: hidden;
    display: none;
    -webkit-transition: -webkit-transform .4s ease;
    transition: transform .4s ease;
    -webkit-backface-visibility: hidden;
    backface-visibility: hidden;
}

this 在构造函数中

如果通过new运算符调用函数,则函数将成为构造函数。 该运算符创建一个新的对象,并通过它通过this传递给构造函数:``

var savedThis; function Constr() { savedThis = this; } var inst = new Constr(); console.log(savedThis === inst); // true

1
2
3
4
5
6
var savedThis;
function Constr() {
   savedThis = this;
}
var inst = new Constr();
console.log(savedThis === inst); // true

在JavaScript中实现,new运算符大致如下所示(更精确的实现稍微复杂一点):

function newOperator(Constr, arrayWithArgs) { var thisValue = Object.create(Constr.prototype); Constr.apply(thisValue, arrayWithArgs); return thisValue; }

1
2
3
4
5
function newOperator(Constr, arrayWithArgs) {
   var thisValue = Object.create(Constr.prototype);
   Constr.apply(thisValue, arrayWithArgs);
   return thisValue;
}

本文由澳门新葡亰手机版发布于web前端,转载请注明出处:js实现简洁的滑屏功能,开始使用Web

上一篇:一篇真正教会你开发移动端页面的文章,你该知 下一篇:面向对象实战之封装拖拽对象,虚假来电
猜你喜欢
热门排行
精彩图文