从前端模块化编程切入想聊聊前端的未来(文末有我想问的问题)

jQuery动画代码详解 文章目录三组基本动画动画展示1、滑入滑出动画2、淡入淡出动画3、自定义动画动画队列停止动画 三组基本动画 show不传参数,没有动画效果 $("div").show(); show(speed) speed:动画的持续时间 可以是毫秒值 还可以是固定字符串 fast:200ms normal:400ms slow:600 $("div").show("ddd"); 动画展示 <!DOCTYPE html> <html lang="zh-CN"&gt 阅读详情

1. JavaScript模块化简述?

1.1 为什么需要模块化

  1. 没有模块化前的项目,常常在一个JS文件中会有很多功能的代码,这使得文件很大,分类性不强,自然而然不易维护;
  2. 那么我们将一个大的JS文件根据一定的规范拆分成几个小的文件的话将会便于管理,可以提高复用性,随之,可以起到分治的效果;
  3. 一个复杂的项目肯定有很多相似的功能模块,如果每次都需要重新编写模块肯定既费时又耗力。同样,某个功能别人已经造好了轮子,我们就调来用用就好,这时就要引用别人编写模块,引用的前提是要有统一的「打开姿势」,如果每个人有各自的写法,那么肯定会乱套,所以会引出模块化规范;
  4. 现在常用的JavaScript模块化规范有四种: Commonjs , AMD , CMD , ES6模块化 。个人理解,ES6模块化才是主流。

1.2 模块的定义

  • 将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并进行组合在一起
  • 块的内部数据相对而言是私有的, 只是向外部暴露一些接口(方法)与外部其它模块通信

所以,我们发现学习或建立模块就是抓住两点:如何引入模块?如何暴露模块?

1.3 模块化的定义

编码时是按照模块一个一个编码的, 整个项目就是一个模块化的项目

1.4 模块化的优势

  • 方便维护代码,更好的分离,按需加载
  • 提高代码复用性
  • 降低代码耦合度(降偶)
  • 分治思想——模块化不仅仅只是复用,不管你将来是否要复用某段代码,你都有充分的理由将其分治为一个模块。(我们在开发中有时候经常会出现一个模块,实则只用到了一次,但还是抽离出来作为单个独立的模块,这就是分而治之的软件工程的思想,在前端模块化同样适用)

2. 模块化的进化史?

2.1 全局Function模式

module1.js (定义一个模块1)

//数据
let data1 = 'module one data'

//操作数据的函数
function foo() {
  console.log(`foo() ${data1}`)
}
function bar() {
  console.log(`bar() ${data1}`)
}

module2.js (定义一个模块2)

let data2 = 'module two data';

function foo() {  //与模块1中的函数冲突了
  console.log(`foo() ${data2}`)
}

test.html (去使用定义好的模块1和模块2)

//同步引入,若函数冲突,则后面覆盖前面
<script type="text/javascript" src="module1.js"></script>
<script type="text/javascript" src="module2.js"></script>
<script type="text/javascript">
  foo()   //foo() module two data
  bar()   //bar() module one data
</script>

说明:

  • 全局函数模式: 将不同的功能封装成不同的全局函数
  • 问题: Global被污染了, 很容易引起命名冲突(比如模块中的data1 data2都是全局变量)

2.2 namespace模式

module1.js (定义一个模块1)

let moduleOne = {
  data: 'module one data',
  foo() {
    console.log(`foo() ${this.data}`)
  },
  bar() {
    console.log(`bar() ${this.data}`)
  }
}

module2.js (定义一个模块2)

let moduleTwo = {
  data: 'module two data',
  foo() {
    console.log(`foo() ${this.data}`)
  },
  bar() {
    console.log(`bar() ${this.data}`)
  }
}

test.html (去使用定义好的模块1和模块2)

<script type="text/javascript" src="module1.js"></script>
<script type="text/javascript" src="module2.js"></script>
<script type="text/javascript">
  moduleOne.foo()   //foo() module one data
  moduleOne.bar()   //bar() module one data

  moduleTwo.foo()  //foo() module two data
  moduleTwo.bar()  //bar() module two data

  moduleOne.data = 'update data' //能直接修改模块内部的数据
  moduleOne.foo()  //foo() update data
</script>

说明:

  • namespace模式: 简单对象封装
  • 作用: 减少了全局变量(如两个模块的 data 都不是全局变量了,而是对象的某一个属性 )
  • 问题: 不安全,可以直接修改模块内部的数据

2.3 IIFE模式

module1.js (定义一个模块1)

