资讯专栏INFORMATION COLUMN

javascript模块化(二)--RequireJS初探

edgardeng / 2084人阅读

摘要:看完视频初步认识了一下,以及模块化开发的概念,在此做一下总结。所以应该将功能抽象成模块。并且非常耗性能解决办法,在滚动条正在运动或者已经到达目的地,就不应该执行动画。

前言:在慕课网上跟着视频《侧边工具栏开发》做了一遍,用到了jquery操作DOM,其中,用requirejs管理模块依赖,然后自定义了两个模块它们都依赖jquery,并且其中一个自定义模块依赖另一个,所以要暴露出接口。看完视频初步认识了一下requirejs,以及模块化开发的概念,在此做一下总结。感谢慕课网上的老师。

使用模块化开发的好处:

有效的防止命名冲突

声明不同的js文件之间的依赖

可以让我们写出模块化的代码,便于复用

1.需求与目标

这个视频《侧边工具栏开发》的需求很简单,就是做一个侧边工具条,

固定定位在页面的某个位置,

在没有把页面向下滚动时,显示三个按钮,

当页面向下滚动一定距离之后,第四个按钮出现。

点击这个按钮,页面会回到顶部。

鼠标hover到每个按钮上都有一些相应的动画(CSS3完成这里不写)

2.HTML结构
       

一些说明:

为了让页面显示滚动条,需要在这个上述代码下面加很多行

标签以便撑开页面显示滚动条。

CSS部分视频中老师讲了三种方法,并且用到了SASS,感兴趣的同学可以去看一下,这里不再赘述。

3.requirejs入门 (1)项目目录结构

其中jquery-3.1.0.js和require.js是在各自官网下载的资源文件。main.js是自定义的入口文件。

(2)加载初始化requirejs

在未引入模块化编写代码以前引入js文件是在标签之前写多个 (3)requirejs的常用方法

requirejs.config为模块指定别名,方便模块的引入),在入口文件中定义
如这个demo要引入多次jquery-3.1.0.js,但是这个名字很长所以可以在入口文件main.js中为它定义一个别名,如下:

    //为jquery模块定义别名
    requirejs.config({
        paths:{
            jquery:"jquery-3.1.0.js"
        }
    });

