整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          (1)響應式內頁布局分析HTML模塊化和CSS模塊化詳解

          頁設計圖

          視頻講解課程

          1.設計圖分析和HTML模塊化結構:https://www.ixigua.com/i6903745684596326915/

          2.HTML模塊化和CSS模塊化示例:https://www.ixigua.com/i6904203127541465611/


          HTML+CSS模塊化基礎代碼

          核心知識點

          1. 分析設計圖結構和模塊劃分
            1. 橫向分:頭部,導航,banner,中間主體,底部
            2. 按頁面分:列表頁,詳情頁,單頁
            3. 模塊劃分:列表,輪播,自定義模塊
          2. 了解頁面布局和模塊化布局的區別
            1. 頁面布局主要是分欄唯一功能,不能定義樣式,一般用 col-為前綴命名
          3. 了解html模塊化命名規范
            1. 列表類模塊使用 ul-為前綴命名
              1. 列表li里面的命名規范
                1. 都以短的英文縮寫為主
                2. 圖片 .pic
                3. 文本 .txt
                4. 標題 .tit
                5. 日期 .date
                6. 簡介 .desc
                7. 信息 .info
                8. 按鈕 .btn
                9. 更多 .more
            2. 其他自定義模塊都用 m- 為前綴命名
            3. 單獨元素都已 g- 為前綴命名
              1. 大標題 g-tit1
              2. 按鈕 g-btn
            4. 通用的模塊統一命名
              1. 頭部 header
              2. 底部 footer
              3. 主導航 nav
              4. 側導航 snv
              5. 分頁 pages
              6. 當前位置 cur
          4. 了解CSS模塊化寫法規范和編碼順序
            1. 先寫初始化樣式
            2. 然后是頭部底部公用樣式
            3. 然后寫每個模塊的樣式
            4. 每個模塊的樣式都以模塊命開頭,每個模塊獨立
            5. .wp是限制頁面寬度的
            6. .col- 是頁面布局分欄的

          隨著 Web 技術的蓬勃發展和依賴的基礎設施日益完善,前端領域逐漸從瀏覽器擴展至服務端(Node.js),桌面端(PC、Android、iOS),乃至于物聯網設備(IoT),其中 JavaScript 承載著這些應用程序的核心部分,隨著其規?;蛷碗s度的成倍增長,其軟件工程體系也隨之建立起來(協同開發、單元測試、需求和缺陷管理等),模塊化編程的需求日益迫切。

          JavaScript 對模塊化編程的支持尚未形成規范,難以堪此重任;一時間,江湖俠士挺身而出,一路披荊斬棘,從刀耕火種過渡到面向未來的模塊化方案;

          更多關于我的文章和項目,歡迎關注 @x-cold

          概念

          模塊化編程就是通過組合一些__相對獨立可復用的模塊__來進行功能的實現,其最核心的兩部分是__定義模塊__和__引入模塊__;

          • 定義模塊時,每個模塊內部的執行邏輯是不被外部感知的,只是導出(暴露)出部分方法和數據;
          • 引入模塊時,同步 / 異步去加載待引入的代碼,執行并獲取到其暴露的方法和數據;

          刀耕火種

          盡管 JavaScript 語言層面并未提供模塊化的解決方案,但利用其可__面向對象__的語言特性,外加__設計模式__加持,能夠實現一些簡單的模塊化的架構;經典的一個案例是利用單例模式模式去實現模塊化,可以對模塊進行較好的封裝,只暴露部分信息給需要使用模塊的地方;

          // Define a module
          var moduleA = (function ($, doc) {
           var methodA = function() {};
           var dataA = {};
           return {
           methodA: methodA,
           dataA: dataA
           };
          })(jQuery, document);
          // Use a module
          var result = moduleA.mehodA();
          

          直觀來看,通過立即執行函數(IIFE)來聲明依賴以及導出數據,這與當下的模塊化方案并無巨大的差異,可本質上卻有千差萬別,無法滿足的一些重要的特性;

          • 定義模塊時,聲明的依賴不是強制自動引入的,即在定義該模塊之前,必須手動引入依賴的模塊代碼;
          • 定義模塊時,其代碼就已經完成執行過程,無法實現按需加載;
          • 跨文件使用模塊時,需要將模塊掛載到全局變量(window)上;

          AMD & CMD 二分天下

          題外話:由于年代久遠,這兩種模塊化方案逐漸淡出歷史舞臺,具體特性不再細聊;

          為了解決”刀耕火種”時代存留的需求,AMD 和 CMD 模塊化規范問世,解決了在瀏覽器端的異步模塊化編程的需求,__其最核心的原理是通過動態加載 script 和事件監聽的方式來異步加載模塊;__

          AMD 和 CMD 最具代表的兩個作品分別對應 require.js 和 sea.js;其主要區別在于依賴聲明和依賴加載的時機,其中 require.js 默認在聲明時執行, sea.js 推崇懶加載和按需使用;另外值得一提的是,CMD 規范的寫法和 CommonJS 極為相近,只需稍作修改,就能在 CommonJS 中使用。參考下面的 Case 更有助于理解;

          // AMD
          define(['./a','./b'], function (moduleA, moduleB) {
           // 依賴前置
           moduleA.mehodA();
           console.log(moduleB.dataB);
           // 導出數據
           return {};
          });
           
          // CMD
          define(function (requie, exports, module) {
           // 依賴就近
           var moduleA = require('./a');
           moduleA.mehodA(); 
           // 按需加載
           if (needModuleB) {
           var moduleB = requie('./b');
           moduleB.methodB();
           }
           // 導出數據
           exports = {};
          });
          

          CommonJS

          2009 年 ry 發布 Node.js 的第一個版本,CommonJS 作為其中最核心的特性之一,適用于服務端下的場景;歷年來的考察和時間的洗禮,以及前端工程化對其的充分支持,CommonJS 被廣泛運用于 Node.js 和瀏覽器;

          // Core Module
          const cp = require('child_process');
          // Npm Module
          const axios = require('axios');
          // Custom Module
          const foo = require('./foo');
          module.exports = { axios };
          exports.foo = foo;
          

          規范

          • module (Object): 模塊本身
          • exports (*): 模塊的導出部分,即暴露出來的內容
          • require (Function): 加載模塊的函數,獲得目標模塊的導出值(基礎類型為復制,引用類型為淺拷貝),可以加載內置模塊、npm 模塊和自定義模塊

          實現

          1、模塊定義

          默認任意 .node .js .json 文件都是符合規范的模塊;

          2、引入模塊

          首先從緩存(require.cache)優先讀取模塊,如果未命中緩存,則進行路徑分析,然后按照不同類型的模塊處理:

          • 內置模塊,直接從內存加載;
          • 外部模塊,首先進行文件尋址定位,然后進行編譯和執行,最終得到對應的導出值;

          其中在編譯的過程中,Node對獲取的JavaScript文件內容進行了頭尾包裝,結果如下:

          (function (exports, require, module, __filename, __dirname) {
           var circle = require('./circle.js');
           console.log('The area of a circle of radius 4 is ' + circle.area(4));
          });
          

          特性總結

          • 同步執行模塊聲明和引入邏輯,分析一些復雜的依賴引用(如循環依賴)時需注意;
          • 緩存機制,性能更優,同時限制了內存占用;
          • Module 模塊可供改造的靈活度高,可以實現一些定制需求(如熱更新、任意文件類型模塊支持);

          ES Module(推薦使用)

          ES Module 是語言層面的模塊化方案,由 ES 2015 提出,其規范與 CommonJS 比之 ,導出的值都可以看成是一個具備多個屬性或者方法的對象,可以實現互相兼容;但寫法上 ES Module 更簡潔,與 Python 接近;

          import fs from 'fs';
          import color from 'color';
          import service, { getArticles } from '../service'; 
          export default service;
          export const getArticles = getArticles;
          

          主要差異在于:

          • ES Module 會對靜態代碼分析,即在代碼編譯時進行模塊的加載,在運行時之前就已經確定了依賴關系(可解決循環引用的問題);
          • ES Module 關鍵字:import export 以及獨有的 default 關鍵字,確定默認的導出值;
          • ES Module 中導出的值是一個 只讀的值的引用 ,無論基礎類型和復雜類型,而在 CommonJS 中 require 的是值的拷貝,其中復雜類型是值的淺拷貝;
          // a.js
          export let a = 1;
          export function caculate() {
           a++;
          };
          // b.js
          import { a, caculate } from 'a.js';
          console.log(a); // 1
          caculate();
          console.log(a); // 2
          a = 2; // Syntax Error: "a" is read-only
          

          UMD

          通過一層自執行函數來兼容各種模塊化規范的寫法,兼容 AMD / CMD / CommonJS 等模塊化規范,貼上代碼勝過千言萬語,需要特別注意的是 ES Module 由于會對靜態代碼進行分析,故這種運行時的方案無法使用,此時通過 CommonJS 進行兼容;

          (function (global, factory) {
           if (typeof exports === 'object') { 
           module.exports = factory();
           } else if (typeof define === 'function' && define.amd) {
           define(factory);
           } else {
           this.eventUtil = factory();
           }
          })(this, function (exports) {
           ? // Define Module
           Object.defineProperty(exports, "__esModule", {
           value: true
           });
           exports.default = 42;
          });
          

          構建工具中的實現

          為了在瀏覽器環境中運行模塊化的代碼,需要借助一些模塊化打包的工具進行打包( 以 webpack 為例),定義了項目入口之后,會先快速地進行依賴的分析,然后將所有依賴的模塊轉換成瀏覽器兼容的對應模塊化規范的實現;

          模塊化的基礎

          從上面的介紹中,我們已經對其規范和實現有了一定的了解;在瀏覽器中,要實現 CommonJS 規范,只需要實現 module / exports / require / global 這幾個屬性,由于瀏覽器中是無法訪問文件系統的,因此 require 過程中的文件定位需要改造為加載對應的 JS 片段(webpack 采用的方式為通過函數傳參實現依賴的引入)。具體實現可以參考:tiny-browser-require。

          webpack 打包出來的代碼快照如下,注意看注釋中的時序;

          (function (modules) {
           // The module cache
           var installedModules = {};
           // The require function
           function __webpack_require__(moduleId) {}
           return __webpack_require__(0); // ---> 0
          })
          ({
           0: function (module, exports, __webpack_require__) {
           // Define module A
           var moduleB = __webpack_require__(1); // ---> 1
           },
           1: function (module, exports, __webpack_require__) {
           // Define module B
           exports = {}; // ---> 2
           }
          });
          

          實際上,ES Module 的處理同 CommonJS 相差無幾,只是在定義模塊和引入模塊時會去處理 __esModule 標識,從而兼容其在語法上的差異。

          異步和擴展

          1、瀏覽器環境下,網絡資源受到較大的限制,因此打包出來的文件如果體積巨大,對頁面性能的損耗極大,因此需要對構建的目標文件進行拆分,同時模塊也需要支持動態加載;

          webpack 提供了兩個方法 require.ensure() 和 import() (推薦使用)進行模塊的動態加載,至于其中的原理,跟上面提及的 AMD & CMD 所見略同,import() 執行后返回一個 Promise 對象,其中所做的工作無非也是動態新增 script 標簽,然后通過 onload / onerror 事件進一步處理。

          2、由于 require 函數是完全自定義的,我們可以在模塊化中實現更多的特性,比如通過修改 require.resolve 或 Module._extensions 擴展支持的文件類型,使得 css / .jsx / .vue / 圖片等文件也能為模塊化所使用;

          附錄1:特性一覽表

          附錄2:參考

          • AMD 模塊化規范: https://github.com/amdjs/amdjs-api/wiki/AMD
          • CMD 模塊定義規范:https://github.com/seajs/seajs/issues/242
          • webpack 模塊相關文檔: https://webpack.js.org/concepts/modules/
          • 瀏覽器加載 CommonJS 模塊的原理與實現:http://www.ruanyifeng.com/blog/2015/05/commonjs-in-browser.html

          作者:x-cold

          本文主要理理js模塊化相關知識。
          涉及到內聯腳本、外聯腳本、動態腳本、阻塞、
          deferasyncCommonJS、AMD、CMDUMDES Module。順帶探究下Vite。

          內聯腳本

          假設你是一個前端新手,現在入門,那么我們創建一個html頁面,需要新建一個index.html文件:

          <!DOCTYPE html>
          <html>
          <head>
            <title>test</title>
          </head>
          <body>
            <p id="content">hello world</p>
          </body>
          </html>

          如果需要在頁面中執行javascript代碼,我們就需要在 HTML 頁面中插入 <script> 標簽。

          有2種插入方式:
          1、放在
          <head>
          2、放在<body>

          比如,點擊hello world之后,在hello world后面加3個感嘆號的功能,我們在head中加入script標簽,并給hello world綁定點擊事件:

          <!DOCTYPE html>
          <html>
          <head>
            <title>test</title>
            <script>
              function myFunction() {
                document.getElementById('content').innerHTML = 'hello world!!!'
              }
            </script>
          </head>
          
          <body>
            <p id="content" onclick="myFunction()">hello world</p>
          </body>
          </html>

          如果加在body中,一般放在body的最后面:

          <!DOCTYPE html>
          <html>
          <head>
            <title>test</title>
          </head>
          
          <body>
            <p id="content" onclick="myFunction()">hello world</p>
            <script>
              function myFunction() {
                document.getElementById('content').innerHTML = 'hello world!!!'
              }
            </script>
          </body>
          </html>

          簡單的邏輯我們可以用這2種方式寫,這種方式叫做內聯腳本。

          外聯腳本

          當邏輯復雜時,我們可以把上面的script標簽中的代碼抽取出來,比如在html的同級目錄創建一個js文件夾,里面新建一個a.js的文件。

          a.js中寫上面script標簽中的代碼:

          function myFunction() {
            document.getElementById('content').innerHTML = 'hello world!!!'
          }

          上面的script標簽則可以改成:

          <script src="./js/a.js"></script>

          阻塞

          上面的2種寫法,瀏覽器在加載html時,遇到script標簽,會停止解析html。
          內聯腳本會立刻執行;外聯腳本會先下載再立刻執行。
          等腳本執行完畢才會繼續解析html。
          (html解析到哪里,頁面就能顯示到哪里,用戶也能看到哪里)

          比如下面的代碼:

          <p>...content before script...</p>
          
          <script src="./js/a.js"></script>
          
          <p>...content after script...</p>

          解析到第一個p標簽,我們能看到...content before script...顯示在了頁面中,然后瀏覽器遇到script標簽,會停止解析html,而去下載a.js并執行,執行完a.js才會繼續解析html,然后頁面中才會出現...content after script...。

          我們可以通過Chrome的Developer Tools分析一下index.html加載的時間線:

          這會導致2個問題:
          1、腳本無法訪問它下面的dom;
          2、如果頁面頂部有個笨重的腳本,在它執行完之前,用戶都看不到完整的頁面。

          對于問題2,我們可以把腳本放在頁面底部,這樣它可以訪問到上面的dom,且不會阻塞頁面的顯示:

          <body>
            ...all content is above the script...
          
            <script src="./js/a.js"></script>
          </body>

          但這不是最好的辦法,我們接著往下看。

          defer

          我們給script標簽加defer屬性,就像下面這樣:

          <p>...content before script...</p>
          
          <script defer src="./js/a.js"></script>
          
          <p>...content after script...</p>

          defer 特性告訴瀏覽器不要等待腳本。于是,瀏覽器將繼續解析html,腳本會并行下載,然后等 DOM 構建完成后,腳本才會執行。

          這樣script標簽不再阻塞html的解析。

          這時再看時間線:

          需要注意的是,具有 defer 特性的腳本保持其相對順序。

          比如:

          <script defer src="./js/a.js"></script>
          <script defer src="./js/b.js"></script>

          上面的2個腳本會并行下載,但是不論哪個先下載完成,都是先執行a.js,a.js執行完才會執行b.js。
          這時,如果b.js依賴a.js,這種寫法將很有用。

          另外需要注意的是,defer 特性僅適用于外聯腳本,即如果 script標簽沒有 src屬性,則會忽略 defer 特性。

          async

          我們可以給script標簽加async屬性,就像下面這樣:

          <script async src="./js/a.js"></script>

          這會告訴瀏覽器,該腳本完全獨立。
          獨立的意思是,DOM 和其他腳本不會等待它,它也不會等待其它東西。async 腳本就是一個會在加載完成時立即執行的完全獨立的腳本。

          這時再看時間線:

          可以看到,雖然下載a.js不阻塞html的解析,但是執行a.js會阻塞。

          還需要注意多個async時的執行順序,比如下面這段代碼:

          <p>...content before script...</p>
          
          <script async src="./js/a.js"></script>
          <script async src="./js/b.js"></script>
          
          <p>...content after script...</p>

          兩個p標簽的內容會立刻顯示出來,a.js和b.js則并行下載,且下載成功后立刻執行,所以多個async時的執行順序是誰先下載成功誰先執行。
          一些比較獨立的腳本,比如性能監控,就很適合用這種方式加載。

          另外,和defer一樣,async 特性也僅適用于外聯腳本。

          動態腳本

          我們可以動態地創建一個script標簽并append到文檔中。

          let script = document.createElement('script')
          script.src = '/js/a.js'
          document.body.append(script)

          append后腳本就會立刻開始加載,表現默認和加了async屬性一致。
          我們可以顯示的設置
          script.async = false來改變這個默認行為,那么這時表現就和加了defer屬性一致。

          上面的這些寫法,當script標簽變多時,容易導致全局作用域污染,還要維護書寫順序,要解決這個問題,需要一種將 JavaScript 程序拆分為可按需導入的單獨模塊的機制,即js模塊化,我們接著往下看。

          CommonJS

          很長一段時間 JavaScript 沒有模塊化的概念,直到 Node.js 的誕生,把 JavaScript 帶到服務端,這時,CommonJS誕生了。

          CommonJS定義了三個全局變量:

          require,exports,module

          require 讀入并執行一個 js 文件,然后返回其 exports 對象;
          exports 對外暴露模塊的接口,可以是任何類型,指向 module.exports;
          module 是當前模塊,exports 是 module 上的一個屬性。

          Node.js 使用了CommonJS規范。

          比如:

          // a.js
          let name = 'Lily'
          export.name = name
          
          // b.js
          let a = require('a.js')
          console.log(a.name) // Lily

          由于CommonJS不適合瀏覽器端,于是出現了AMD和CMD規范。

          AMD

          AMD(Asynchronous Module Definition) 是 RequireJS 在推廣過程中對模塊定義的規范化產出。

          基本思想是,通過 define 方法,將代碼定義為模塊。當這個模塊被 require 時,開始加載依賴的模塊,當所有依賴的模塊加載完成后,開始執行回調函數,返回該模塊導出的值。

          使用時,需要先引入require.js:

          <script src="require.js"></script>
          <script src="a.js"></script>

          然后可以這樣寫:

          // a.js
          define(function() {
              let name = 'Lily'
              return {
                  name
              }
          })
          // b.js
          define(['a.js'], function(a) {
              let name = 'Bob'
              console.log(a.name) // Lily
              return {
                  name
              }
          })

          CMD

          CMD(Common Module Definition) 是 Sea.js 在推廣過程中對模塊定義的規范化產出。

          使用時,需要先引入sea.js:

          <script src="sea.js"></script>
          <script src="a.js"></script>

          然后可以這樣寫:

          // a.js
          define(function(require, exports, module) {
              var name = 'Lily'
              exports.name = name
          })
          
          // b.js
          define(function(require, exports, module) {
              var name = 'Bob'
              var a = require('a.js')
              console.log(a.name) // 'Lily'
              exports.name = name
          })

          UMD

          UMD (Universal Module Definition) 目的是提供一個前后端跨平臺的解決方案(兼容全局變量、AMD、CMD和CommonJS)。

          實現很簡單,判斷不同的環境,然后以不同的方式導出模塊:

          (function (root, factory) {
              if (typeof define === 'function' && (define.amd || define.cmd)) {
                  // AMD、CMD
                  define([], factory);
              } else if (typeof module !== 'undefined' && typeof exports === 'object') {
                  // Node、CommonJS
                  module.exports = factory();
              } else {
                  // 瀏覽器全局變量
                  root.moduleName = factory();
            }
          }(this, function () {
              // 只需要返回一個值作為模塊的export
              // 這里我們返回了一個空對象
              // 你也可以返回一個函數
              return {};
          }));

          ES Module

          AMD 和 CMD 是社區的開發者們制定的模塊加載方案,并不是語言層面的標準。從 ES6 開始,在語言標準的層面上,實現了模塊化功能,而且實現得相當簡單,完全可以取代上文的規范,成為瀏覽器和服務器通用的模塊解決方案。

          ES6 的模塊自動采用嚴格模式。模塊功能主要由兩個命令構成:export和import。

          export命令用于規定模塊的對外接口;
          import命令用于輸入其他模塊提供的功能。

          比如上面的代碼,我們可以這樣寫:

          // a.js
          const name = 'Lily'
          
          export {
            name
          }
          
          // 等價于
          export const name = 'Lily'
          
          // b.js
          import { name } from 'a.js'
          console.log(name) // Lily
          
          // b.js
          import * as a from 'a.js'
          console.log(a.name) // Lily

          此外,還可以用export default默認導出的寫法:

          // a.js
          const name = 'Lily'
          
          export default {
            name
          }
          
          // b.js
          import a from 'a.js'
          console.log(a.name) // Lily

          如果只想運行a.js,可以只import:

          // b.js
          import 'a.js'

          我們可以給script標簽加type=module讓瀏覽器以 ES Module 的方式加載腳本:

          <script type="module" src="./js/b.js"></script>

          這時,script標簽會默認有defer屬性(也可以設置成async),支持內聯和外聯腳本。

          這時我們運行打開index.html,會發現瀏覽器報錯了:

          這是因為 type=module 的 script 標簽加強了安全策略,瀏覽器加載不同域的腳本資源時,如果服務器未返回有效的 Allow-Origin 相關 CORS 頭,會禁止加載改腳本。而這里啟動的index.html是一個本地文件(地址是file://路徑),將會遇到 CORS 錯誤,需要通過一個服務器來啟動 HTML 文件。

          Vite

          在瀏覽器支持 ES Module 之前,我們用工具實現JavaScript模塊化的開發,比如webpack、Rollup 和 Parcel 。但是當項目越來越大后,本地熱更新越來越慢,而 Vite 旨在利用ESM解決上述問題。

          Vite使用簡單,可以去官網(https://cn.vitejs.dev/)看看。

          總結

          老的規范了解即可,未來是ES Module的,用Vite可以極大的提升開發時的體驗,生產環境用Rollup打包。


          主站蜘蛛池模板: 国精无码欧精品亚洲一区| 老熟妇高潮一区二区三区| 久久精品国产亚洲一区二区| 久久se精品一区二区国产| 91精品国产一区| 一区二区三区四区视频| 亚洲av成人一区二区三区观看在线 | 中文字幕一区二区三区在线播放 | 亚州国产AV一区二区三区伊在| 色欲AV蜜臀一区二区三区| 国产乱码精品一区二区三| 精品国产精品久久一区免费式| 麻豆AV一区二区三区| 国产精品熟女一区二区| 2014AV天堂无码一区| 亚洲国产综合无码一区二区二三区| 春暖花开亚洲性无区一区二区| 免费无码VA一区二区三区| 亚洲AV无码一区二区二三区软件| 欲色影视天天一区二区三区色香欲 | 精品亚洲一区二区| 成人区人妻精品一区二区不卡视频| 大帝AV在线一区二区三区| 精品人妻无码一区二区色欲产成人| 久久精品一区二区三区日韩| 国产在线精品一区二区在线观看| 国产免费一区二区三区不卡| 亚洲成人一区二区| 中文字幕一区二区三区日韩精品| jazzjazz国产精品一区二区| 国产精品被窝福利一区| 国产精品小黄鸭一区二区三区| 一区二区三区AV高清免费波多| 无码人妻久久一区二区三区蜜桃 | 国产精品乱码一区二区三| 久久久无码精品人妻一区| 精品久久久久久中文字幕一区| 日本美女一区二区三区| 一级毛片完整版免费播放一区| 伊人精品视频一区二区三区| 国产av成人一区二区三区|