(function (window) {
  //数据
  let data = 'IIFE module data'

  //操作数据的函数
  function foo() { //用于暴露的函数
    console.log(`foo() ${data}`)
  }

  function bar() {//用于暴露的函数
    console.log(`bar() ${data}`)
    otherFun() //内部调用
  }

  function otherFun() { //内部私有的函数
    console.log('privateFunction go otherFun()')
  }

  //暴露foo函数和bar函数
  window.moduleOne = {foo, bar}
})(window)

test.html (去使用定义好的模块1)

<script type="text/javascript" src="module1.js"></script>
<script type="text/javascript">
  moduleOne.foo()  //foo() IIFE module data
  moduleOne.bar()  //bar() IIFE module data    privateFunction go otherFun()
  //moduleOne.otherFun()  //报错,moduleOne.otherFun is not a function
  console.log(moduleOne.data) //undefined 因为我暴露的moduleOne对象中无data
  moduleOne.data = 'xxxx' //不是修改的模块内部的data,而是在moduleOne新增data属性
  moduleOne.foo() //验证内部的data没有改变  还是会输出 foo() IIFE module data
</script>

说明:

  • IIFE模式: 匿名函数自调用(闭包)
  • IIFE : immediately-invoked function expression(立即调用函数表达式)
  • 作用: 数据是私有的, 外部只能通过暴露的方法操作
  • 问题: 如果当前这个模块依赖另一个模块怎么办? 见下面IIFE增强版的(模块依赖于jQuery)

2.3 IIFE模式增强

引入jquery到项目中

module1.js (定义一个模块1)

(function (window,$) {
  //数据
  let data = 'IIFE Strong module data'

  //操作数据的函数
  function foo() { //用于暴露的函数
    console.log(`foo() ${data}`)
    $('body').css('background', 'red')
  }

  function bar() {//用于暴露的函数
    console.log(`bar() ${data}`)
    otherFun() //内部调用
  }

  function otherFun() { //内部私有的函数
    console.log('privateFunction go otherFun()')
  }

  //暴露foo函数和bar函数
  window.moduleOne = {foo, bar}
})(window,jQuery)

test.html (去使用定义好的模块1)

<!--引入的js必须有一定顺序-->
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="module1.js"></script>
<script type="text/javascript">
  moduleOne.foo()  //foo() IIFE Strong module data  而且页面背景会变色
</script>

说明:

  • IIFE模式增强 : 引入依赖

  • 这就是现代模块实现的基石。其实很像了,有引入和暴露两个方面。

  • 存在的问题:一个页面需要引入多个JS的问题

    <script type="text/javascript" src="module1.js"></script>
    <script type="text/javascript" src="module2.js"></script>
    <script type="text/javascript" src="module3.js"></script>
    <script type="text/javascript" src="module4.js"></script>
    

    请求过多:一个script标签就是一次请求
    依赖模糊:看不出来谁依赖着谁?哪些模块是有依赖关系的,很难看出来。
    难以维护:内部依赖关系混乱也就难以维护啦

3. 现代模块化方案?

3.1 CommonJS

CommonJS 是服务器端模块的规范,Node.js 就是采用了这个规范。但目前也可用于浏览器端,需要使用 Browserify 进行提前编译打包。

CommonJS 模块化的引入方式使用require ; 暴露的方式使用module.exports或exports。

COMMONJS

CommonJS基于服务器端

  1. 下载安装node.js

  2. 创建项目结构

    |-modules
      |-module1.js
      |-module2.js
      |-module3.js
    |-index.js
    
  3. 模块化编码
    module1.js (定义一个模块1)
    定义一个没有依赖的模块,此模块用来定义配置常量

    const newsUrl = 'http://localhost:3000/news';
    const commentsUrl = 'http://localhost:3000/comments';
    //通过exports暴露出去
    exports.newsUrl = newsUrl;
    exports.commentsUrl = commentsUrl;
    

    module2.js(定义一个模块2)
    定义一个有依赖的模块(这个模块2又依赖模块1,故需要引入模块1),用来模拟发送请求获取数据的一个模块

    //引入依赖
    const m1 = require('./module1');
    
    //定义发送请求的方法
    function getNews(url) {
      console.log('发送请求获取数据,请求地址为:' + url);
      return 'newsData';
    }
    function getComments(url) {
      console.log('发送请求获取数据,请求地址为:' + url);
      return 'commentsData';
    }
    
    const newsData = getNews(m1.newsUrl);
    const commentsData = getComments(m1.commentsUrl);
    
    //通过module.exports暴露模块
    module.exports = {
      newsData,
      commentsData
    }
    

    module3.js(定义一个模块3)
    定义一个模块,用来显示用户数据

    //定义显示内容的方法
    function showData(data) {
      console.log('要显示的信息:' + data);
    }
    //通过module.exports暴露模块
    module.exports = showData;
    

    index.js (主模块,用来启动整个项目)
    需要引入所有需要启动的模块

    const m2 = require('./modules/module2');
    const showData = require('./modules/module3');
    
    showData(m2.newsData);
    showData(m2.commentsData)
    

    结果输出:

    发送请求获取数据,请求地址为:http://localhost:3000/news
    发送请求获取数据,请求地址为:http://localhost:3000/comments
    要显示的信息:newsData
    要显示的信息:commentsData
    
  4. 通过node运行index.js
    执行命令: node index.js

