zoukankan      html  css  js  c++  java
  • 原生js实现简洁的返回顶部组件

    本文内容相当简单,所以没有发布到博客园首页,如果你不幸看到,那只能是我这篇文章的荣幸,谢谢你的大驾光临~(本博客返回顶部的功能就使用的是这个组件)

    返回顶部组件是一种极其常见的网页功能,需求简单:页面滚动一定距离后,显示返回顶部的按钮,点击该按钮可以将滚动条滚回至页面开始的位置。实现思路也很容易,只要改变document.documentElement.scrollTop或document.body.scrollTop的值即可。本文抛弃所有加速减速的酷炫效果,回归软件的本质,提供一个最简洁的实现,只追求实用性,不追求所谓的用户体验,效果如下(代码下载):

    demo

    由于思路跟代码都很简单,所以就直接贴出实现细节了:

    var BackTop = function (domE,distance) {
        if (!domE) return;
        var _onscroll = window.onscroll,
            _onclick = domE.onclick;
    
        window.onscroll = throttle(function(){
            typeof _onscroll === 'function' && _onscroll.apply(this, arguments);
            toggleDomE();
        },100);
        domE.onclick = function(){
            typeof _onclick === 'function' && _onclick.apply(this, arguments);
            document.documentElement.scrollTop = 0;
            document.body.scrollTop = 0;
        };
    
        function toggleDomE(){
            domE.style.display = (document.documentElement.scrollTop || document.body.scrollTop) > (distance || 500) ? 'block' : 'none';
        }
    
        function throttle(func, wait) {
            var timer = null;
            return function () {
                var self = this, args = arguments;
                if (timer) clearTimeout(timer);
                timer = setTimeout(function () {
                    return typeof func === 'function' && func.apply(self, args);
                }, wait);
            }
        }
    };

    调用方式:

    <script>
        new BackTop(document.getElementById('backTop'))
    </script>

    之所以写这篇博客,弄这么个简单的东西,有两个方面的原因:

    1)这段时间一直在手写一些常见的简单组件,这算是一个简单中更简单的一个,为了让这系列的博客更加完整,所以把这个组件补充了进来;

    2)我想表达自己在工作过程中的一个观点:就是不要过渡用用户体验来装饰你的软件或者说产品,用户体验这个东西说白了就是两个词,一个是好印象,第二个就是好玩,但这并不是产品开发运营的最终目的,你把东西做的再漂亮,产品的核心价值和服务做的不够的话,就算把返回顶部这种功能做成超级无敌的火箭也是徒劳无功的。做前端开发,得锻炼点控制产品经理瞎提用户体验功能的度,以这个组件来说,我认为做加速或减速效果都是多余的,既增加开发时间,又耽误用户使用的时间,抛弃自己心中那点对技术玩弄的固执,可以让自己的工作做的更加完美。

    最后,还是非常感谢你把它看完:)


    补充于2016-03-16

    感谢普通男孩在评论中指出的问题:由于我提供的实现在注册事件回调的时候用的onscroll和onclick的方式,虽然在组件内部会记录这两个事件之前可能注册的回调,并在注册组件的回调时,会先调用之前的回调,但是还存在另外一种情况:别人可能使用了这个组件,并且在这个组件之后也用onscroll或onclick给同一个对象注册事件,如果没把之前的回调调用一下,就会导致组件内部的回调被它后定义的回调覆盖,导致组件失效。如果用addEventListener来注册事件就不会有这个问题,因为它是可针对同一个事件注册多个回调的,并且不存在覆盖的问题,所以在此提供另外一个改良版的实现(对应代码中的backTop2.js和index2.html):

    var BackTop = function(domE, distance) {
        if (!domE) return;
    
        var AddListener = function(domE, type, fn) {
            if (typeof domE.addEventListener === 'function') {
                AddListener = function(domE, type, fn) {
                    domE.addEventListener(type, fn, false);
                };
            } else if (typeof el.attachEvent === 'function') {
                AddListener = function(domE, type, fn) {
                    domE.attachEvent('on' + type, fn);
                };
            } else {
                AddListener = function(domE, type, fn) {
                    var old = el['on' + type];        
                    el['on' + type] = function(){
                        typeof old === 'function' && old.apply(this, arguments);
                        typeof fn === 'function' && fn.apply(this, arguments);
                    };
                };
            }
            AddListener(domE, type, fn);
        }
    
        AddListener(window, 'scroll', throttle(function() {
            toggleDomE();
        }, 100));
    
        AddListener(domE, 'click', function() {
            document.documentElement.scrollTop = 0;
            document.body.scrollTop = 0;
        })
    
        function toggleDomE() {
            domE.style.display = (document.documentElement.scrollTop || document.body.scrollTop) > (distance || 500) ? 'block' : 'none';
        }
    
        function throttle(func, wait) {
            var timer = null;
            return function() {
                var self = this,
                    args = arguments;
                if (timer) clearTimeout(timer);
                timer = setTimeout(function() {
                    return typeof func === 'function' && func.apply(self, args);
                }, wait);
            }
        }
    };

    注:以上代码中的AddListener以及throttle的实现均可抽出来,作为单独的工具函数使用,这样组件会看起来更简洁。这里是为了组件的完整性,才把她们放在一块。throttle是函数节流的简单实现。在下一篇文章中有更详细地关于该函数作用的介绍:利用getBoundingClientRect方法实现简洁的sticky组件


    补充于2016-03-18

    以上代码中有一处可以进一步简化:

    image

    可以改成:

    AddListener(domE, 'click', function() {
        window.scrollTo(0,0);
    });

    注:本次修改对应代码下载中的backTop3.js。

  • 相关阅读:
    Sharding-Jdbc 自定义分库分表-复合分片算法自定义实现
    sklearn:Python语言开发的通用机器学习库
    php验证码--图片
    ListView中的Item点击事件和子控件的冲突或者item点击没有反应的解决的方法
    【转载】C# Graphics类具体解释
    Oracle之外键(Foreign Key)使用方法具体解释(二)- 级联删除(DELETE CASCADE)
    职业生涯-小公司和大公司的不同(持续更新)
    视音频数据处理入门:AAC音频码流解析
    让人非常easy误解的TCP拥塞控制算法
    Redis资料整理
  • 原文地址:https://www.cnblogs.com/lyzg/p/5281690.html
Copyright © 2011-2022 走看看