JS 效果集合(回到顶部、轮播图、瀑布流、图片帧播放)

回到顶部

<style type="text/css">

        #btn {width:40px; height:40px; position:fixed; right:65px; bottom:10px; display:none; 

                 background:url(images/top_bg.png) no-repeat left top;}   //固定定位,默认隐藏

        #btn:hover {background:url(images/top_bg.png) no-repeat 0 -39px;}   //鼠标悬浮样式变化
</style>
<body>
    <a href="javascript:void(0);" id="btn" title="回到顶部"></a>
</body>
<script>

    $(document).ready(onLoad);

    function onLoad(){
        var timer = null;    // 定时器

        var enableBack= false;   //是否允许自动滚动

        $("#btn").click(function(){     
            timer = setInterval(function(){   //点击按钮时,设置定时器
                var scrollHeight = $(window).scrollTop();   //获取滚动高度
                var speed = Math.floor(-scrollHeight / 6);   //自动滚动速度由快变慢
                $(window).scrollTop(scrollHeight  + speed);  //自动滚动,这时还未触发滚动回调函数,定时器执行完才回调
                enableBack= true;    //自动滚动时,设置允许自动滚动
                if(scrollHeight <= 0){   //自动滚到顶部时,清除定时器
                   clearInterval(timer);
                }
            },30);
        });

     $(window).on('scroll',function(){
           if($(window).scrollTop() > $(window).height()){
               $("#btn").show();  //滚出第一屏时,显示按钮
           }
           else{
               $("#btn").hide();    //回到第一屏时,显示按钮
           }

           if(!enableBack){

                //上一次为自动或者这次为自动,那么enableBack为true;

               //上一次为手动,这次也为手动,则enableBack为false;

               //手动滚动时,往往要触发多次,因此第二次以后enableBack为false

                clearInterval(timer);
           }
           enableBack = false;
     });
}

</script>

top_bg.png

轮播图

    基本原理为,横向并排的多张图片,在overflow为hidden的父元素内移动。