CommonJS基于浏览器端

  1. 创建项目结构

    |-dist    //打包生成文件的目录
    |-src    //源码所在的目录
      |-module1.js
      |-module2.js
      |-module3.js
      |-index.js //应用主源文件(只需打包主模块)
    |-index.html //引入dist里面的打包好的js文件,[需要在html文件中引入就是基于浏览器端咯]
    
  2. 下载browserify
    全局安装下载: npm install browserify -g

  3. 定义模块代码
    module1.js
    定义一个没有依赖的模块,此模块用来定义配置常量

    //定义配置常量
    const newsUrl = 'http://localhost:3000/news';
    const commentsUrl = 'http://localhost:3000/comments';
    //暴露出去
    exports.newsUrl = newsUrl;
    exports.commentsUrl = commentsUrl;
    

    module2.js
    定义一个有依赖的模块(依赖模块1),用来模拟发送请求获取数据的一个模块

    //引入依赖
    const m1 = require('./module1');
    
    //定义发送请求的方法
    function getNews(url) {
      console.log('发送请求获取数据,请求地址为:' + url);
      return 'newsData';
    }
    function getComments(url) {
      console.log('发送请求获取数据,请求地址为:' + url);
      return 'commentsData';
    }
    
    const newsData = getNews(m1.newsUrl);
    const commentsData = getComments(m1.commentsUrl);
    
    //暴露模块
    module.exports = {
      newsData,
      commentsData
    }
    

    module3.js
    定义一个模块,用来显示用户数据

    //定义显示内容的方法
    function showData(data) {
      console.log('要显示的信息:' + data);
    }
    //暴露模块
    module.exports = showData;
    

    index.js (应用的主模块JS)
    主模块,用来启动整个项目。需要引入所有需要启动的模块。

    const m2 = require('./module2');
    const showData = require('./module3');
    
    showData(m2.newsData);
    showData(m2.commentsData);
    

    打包处理index.js
    执行命令:browserify src/index.js -o dist/bundle.js
    src/index.js 表示就是src目录下的index主模块
    -o 表示 outfile
    dist/bundle.js 表示打包处理结果生成到dist/bundle.js

    在主页面index.html中使用引入:
    直接引入主模块就可以了,因为主模块上就有各种依赖,他会自动去解析打包处理。

    <script type="text/javascript" src="dist/bundle.js"></script>
    

    结果输出:

    发送请求获取数据,请求地址为:http://localhost:3000/news
    发送请求获取数据,请求地址为:http://localhost:3000/comments
    要显示的信息:newsData
    要显示的信息:commentsData
    

    如果直接引用未打包处理的index.js 则会报错:

    引入方式:<script src="src/index.js"></script>
    报错信息为:Uncaught ReferenceError: require is not defined-->
    

    我们现在是基于浏览器端的使用。只有在node环境下才可以直接使用未打包的index.js引入,因为在node环境下有exports,modular,require 这些全局方法。node函数中是这样的:function (exports, require, module, filename, dirname) {},所以我们引入一个browserify就会自动配置好这些参数。

彻底说明白module.exports和exports的区别:

在nodejs中,module是一个全局变量,类似于在浏览器端的window也是一个全局变量一样的道理。
module.exports 初始的时候置为{}, exports也指向这个空对象。
内部的代码实现是:

var module = {
  id: 'xxxx', // 我总得知道怎么去找到他吧
  exports: {}, // exports 就是个空对象
}

var exports = module.exports;  //exports是对module.exports的引用
//也就是exports现在指向的内存地址和module.exports指向的内存地址是一样的

上面的代码可以看出我们平常使用的exports是对module.exports的一个引用,两者都是指向同一个对象。

用一句话来说明就是,模块的require(引入)能看到的只有module.exports这个对象,它是看不到exports对象的,而我们在编写模块时用到的exports对象实际上只是对module.exports的引用。(exports = module.exports)。

我们可以使用exports.a = ‘xxx’ 或 exports.b = function () {} 添加方法或属性,本质上它也添加在module.exports所指向的对象身上。但是你不能直接exports = { a: 'xxx'} 这样子的意义就是将exports重新指向新的对象!它和module.exports就不是指向同一个对象,也就这两者已经失去了关系,而nodejs中require(引入)能看到的是module.exports指向的对象。
module.exports
故,我们一般都会直接使用module.exports。
再举例说明两者区别:

