目录
原理
功能实现
首页 web前端 html教程 还在为无缝滚动而烦恼?是时候彻底get到这个知识点了_html/css_WEB-ITnose

还在为无缝滚动而烦恼?是时候彻底get到这个知识点了_html/css_WEB-ITnose

Jun 21, 2016 am 08:48 AM

最近一直在忙公司炒股大赛的页面,终于在昨天把他给上线了。一个看似简单的页面,做起来才知道其中的艰辛,暗藏深坑。由于直接使用jquery来写页面逻辑,因此要比想象中复杂很多。无论是从布局,功能还是逻辑上来说,都有值得总结的地方。

点击可查看我昨天上线的页面

这篇文章主要说说关于无缝滚动的实现。

刚开始学习js的时候,真心觉得无缝滚动是一个神奇的功能。背后到底是怎么回事?为什么明明只有几个方块就是滚不到头?后来明白了原理之后,发现原来是通过一些障眼法来实现。

原理

假如需要无缝滚动的4个元素是一个 ul.items中的6个 li.item。我们将控制 ul.items在容器 .wrap中滚动。html代码如下:

ul.items表示className为items的ul元素,其他地方同理

<div class="wrap">    <ul class="items"><!--    --><li class="item"><img src="/static/imghw/default1.png"  data-src="https://static.tigerbrokers.com/portal/images/cooperation/stockGame/v2-partner0.8a07a886.jpg"  class="lazy" alt=""></li><!--    --><li class="item"><img src="/static/imghw/default1.png"  data-src="https://static.tigerbrokers.com/portal/images/cooperation/stockGame/v2-partner1.56bcecb3.png"  class="lazy" alt=""></li><!--    --><li class="item"><img src="/static/imghw/default1.png"  data-src="https://static.tigerbrokers.com/portal/images/cooperation/stockGame/v2-partner2.9a7e8842.jpg"  class="lazy" alt=""></li><!--    --><li class="item"><img src="/static/imghw/default1.png"  data-src="https://static.tigerbrokers.com/portal/images/cooperation/stockGame/v2-partner3.47acdfbd.png"  class="lazy" alt=""></li><!--    --><li class="item"><img src="/static/imghw/default1.png"  data-src="https://static.tigerbrokers.com/portal/images/cooperation/stockGame/v2-partner5.e9205d49.jpg"  class="lazy" alt=""></li><!--    --><li class="item"><img src="/static/imghw/default1.png"  data-src="https://static.tigerbrokers.com/portal/images/cooperation/stockGame/v2-partner6.83b14a71.png"  class="lazy" alt=""></li><!--    --></ul></div>
登录后复制

我们的目标是实现水平方向上的滚动,因此需要 li.item水平排列。能够达到目标的方式常用的有使用 float: left,或者使用 display: inline-block。我们知道控制页面元素的移动无非就是控制元素的 left, top, translateX, translateY,还有一种就是控制滚动距离 scrollTop, scrollLeft。布局的选择,同时也会影响到js控制属性的选择。

本例选择使用 display: inline-block布局,并控制 ul.items的 scrollLeft值,让整个ul滚动起来。布局上需要注意的有以下几点:

  1. 超出容器的部分需要隐藏,注意,此处的隐藏是给 ul.items的,注意与 float: left布局的差别。

    .items { overflow: hidden; }
    登录后复制
  2. ul.items的内容不能折行,因此

    .items { white-space: nowrap; }
    登录后复制
  3. 需要适配到移动端,因此 li.item的宽度就必然会随着设配宽度的变小而变小。

    @media (max-width: 780px) {    .item {        width: 190px;    }}@media (max-width: 580px) {    .item {        width: 160px;    }}
    登录后复制
  4. html布局中的 是为了消除 display: inline-block元素之间带来的间隙。

那么无缝滚动的障眼法到底是什么呢?本来用图片描述会更加直观一点,不过这里我想偷个懒,用文字给大家讲述一下,希望大家能看懂。

我们有子元素123456, 一个一个向左滚动,复制一份,就变成 123456123456。如果我们在整体移动到第二个1的时候,将整体的位置拉回到第一个1来,也就是初始位置,由于有 div.items的 overflow: hidden在,中间发生的变化我们没办法用肉眼识别出来,就感觉是一直在向左移动,永远都停不下来。

表达能力有限,如果没懂再结合代码理解一下吧,或者留言给我

功能实现

一说到运动,我们常常想到的方法可能是利用 setTimeout或者 setInterval, 不过呢,html5为我们提供了一个更加高性能的方法 requestAnimationFrame。

在性能上, requestAnimationFrame > setTimeout > setInterval。具体原因大家可以找找相关的资料了解一下。而 setTimeout的最小定时值为 100/60,因此,我们在实现运动时,从性能与兼容性两方面考虑,常常会如下声明:

var lastTime = 0,    nextFrame = window.requestAnimationFrame       ||                window.webkitRequestAnimationFrame ||                window.mozRequestAnimationFrame    ||                window.msRequestAnimationFrame     ||                function(callback) {                    var currTime = + new Date,                        delay = Math.max(1000/60, 1000/60 - (currTime - lastTime));                    lastTime = currTime + delay;                    return setTimeout(callback, delay);                },    cancelFrame = window.cancelAnimationFrame               ||                  window.webkitCancelAnimationFrame         ||                  window.webkitCancelRequestAnimationFrame  ||                  window.mozCancelRequestAnimationFrame     ||                  window.msCancelRequestAnimationFrame      ||                  clearTimeout;
登录后复制

我们需要知道滚动到什么位置回退到0,这个位置刚好就是复制之前所有子元素加一起的总长度。但是子元素的宽度会因为设备宽度的改变而改变,因此配合布局,我们需要作如下处理:

