整合營銷服務商

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

          免費咨詢熱線:

          前端入門-什么是HTML,如何快速學習

          一篇介紹了網頁的基本結構,那如何編寫網頁的內容? 前提是要學會HTML標簽的用法,本篇主要介紹HTML標簽是什么,如何學習,需要大概多長時間學習。

          本篇主要基于html5介紹,html5 是最新版的標準,之前的版本可以自己了解下。

          HTML 簡介

          HTML的英文全稱是Hyper Text Markup Language,直譯為超文本標記語言。它是全球廣域網上描述網頁內容和外觀的標準。HTML包含了一對打開和關閉的標記,在當中包含有屬性和值。標記描述了每個在網頁上的組件,例如文本段落、表格或圖像等。

          事實上,HTML是一種因特網上較常見的網頁制作標注性語言,而并不能算做一種程序設計語言,因為它缺少程序設計語言所應有的特征。HTML通過IE等瀏覽器的翻譯,將網頁中所要呈現的內容、排版展現在用戶眼前。

          一個html標簽基本結構如下:

          <標簽名稱  屬性="屬性值"></標簽名稱> 或 <標簽名稱 屬性="屬性值"/>

          有以下特點:

          1. 由尖括“<”、“>”號包圍的標記元素,比如 <html>和</html>就是一對標記。
          2. 通常是成對出現的,比如 <div> 和 </div>,也有單獨呈現的標簽,如:<img />、<input/>等。
          3. 標簽對中的第一個標簽是開始標簽,第二個標簽是結束標簽;
          4. 一般成對出現的標簽,其內容在兩個標簽中間,如<h1>標題</h1>。單獨呈現的標簽,則在標簽屬性中賦值,如<input type="text" />。
          5. 網頁展示的內容需寫在<body>標簽中。
          6. 標簽不區分大小寫,建議按規范小寫。

          HTML標簽按功能大體可分以下幾種類型:

          1. 構成網頁基本架構的標簽,比如:<!DOCTYPE>(定義文檔類型)、<html>(根標簽),<meta>(元信息)、<head> (網頁頭部區域)、<body> (網頁內容區域)。
          2. 用于引入外部資源客戶端腳本的標簽,比如:<link>(外部資源,css樣式文件), <script>(客戶端js腳本)。
          3. 用于描述布局的標簽,比如: <div>、<ul>(無序列表)、<ol>(有序列表)、<h1>到<h6>(標題1到6)、<table>(表格)、<footer>(頁腳)、<header>(頁頭)等。
          4. 用于描述文本格式的標簽,比如:<p> (段落)、<strong>(加粗)、<q>(引用)、<span>等。
          5. 用于引入多媒體資源的標簽,比如:<img>、<video>、<audio>等。
          6. 用于制作表單的標簽,比如:<form>(表單),<input>(輸入框),<textarea>(文本域),<select>(下拉菜單),<radio>(單選項),<checkbox>(多選項)等。
          7. 其它標簽(不是很常用的)。

          如何學習html的標簽用法

          沒有捷徑,需要多看,多練。在這里我不一一介紹每個標簽的具體含義及用法,相關語法可以參考以下幾個網站:

          1. https://www.w3cschool.cn/html5/
          2. https://developer.mozilla.org/zh-CN/docs/Web/HTML

          制定一個學習計劃,每天堅持下去

          要求,每天花費3到5個小時學習,至少1到2周掌握常用的html標簽含義及用法,可以按照上面介紹的標簽進行分類學習,感謝關注,祝你學習愉快。

          法匯總

          declare var 聲明全局變量

          declare function 聲明全局方法

          declare class 聲明全局類

          declare enum 聲明全局枚舉類型

          declare namespace 聲明(含有子屬性的)全局對象

          interface 和 type 聲明全局類型

          export 導出變量

          export namespace 導出(含有子屬性的)對象

          export default ES6 默認導出

          export = commonjs 導出模塊

          export as namespace UMD 庫聲明全局變量

          declare global 擴展全局變量

          declare module 擴展模塊

          /// <reference /> 三斜線指令

          什么是聲明語句

          假如我們想使用第三方庫 jQuery,一種常見的方式是在 html 中通過 <script> 標簽引入 jQuery,然后就可以使用全局變量 $ 或 jQuery 了。

          我們通常這樣獲取一個 id 是 foo 的元素:

          $('#foo');
          // or
          jQuery('#foo');
          

          但是在 ts 中,編譯器并不知道 $ 或 jQuery 是什么東西1:

          jQuery('#foo');
          // ERROR: Cannot find name 'jQuery'.
          

          這時,我們需要使用 declare var 來定義它的類型2:

          declare var jQuery: (selector: string) => any;
          jQuery('#foo');
          

          上例中,declare var 并沒有真的定義一個變量,只是定義了全局變量 jQuery 的類型,僅僅會用于編譯時的檢查,在編譯結果中會被刪除。它編譯結果是:

          jQuery('#foo');
          

          除了 declare var 之外,還有其他很多種聲明語句,將會在后面詳細介紹。

          什么是聲明文件

          通常我們會把聲明語句放到一個單獨的文件(jQuery.d.ts)中,這就是聲明文件3:

          // src/jQuery.d.ts
          declare var jQuery: (selector: string) => any;
          
          // src/index.ts
          jQuery('#foo');
          

          聲明文件必需以 .d.ts 為后綴。

          一般來說,ts 會解析項目中所有的 *.ts 文件,當然也包含以 .d.ts 結尾的文件。所以當我們將 jQuery.d.ts 放到項目中時,其他所有 *.ts 文件就都可以獲得 jQuery 的類型定義了。

          /path/to/project
          ├── src
          | ├── index.ts
          | └── jQuery.d.ts
          └── tsconfig.json
          

          假如仍然無法解析,那么可以檢查下 tsconfig.json 中的 files、include 和 exclude 配置,確保其包含了 jQuery.d.ts 文件。

          這里只演示了全局變量這種模式的聲明文件,假如是通過模塊導入的方式使用第三方庫的話,那么引入聲明文件又是另一種方式了,將會在后面詳細介紹。

          第三方聲明文件

          當然,jQuery 的聲明文件不需要我們定義了,社區已經幫我們定義好了:jQuery in DefinitelyTyped。

          我們可以直接下載下來使用,但是更推薦的是使用 @types 統一管理第三方庫的聲明文件。

          @types 的使用方式很簡單,直接用 npm 安裝對應的聲明模塊即可,以 jQuery 舉例:

          npm install @types/jquery --save-dev
          

          可以在這個頁面搜索你需要的聲明文件。

          書寫聲明文件

          當一個第三方庫沒有提供聲明文件時,我們就需要自己書寫聲明文件了。前面只介紹了最簡單的聲明文件內容,而真正書寫一個聲明文件并不是一件簡單的事,以下會詳細介紹如何書寫聲明文件。

          在不同的場景下,聲明文件的內容和使用方式會有所區別。

          庫的使用場景主要有以下幾種:

          • 全局變量:通過 <script> 標簽引入第三方庫,注入全局變量
          • npm 包:通過 import foo from 'foo' 導入,符合 ES6 模塊規范
          • UMD 庫:既可以通過 <script> 標簽引入,又可以通過 import 導入
          • 直接擴展全局變量:通過 <script> 標簽引入后,改變一個全局變量的結構
          • 在 npm 包或 UMD 庫中擴展全局變量:引用 npm 包或 UMD 庫后,改變一個全局變量的結構
          • 模塊插件:通過 <script> 或 import 導入后,改變另一個模塊的結構

          全局變量

          全局變量是最簡單的一種場景,之前舉的例子就是通過 <script> 標簽引入 jQuery,注入全局變量 $ 和 jQuery。

          使用全局變量的聲明文件時,如果是以 npm install @types/xxx --save-dev 安裝的,則不需要任何配置。如果是將聲明文件直接存放于當前項目中,則建議和其他源碼一起放到 src 目錄下(或者對應的源碼目錄下):

          /path/to/project
          ├── src
          | ├── index.ts
          | └── jQuery.d.ts
          └── tsconfig.json
          

          如果沒有生效,可以檢查下 tsconfig.json 中的 files、include 和 exclude 配置,確保其包含了 jQuery.d.ts 文件。

          全局變量的聲明文件主要有以下幾種語法:

          • declare var 聲明全局變量
          • declare function 聲明全局方法
          • declare class 聲明全局類
          • declare enum 聲明全局枚舉類型
          • declare namespace 聲明(含有子屬性的)全局對象
          • interface 和 type 聲明全局類型

          declare var

          在所有的聲明語句中,declare var 是最簡單的,如之前所學,它能夠用來定義一個全局變量的類型。與其類似的,還有 declare let 和 declare const,使用 let 與使用 var 沒有什么區別:

          // src/jQuery.d.ts
          declare let jQuery: (selector: string) => any;
          
          // src/index.ts
          jQuery('#foo');
          // 使用 declare let 定義的 jQuery 類型,允許修改這個全局變量
          jQuery = function(selector) {
           return document.querySelector(selector);
          };
          

          而當我們使用 const 定義時,表示此時的全局變量是一個常量,不允許再去修改它的值了4:

          // src/jQuery.d.ts
          declare const jQuery: (selector: string) => any;
          jQuery('#foo');
          // 使用 declare const 定義的 jQuery 類型,禁止修改這個全局變量
          jQuery = function(selector) {
           return document.querySelector(selector);
          };
          // ERROR: Cannot assign to 'jQuery' because it is a constant or a read-only property.
          

          一般來說,全局變量都是禁止修改的常量,所以大部分情況都應該使用 const 而不是 var 或 let。

          需要注意的是,聲明語句中只能定義類型,切勿在聲明語句中定義具體的實現5:

          declare const jQuery = function(selector) {
           return document.querySelector(selector);
          };
          // ERROR: An implementation cannot be declared in ambient contexts.
          

          declare function

          declare function 用來定義全局函數的類型。jQuery 其實就是一個函數,所以也可以用 function 來定義:

          // src/jQuery.d.ts
          declare function jQuery(selector: string): any;
          
          // src/index.ts
          jQuery('#foo');
          

          在函數類型的聲明語句中,函數重載也是支持的6:

          // src/jQuery.d.ts
          declare function jQuery(selector: string): any;
          declare function jQuery(domReadyCallback: () => any): any;
          
          // src/index.ts
          jQuery('#foo');
          jQuery(function() {
           alert('Dom Ready!');
          });
          

          declare class

          當全局變量是一個類的時候,我們用 declare class 來定義它的類型7:

          // src/Animal.d.ts
          declare class Animal {
           name: string;
           constructor(name: string);
           sayHi(): string;
          }
          
          // src/index.ts
          let cat = new Animal('Tom');
          

          同樣的,declare class 語句也只能用來定義類型,不能用來定義具體的實現,比如定義 sayHi 方法的具體實現則會報錯:

          // src/Animal.d.ts
          declare class Animal {
           name: string;
           constructor(name: string);
           sayHi() {
           return `My name is ${this.name}`;
           };
           // ERROR: An implementation cannot be declared in ambient contexts.
          }
          

          declare enum

          使用 declare enum 定義的枚舉類型也稱作外部枚舉(Ambient Enums),舉例如下8:

          // src/Directions.d.ts
          declare enum Directions {
           Up,
           Down,
           Left,
           Right
          }
          
          // src/index.ts
          let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
          

          與其他全局變量的類型聲明一致,declare enum 僅用來定義類型,而不是具體的值。

          Directions.d.ts 僅僅會用于編譯時的檢查,聲明文件里的內容在編譯結果中會被刪除。它編譯結果是:

          var directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
          

          其中 Directions 是由第三方庫定義好的全局變量。

          declare namespace

          namespace 是 ts 早期時為了解決模塊化而創造的關鍵字,中文稱為命名空間。

          由于歷史遺留原因,在早期還沒有 ES6 的時候,ts 提供了一種模塊化方案,使用 module 關鍵字表示內部模塊。但由于后來 ES6 也使用了 module 關鍵字,ts 為了兼容 ES6,使用 namespace 替代了自己的 module,更名為命名空間。

          隨著 ES6 的廣泛應用,現在已經不建議再使用 ts 中的 namespace,而推薦使用 ES6 的模塊化方案了,故我們不再需要學習 namespace 的使用了。

          namespace 被淘汰了,但是在聲明文件中,declare namespace 還是比較常用的,它用來表示全局變量是一個對象,包含很多子屬性。

          比如 jQuery 是一個全局變量,它是一個對象,提供了一個 jQuery.ajax 方法可以調用,那么我們就應該使用 declare namespace jQuery 來聲明這個擁有多個子屬性的全局變量。

          // src/jQuery.d.ts
          declare namespace jQuery {
           function ajax(url: string, settings?: any): void;
          }
          
          // src/index.ts
          jQuery.ajax('/api/get_something');
          

          注意,在 declare namespace 內部,我們直接使用 function ajax 來聲明函數,而不是使用 declare function ajax。類似的,也可以使用 const, class, enum 等語句9:

          // src/jQuery.d.ts
          declare namespace jQuery {
           function ajax(url: string, settings?: any): void;
           const version: number;
           class Event {
           blur(eventType: EventType): void
           }
           enum EventType {
           CustomClick
           }
          }
          
          // src/index.ts
          jQuery.ajax('/api/get_something');
          console.log(jQuery.version);
          const e = new jQuery.Event();
          e.blur(jQuery.EventType.CustomClick);
          

          嵌套的命名空間

          如果對象擁有深層的層級,則需要用嵌套的 namespace 來聲明深層的屬性的類型10:

          // src/jQuery.d.ts
          declare namespace jQuery {
           function ajax(url: string, settings?: any): void;
           namespace fn {
           function extend(object: any): void;
           }
          }
          
          // src/index.ts
          jQuery.ajax('/api/get_something');
          jQuery.fn.extend({
           check: function() {
           return this.each(function() {
           this.checked = true;
           });
           }
          });
          

          假如 jQuery 下僅有 fn 這一個屬性(沒有 ajax 等其他屬性或方法),則可以不需要嵌套 namespace11:

          // src/jQuery.d.ts
          declare namespace jQuery.fn {
           function extend(object: any): void;
          }
          
          // src/index.ts
          jQuery.fn.extend({
           check: function() {
           return this.each(function() {
           this.checked = true;
           });
           }
          });
          

          interface 和 type

          除了全局變量之外,可能有一些類型我們也希望能暴露出來。在類型聲明文件中,我們可以直接使用 interface 或 type 來聲明一個全局的接口或類型12:

          // src/jQuery.d.ts
          interface AjaxSettings {
           method?: 'GET' | 'POST'
           data?: any;
          }
          declare namespace jQuery {
           function ajax(url: string, settings?: AjaxSettings): void;
          }
          

          這樣的話,在其他文件中也可以使用這個接口或類型了:

          // src/index.ts
          let settings: AjaxSettings = {
           method: 'POST',
           data: {
           name: 'foo'
           }
          };
          jQuery.ajax('/api/post_something', settings);
          

          type 與 interface 類似,不再贅述。

          防止命名沖突

          暴露在最外層的 interface 或 type 會作為全局類型作用于整個項目中,我們應該盡可能的減少全局變量或全局類型的數量。故最好將他們放到 namespace 下13:

          // src/jQuery.d.ts
          declare namespace jQuery {
           interface AjaxSettings {
           method?: 'GET' | 'POST'
           data?: any;
           }
           function ajax(url: string, settings?: AjaxSettings): void;
          }
          

          注意,在使用這個 interface 的時候,也應該加上 jQuery 前綴:

          // src/index.ts
          let settings: jQuery.AjaxSettings = {
           method: 'POST',
           data: {
           name: 'foo'
           }
          };
          jQuery.ajax('/api/post_something', settings);
          

          聲明合并

          假如 jQuery 既是一個函數,可以直接被調用 jQuery('#foo'),又是一個對象,擁有子屬性 jQuery.ajax()(事實確實如此),那么我們可以組合多個聲明語句,它們會不沖突的合并起來14:

          // src/jQuery.d.ts
          declare function jQuery(selector: string): any;
          declare namespace jQuery {
           function ajax(url: string, settings?: any): void;
          }
          
          // src/index.ts
          jQuery('#foo');
          jQuery.ajax('/api/get_something');
          

          關于聲明合并的更多用法,可以查看聲明合并章節。

          npm 包

          一般我們通過 import foo from 'foo' 導入一個 npm 包,這是符合 ES6 模塊規范的。

          在我們嘗試給一個 npm 包創建聲明文件之前,需要先看看它的聲明文件是否已經存在。一般來說,npm 包的聲明文件可能存在于兩個地方:

          1. 與該 npm 包綁定在一起。判斷依據是 package.json 中有 types 字段,或者有一個 index.d.ts 聲明文件。這種模式不需要額外安裝其他包,是最為推薦的,所以以后我們自己創建 npm 包的時候,最好也將聲明文件與 npm 包綁定在一起。
          2. 發布到 @types 里。我們只需要嘗試安裝一下對應的 @types 包就知道是否存在該聲明文件,安裝命令是 npm install @types/foo --save-dev。這種模式一般是由于 npm 包的維護者沒有提供聲明文件,所以只能由其他人將聲明文件發布到 @types 里了。

          假如以上兩種方式都沒有找到對應的聲明文件,那么我們就需要自己為它寫聲明文件了。由于是通過 import 語句導入的模塊,所以聲明文件存放的位置也有所約束,一般有兩種方案:

          1. 創建一個 node_modules/@types/foo/index.d.ts 文件,存放 foo 模塊的聲明文件。這種方式不需要額外的配置,但是 node_modules 目錄不穩定,代碼也沒有被保存到倉庫中,無法回溯版本,有不小心被刪除的風險,故不太建議用這種方案,一般只用作臨時測試。
          2. 創建一個 types 目錄,專門用來管理自己寫的聲明文件,將 foo 的聲明文件放到 types/foo/index.d.ts 中。這種方式需要配置下 tsconfig.json 中的 paths 和 baseUrl 字段。

          目錄結構:

          /path/to/project
          ├── src
          | └── index.ts
          ├── types
          | └── foo
          | └── index.d.ts
          └── tsconfig.json
          

          tsconfig.json 內容:

          {
           "compilerOptions": {
           "module": "commonjs",
           "baseUrl": "./",
           "paths": {
           "*": ["types/*"]
           }
           }
          }
          

          如此配置之后,通過 import 導入 foo 的時候,也會去 types 目錄下尋找對應的模塊的聲明文件了。

          注意 module 配置可以有很多種選項,不同的選項會影響模塊的導入導出模式。這里我們使用了 commonjs 這個最常用的選項,后面的教程也都默認使用的這個選項。

          不管采用了以上兩種方式中的哪一種,我都強烈建議大家將書寫好的聲明文件(通過給第三發庫發 pull request,或者直接提交到 @types 里)發布到開源社區中,享受了這么多社區的優秀的資源,就應該在力所能及的時候給出一些回饋。只有所有人都參與進來,才能讓 ts 社區更加繁榮。

          npm 包的聲明文件主要有以下幾種語法:

          • export 導出變量
          • export namespace 導出(含有子屬性的)對象
          • export default ES6 默認導出
          • export = commonjs 導出模塊

          export

          npm 包的聲明文件與全局變量的聲明文件有很大區別。在 npm 包的聲明文件中,使用 declare 不再會聲明一個全局變量,而只會在當前文件中聲明一個局部變量。只有在聲明文件中使用 export 導出,然后在使用方 import 導入后,才會應用到這些類型聲明。

          export 的語法與普通的 ts 中的語法類似,區別僅在于聲明文件中禁止定義具體的實現15:

          // types/foo/index.d.ts
          export const name: string;
          export function getName(): string;
          export class Animal {
           constructor(name: string);
           sayHi(): string;
          }
          export enum Directions {
           Up,
           Down,
           Left,
           Right
          }
          export interface Options {
           data: any;
          }
          

          對應的導入和使用模塊應該是這樣:

          // src/index.ts
          import { name, getName, Animal, Directions, Options } from 'foo';
          console.log(name);
          let myName = getName();
          let cat = new Animal('Tom');
          let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
          let options: Options = {
           data: {
           name: 'foo'
           }
          };
          

          混用 declare 和 export

          我們也可以使用 declare 先聲明多個變量,最后再用 export 一次性導出。上例的聲明文件可以等價的改寫為16:

          // types/foo/index.d.ts
          declare const name: string;
          declare function getName(): string;
          declare class Animal {
           constructor(name: string);
           sayHi(): string;
          }
          declare enum Directions {
           Up,
           Down,
           Left,
           Right
          }
          interface Options {
           data: any;
          }
          export { name, getName, Animal, Directions, Options };
          

          注意,與全局變量的聲明文件類似,interface 前是不需要 declare 的。

          export namespace

          與 declare namespace 類似,export namespace 用來導出一個擁有子屬性的對象17:

          // types/foo/index.d.ts
          export namespace foo {
           const name: string;
           namespace bar {
           function baz(): string;
           }
          }
          
          // src/index.ts
          import { foo } from 'foo';
          console.log(foo.name);
          foo.bar.baz();
          

          export default

          在 ES6 模塊系統中,使用 export default 可以導出一個默認值,使用方可以用 import foo from 'foo' 而不是 import { foo } from 'foo' 來導入這個默認值。

          在類型聲明文件中,export default 用來導出默認值的類型18:

          // types/foo/index.d.ts
          export default function foo(): string;
          
          // src/index.ts
          import foo from 'foo';
          foo();
          

          注意,只有 function、class 和 interface 可以直接默認導出,其他的變量需要先定義出來,再默認導出19:

          // types/foo/index.d.ts
          export default enum Directions {
          // ERROR: Expression expected.
           Up,
           Down,
           Left,
           Right
          }
          

          上例中 export default enum 是錯誤的語法,需要使用 declare enum 定義出來,然后使用 export default 導出:

          // types/foo/index.d.ts
          declare enum Directions {
           Up,
           Down,
           Left,
           Right
          }
          export default Directions;
          

          針對這種默認導出,我們一般會將導出語句放在整個聲明文件的最前面20:

          // types/foo/index.d.ts
          export default Directions;
          declare enum Directions {
           Up,
           Down,
           Left,
           Right
          }
          

          export =

          在 commonjs 規范中,我們用以下方式來導出一個模塊:

          // 整體導出
          module.exports = foo;
          // 單個導出
          exports.bar = bar;
          

          在 ts 中,針對這種模塊導出,有多種方式可以導入,第一種方式是 const ... = require:

          // 整體導入
          const foo = require('foo');
          // 單個導入
          const bar = require('foo').bar;
          

          第二種方式是 import ... from,注意針對整體導出,需要使用 import * as 來導入:

          // 整體導入
          import * as foo from 'foo';
          // 單個導入
          import { bar } from 'foo';
          

          第三種方式是 import ... require,這也是 ts 官方推薦的方式:

          // 整體導入
          import foo = require('foo');
          // 單個導入
          import bar = foo.bar;
          

          對于這種使用 commonjs 規范的庫,假如要為它寫類型聲明文件的話,就需要使用到 export = 這種語法了21:

          // types/foo/index.d.ts
          export = foo;
          declare function foo(): string;
          declare namespace foo {
           const bar: number;
          }
          

          需要注意的是,上例中使用了 export = 之后,就不能再單個導出 export { bar } 了。所以我們通過聲明合并,使用 declare namespace foo 來將 bar 合并到 foo 里。

          準確地講,export = 不僅可以用在聲明文件中,也可以用在普通的 ts 文件中。實際上,import ... require 和 export = 都是 ts 為了兼容 AMD 規范和 commonjs 規范而創立的新語法,由于并不常用也不推薦使用,所以這里就不詳細介紹了,感興趣的可以看官方文檔。

          由于很多第三方庫是 commonjs 規范的,所以聲明文件也就不得不用到 export = 這種語法了。但是還是需要再強調下,相比與 export =,我們更推薦使用 ES6 標準的 export default 和 export。

          UMD 庫

          既可以通過 <script> 標簽引入,又可以通過 import 導入的庫,稱為 UMD 庫。相比于 npm 包的類型聲明文件,我們需要額外聲明一個全局變量,為了實現這種方式,ts 提供了一個新語法 export as namespace。

          export as namespace

          一般使用 export as namespace 時,都是先有了 npm 包的聲明文件,再基于它添加一條 export as namespace 語句,即可將聲明好的一個變量聲明為全局變量,舉例如下22:

          // types/foo/index.d.ts
          export as namespace foo;
          export = foo;
          declare function foo(): string;
          declare namespace foo {
           const bar: number;
          }
          

          當然它也可以與 export default 一起使用:

          // types/foo/index.d.ts
          export as namespace foo;
          export default foo;
          declare function foo(): string;
          declare namespace foo {
           const bar: number;
          }
          

          直接擴展全局變量

          有的第三方庫擴展了一個全局變量,可是此全局變量的類型卻沒有相應的更新過來,就會導致 ts 編譯錯誤,此時就需要擴展全局變量的類型。比如擴展 String 類型23:

          interface String {
           prependHello(): string;
          }
          'foo'.prependHello();
          

          通過聲明合并,使用 interface String 即可給 String 添加屬性或方法。

          也可以使用 declare namespace 給已有的命名空間添加類型聲明24:

          // types/jquery-plugin/index.d.ts
          declare namespace JQuery {
           interface CustomOptions {
           bar: string;
           }
          }
          interface JQueryStatic {
           foo(options: JQuery.CustomOptions): string;
          }
          
          // src/index.ts
          jQuery.foo({
           bar: ''
          });
          

          在 npm 包或 UMD 庫中擴展全局變量

          如之前所說,對于一個 npm 包或者 UMD 庫的聲明文件,只有 export 導出的類型聲明才能被導入。所以對于 npm 包或 UMD 庫,如果導入此庫之后會擴展全局變量,則需要使用另一種語法在聲明文件中擴展全局變量的類型,那就是 declare global。

          declare global

          使用 declare global 可以在 npm 包或者 UMD 庫的聲明文件中擴展全局變量的類型25:

          // types/foo/index.d.ts
          declare global {
           interface String {
           prependHello(): string;
           }
          }
          export {};
          
          // src/index.ts
          'bar'.prependHello();
          

          注意即使此聲明文件不需要導出任何東西,仍然需要導出一個空對象,用來告訴編譯器這是一個模塊的聲明文件,而不是一個全局變量的聲明文件。

          模塊插件

          有時通過 import 導入一個模塊插件,可以改變另一個原有模塊的結構。此時如果原有模塊已經有了類型聲明文件,而插件模塊沒有類型聲明文件,就會導致類型不完整,缺少插件部分的類型。ts 提供了一個語法 declare module,它可以用來擴展原有模塊的類型。

          declare module

          如果是需要擴展原有模塊的話,需要在類型聲明文件中先引用原有模塊,再使用 declare module 擴展原有模塊26:

          // types/moment-plugin/index.d.ts
          import * as moment from 'moment';
          declare module 'moment' {
           export function foo(): moment.CalendarKey;
          }
          
          // src/index.ts
          import * as moment from 'moment';
          import 'moment-plugin';
          moment.foo();
          

          declare module 也可用于在一個文件中一次性聲明多個模塊的類型27:

          // types/foo-bar.d.ts
          declare module 'foo' {
           export interface Foo {
           foo: string;
           }
          }
          declare module 'bar' {
           export function bar(): string;
          }
          
          // src/index.ts
          import { Foo } from 'foo';
          import * as bar from 'bar';
          let f: Foo;
          bar.bar();
          

          聲明文件中的依賴

          一個聲明文件有時會依賴另一個聲明文件中的類型,比如在前面的 declare module 的例子中,我們就在聲明文件中導入了 moment,并且使用了 moment.CalendarKey 這個類型:

          // types/moment-plugin/index.d.ts
          import * as moment from 'moment';
          declare module 'moment' {
           export function foo(): moment.CalendarKey;
          }
          

          除了可以在聲明文件中通過 import 導入另一個聲明文件中的類型之外,還有一個語法也可以用來導入另一個聲明文件,那就是三斜線指令。

          三斜線指令

          與 namespace 類似,三斜線指令也是 ts 在早期版本中為了描述模塊之間的依賴關系而創造的語法。隨著 ES6 的廣泛應用,現在已經不建議再使用 ts 中的三斜線指令來聲明模塊之間的依賴關系了。

          但是在聲明文件中,它還是有一定的用武之地。

          類似于聲明文件中的 import,它可以用來導入另一個聲明文件。與 import 的區別是,當且僅當在以下幾個場景下,我們才需要使用三斜線指令替代 import:

          • 當我們在書寫一個全局變量的聲明文件時
          • 當我們需要依賴一個全局變量的聲明文件時

          書寫一個全局變量的聲明文件

          這些場景聽上去很拗口,但實際上很好理解——在全局變量的聲明文件中,是不允許出現 import, export 關鍵字的。一旦出現了,那么他就會被視為一個 npm 包或 UMD 庫,就不再是全局變量的聲明文件了。故當我們在書寫一個全局變量的聲明文件時,如果需要引用另一個庫的類型,那么就必須用三斜線指令了28:

          // types/jquery-plugin/index.d.ts
          /// <reference types="jquery" />
          declare function foo(options: JQuery.AjaxSettings): string;
          
          // src/index.ts
          foo({});
          

          三斜線指令的語法如上,/// 后面使用 xml 的格式添加了對 jquery 類型的依賴,這樣就可以在聲明文件中使用 JQuery.AjaxSettings 類型了。

          注意,三斜線指令必須放在文件的最頂端,三斜線指令的前面只允許出現單行或多行注釋。

          依賴一個全局變量的聲明文件

          在另一個場景下,當我們需要依賴一個全局變量的聲明文件時,由于全局變量不支持通過 import 導入,當然也就必須使用三斜線指令來引入了29:

          // types/node-plugin/index.d.ts
          /// <reference types="node" />
          export function foo(p: NodeJS.Process): string;
          
          // src/index.ts
          import { foo } from 'node-plugin';
          foo(global.process);
          

          在上面的例子中,我們通過三斜線指引入了 node 的類型,然后在聲明文件中使用了 NodeJS.Process 這個類型。最后在使用到 foo 的時候,傳入了 node 中的全局變量 process。

          由于引入的 node 中的類型都是全局變量的類型,它們是沒有辦法通過 import 來導入的,所以這種場景下也只能通過三斜線指令來引入了。

          以上兩種使用場景下,都是由于需要書寫或需要依賴全局變量的聲明文件,所以必須使用三斜線指令。在其他的一些不是必要使用三斜線指令的情況下,就都需要使用 import 來導入。

          拆分聲明文件

          當我們的全局變量的聲明文件太大時,可以通過拆分為多個文件,然后在一個入口文件中將它們一一引入,來提高代碼的可維護性。比如 jQuery 的聲明文件就是這樣的:

          // node_modules/@types/jquery/index.d.ts
          /// <reference types="sizzle" />
          /// <reference path="JQueryStatic.d.ts" />
          /// <reference path="JQuery.d.ts" />
          /// <reference path="misc.d.ts" />
          /// <reference path="legacy.d.ts" />
          export = jQuery;
          

          其中用到了 types 和 path 兩種不同的指令。它們的區別是:types 用于聲明對另一個庫的依賴,而 path 用于聲明對另一個文件的依賴。

          上例中,sizzle 是與 jquery 平行的另一個庫,所以需要使用 types="sizzle" 來聲明對它的依賴。而其他的三斜線指令就是將 jquery 的聲明拆分到不同的文件中了,然后在這個入口文件中使用 path="foo" 將它們一一引入。

          其他三斜線指令

          除了這兩種三斜線指令之外,還有其他的三斜線指令,比如 /// <reference no-default-lib="true"/>, /// <amd-module /> 等,但它們都是廢棄的語法,故這里就不介紹了,詳情可見官網。

          自動生成聲明文件

          如果庫的源碼本身就是由 ts 寫的,那么在使用 tsc 腳本將 ts 編譯為 js 的時候,添加 declaration 選項,就可以同時也生成 .d.ts 聲明文件了。

          我們可以在命令行中添加 --declaration(簡寫 -d),或者在 tsconfig.json 中添加 declaration 選項。這里以 tsconfig.json 為例:

          {
           "compilerOptions": {
           "module": "commonjs",
           "outDir": "lib",
           "declaration": true,
           }
          }
          

          上例中我們添加了 outDir 選項,將 ts 文件的編譯結果輸出到 lib 目錄下,然后添加了 declaration 選項,設置為 true,表示將會由 ts 文件自動生成 .d.ts 聲明文件,也會輸出到 lib 目錄下。

          運行 tsc 之后,目錄結構如下30:

          /path/to/project
          ├── lib
          | ├── bar
          | | ├── index.d.ts
          | | └── index.js
          | ├── index.d.ts
          | └── index.js
          ├── src
          | ├── bar
          | | └── index.ts
          | └── index.ts
          ├── package.json
          └── tsconfig.json
          

          在這個例子中,src 目錄下有兩個 ts 文件,分別是 src/index.ts 和 src/bar/index.ts,它們被編譯到 lib 目錄下的同時,也會生成對應的兩個聲明文件 lib/index.d.ts 和 lib/bar/index.d.ts。它們的內容分別是:

          // src/index.ts
          export * from './bar';
          export default function foo() {
           return 'foo';
          }
          
          // src/bar/index.ts
          export function bar() {
           return 'bar';
          }
          
          // lib/index.d.ts
          export * from './bar';
          export default function foo(): string;
          
          // lib/bar/index.d.ts
          export declare function bar(): string;
          

          可見,自動生成的聲明文件基本保持了源碼的結構,而將具體實現去掉了,生成了對應的類型聲明。

          使用 tsc 自動生成聲明文件時,每個 ts 文件都會對應一個 .d.ts 聲明文件。這樣的好處是,使用方不僅可以在使用 import foo from 'foo' 導入默認的模塊時獲得類型提示,還可以在使用 import bar from 'foo/lib/bar' 導入一個子模塊時,也獲得對應的類型提示。

          除了 declaration 選項之外,還有幾個選項也與自動生成聲明文件有關,這里只簡單列舉出來,不做詳細演示了:

          • declarationDir 設置生成 .d.ts 文件的目錄
          • declarationMap 對每個 .d.ts 文件,都生成對應的 .d.ts.map(sourcemap)文件
          • emitDeclarationOnly 僅生成 .d.ts 文件,不生成 .js 文件

          發布聲明文件

          當我們為一個庫寫好了聲明文件之后,下一步就是將它發布出去了。

          此時有兩種方案:

          1. 將聲明文件和源碼放在一起
          2. 將聲明文件發布到 @types 下

          這兩種方案中優先選擇第一種方案。保持聲明文件與源碼在一起,使用時就不需要額外增加單獨的聲明文件庫的依賴了,而且也能保證聲明文件的版本與源碼的版本保持一致。

          僅當我們在給別人的倉庫添加類型聲明文件,但原作者不愿意合并 pull request 時,才需要使用第二種方案,將聲明文件發布到 @types 下。

          將聲明文件和源碼放在一起

          如果聲明文件是通過 tsc 自動生成的,那么無需做任何其他配置,只需要把編譯好的文件也發布到 npm 上,使用方就可以獲取到類型提示了。

          如果是手動寫的聲明文件,那么需要滿足以下條件之一,才能被正確的識別:

          • 給 package.json 中的 types 或 typings 字段指定一個類型聲明文件地址
          • 在項目根目錄下,編寫一個 index.d.ts 文件
          • 針對入口文件(package.json 中的 main 字段指定的入口文件),編寫一個同名不同后綴的 .d.ts 文件

          第一種方式是給 package.json 中的 types 或 typings 字段指定一個類型聲明文件地址。比如:

          {
           "name": "foo",
           "version": "1.0.0",
           "main": "lib/index.js",
           "types": "foo.d.ts",
          }
          

          指定了 types 為 foo.d.ts 之后,導入此庫的時候,就會去找 foo.d.ts 作為此庫的類型聲明文件了。

          typings 與 types 一樣,只是另一種寫法。

          如果沒有指定 types 或 typings,那么就會在根目錄下尋找 index.d.ts 文件,將它視為此庫的類型聲明文件。

          如果沒有找到 index.d.ts 文件,那么就會尋找入口文件(package.json 中的 main 字段指定的入口文件)是否存在對應同名不同后綴的 .d.ts 文件。

          比如 package.json 是這樣時:

          {
           "name": "foo",
           "version": "1.0.0",
           "main": "lib/index.js"
          }
          

          就會先識別 package.json 中是否存在 types 或 typings 字段。發現不存在,那么就會尋找是否存在 index.d.ts 文件。如果還是不存在,那么就會尋找是否存在 lib/index.d.ts 文件。假如說連 lib/index.d.ts 都不存在的話,就會被認為是一個沒有提供類型聲明文件的庫了。

          有的庫為了支持導入子模塊,比如 import bar from 'foo/lib/bar',就需要額外再編寫一個類型聲明文件 lib/bar.d.ts 或者 lib/bar/index.d.ts,這與自動生成聲明文件類似,一個庫中同時包含了多個類型聲明文件。

          站設計的編程語言有哪些?珠海網站建設杰作科技小編帶您一起來看看吧、

          1.HTML語言1.HTML是Hyper Text Markup Language的縮寫,中文譯為“超文本標 記語言”。它是一種用來撰寫網頁的程序語言,用來表示Web文檔的規范。顧名思義,HTML使 用標記符來確定網頁顯示的格式。因此,雖然HTML原始文件為純文本文件,沒有圖片和 動畫等多媒體組件,但卻包含了指向這些多媒體組件的指針。每個Web頁對應一個HTML文件, 當打開HTML的文件后,便可看到不同文本屬性、圖片和動畫等很多效果。HTML文件 的擴展名為.html或.htmo

          2. XML語言XML語言是Extensible Markup Language的縮寫,中文譯為“可擴展 標記語言”,主要的用途是在Internet上傳送或處理數據。XML與HTML不是并列的概念,它可以 說是HTML的補丁,以便彌補HTML語言中的不足。比如,在HTML語言中不允許用戶自 定義控制標記符,而在XML語言中則允許用戶這樣做。XML文件的擴展名為.xml。

          3 .VRML語言VRML語言是Virtual Reality Modeling Language的縮寫,中文譯為 “虛擬實境描述模塊語言”,主要的用途是描述物體的三維空間信息,使游覽者可以看到三維 物體。也就是游覽者不僅可以看到物體的正面,還可以將物體加以旋轉、拉遠、拉近或者是從 各個角度來觀察物體。

          4. CSS語官CSS語言是Cascading Style Sheets的縮寫,中文譯為“層疊樣式表 ”,主要的用途是定義網頁數據的編排、格式化、顯示及特殊效果等,可以彌補HTML的某些不足 。

          5.游覽器端script腳本語盲腳本(script)是一段嵌在.HTML原始代碼內的小程序。Netscape公司 開發的Javascript和Microsoft公司開發的VBscript均可用來撰寫瀏覽器端的腳本,但在使 用效果上Javascript似乎更勝一籌。

          6.服務冊端的script腳本語官盡管瀏覽器端的腳本已經可以完成許多工作,但有些工作還需要在 服務器端執行才可以完成。目前常見的服務器端的腳本語言是ASP程序。

          ASP是Active Serve Pages的縮寫,中文譯為“動態服務器網頁”。 ASP程序是在MicrosoftHS或PWS等Web服務器執行的腳本,通常是由VBscript或是Javascript撰 寫而成。

          7.DHML語言DHTML(Dynamic HTML),即動態HTML,它是一種技術的總稱,它使用 HTMLVBscript, Javascript和CSS等語言技術使得網頁能夠具有動態交互功能 。雖然HTML語言可以制作出具有復雜格式的網頁,但這樣制作出來的網頁中只包含靜態內容,如果網頁上有任何信息需要更新,瀏覽器就必須從服務器重新下載整個網頁,因而造成 網絡的極大的負荷。

          了解更多網絡營銷請關注珠海網站建設-杰作科技:www.jiezuo.org www.jiezuo.net www.jzuo.cn 珠海網站建設.com

          原文鏈接:http://www.jiezuo.org/seojichu/833.html


          主站蜘蛛池模板: 色一情一乱一区二区三区啪啪高| 国产成人欧美一区二区三区| 无码人妻久久一区二区三区免费丨| 亚洲.国产.欧美一区二区三区 | 麻豆高清免费国产一区| 国产一区二区三区在线免费| 99久久综合狠狠综合久久一区| 变态调教一区二区三区| 亚洲国产精品无码第一区二区三区 | 国产丝袜一区二区三区在线观看| 色老头在线一区二区三区| 精品一区二区三区免费视频| 日韩伦理一区二区| 久久99国产精一区二区三区| 日韩在线视频不卡一区二区三区| 亚洲av无码片区一区二区三区| 国产在线无码视频一区二区三区 | 精品日产一区二区三区手机| 无码毛片一区二区三区视频免费播放 | 好湿好大硬得深一点动态图91精品福利一区二区 | 亚洲人AV永久一区二区三区久久| 在线视频精品一区| 成人区人妻精品一区二区三区| 亚洲福利秒拍一区二区| 99精品一区二区免费视频 | 91亚洲一区二区在线观看不卡| 国产成人无码精品一区二区三区| 国产在线aaa片一区二区99| 插我一区二区在线观看| 亚洲一区二区三区国产精品| 一区二区在线视频免费观看| aⅴ一区二区三区无卡无码| 无码人妻精品一区二| 国产精品99无码一区二区| 日本一区二区三区在线视频| 日本强伦姧人妻一区二区| 午夜福利国产一区二区| 国产精品主播一区二区| 国产午夜精品一区二区三区不卡| 中文无码AV一区二区三区| 国产成人精品一区二区三区无码|