function foo() {
  console.log('foo');
}

function bar() {
  console.log('bar');
}

想要将这两个函数暴露出去,可以直接使用exports

exports.foo = foo;
exports.bar = bar;

也可以对module.exports赋值

module.exports = {
  foo: foo,
  bar: bar
}

但是不能直接对exports赋值

// 错误
exports = {
  foo: foo,
  bar: bar
}

因为这样做仅仅改变了exports的引用,而不改变module.exports。
好,剧终。这个问题讲明白了吧。

总结CommonJS
特点:同步加载,有缓存
用法:(抓住引入和暴露)

  • 暴露模块
    exports
    module.exports
  • 引入模块
    require
    路径:
    自定义模块:路径必须以./或者 ../开头
    第三方模块/内置模块/核心模块:路径直接使用模块名称

主要是在服务器端使用的,但是也能在浏览器端运行,需要借助browserify进行编译。

3.2 AMD

CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。由于Node.js主要用于服务器编程,模块文件一般都已经存在于本地硬盘,所以加载起来比较快,所以同步加载没有问题。但是如果是浏览器端,同步加载很容易阻塞,这时候AMD规范就出来了。AMD规范则是非同步加载模块,允许指定回调函数。故浏览器端一般会使用AMD规范。

AMD 是 RequireJS 在推广过程中对模块定义的规范化产出 。

AMD

  1. 下载require.js, 并引入

    官网: http://www.requirejs.cn/
    github : https://github.com/requirejs/requirejs
    将require.js导入项目: js/libs/require.js

  2. 创建项目结构

    |-libs
      |-require.js
    |-modules
      |-alerter.js
      |-dataService.js
    |-main.js
    |-index.html
    
  3. 定义require.js的模块代码
    dataService.js (定义一个无依赖的模块)

    define(function () {
      let msg = 'hello world lyuya';
      function dataServer() {
        return msg.toUpperCase();
      }
      //暴露这个模块
      return dataServer;
    });
    

    alerter.js (定义一个有依赖的模块)
    定义方法:define(['模块1', '模块2', '模块3'], function (m1, m2,m3) {}) 注意前后一一对应

    //一定要注意一一对应,前面有,后面一定要有,别忘记后面的传参
    define(['dataServer'],function (dataServer) {
      let msg = dataServer();
      function alerter() {
        alert(msg);
      }
      return alerter;
    });
    
  4. 应用主(入口):main.js (主模块)

    //配置模块的路径
    requirejs.config({
      baseUrl:'./',  //配置所有引入模块的公共路径(基本路径)
      //模块标识名与模块路径映射
      paths : {
        // 模块名称(一定要与引入的模块名称一一对应): 模块的路径
        dataServer: 'modular/dataServer',  
        //一定不能写文件的后缀名,它会自动补全
        alerter: 'modular/alerter',
        //库/框架自己实现模块化的功能,定义了暴露模块的名称
        jquery: 'libs/jquery-1.10.1'
      }
    })
    
    //主模块,下面requirejs可以用require代替,require是异步可缓存的
    requirejs(['alerter','jquery'],function (alerter,$) {
      alerter();
      $('body').css('background','pink')
    });
    
  5. 在页面index.html中使用模块

    <!--src引入requirejs模块去用这个模块解析主模块-->
    
    <script data-main="./main" src="./libs/require.js"></script>
    

总结requireJS
特点:异步加载,有缓存
用法:(抓住引入和暴露)

  • 暴露模块
    在模块内部使用return
  • 定义模块
    define(['模块名'], function (模块暴露内容) {})
    require(['模块名'], function (模块暴露内容) {})
    在模块内部可以使用require定义异步模块
  • 主模块:
    requirejs.config({}) 配置使用的模块路径
    requirejs(['模块名'], function (模块暴露内容) {})
  • html文件引入script标签
    <script data-main='app.js' src='require.js'></script>

AMD(通用模块定义)主要是在浏览器使用的。

3.3 CMD

CMD是根据CommonJS和AMD基础上提出的。
CMD(通用模块定义)和AMD(异步模块定)是比较相似的。
RequireJS 遵循的是 AMD(异步模块定义)规范,SeaJS 遵循的是 CMD (通用模块定义)规范。
seaJS 是国人阿里建立的,代表着海纳百川之意。