requirejs()方法(将写好的模块进行引入
requirejs()接收两个参数,第一个参数是一个数组,写入要引入的模块的名字。第二个参数是一个回调函数,需要传递一个参数,来代替前面所引入的模块。如:引入jquery模块

    requirejs(["jquery"],function($){
        //写一段代码验证jquery是否被正确引入
        //将body背景颜色变为红色
        $("body").css("background-color","red");
    });

define()(利用它定义编写模块,然后在相应的地方进行引入。)
define()接收三个参数,第一个参数是为本模块命名的值,可以不写,第二个参数表示需要引入的模块,第三个参数是各依赖项成功加载后所运行的函数,传入的参数与各个依赖项形成对应的关系。

    define(
        moduleName,  //可选,如果此参数不写,则默认使用本模块所在文件的文件名
        dependencies,    //一个数组,此数组包含着此文件所需的各个依赖项目,这个数组中各项对应的是所依赖文件相对于requirejs库所形成的相对路径文件名。
        function(parameters){  
            //各依赖项成功加载后所运行的函数
            //传入的参数与dependencies数组中的各个依赖项形成对应关系
        }
    );
(4)demo的基本功能实现

现在先对demo中的基本功能进行实现:

目前的目录结构如下:

首先在HTML中初始化requirejs:在标签之前:

在入口文件main.js中实现基本功能

    //1.首先为jquery模块定义别名
    requirejs.config({
        paths: {
            jquery: "jquery-3.1.0"
        }
    });
        
    //2.然后用requirejs()方法引入jquery模块实现demo中需求
    requirejs(["jquery"],function($){
    
        //为id值为backTop的第四个按钮添加点击回到顶部事件,当点击时执行move函数回到顶部
        $("#backTop").on("click",move);
        
        //监听一下windows对象的滚动事件,
        //每次滚动都执行函数checkPosition确定一下位置,是否到达设定的临界点,以显示和隐藏第四个按钮
        $(window).on("scroll",function(){
            checkPosition($(window).height());
        });
        
        //解决bug:在刷新页面时也出现第四个按钮,即页面加载时就检查一下滚动位置
        checkPosition($(window).height());

//------------------------------分割线------------------------------------------
        //move函数的具体实现,加动画效果
        function move(){
            $("html, body").animate({
                scrollTop:0
            },800);
        }
        //go函数可以立即移动到顶部
        function go(){
            $("html, body").scrollTop(0);
        }

        //checkPosition函数的具体实现
        function checkPosition(pos){
            if($(window).scrollTop() > pos){
                $("#backTop").fadeIn();
            }else{
                $("#backTop").fadeOut();
            }
        }
    });

分割线以上是执行的代码,分割线以下是写的被调用的函数。

(5)将功能抽象成模块

上述代码虽然实现了功能,但是存在以下问题:

move和go函数都是到达顶部的功能,实现的功能很相似,作用如果想在其它地方使用这个功能,就要再进行代码的复制,不方便功能的复用。所以应该将功能抽象成模块。

实现功能的功能单一:两个函数都是到达顶部,这样即便抽象成模块也会受到很大的限制,所以可以进一步将问题抽象成移动滚动条到指定位置。

第一步:创建一个新模块,用scrollto.js表示,目前这个demo的目录结构如图:

第二步:将功能抽象成模块,写入scrollto.js

//1.先定义这个模块,因为要用到jquery,所以还要引入jquery
    define(["jquery"],function($){
        //定义构造函数
        function ScrollTo(opts){
            this.opts = $.extend({},ScrollTo.DEFAULTS,opts);   //实现传参覆盖
            this.$el = $("html, body");
        }
    
        //原型添加方法
        ScrollTo.prototype.move = function (){
            var opts = this.opts;
            this.$el.animate({
                scrollTop:opts.dest
            },opts.speed);
        };
        ScrollTo.prototype.go = function(){
            this.$el.scrollTop(opts.dest);
        };
    
        //定义默认的参数
        ScrollTo.DEFAULTS = {
            dest:0,
            speed:800
        };
        
        //定义接口
        return {
            ScrollTo:ScrollTo
        };
        
    });
    

代码详解:

传递的参数为一个对象,用opts表示

用户没有传递参数时,使用默认的参数,默认参数直接写在ScrollTo构造函数上,相当于形成一个静态属性,然后通过jquery的extend()方法进行原型的扩展

实现用户传递参数用之,不传递参数用默认值。jquery的extend()方法

在原型上添加move和go方法

第三步:在入口文件main.js中引入这个scrollto.js的模块

    requirejs(["jquery","scrollto"], function($,scrollto){
    
        //为了使用scrollto模块,需要实例化一下
        var scroll = new scrollto.ScrollTo({
            dest:0,
            speed:2000
        });
        //点击回到顶部按钮回到指定位置功能
        $("#backTop").on("click", $.proxy(scroll.move, scroll));
    
    });

上述代码中有一点需要注意:

在第6行中,如果添加点击按钮回到指定位置事件时,这么写:
$("#backTop").on("click", scroll.move);

此时浏览器控制台会报错:Uncaught TypeError: Cannot read property "ScrollTo" of undefined

分析原因是因为,在main.js中调用scrollto.js模块中在ScrollTo.prototype.move原型方法move时,main.js中this指的是ScrollTo的实例,即scrollto,而在语句$("#backTop").on("click", scroll.move);中,这个this指代的是id为backTop的这个按钮。

解决办法:用jquery提供的方法,直接将this指向scroll对象。
$("#backTop").on("click", $.proxy(scroll.move, scroll))

第四步:一个bug
这时基本功能虽然实现了,点击底部那个按钮,传入设定的返回位置和返回的速度,页面可以再次返回顶部指定位置,但是目前还存在一个bug:在点击底部按钮回到顶部指定位置时,假如连续多次点击这个按钮,则页面回到顶部后就无法再次向下滚动页面。

bug分析:

假如执行的函数如上面第三步中代码,速度设置成较慢的速度2000,那么在返回顶部指定位置时可以多次点击这个按钮,

这样每次点击按钮事件都要调用move方法执行里面的动画,点击多少次,这个动画就要执行多少次。

因此在页面返回顶部后,再次滚动页面向下会立即执行返回顶部动画,所以在执行完点击次数的动画之前,用户都无法向下滚动。(并且非常耗性能)

解决办法,在滚动条正在运动或者已经到达目的地,就不应该执行动画。添加判断。
所以scrollto.js的代码可以改成如下:

    define(["jquery"],function($){
        //定义构造函数
        function ScrollTo(opts){
            this.opts = $.extend({},ScrollTo.DEFAULTS,opts);   //实现传参覆盖
            this.$el = $("html, body");
        }
    
        //原型添加方法
        ScrollTo.prototype.move = function (){
            var opts = this.opts;
            if ($(window).scrollTop() != opts.dest){  //判断是否到达指定位置
                if(!this.$el.is(":animated")){    //判断是否在运动
                    this.$el.animate({
                        scrollTop:opts.dest
                    },opts.speed);
                }
            }
        };
        ScrollTo.prototype.go = function(){
            var dest = this.opts.dest;
            if($(window).scrollTop() != dest){
                this.$el.scrollTop(dest);
            }
        };
    
        //定义默认的参数
        ScrollTo.DEFAULTS = {
            dest:0,
            speed:800
        };
        
        //定义接口
        return {
            ScrollTo:ScrollTo
        };
              
    });
    
(6)将返回顶部整体抽象成模块

我们把返回的功能函数move和go都抽象在了scrollto.js模块中,现在还可以直接把整个返回顶部的功能(包括滚动一定距离后隐藏的按钮出现,和点击按钮之后回到顶部指定位置)
然后在入口文件中只需要引入这个模块(取名叫backtop.js),这个back.js需要依赖上面定义的scrollto.js模块。

所以目前的项目目录如下图:

第一步:现在来写backtop.js模块

    define(["jquery", "scrollto"], function($, scrollto){
        //执行函数部分
        function BackTop(el, opts){
            this.opts = $.extend({}, BackTop.DEFAULTS, opts);
            this.$el = $(el);   //el是节点
            this.scroll = new scrollto.ScrollTo({
                dest: 0,
                speed: this.opts.speed     
            });
            
            this._checkPosition();   //加载时就检查位置,解决bug
            
            if(this.opts.mode == "move"){  //是move才执行move函数,其他执行go
                this.$el.on("click", $.proxy(this._move, this));
            }else{
                this.$el.on("click", $.proxy(this._go, this));
            }
            
            $(window).on("scroll", $.proxy(this._checkPOsition, this));
 
        }
    
        //定义默认属性部分
        BackTop.DEFAULTS = {
            mode: "move",
            pos: $(window).height(),
            speed: 800
        };
    
    
        //定义功能函数部分
        BackTop.prototype._move = function(){
            this.scroll.move();
        };
    
        BackTop.prototype._go = function(){
            this.scroll.go();
        };
    
        BackTop.prototype._checkPosition = function(){
            if($(window).scrollTop() > this.opts.pos){
                this.$el.fadeIn();
            }else{
                this.$el.fadeOut();
            }
        };
    
        //暴露模块接口,返回整个对象
        return{
            BackTop: BackTop
        };
    
    
    });

第二步:scrollto.js保持不变

第三步:写main.js入口文件

    //定义别名
    requirejs.config({
        paths: {
            jquery: "jquery-3.1.0"
        }
    });
    
    //调用backtop.js模块
    requirejs(["jquery", "backtop"], function($, backtop){
        //实例化BackTop
        new backtop.BackTop($("#backtop"),{
            mode: "move",
            pos:100,
            speed: 2000
        });

    });
    
4.总结

这个demo中的模块化是这样一种思想:

首先把功能函数放在一个模块中(move和go)

把整个实现功能也抽象成一个模块,依赖上一个功能函数模块

最后只需要在入口文件中实例化一下这个最外层的模块,即可完成一系列功能的调用。

每个模块都用面向对象的思想,定义模块并且暴露接口

默认值的用法可以让调用者拿起就用,可以不用考虑传参数。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/86384.html

相关文章

  • 前端资源系列(4)-前端学习资源分享&前端面试资源汇总

    摘要:特意对前端学习资源做一个汇总,方便自己学习查阅参考,和好友们共同进步。 特意对前端学习资源做一个汇总,方便自己学习查阅参考,和好友们共同进步。 本以为自己收藏的站点多,可以很快搞定,没想到一入汇总深似海。还有很多不足&遗漏的地方,欢迎补充。有错误的地方,还请斧正... 托管: welcome to git,欢迎交流,感谢star 有好友反应和斧正,会及时更新,平时业务工作时也会不定期更...

    princekin 评论0 收藏0
  • 详解JavaScript块化开发

    摘要:目前,通行的模块规范主要有两种和。所有依赖某些模块的语句均放置在回调函数中。首先采用了模块化的概念。然后通过参数一,参数二参数一是数组,传入我们需要引用的模块名,第二个参数是个回调函数,回调函数传入一个变量,代替刚才所引入的模块。 什么是模块化开发? 前端开发中,起初只要在script标签中嵌入几十上百行代码就能实现一些基本的交互效果,后来js得到重视,应用也广泛起来了,jQuery,...

    waruqi 评论0 收藏0
  • 【前端构建】RequireJS及其优化工具

    摘要:介绍一款模块加载工具的入门,并且重点介绍其优化工具。发布目录项目源代码工具目录,例如构建工具等。另外,前端代码发布前都会进行压缩,使文件足够小。原来是因为里了,所以优化工具把也合并进来了。而优化工具要用好,要多尝试他们的配置选项。 前端变化太快,如今RequireJS已经无法吸引眼球了。介绍一款模块加载工具:RequireJS的入门,并且重点介绍其优化工具。 一、RequireJS简介...

    Loong_T 评论0 收藏0
  • Babel快速入门

    摘要:首先,作为入门的话,的用户手册是个很不错的选择,里面基本覆盖了使用的各方面。所以下面主要是我学习的一些笔记,姑且当作是一篇入门吧。下面我们正式进入正题。这也是最常用的一个用法之一。有两个方式进行配置。 首先,作为入门的话,Babel的用户手册是个很不错的选择,里面基本覆盖了Babel使用的各方面。所以下面主要是我学习Babel的一些笔记,姑且当作是一篇入门吧。 Babel是什么 按照B...

    notebin 评论0 收藏0
  • 再谈JavaScript块化

    摘要:应用日益复杂,模块化已经成为一个迫切需求。异步模块加载机制。引用的资源列表太长,懒得回调函数中写一一对应的相关参数假定这里引用的资源有数十个,回调函数的参数必定非常多这就是传说中的 简述 缘起 模块通常是指编程语言所提供的代码组织机制,利用此机制可将程序拆解为独立且通用的代码单元。 模块化主要是解决代码分割、作用域隔离、模块之间的依赖管理以及发布到生产环境时的自动化打包与处理等多个方面...

    MorePainMoreGain 评论0 收藏0

发表评论

0条评论

edgardeng

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<