// 单个子元素的宽度var itemW = 240;if ($items.children().eq(0).width() == 190) {    itemW = 190;}if ($items.children().eq(0).width() == 160) {    itemW = 160;}// 目标位置var target = itemW * $items.children().length;
登录后复制

为了实现障眼法,需要复制一份子元素

$items.html( $items.html() + $items.html() );
登录后复制

定义一个运动函数,这里的运动为匀速运动,因此比较简单,只需要一直+1即可。如果需要运动快一点,就多加一点

var timer = null;function adAni() {    timer = nextFrame(function() {        scrollX += 1;        // 当递增到大于了目标距离,就直接变为0        if (scrollX >= target) {            scrollX = 0;        }        $items.scrollLeft(scrollX);        adAni();    });}// 运行这个函数就可以实现无缝滚动啦。adAni();
登录后复制

这样无缝滚动就已经实现了。不过还有一些其他的需求。比如,鼠标mouseover时,需要停止滚动,离开之后又要重新启动滚动。因为需求的变化,在移动端还需要能够滑动 items.ul,手指松开之后继续滚动。因此我们需要一个区别pc于移动端的函数。通过UA的不同来区分。

function isMobile() {    return /(iphone|ipad|ipod|ios|android|mobile|blackberry|iemobile|mqqbrowser|juc|fennec|wosbrowser|browserng|Webos|symbian|windows phone)/i.test(navigator.userAgent);}
登录后复制

在pc端,鼠标移入时停止,鼠标移除时继续滚动

if (!isMobile()) {    $items.on('mouseover', function() {        cancelFrame(timer);    }).on('mouseout', function() { adAni(); });}
登录后复制

在移动端,可以左右滑动,滑动时停止自动滚动,松开之后继续自动滚动。移动端的滑动事件,主要通过 touchstart, touchmove, touchend来实现,与pc端的 mousedown, mousemove, mouseup类似。

var sX, sL;$items.on('touchstart', function(e) {    cancelFrame(timer);    sX = e.originalEvent.changedTouches[0].pageX;    sL = $items.scrollLeft();}).on('touchmove', function(e) {    var dis = e.originalEvent.changedTouches[0].pageX - sX;    var nowX = sL - dis;    if (nowX > target) {        nowX = 0;    }    $items.scrollLeft(nowX);}).on('touchend', function(e) {    scrollX = $items.scrollLeft();    if (scrollX >= target) {        scrollX = 0;    }    adAni();})
登录后复制

那么到这里,就已经基本搞定啦。虽然是一个比较简单的小例子,但是其中也包含了一些常用的功能,比如使用 requestAnimationFrame来实现运动,移动端的滑动事件等。在这里总结一下分享给大家,有疑问欢迎探讨。

由于segmentfault的文章中不支持codepen的demo,因此大家可以到文初提供的链接查看,也可以到我的个人博客里面查看 博客原文。

如果大家有任何疑问,都可以在公众号里面留言给我,微信中搜索 isreact可以找到我^_^,我需要您的关注。

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

&gt; gt;的目的是什么 元素? &gt; gt;的目的是什么 元素? Mar 21, 2025 pm 12:34 PM

本文讨论了HTML&lt; Progress&gt;元素,其目的,样式和与&lt; meter&gt;元素。主要重点是使用&lt; progress&gt;为了完成任务和LT;仪表&gt;对于stati

&lt; datalist&gt;的目的是什么。 元素? &lt; datalist&gt;的目的是什么。 元素? Mar 21, 2025 pm 12:33 PM

本文讨论了html&lt; datalist&gt;元素,通过提供自动完整建议,改善用户体验并减少错误来增强表格。Character计数:159

HTML5中跨浏览器兼容性的最佳实践是什么? HTML5中跨浏览器兼容性的最佳实践是什么? Mar 17, 2025 pm 12:20 PM

文章讨论了确保HTML5跨浏览器兼容性的最佳实践,重点是特征检测,进行性增强和测试方法。

&lt; meter&gt;的目的是什么。 元素? &lt; meter&gt;的目的是什么。 元素? Mar 21, 2025 pm 12:35 PM

本文讨论了HTML&lt; meter&gt;元素,用于在一个范围内显示标量或分数值及其在Web开发中的常见应用。它区分了&lt; meter&gt;从&lt; progress&gt;和前

我如何使用html5&lt; time&gt; 元素以语义表示日期和时间? 我如何使用html5&lt; time&gt; 元素以语义表示日期和时间? Mar 12, 2025 pm 04:05 PM

本文解释了HTML5&lt; time&gt;语义日期/时间表示的元素。 它强调了DateTime属性对机器可读性(ISO 8601格式)的重要性,并在人类可读文本旁边,增强Accessibilit

如何使用HTML5表单验证属性来验证用户输入? 如何使用HTML5表单验证属性来验证用户输入? Mar 17, 2025 pm 12:27 PM

本文讨论了使用HTML5表单验证属性,例如必需的,图案,最小,最大和长度限制,以直接在浏览器中验证用户输入。

视口元标签是什么?为什么对响应式设计很重要? 视口元标签是什么?为什么对响应式设计很重要? Mar 20, 2025 pm 05:56 PM

本文讨论了视口元标签,这对于移动设备上的响应式Web设计至关重要。它解释了如何正确使用确保最佳的内容缩放和用户交互,而滥用可能会导致设计和可访问性问题。

&lt; iframe&gt;的目的是什么。 标签?使用时的安全考虑是什么? &lt; iframe&gt;的目的是什么。 标签?使用时的安全考虑是什么? Mar 20, 2025 pm 06:05 PM

本文讨论了&lt; iframe&gt;将外部内容嵌入网页,其常见用途,安全风险以及诸如对象标签和API等替代方案的目的。

See all articles