在这里插入图片描述

  1. 下载sea.js, 并引入

    官网: http://seajs.org/
    github : https://github.com/seajs/seajs
    将sea.js导入项目: libs/sea.js

  2. 创建项目结构

    |-libs 
      |-sea.js 
    |-modules 
      |-module1.js 
      |-module2.js 
      |-module3.js 
      |-module4.js 
    |-main.js 
    |-index.html
    
  3. 定义sea.js的模块代码
    module1.js

    define(function (require, exports, module) {
        /*
          require: 引入依赖模块
          exports: 暴露模块
          module: 暴露模块
         */
        const msg = 'moduleone';
        function getMsg() {
          console.log('module1 getMsg() ' + msg);
          return msg;
        }
        //暴露模块
        module.exports = getMsg;
      })
    

    module2.js

     define(function (require, exports, module) {
        exports.msg1 = 'lyuya';
        exports.msg2 = 'hello';
      })
    

    module3.js

      define(function (require, exports, module) {
        //同步引入模块
        const getMsg = require('./module1');
    
        let msg = getMsg();
    
        msg = msg.toUpperCase();
    
        module.exports = {
          msg
        }
    
      })
    

    module4.js

      //异步引入模块
        require.async('./module2', function (m2) {
          console.log(m2.msg1, m2.msg2);
        })
        console.log('module4执行了~~~');
      })
    

    main.js :主(入口)模块

    define(function (require) {
        const m3 = require('./module3');
        require('./module4');
    
        console.log(m3.msg);
      })
    

    index.html:

    <script type="text/javascript" src="libs/sea.js"></script> 
    <script type="text/javascript"> seajs.use('./modules/main') </script>
    

    结果输出:

     module1 getMsg() moduleone      =====module1.js:12
    
     module4执行了~~~               =====module4.js:9 
    
     MODULEONE                       =====main.js:9
    
     lyuya hello                 =====module4.js:7 
    

总结seaJS

特点:异步加载,有缓存
用法:

  • 定义模块
    define(function (require, exports, module) {})

  • 引入模块
    同步加载require()
    异步加载require.async(['模块名'], function (模块暴露内容) {})

  • 暴露模块
    exports
    module.exports

  • html文件引入script标签
    <script src='sea.js'></script>
    <script>seajs.use('app.js')</script>

seajs 和requirejs一样主要在浏览器中使用。其实这两个一般都很少使用。用的比较多的是commonjs 和马上要介绍的es6模块化。

3.4 ES6模块化⭐⭐

ES6模块化的出现,给前端更大的方便。旨在成为浏览器和服务器通用的模块解决方案,但还是主要专门针对浏览器端。其模块功能主要由两个命令构成:export和import。现在很多项目都在使用ES6模块化规范。

在这里插入图片描述

  1. 定义package.json文件

  2. 安装babel-cli, babel-preset-es2015 和browserify

    npm install babel-cli browserify -g
    npm install babel-preset-es2015 --save-dev
    preset 预设(将es6转换成es5的所有插件打包)

  3. 定义.babelrc文件

    {
     "presets": ["es2015"]
    }
    
  4. 编码
    module1.js 分别暴露 后面需要完整的定义(变量或函数定义)

    export function foo() {
       console.log('module1 foo()');
     }
     export function bar() {
       console.log('module1 bar()');
     }
     export const DATA_ARR = [1, 3, 5, 1]
    

    module2.js 统一暴露 暴露的是一个对象,要暴露的数据添加为对象的属性/方法

    let data = 'module2 data'
     
     function fun1() {
       console.log('module2 fun1() ' + data);
     }
     
     function fun2() {
       console.log('module2 fun2() ' + data);
     }
     
     export {fun1, fun2}
    

    module3.js 静默暴露 只能暴露一个内容,默认暴露的本质:定义了default变量,将后面的值赋值给default变量,暴露出去

    export default {
       name: 'Tom',
       setName: function (name) {
         this.name = name
       }
     }
    

    app.js主模块用import引入模块

     import {foo, bar} from './module1'
     import {DATA_ARR} from './module1'
     import {fun1, fun2} from './module2'
     import person from './module3'
    
     import $ from 'jquery'  //引入第三方jQuery模块 npm install jquery@1 --save
    
     $('body').css('background', 'red')
    
     foo()
     bar()
     console.log(DATA_ARR);
     fun1()
     fun2()
    
     person.setName('JACK')
     console.log(person.name);
    

    输出结果:

     module1 foo()
     module1 bar()
     [1, 3, 5, 1]
     module2 fun1() 
     module2 fun2() 
     JACK
    
  5. 编译
    使用Babel将ES6编译为ES5代码(但包含CommonJS语法):babel src -d build
    使用Browserify编译js:browserify build/app.js -o dist/bundle.js

  6. 在页面index.html中引入测试
    <script type="text/javascript" src="lib/bundle.js"></script>

