• 前端开发日常——CSS动画无限轮播


      近来没有什么值得写的东西,空闲的时候帮前端的同学做了些大屏上的展示模块,就放在这里写写吧,手把手“需求->设计-> 实现”,受众偏新手向。

      

      为了直观便于理解, 直接把结果贴在上面。

      如上所示,基本需求比较简单明了, “分页显示供应商、供应占比列表,自动轮播”。

     

      一、需求评审

      该有的环节还是要有,尽管需求简单,评审不能省略,无论形式。开发的同学千万不要真的相信需求就这么简单,否则南辕北辙,出力不讨好,那必定是日常-_-||。

      于是有丰富填坑经验的开发同学,对于这个简单的模块需求,可能会提出如下的一些问题

      1. 如果只有一页,要不要轮播?

      2.每页的轮播间隔频率是多少?

      3.如果列表没有数据,如何显示这个模块?

      4.数据的刷新时机?是翻页刷新,轮播一圈刷新,还是其他?

      5.这个绿色的比值是什么含义? 是不是还有红色?

      6.百分比的小数位?

      7.如果接口异常比如网络不通,如何表示这种异常?

      8.供应商的名字会不会有500字那么长? 放不下如何布局?

      ……等等

      以上任何一个未明确的需求,都可能成为你编码完成后的一个bug或优化建议。 o(* ̄︶ ̄*)o。

     

      二、设计评审  

      关于上面待确认的每一个问题,我们伟大的产品经理都一一耐心的给出了“令人信服的”回答后。还是不能马上开始编码。下面我们需要进行一些技术方案的设计讨论,由技术leader把关。例如:

      1. 数据流,这个列表的数据,是从数据库中的哪几个表取出的? 确认下查询逻辑。

      2.接口设计,是一次返回前端所有数据,还是支持分页查询。

      3.性能考虑,查询频率是不是较高,并发是不是大,缺不缺索引,要不要上缓存?

      4.轮播如何实现? 有没有已经集成的轮播控件,是否满足要求,还是需要自己写一个。

      5.如何进行模块化开发,作为一个模块集成嵌入到整体页面中。

      ……等等

      明确了以上的问题后,作为前端同学的我,是不是可以开始撸代码了?

       

      三、想清楚再写

      说到这里,

      一类同学已经开始着手编码了, 第一个想到需要写的方法可能是,ajax 去后台请求数据列表的接口。

      另一类同学,可能仍在构思,如何组织代码,提炼主要的数据结构和功能方法。

      这里我们显然应该向“另外一类”同学学习。想清楚再写,是一个毫无疑问的好习惯

      技术预研

      实现一个功能,首先要扫除其中的未知技术点,扫除了所有未知之后,才能够优化的组织实现方案

      上面的需求对于我这种半吊子前端来说,比较关键的两个技术问题是。

      1)用什么方案来实现滑动动画。 2)如何实现“无限滚动”。

     

      滑动动画——经过一番百度,总结下动画可能的实现方案,包括用JS实现或者用CSS实现。 各有优劣,js 兼容性好,控制灵活;CSS性能高,平滑流畅。因为我们的动画非常线性,简单,于是这里我们决定采用CSS动画作为动画的实现方案。

      通过简单的研究,我们已经弄清楚了, 想让一个页面元素具有一个动画效果,可以通过向他添加一个包含了动画关键真的选择器来实现,比如定义一个滑出动画类,把这个css类加到元素上,元素就可以实现滑出的动画效果。

     

      无限滚动——思考下滚动页面,虽然对于数据来说可能会分成很多页,但对于屏幕展示来说,实际上最多同时出现两个页面,一个是前一页,一个是当前页。在不滚动的时候只有当前页需要显示。

      顺着这个思路, 滚动这个动作对应,“当前页飞入”“前一页飞出”这两个细分动作,特别的情况是,初始显示时,是没有“前一页”的。

      那么滚动这个动作大概思路就是,

      1. 根据当前页号取得对应数据,绘制HTML页面,append到滚动区域,对其添加“飞入”动画

      2. 根据当前页号取得上一页页面元素,对其添加“飞出”动画,动画结束后将其移除, 仅显示当前页。

     

      四、编码实现

      终于到了编码的时间了。

      用到的 css 动画类选择器,以及关键帧 

    复制代码
    .slip_in_animation{
        animation: slip_in 1s;
    }
    
    .slip_out_animation{
        animation: slip_out 1s;
    }
    
    /*右侧滑入*/
    @keyframes slip_in
    {
        from {transform:translateX(100%);}
        to {transform:translateX(0);}
    
    }
    
    /*右侧滑入*/
    @keyframes slip_out
    {
        from {transform:translateX(0);}
        to {transform:translateX(-100%);}
    }
    复制代码

      js应用于页面元素,飞入飞出, 飞出后删除,*动画在结束后并不会改变元素实际位置。所以要在动画结束前,移除元素,避免它回到之前位置,挡住当前页,发生“闪烁”

    复制代码
        //页面滑入,要显示的页面
        this.slipIn = function(pageNo){
            $("#supplierListPage_"+pageNo).addClass("slip_in_animation");
        };
    
        //页面滑出,
        this.slipOut = function(pageNo){
            $("#supplierListPage_"+pageNo).addClass("slip_out_animation");
    
            //移除上一页,定时比动画稍短,避免闪烁
            setTimeout(function(){
                $("#supplierListPage_"+pageNo).remove();
            },900);
        };
    复制代码

      翻页的逻辑,第一次不滚动;滚到头,把最后一页飞出,第一页飞入。

    复制代码
        this.switchNext = function(pageNo){
    
            //附加生成新的页面
            var newPageHtml =  _this.makePageHtml(pageNo);
            $("#"+ _this.containerId).append(newPageHtml);
    
            //多于一页的情况
            if(_this.firtshow){
                _this.firtshow= false;
                //第一次换页 不需要移除之前页面。
            }else{
                //前面已经有显示过的页面,需要把前面的页面滚动出去。
                var olderPage =  pageNo -1;
                if(olderPage <=0){
                    //当前页是第一个,前一页就是最后一页
                    olderPage = _this.totalPage;
                }
                _this.slipOut(olderPage);
            }
            _this.slipIn(pageNo);
        };
    复制代码

      定时滚动到下一页。如果是最后一页,重新开始第一页。

    复制代码
        this.startRolling = function(){
                _this.switchNext(_this.curPage);
    
                //按间隔轮播
                _this.switchTimer =  setInterval(function(){
    
                    if(_this.totalPage == 1)
                        return;
    
                    if(_this.curPage < _this.totalPage) {
                        _this.curPage++;
                    }else{
                        _this.curPage = 1;
                    }
                    _this.switchNext(_this.curPage);
                },_this.switchInterval);
        };
    复制代码

    写到这里,下面是完整代码,需要的可以参考。

     

    完整的代码CSS:

    .slip_in_animation{
        animation: slip_in 1s;
    }
    
    .slip_out_animation{
        animation: slip_out 1s;
    }
    
    /*右侧滑入*/
    @keyframes slip_in
    {
        from {transform:translateX(100%);}
        to {transform:translateX(0);}
    
    }
    
    /*右侧滑入*/
    @keyframes slip_out
    {
        from {transform:translateX(0);}
        to {transform:translateX(-100%);}
    }
    View Code

     

    完整JS:

    function SupplierListTable(){
    
        var _this = this;
        //echart 图表对象。
    
        //轮播间隔 毫秒
        this.switchInterval = 5000;
    
        //当前轮播的页,从1开始
        this.curPage=1;
    
        //每页条数
        this.pageSize = 5;
    
        //当前数据对应总页数
        this.totalPage = 0;
    
        //数据列表
        this.chartDataList = new Array();
    
    
        //第一次展示标志
        this.firtshow =true;
    
        this.containerId = null;
        //轮播定时器
        this.switchTimer = null;
    
        this.init  = function(containerId){
            _this.containerId = containerId;
            //初始化图表
            $("#"+containerId).html("");
            _this.reloadData(containerId);
        };
    
    
        this.getTotalPage = function(){
           var totalPage  = Math.ceil(_this.chartDataList.length/_this.pageSize);
           return totalPage;
        };
    
        this.reloadData =function(containerId){
    
    
            //从网络请求数据。
    
            setTimeout(function(){
    
                _this.chartDataList= [
                    {name:"供应商1",percent:"12%"},
                    {name:"供应商2",percent:"13%"},
                    {name:"供应商3",percent:"14%"},
                    {name:"供应商4",percent:"15%"},
                    {name:"供应商5",percent:"16%"},
                    {name:"供应商6",percent:"13%"},
                    {name:"供应商7",percent:"14%"},
                    {name:"供应商8",percent:"15%"},
                    {name:"供应商9",percent:"16%"}
    
                    ];
    
    
                _this.totalPage = _this.getTotalPage();
                _this.curPage = 1;
    
    
                _this.stopRolling();
                _this.startRolling();
    
            },300);
    
        };
    
    
        this.stopRolling= function(){
            if(_this.switchTimer != null){
                clearInterval(_this.switchTimer);
                _this.switchTimer = null;
                _this.curPage = 0;
            }
        };
    
    
        this.startRolling = function(){
                _this.switchNext(_this.curPage);
    
                //按间隔轮播
                _this.switchTimer =  setInterval(function(){
    
                    if(_this.totalPage == 1)
                        return;
    
                    if(_this.curPage < _this.totalPage) {
                        _this.curPage++;
                    }else{
                        _this.curPage = 1;
                    }
                    _this.switchNext(_this.curPage);
                },_this.switchInterval);
        };
    
        this.switchNext = function(pageNo){
    
            //附加生成新的页面
            var newPageHtml =  _this.makePageHtml(pageNo);
            $("#"+ _this.containerId).append(newPageHtml);
    
            //多于一页的情况
            if(_this.firtshow){
                _this.firtshow= false;
                //第一次换页 不需要移除之前页面。
            }else{
                //前面已经有显示过的页面,需要把前面的页面滚动出去。
                var olderPage =  pageNo -1;
                if(olderPage <=0){
                    //当前页是第一个,前一页就是最后一页
                    olderPage = _this.totalPage;
                }
                _this.slipOut(olderPage);
            }
            _this.slipIn(pageNo);
        };
    
        //生成指定页的html。
        this.makePageHtml = function(pageNo){
    
            var startRecIndex=  _this.pageSize * (pageNo - 1);
            var endRecIndex =   _this.pageSize *  pageNo ;
    
            if(endRecIndex > _this.chartDataList.length){
                endRecIndex = _this.chartDataList.length;
            }
    
            var html = "
    "; for (var i = startRecIndex; i < endRecIndex; i++) { html+= "
    " +_this.chartDataList[i].name+" "+_this.chartDataList[i].percent+"
    " } html+="
    " return html; }; //页面滑入,要显示的页面 this.slipIn = function(pageNo){ $("#supplierListPage_"+pageNo).addClass("slip_in_animation"); }; //页面滑出, this.slipOut = function(pageNo){ $("#supplierListPage_"+pageNo).addClass("slip_out_animation"); //移除上一页,定时比动画稍短,避免闪烁 setTimeout(function(){ $("#supplierListPage_"+pageNo).remove(); },900); }; } $(document).ready(function(){ var containerId = 'supplierListChart'; var supplierListTable = new SupplierListTable(); supplierListTable.init(containerId); });
    View Code

     

    HTML页面容器:

    <div  style="height: 300px;width:400px;overflow-x: hidden;position: relative" id="supplierListChart" >
    div>
    View Code

     

  • 相关阅读:
    【Linux:进程概念】
    【Azure Developer】在Azure VM (Windows) 中搭建 kafka服务,并且通过本地以及远程验证 发送+消费 消息
    时间戳转换为正常时间
    libcrypt.so.1丢失,重新在Ubuntu 20.04安装的方法
    【C# 调试】.net中的 .pdb文件是什么,有什么用
    【光学】Matlab模拟透射光条纹强度分布曲线仿真
    PTL货位指引标签为仓储管理打开新思路
    [Halcon&3D] 3D手眼标定理论与示例解析
    python简介常考面试题目:python是什么,有什么好处,python2和python3的主要区别
    探索设计模式:从组合到享元的软件架构之旅 (软件设计师笔记)
  • 原文地址:https://www.cnblogs.com/uncleguo/p/16809968.html