最近有个任务,做一个非常小的h5的应用,只有2屏,需要做横向的全屏滑动切换和一些简单的动画效果,之前做这种东西用的是fullpage.js和jquery,性能不是很好,于是就想自己动手弄一个简单的东西来实现。最后我用zepto + hammer.js 和轮播的方式解决了这个问题,效果还不错,整个页面不开启Gzip时所有资源请求的数据大小为200KB左右。这篇文章总结下这个方法的实现思路。

效果演示:

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联合使用。

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

2. html结构

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

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结构是:

下一页

1

上一页下一页

2

上一页

3

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

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);

}

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

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图说明如下:

向右滑屏原理类似:

第一步,找到上一页的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函数如下:

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的作用,这个在下一部分说明。

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;

};

})();

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

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;

}

5. hashchange事件

PC端滑屏都是给元素添加点击事件触发的,移动端可以利用window的hashchange事件:

$(window).on('hashchange', function (e) {

var hash = location.hash;

if (!hash) hash = '#page-1';

slide(hash.substring(1));

});

location.hash = '#page-1';

hashchange事件,在js代码中通过改变loaction.hash或者是点击下一页这样的超链接时,都会触发,所以只要在这个事件的回调去做滑屏切换即可。这样那些上一页和下一页的链接元素都不用加事件了。

6. hammer.js使用简介

hammer.js是一个手势库,支持常用的手势操作,使用简单,引入它的js之后,通过以下的方式来支持手势滑屏:

//初始化手势滑动

var container = document.getElementById('container'),

mc = new Hammer.Manager(container),

Swipe = new Hammer.Swipe();

mc.add(Swipe);

mc.on('swipeleft', function (e) {

swipteTo('next', e);

});

mc.on('swiperight', function (e) {

swipteTo('prev', e);

});

function swipteTo(slideType, e) {

var $targetPage = $activePage[slideType]('.page');

$targetPage.length && (location.hash = '#' + $targetPage.attr('id'));

}

把整个container元素作为滑屏的stage,监听到swipeleft事件,就表示向左滑,页面应该显示下一页;监听到swiperight事件,就表示向右滑,页面应该显示下一页。

7. 结束语

animate.css的使用就不详细介绍了,比较简单,这是它的github地址:https://github.com/daneden/animate.css,是一个非常好用的动画库。本文把最近的一点工作经验记录了下来,技术上的东西,有的时候一些文字不能完全讲的清楚,所以我只能尽自己的能力去把一些问题讲地稍微细致一点,说的不对和有问题的尽管在评论区与我说明,我会认真查看,另外我自己对移动端这一块入门不深,您有更好的见解,欢迎与我们一起分享。谢谢您的阅读,马上就新年,祝您猴年大吉!

手机 html5 hammer drag widget,Hammer.js+轮播原理实现简洁的滑屏功能相关推荐

  1. 【前端】js轮播图,简洁代码,一目了然

    对于很多时候,找不到写轮播的方法,都是用框架写的比较多,虽然好用,但作为程序员来说,还是要自己写,才有成就感.废话不多说,最近写了个小小的轮播代码,下面附上代码. 一.第一步写好静态网页代码 < ...

  2. html5移动端轮播图特效,支持移动端的纯js轮播图插件awesome-slider

    awesome-slider是一款支持移动端的纯js轮播图插件.该轮播图插件支持任何HTML标签,可以自定义分页标签和Loading效果,支持在前端框架如react中使用. 使用方法 安装: /* y ...

  3. JavaScript的案例(数据校验,js轮播图,页面定时弹窗)

    1.数据校验             步骤             1.确定事件(onsubmit)并绑定一个函数             2.书写这个函数,获取数据,并绑定id            ...

  4. php 走马灯轮播,Vue.js轮播图走马灯代码实例(全)

    这个是html, 数据中我用了一个数组来放图片的目录, data() { return { superurl: [ { url: '', img: '../../../../static/image/ ...

  5. JS 轮播图 图片切换(定时器)

    标题JS 轮播图 图片切换(定时器) 这次的轮播图与上次的图片切换相比,仅仅是加上了定时器,使其可以自动切换. 上次的图片切换的链接:https://blog.csdn.net/qq_38318589 ...

  6. JS轮播图(网易云轮播图)

    JS 轮播图 写在前面 最聪明的人是最不愿浪费时间的人.--但丁 实现功能 图片自动切换 鼠标移入停止自动播放,显示按钮 点击按钮,实现前后翻 鼠标移入小圆圈,可以跳转到对应图片 点击左右两侧图片部分 ...

  7. JS轮播图(点击切换、自动播放、悬停控制)

    JS轮播图 轮播图可以说是网页上十分常见的效果,很多朋友在学习JavaScript后都迫不及待的想写一些好看对的效果出来,那么轮播图就是一个很不错的练手实例.下面就是通过JS写的轮播图效果: 功能介绍 ...

  8. 三种js轮播实现方式详解(看一遍就会)

    js轮播的三种实现方式 1.替换scr(入门级) <!DOCTYPE html> <html><head><meta charset="utf-8& ...

  9. Bootstrap4框架处理JS轮播

    Bootstrap4框架处理JS轮播 开发工具与关键技术:使用Bootstrap4框架作者:郑健鹏撰写时间:2019年1月16日 我们之前的JS轮播是用原生的JS代码实现,这个方法比较耗费时间,因为还 ...

最新文章

  1. Intent携带额外的数据的方法
  2. 如何轻松应对DNS劫持
  3. python中国地图热力图是什么意思_python实现输入的数据在地图上生成热力图效果...
  4. 学好python能干嘛-学会Python后都能做什么?网友们的回答简直不要太厉害
  5. SYN攻击原理 accpet()函数调用时机
  6. 2017腾讯编程题----素数对
  7. redis源码分析 ppt_【Redis】redis各类型数据结构和底层实现源码分析
  8. python 字典练习 记录学生是否交作业的小程序
  9. MySQL “error C3646: 'fd': 未知重写说明符”
  10. Scala学习笔记(二)表达式和函数
  11. python中高阶函数和装饰器_Python高阶函数与装饰器函数的深入讲解
  12. java发送email_java发送email一般步骤(实例讲解)
  13. NetAssist连接报错!
  14. 一个独特的简历生成器,开源了!
  15. [渝粤教育] 扬州市职业大学 液压与气动技术 参考 资料
  16. win10 pip install talib一直安装失败
  17. FTP服务器 虚拟用户 530 Login incorrect. Login failed 解决办法
  18. Python数据可视化之美
  19. 安卓电话补充业务 SS
  20. 营养百科之莲藕蜂蜜水

热门文章

  1. 技术分享 | 新手入门-带你使用Qt实现离线缓存地图
  2. 2012中国互联网哈哈榜之1:十大网络流行语
  3. 数据库系统原理实验一——数据库定义实验
  4. 计算机班级队名大全,班级队名和口号大全
  5. 静态HTML网页设计作品web网页设计实例作业 ——个人书画作品展示HTML模板(6页) HTML+CSS大作业
  6. Java市场调研_Java开源电商系统的市场调研怎么做
  7. 在线教育项目04_讲师管理前端开发
  8. 【正点原子STM32连载】 第二十七章 RTC实时时钟实验 摘自【正点原子】MiniPro STM32H750 开发指南_V1.1
  9. 外汇交易与实务--远期外汇交易
  10. 钉钉注册阿里云账号全流程