总结ES6
特点:动态引入(按需加载),没有缓存
用法:(抓住引入和暴露)

  • 引入模块使用import
    • 对于统一暴露/分别暴露
      import {模块暴露的内容} from '模块路径';或 import * as m1 from './module1'
      这两者暴露的本质是对象,接收的时候只能以对象的解构赋值的方式来接收值
    • 对于默认暴露
      直接使用import 模块暴露的内容 from '模块路径'
      默认暴露,暴露任意数据类型,暴露什么数据类型,接收什么数据类型
  • 暴露模块使用export
    • 分别暴露 (基本不用)
    • 统一暴露 (暴露多个内容)
    • 默认暴露 (暴露单个内容)

主要是用在浏览器,服务器端也使用。但是现在浏览器和服务器均不支持ES6的模块化语法,所以要借助工具来编译运行

  • babel 将ES6 - ES5 (ES6的模块化语法 编译成commonjs)
  • browserify将commonjs语法编译成能让浏览器识别的语法

3. 模块化的扩展阅读

前端模块化开发那点历史
Javascript模块化编程@阮一峰
知乎专栏 | AMD和CMD的区别

4. 本片我想说的话 ? ?

既然说到模块化,其实我更想说说模块化与组件化。这两个概念在前端领域已经十分普遍。

先有模块化后有组件化。组件化是建立在模块化思想上的一次演进,一个变种。所以,我们会在软件工程体系中看过一句话:模块化是组件化的基石。

组件化和模块化的思想都是分而治之的思想。但还是有细小的区分,他们的侧重点有所不同。

组件化更加倾向于UI层面上,是一个可以独立展示内容的「积木」,比如一个页面的头部组件,包含结构HTML、样式CSS、逻辑JS、以及静态资源图片组合一个集合体。一个页面是由众多组件组成的,就像由众多「积木」搭成的「城堡」一样;
模块化更加倾向于功能或者数据的封装,一般由几个组件或1个组件构成的带有一定功能的集合体;

引用一下@张云龙「?大神」对组件化的理解:

组件化的理解JS
就如上图的这个title组件,包含了结构HTML、样式CSS、逻辑JS、以及静态资源图片,往往组件的组成就是以上四个方面。这个header文件夹我们可以拿到其他项目中使用,它具有可以独立展示内容的特点。

结合前面提到的模块化开发,整个前端项目可以划分为这么几种开发概念:

前端模块化开发那么它们之间的关系如下图所示,一个应用由多个下图的页面组成。一个页面由多个组件组合。组件中可依赖JS模块。

组件与模块之间的区别
所以,前端开发现在不仅仅只是别人说的「画画页面实现点效果」的职位,它是软件的图形用户界面(Graphical User Interface,简称GUI)。现在前端开发都是基于模块化和组件化的开发,可以说是工程化的项目了。从单页面应用(SPA)的应用就可以看出JavaScript大大改善了Web应用的用户体验。

但是,2019了。现在还是有很多团队会把前端开发归类为产品或设计岗位底下,嗯,我不好说什么,唉···。

你在的公司前端的组织架构是肿么样呐? ??

好啦,好好学习吧,做一个π型人。打铁还需自身硬。Confidence~?

今天是2019年3月8日,农历二月二(龙?抬头),星期五,深圳阴阴天气。祝福各位女同胞唷节日快乐永远美丽,祝福男同胞单身幸福~biubiu???????


此文档为吕涯原创,可任意转载,但请保留原链接,标明出处。
文章只在优快云和掘金第一时间发布:
优快云主页:https://blog.youkuaiyun.com/LY_code
掘金主页:https://juejin.im/user/5b220d93e51d4558e03cb948
若有错误,及时提出,一起学习,共同进步。谢谢。 ???

VISIO网络设备图标集使用指南:从pptx导入到拓扑图绘制 网络拓扑图是网络工程的基础交付物,而图标集是提升绘图效率的关键。VISIO作为主流绘图工具,支持通过模具(stencil)管理可复用图形。将pptx格式的图标集导入VISIO,需识别矢量组合形状并转换为.vssx模具文件,从而保留可编辑性。合理分类、命名和设置连接点,能显著减少重复劳动,确保拓扑图风格统一、逻辑清晰。本文围绕网络设备图标集在VISIO中的实际应用,详解导入、排布与避坑技巧,帮助网络工程师快速产出专业拓扑图。 阅读详情

相关推荐

jQ+CSS3创意动画添加删除效果特效代码

jQ+CSS3创意动画添加删除效果是一款基于jquery+css3实现的创意动画列表项添加删除效果。

html用jq设置动态效果,7款绚丽的jQuery/HTML5动画及源码

