css+js实现左右滑动卡片组件

最近的一个活动页面需要做一个可以左右滑动的抽签效果,故通过用css的transform属性和js结合来模拟可以无限滚动的效果。

先上效果:

demo地址:https://kiroroyoyo.github.io/cardTransform/index.html

实现过程

1. 结构与样式

结构:卡片分前后两排,每列插入10个div结点,以便做左右位移效果。

样式:设置每一列都恰好好在中间位置(或中间位置附近),如下所示。

a. 前排(cardFrond)相对于视口的初始位置(left:-255.5%;):

b. 后排(backFrond)相对于视口的初始位置(left:-228.3%;):

2. 无限滚动原理

由于这里的停止位置是固定的,前排永远是当前卡片相对于视口居中,后排永远是两个卡片相对于视口居中,且每个卡片是一样的,所以当卡片列表向前或向右移动到一个目标位置时,都将列表重置为初始位置继续滚动。如下图以前排卡片为例:

所以当滚动停止后会统一将列表样式设置为transform: translateX(0)。而对于用户这一操作是无感知的,认为已经滑动到了新的位置。

3.滑动过程实现

a. 目标位移与帧位移

为了做出滑动后到停留位置的缓动效果,所以当用户左右滑动屏幕时,会记录滑动距离,计算出卡片该到的目标位移位置,目标位移位置是有规则的,因为这里有10张卡片均分宽度,位置必须是(100%/10)的整数倍,例如-40%、-30%、……40%,这样才能保证目标位置与初始位置相重合。

目标位移代码片段

onDocumentMouseUp : function(e){
    //如果是点击事件 不设置移动
    if (!this.fingerTouch)
      return;
    this.moveDirect = this.lon > 0 ? 1 : -1;
    this.transNum = this.lon/10 + this.moveDirect;
    this.lon = Math.round(this.transNum) * 10;
    this.fingerTouch = false;   
}

记录了目标位移后,每一帧会以一定的帧位移不断靠近目标位移,使其在手指离开屏幕时仍有慢慢滑动到目标位置的缓动效果。此时需要判断当前位置是否大于40%或者小于-40%,若超过这个极限值需要重设目标位移及帧位移,使其在极限值内。

animate: function(){
    this.prePos += (this.lon - this.prePos) * 0.1;
    if (this.prePos > 40) {
      this.lon = this.lon - 40;
      this.prePos = this.prePos - 40;
    }else if (this.prePos < -40) {
      this.lon = this.lon + 40;
      this.prePos = this.prePos + 40;
    }
    //判断是否到达了目标位置
    if (Math.abs(this.prePos - this.lon) < 0.01 && Math.abs(this.lon) > 0.01 && (!this.fingerTouch))
    {
        this.ani_move = false;
        this.prePos = 0;
        this.frondCard.style = "transform: translateX("+ this.prePos +"%)";
        this.backCard.style = "transform: translateX("+ this.prePos +"%)";
    }else{
        this.frondCard.style = "transform: translateX("+ this.prePos +"%)";
        this.backCard.style = "transform: translateX("+ (-this.prePos) +"%)";
        requestAnimationFrame(this.animate.bind(this));
    }
  },

b. 连续滑动判断

当在上次滑动动画还未播放结束时用户又进行了第二次滑动时,需要执行一下操作:

    1). 判断滑动时机处于上次滑动手指已离开屏幕但动画还未结束,此时需要记录两个flag,一个是ani_move,记录动画是否仍在进行,fingerTouch记录手指是否停留屏幕。

    2). 判断第二次滑动是否与第一次不同方向,若不同向需重置上次帧位移为0。以免上次帧位移太大影响移动方向。

1)与2)代码片段:

if( this.ani_move && this.fingerTouch == false) {
    // 判断是否不同向
    if (((e.clientX - prex) > 0 ? 1: -1) == -this.moveDirect ) {
        this.lon = 0;
        this.prePos = 0;
        this.moveDirect = -this.moveDirect;
    }
}

3). 取消第二次滑动时的动画播放和位移重置

// 若是上次动画未结束不需要再次启动动画和重置目标位移
if( this.ani_move && this.fingerTouch == false) {
}
else {
    this.lon = 0;
     cardAnimate.animate();
}

写在最后

目前这个滑动效果只能针对卡片相同,停留位置固定的情况,因为需要做到位置重合。使用css transform来做无限滚动的效果,可以避免改变dom结点带来的页面重新布局。

下图是chrome cpu6倍减速调试效果,没有触发layout,FPS基本维持在60左右。

代码地址:

https://github.com/kiroroyoyo/cardTransform

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏V站

自适应丨Html5响应式(自适应)网页设计

viewport是网页默认的宽度和高度, 上面这行代码的意思是:网页宽度默认等于屏幕宽度(width=device-width), 原始缩放比例(initia...

3695
来自专栏GIS讲堂

CSS+JS实现tab标签切换

循环将所有的内容标签隐藏,并将tab标题栏的active样式清除,完了之后设置选中标签的内容显示,并给tab标题栏添加active样式。

3543
来自专栏前端笔记

【CSS3 理论知识】表格边框(table-border)你知多少???

table之间的边框存在共用问题,自然而然就存在冲突。既然存在冲突,那么就势必涉及到最后渲染哪一个样式的问题。本文就主要研究当冲突产生时,如何让浏览器按照自己...

3026
来自专栏黑白安全

javascript实现background 定时循环随机背景图

这里用的固定地址,用的新浪图床,喜欢的话可以自己扩充图片,我这里简短的展示了10个图片!

1433
来自专栏Coding01

推荐一款快速生成海报的微信小插件

现在很多小程序都有生成海报,分享海报的功能。我们自己的几个小程序 (如:爸妈搜商城、爸妈搜云课堂、幼师大学、跟着外教学英语等) 也都有生成海报的功能。因此技术团...

812
来自专栏数据小魔方

裁图、抠图、换背景,PPT也可以

今天跟大家聊一聊PPT的基本图片处理功能! ▽ 每次做PPT的时候 总想弄几个感觉还不错的图片 插入PPT里来装装bigger 可是能找到的图片 不是背景不搭 ...

37710
来自专栏IMWeb前端团队

CSS StickyFooter——当内容不足一屏时footer紧贴底部

一般来说我们的footer是跟着内容走的,所以当内容较少不足一屏的时候,footer也会跟着内容往上走,导致下面一段空白。所以这里我们来探讨下当内容不足一屏时f...

2117
来自专栏腾讯社交用户体验设计

表格边框你知多少

1763
来自专栏Thinks

【译】W3C WAI-ARIA最佳实践 -- 布局

面包屑包含当前页面的父页面的链接列表,该列表是层级顺序的。它可以帮助用户在网站或网络应用程序中找到自己的位置。面包屑通常水平放置在页面的主要内容之前。

9525
来自专栏前端说吧

一个有趣的鼠标移上去的动画-整理

3766

扫码关注云+社区