<style type="text/css">

        *{ margin: 0; padding: 0; text-decoration: none;}
        #container { width: 600px; height: 400px; border: 3px solid #333; overflow: hidden; position: relative;}
        #list { width: 4200px; height: 400px; position: absolute; z-index: 1;}
        #list img { float: left;}    //左浮动,使得图片并排
        #buttons { position: absolute; height: 10px; width: 100px; z-index: 2; bottom: 20px; left: 250px;}

        #buttons span { cursor: pointer; float: left; border: 1px solid #fff; width: 10px; height: 10px;

                   border-radius: 50%; background: #333; margin-right: 5px;}  //圆角半径为50%,使得边框闭合为一个圆圈

        #buttons .on {  background: orangered;}

        .arrow { cursor: pointer; display: none; line-height: 39px; text-align: center; font-size: 36px; font-weight: bold;

         width: 40px; height: 40px;  position: absolute; z-index: 2; top: 180px; background-color: RGBA(0,0,0,.3); color: #fff;}

        .arrow:hover { background-color: RGBA(0,0,0,.7);}
        #container:hover .arrow { display: block;}
        #prev { left: 20px;}
        #next { right: 20px;}

    </style>

<div id="container">
    <div id="list" style="left: -600px;">   <!--图串偏移量-->
        <img src="img/5.jpg" alt="1"/>
        <img src="img/1.jpg" alt="1"/>
        <img src="img/2.jpg" alt="2"/>
        <img src="img/3.jpg" alt="3"/>
        <img src="img/4.jpg" alt="4"/>
        <img src="img/5.jpg" alt="5"/>
        <img src="img/1.jpg" alt="5"/>
    </div>
    <div id="buttons">   <!--定位按钮-->
        <span index="1" class="on"></span>
        <span index="2"></span>
        <span index="3"></span>
        <span index="4"></span>
        <span index="5"></span>
    </div>
    <a href="javascript:;" id="prev" class="arrow">&lt;</a>    <!--左切按钮-->
    <a href="javascript:;" id="next" class="arrow">&gt;</a>   <!--右切按钮-->

</div>

    <script type="text/javascript">
        $(function () {
            var container = $('#container');
            var list = $('#list');
            var buttons = $('#buttons span');
            var prev = $('#prev');
            var next = $('#next');
            var index = 1;
            var len = 5;
            var interval = 3000;

            var timer;


            next.bind('click', function () {
                if (list.is(':animated')) {  //正在切换中
                    return;
                }
                if (index == 5) {
                    index = 1;
                }
                else {
                    index += 1;
                }
                animate(-600);   //左移600px
                showButton();
            });

            prev.bind('click', function () {
                if (list.is(':animated')) {
                    return;
                }
                if (index == 1) {
                    index = 5;
                }
                else {
                    index -= 1;
                }
                animate(600);
                showButton();
            });

            buttons.each(function () {
                 $(this).bind('click', function () {
                     if (list.is(':animated') || $(this).attr('class')=='on') {
                         return;
                     }
                     var myIndex = parseInt($(this).attr('index'));
                     var offset = -600 * (myIndex - index);   //算出要到的位置离当前位置多少像素

                     animate(offset);
                     index = myIndex;
                     showButton();
                 })
            });

            container.hover(stop, play);
            play();

            function animate (offset) {
                var left = parseInt(list.css('left')) + offset;
                if (offset>0) {
                    offset = '+=' + offset;
                }
                else {
                    offset = '-=' + Math.abs(offset);
                }
                list.animate({'left': offset}, 300, function () {    //使用jquery的动画效果
                    if(left > -200){    //如果翻到了图片1前面的图片5,则切到图片4后面的图片5
                        list.css('left', -600 * len);
                    }
                    if(left < (-600 * len)) {  //如果翻到了图片5后面的图片1,则切到图片2前面的图片1
                        list.css('left', -600);
                    }
                });
            }

            function showButton() {
                buttons.eq(index-1).addClass('on').siblings().removeClass('on');
            }

            function play() {
                timer = setTimeout(function () {
                    next.trigger('click');
                    play();
                }, interval);
            }
            function stop() {
                clearTimeout(timer);
            }

        });

    </script>

瀑布流

方案一:一次摆一个盒子

每个盒子等宽不等高,向下延续。基本原理是,一次摆放一个盒子,把后面出现的盒子放在高度最小的列的下方。

<style>

*{margin:0;padding:0;}

#main{position:relative;}

.box{padding:15px 0 0 15px;float:left}

.pic{padding:10px;boder:1px solid #ccc;border-radius:5px;}

.pic img{width:150px;heigth:auto;}

</style>

<div id="main">

      <div class="box">

          <div class="pic">

               <img src="0.jpg"/>

          </div>

      </div>

</div>



<script>

$(window).on("load",function(){

   //初始排列

    waterfall();

    var dataInt = {data:[{src:'0.jpg'},{src:'1.jpg'},{src:'2.jpg'},{src:'3.jpg'},{src:'4.jpg'},{src:'5.jpg'}]}

   //滚动事件

    $(window).on('scroll',function(){

        if(checkScrollSlide()){

            //添加新盒子

            $.each(dataInt.data,function(key,value){

                var oBox=$('<div>').addClass('box').appendTo($('#main'));

                var oPic = $('<div>').addClass('pic').appendTo(oBox);

                $('<img>').attr('src',value.src).appendTo(oPic);

            });

            //重新排列

            waterfall();

        }

    });

});

function waterfall(){

    //获取目前所有的盒子

    var $boxs = $('#main>div');

   //获取每个盒子的宽度

    var boxWidth = $boxs.eq(0).outerWidth();

   //获取列数

    var colNum = Math.floor($(window).width()/boxWidth);

   //设置主体的宽度和居中

    $('#main').width(boxWidth*colNum).css('maingin','0 auto');

   //存放每一列列高的数组

    var colHeights = [];

    $boxs.each(function(index,value){

        var boxHeight=$(value).outerHeight();

        if(index<colNum){

            //存放第一行列高

            colHeights[index]=boxHeight;

        }else{

            //获取最小列高

            var minH=Math.min.apply(null,colHeights);

            //获取高度最小列的索引

            var minHInex = $.inArry(minH,colHeights);

            //放置新盒子

            $(value).css({

                'position':'absolute',

                'top':minH+'px',

                 'left':minHIndex*boxWidth+'px'

             });

             //更新列高

             colHeights[minHIndex]+=$(value).outerHeight();

        }

    });

}

function checkScrollSlide(){

    //获取最后一个盒子

    var $lastBox = $('#main>div').last();

   //获取最后一个盒子腰部相对于主体的高度位置

    var lastBoxTop = $lastBox.offset().top+Math.floor($lastBox.outerHeight()/2);

    //获取窗口底部相对于主体的高度位置

    var viewTop =  $(windwo).scrollTop()+$(window).height();

   //判断窗口底部是否超过了最后一个盒子的一半

    return lastBoxTop<viewTop ;

}

</script>

缺点:要等图片加载完后,一个盒子的高度才能确定,因此会出现一个个盒子慢慢往下排的情况

补救:1、提前大量加载,使得用户看不到底部的情况;2、一个周期:左右等量加载,加载完后再一个一个补短的列

2种补救的缺点:都无法处理 用户持续快速下滑的情况

方案二:CSS3多栏布局

#main{
    column-count: 2;
    .item{
        break-inside: avoid;  // 避免项目内换行
    }
}

多栏布局,元素的排列顺序是 先排第一列,再排第二列...,最终能使多列差不多高

缺点:不是左右左右排序,使得展示失去正常的顺序

补救:每一页另起一个 #main,使得页与页之间顺序正常

补救的缺点:页内顺序失常,页与页之间会有空隙

方案三:预存宽高比,占位排列

在方案一的基础上,不用等图片加载完,预留图片的高度,进行快速排列

阿里云OSS有不用下载就获取图片宽高信息的接口,提前调用该接口,将高宽比填到数据库中;使得前端取得列表数据时,里面带有瀑布流卡片封面的高宽比

优点:卡片快速渲染,不怕用户持续快速下滑,顺序正常

长列表的性能优化

1、屏下懒加载,例如微信小程序 image.lazy-load

2、屏外懒加载:只显示屏幕内的图片,屏幕外的图片空白占位,参考微信小程序的扩展组件 recycle-view、IntersectionObserver 对象

3、图片尺寸压缩(可以利用OSS的图片样式来压缩)

图片帧播放

视频以图片帧的形式存储,前端拉取图片帧播放,并做一些处理,比如画框

<!DOCTYPE html>
<html>
<body>
	<canvas id="canvas2d" width="600" height="600"/>
<script>
    let canvasWidth = 600;
    let canvasHeight = 600;
    let pageNumber = 1;
    let pageSize = 60;
    let total = 0;
    let curIndex = 0;
    let list = [];
    let preFrameTime;

    let canvas2d = document.getElementById("canvas2d");
    let context2d = canvas2d.getContext("2d");

    // 分页拉取 帧列表数据
    let fetchList = () => {
        let xhr = new XMLHttpRequest();
        xhr.open('POST','http://**/data/list');
        xhr.setRequestHeader('Content-Type','application/json');
        xhr.setRequestHeader('Authorization','Bearer **');
        xhr.send(JSON.stringify({pageNumber,pageSize}));
        xhr.onreadystatechange = ()=> {
            if(xhr.readyState === 4 && xhr.status === 200) {
                let response = JSON.parse(xhr.response);
                total = response.total;
                list = list.concat(response.data);
                animationFrame();
            }
        };
	};

    let animationFrame = () => {
        let item = list[curIndex];
        if(!item){
            // 一页播完,拉取下一页
            if(list.length < total){
                pageNumber++;
                fetchList();
			}
            return;
        }
        // 两帧播放间隔要超过50ms,即一秒最多播放20帧
        if(!preFrameTime || new Date().getTime() - preFrameTime >= 50 ){
            let img = new Image();
            // 帧列表数据里有图片地址
            img.src = item.img_url;
            img.onload = () => {
                // 帧列表数据里有json地址,里面是框数据
                fetch(item.json_url).then((response) => {
                    if(response.status === 200){
                        response.json().then((boxJson)=>{
                            context2d.clearRect(0, 0, canvasWidth, canvasHeight);
                            context2d.drawImage(img, 0, 0, canvasWidth, canvasHeight);
                            // 图片显示在画布上会有缩放,框也要对应调整
                            let widthZoom = canvasWidth/img.naturalWidth;
                            let heightZoom = canvasHeight/img.naturalHeight;
                            Object.values(boxJson).forEach((box)=>{
                                box = box['2d_bbox'];
                                context2d.strokeStyle = 'yellow';
                                context2d.moveTo(box[0]*widthZoom, box[1]*heightZoom);
                                context2d.lineTo(box[2]*widthZoom, box[1]*heightZoom);
                                context2d.lineTo(box[2]*widthZoom, box[3]*heightZoom);
                                context2d.lineTo(box[0]*widthZoom, box[3]*heightZoom);
                                context2d.closePath();
                                context2d.stroke();
                            });
                                
                            preFrameTime = new Date().getTime();
                            curIndex++;
                            requestAnimationFrame(animationFrame);
						});
                    }
                });
            };
            img.onerror = () => {
                curIndex++;
                requestAnimationFrame(animationFrame);
			}
        }
        else{
            requestAnimationFrame(animationFrame);
        }
    };
    fetchList();
</script>
</body>
</html>

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值