jQuery是一款非常流行的JavaScript框架,利用jQuery,我们可以制作简单的动画效果,但是结合HTML5,这样的动画效果就会变得更加出彩。本文分享了7款jQuery结合HTML5的动画以及源码下载。1、HTML5/SVG实现布谷鸟时钟动画这是一款非常有意思的HTML5动画,它是一个老式的时钟,有布谷鸟报时,情侣的浪漫舞蹈。2、HTML5/CSS3实现图片倒影3D效果这款应用主要利用了...

weixin_31491059的博客 656

qt使用qxlsx实现xlsx、xls表格文件快速写入和读取

新年第二篇文章,收尾一个去年计划中发表文章和实现功能。

kbq的博客 1万+

年薪30W,2018年前端发展趋势分析

  互联网发展如火如荼,前端开发在经历了前两年的火热之后,大浪淘沙,沉淀下来,计算机科学基础的核心没有变化,而其领域将继续分化,专业将细分。  行业的持续发展使前后端逐渐...

程序员之家 3200

城市规划师必备:ArcMap里用这个免费工具,5步完成建筑群通风廊道分析

本文介绍了城市规划中利用ArcMap进行建筑群通风廊道分析的高效方法,重点讲解了迎风面投影指数(FAI)的应用。通过5个步骤,从数据准备到规划应用,帮助规划师快速评估城市通风潜力,优化建筑布局,提升城市风环境质量。

weixin_26800111的博客 412

Tomcat漏洞——弱口令爆破

靶机:CentOS7 IP:192.168.100.40。攻击机:kali IP:192.168.100.60。版 权 声 明:本博客所有文章除特别声明外,均采用。文章版权归作者所有,未经允许请勿转载!作 者:PeiyuJue。

weixin_57379923的博客 911

WEB前端简历模板

详细资料             姓名:XXX                     出生年月:XXXX年X月                                               名 族:X 族                政治面貌:XXXX                                                        Q Q

小屋博客 11万+

用Python和CasADi实现高斯伪谱法:一个轨迹优化问题的保姆级教程

本文详细介绍了如何使用Python和CasADi框架实现高斯伪谱法解决轨迹优化问题。通过保姆级教程,从环境准备、问题建模到高斯伪谱法的核心实现,包括配点与权重计算、微分矩阵构造和动力学约束实现,最终完成问题求解与结果可视化。适用于机器人轨迹规划和无人机路径优化等工程场景。

weixin_30776273的博客 294

这三个月,我如何一点点地成长(海康前端实习)

文末彩蛋 一、讲讲我在海康那些事 今天不跟大家聊太多技术,想聊聊最近我身边的事。 6月中旬入职,昨天离职了,准备11号入职有赞。虽然真正呆在海康也就两个月,但对我的影响真的非常大。我在这里收获了技术,也收获了人情。 第一天的海康 从刚开始的只需一些基础框架(jq、bs)还有一丢丢vue基础,到现在对ES6的熟悉应用...自行搭建react+express(koa)+webpack的...

weixin_30420305的博客 562

RT-Thread与ROS2通信:micro-ROS在STM32上的移植实践

本文详细介绍了在STM32平台上使用RT-Thread实时操作系统移植micro-ROS实现与ROS2通信的实践方案。通过对比rosserial方案,重点阐述了micro-ROS基于XRCE-DDS协议栈在数据可靠性(丢包率低于1%)、双模式通信(UDP/串口)以及C/C++混合编程方面的优势,为嵌入式设备与ROS2的高效通信提供了完整解决方案。

emacs5lisp的博客 332

9、从统计到电路:未来物理不可克隆函数的基础

本文探讨了物理不可克隆函数(PUF)的关键技术,包括补偿环境影响、处理相关工艺变化、身份映射和测试方法。提出了一种基于新测试统计量Q的方法,有效提升了PUF的熵值和安全性。通过实验验证,新方法能够显著区分不同芯片,并增强PUF在不同环境下的适应性和可靠性,为未来PUF的设计与应用提供了重要基础。

pluto的博客 120

一个月面试大厂,中厂,小厂的总结|2021 年中总结

推荐:两年前端程序媛从0到18k的逆袭之路 | 2021年中总结image.png求点赞+求分享+求评论,哦耶!!!(基本工资有一部分花在付费学习上)(文末有彩蛋。。。)。一个朋友,面试的...

程序员哆啦A梦,蓝胖子 1187

nvidia系列教程-AGX-Orin系统刷机及备份

NVIDIA AGX Orin 是一款高性能的嵌入式计算平台,专为边缘计算和 AI 应用而设计。为了确保系统的稳定性和适应不同的应用场景,用户可能需要对 AGX Orin 进行系统刷机和备份操作。本文将详细介绍如何完成这些操作,帮助您更好地管理和维护 AGX Orin 设备。通过以上步骤,您可以成功地为 NVIDIA AGX Orin 刷写系统并创建备份。这些操作不仅能帮助您保持系统的更新和安全,还能在遇到问题时快速恢复系统。

flypig has a dream! 3328

用一个月面试了 大厂,中厂,小厂的总结|2021 年中总结

推荐:两年前端程序媛从0到18k的逆袭之路 | 2021年中总结image.png求点赞+求分享+求评论,哦耶!!!(基本工资有一部分花在付费学习上)(文末有彩蛋。。。)。一个朋友,面试的...

全栈修炼 1551

开源工具对比:5款主流大数据脱敏框架评测

数据脱敏(Data Masking/Anonymization),也称为数据漂白、数据去标识化,是指在不影响数据可用性的前提下,通过一定的技术手段对敏感信息进行处理,使其无法被识别或关联到具体个人或实体的过程。当应用程序向数据库写入数据(INSERT/UPDATE)时,ShardingSphere 会拦截 SQL,对配置了脱敏规则的字段,使用指定的算法进行加密/脱敏处理,然后将处理后的数据写入到。如果你的答案是“是”,那么数据脱敏,尤其是针对海量数据的。好的,各位技术同仁,数据安全领域的探索者们,大家好。

小程序开发 1185

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

GTE-Pro低代码集成:基于Streamlit的语义应用快速开发

本文介绍了如何在星图GPU平台上自动化部署🧠 GTE-Pro: Enterprise Semantic Intelligence Engine镜像,并基于此快速构建语义智能应用。通过结合Streamlit低代码框架,开发者可轻松搭建具备语义搜索、文档推荐等功能的演示界面,直观展示模型对文本深层含义的理解能力,极大加速了语义应用的开发与验证流程。

weixin_33072399的博客 376

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

用Vue实现个人博客的前端界面

上一次认真的学习使用Vue已经是四月份的事了,当时只是简单的就像使用jQuery一样,直接引入页面,没有使用任何组件、路由,写了个cakeroom的小demo,感兴趣的可以去看下: github展示链接:https://lwjcode.github.io/cakeroom/view/home.html 这次就更加深入的学习如何使用vue-cli,去组件化的开发一个项目;以及如何使用路由vue-...

Picking_up_stones的博客 2万+

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

什么是前端模块化?前端模块化开发到底有无必要

转自:http://www.jianshu.com/p/e422c28e2471 序: 所谓前端开发,就是前台,常见的包括几个端:PC、pad、手机、其他智能设备,可以跑浏览器的地方就是我们前端人大施拳脚的乐土。自从node的问世,现在不光可以在浏览上了,疆土可以扩展到服务端即后台。这样一来JavaScript又牛了一级有着前后台通吃的能力,当然操作太底层的东西还需要Java等传统

周清城的博客 1万+

jQuery 实现图片动画代码

向下移动动画 $(".image").click(function(){ $(this).animate({height:'0px'}) }); <!doctype html> <html> <h...

QDY5945的博客 646

jquery动画(附有简单网页广告代码实例以及运行截图)

动画的操作有很多,分享几个常见的动画 显示和隐藏 show()即显示方法和hide()即隐藏方法是jQuery中最基本的动画方法。在HTML文档里,为一个元素调用hide()方法,会将该元素的display样式改为“none”。 hide() 和 show() 分别可以携带两个可选参数,一个是speed参数另外一个是callback参数。speed的作用是控制显示和隐藏的速度,它可以取以下值:“slow”、“fast” 或毫秒。,callback则为执行完以后进行的函数,学过汇编语言对这个应该很好理解,返回

GodGump的博客 429

前端模块化-5分钟快速入门RequireJs

各位开发项目的时候引用JS都会遇到以下的情景 产生AMD规范的背景 因为使用各种插件,或者团队协同合作,产生多个js文件, 假如使用的JQ插件,则必须先引用jquery库才能够正常执行, JS文件之间强依赖关系,让我们不敢动文件的引入顺序。 并且,在渲染页面的过程中,同步读取JS文件会堵塞整个页面, 这对网站的性能起到很大的影响,因此,我们需要异步加载JS文件。 AMD规范 AMD...

qq 2903359018博客 361

JQuery 从右侧向左滑动

html:

韩世雷 程序员专栏 3万+

个人博客前端框架

使用vue实现我的个人博客,连接路径:https://eight1302.github.io/blog/blog/view/home/index.html

FREE-FLY的博客 8973

jQuery炫酷前端页面动画代码

下载地址 几种前端页面特效jQuery代码组合,包括鼠标跟随特效,卡牌打开扇形特效,右上角悬浮提示层等。 dd:

ICode联盟 397
上一篇: 事件对象与事件机制
风或许自媒体
博客等级 码龄12年 76粉丝 35原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值