整合營銷服務商

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

          免費咨詢熱線:

          七爪源碼:如何在 JavaScript 中檢查字符串

          七爪源碼:如何在 JavaScript 中檢查字符串是否僅包含數字

          解如何在 JavaScript 中輕松檢查字符串是否僅包含數字。 匹配包含由字符分隔的數字的字符串。

          要檢查字符串是否僅包含 JavaScript 中的數字,請在此正則表達式上調用 test() 方法:^\d+$。 如果字符串僅包含數字,則 test() 方法將返回 true。 否則,它將返回 false。

          例如:

          function containsOnlyNumbers(str) {
            return /^\d+$/.test(str);
          }console.log(containsOnlyNumbers('HTML5')); // false
          console.log(containsOnlyNumbers('1234')); // true
          console.log(containsOnlyNumbers('3 bananas')); // false

          RegExp test() 方法搜索正則表達式和字符串之間的匹配項。

          / 和 / 字符用于開始和結束正則表達式。

          ^ 字符標記字符串輸入的開始,$ 字符標記字符串的結束。

          \d 模式匹配字符串中的任何數字 (0 - 9)。

          在 \d 之后添加 + 字符會使正則表達式匹配一次或多次出現的 \d 模式。

          因此,正則表達式匹配一個以連續數字序列開頭和結尾的字符串。

          我們可以使用 [0-9] 模式來匹配數字。 此模式匹配 0 到 9 之間的任何數字字符。

          function containsOnlyNumbers(str) {
            return /^[0-9]+$/.test(str);
          }console.log(containsOnlyNumbers('HTML5')); // false
          console.log(containsOnlyNumbers('1234')); // true
          console.log(containsOnlyNumbers('3 bananas')); // false

          您可能會發現 [0-9] 比 \d 更具可讀性,尤其是在您對正則表達式中的特殊字符不是很熟悉的情況下。


          匹配包含由字符分隔的數字的字符串

          有時我們希望匹配數字可能由特定字符(例如空格或逗號)分隔的字符串。

          function containsOnlyNumbers(str) {
            return /^(\d+,)*(\d+)$/.test(str);
          }console.log(containsOnlyNumbers('123456789')); // true (separator not required)
          console.log(containsOnlyNumbers('123,456,789')); // true
          console.log(containsOnlyNumbers('123-456-789')); // false

          我們使用這種格式的正則表達式來做到這一點:^(\d+{ch})*(\d+)$,其中 {ch} 是分隔數字的字符。

          所以我們可以使用一個非常相似的正則表達式來匹配一個只包含用連字符分隔的數字的字符串:

          function containsOnlyNumbers(str) {
            return /^(\d+-)*(\d+)$/.test(str);
          }console.log(containsOnlyNumbers('123456789')); // true
          console.log(containsOnlyNumbers('123,456,789')); // false
          console.log(containsOnlyNumbers('123-456-789')); // true

          或空格:

          function containsOnlyNumbers(str) {
            return /^(\d+ )*(\d+)$/.test(str);
          }console.log(containsOnlyNumbers('123456789')); // true
          console.log(containsOnlyNumbers('123 456 789')); // true
          console.log(containsOnlyNumbers('123-456-789')); // false

          提示:如果您遇到過帶有難以理解的模式的正則表達式,來自 MDN 文檔的正則表達式備忘單可能會有所幫助。

          像以前一樣,我們可以使用 [0-9] 代替 \d 來表示正則表達式:

          function containsOnlyNumbers(str) {
            return /^([0-9]+-)*([0-9]+)$/.test(str);
          }console.log(containsOnlyNumbers('123456789')); // true
          console.log(containsOnlyNumbers('123,456,789')); // false
          console.log(containsOnlyNumbers('123-456-789')); // true


          關注七爪網,獲取更多APP/小程序/網站源碼資源!

          TML 段落

          段落是通過 <p> 標簽定義的。

          實例

          [demo]

          <html>

          <head>

          <meta charset="UTF-8">

          </head>

          <body>

          <p>這是段落。</p>

          <p>這是段落。</p>

          <p>這是段落。</p>

          <p>段落元素由 p 標簽定義。</p>

          </body>

          </html>

          [/demo]

          注釋:瀏覽器會自動地在段落的前后添加空行。(<p> 是塊級元素)

          提示:使用空的段落標記 <p></p> 去插入一個空行是個壞習慣。用 <br /> 標簽代替它!(但是不要用 <br /> 標簽去創建列表。不要著急,您將在稍后的篇幅學習到 HTML 列表。)

          不要忘記結束標簽

          即使忘了使用結束標簽,大多數瀏覽器也會正確地將 HTML 顯示出來:

          實例

          [demo]

          <html>

          <head>

          <meta charset="UTF-8">

          </head>

          <body>

          <p>This is a paragraph.

          <p>This is a paragraph.

          <p>This is a paragraph.

          <p>不要忘記關閉你的 HTML 標簽!</p>

          </body>

          </html>

          [/demo]

          上面的例子在大多數瀏覽器中都沒問題,但不要依賴這種做法。忘記使用結束標簽會產生意想不到的結果和錯誤。

          注釋:在未來的 HTML 版本中,不允許省略結束標簽。

          提示:通過結束標簽來關閉 HTML 是一種經得起未來考驗的 HTML 編寫方法。清楚地標記某個元素在何處開始,并在何處結束,不論對您還是對瀏覽器來說,都會使代碼更容易理解。

          HTML 折行

          如果您希望在不產生一個新段落的情況下進行換行(新行),請使用 <br /> 標簽:

          [demo]

          <html>

          <head>

          <meta charset="UTF-8">

          </head>

          <body>

          <p>

          To break<br />lines<br />in a<br />paragraph,<br />use the br tag.

          </p>

          </body>

          </html>

          [/demo]

          <br /> 元素是一個空的 HTML 元素。由于關閉標簽沒有任何意義,因此它沒有結束標簽。

          <br> 還是 <br />

          您也許發現 <br> 與 <br /> 很相似。

          在 XHTML、XML 以及未來的 HTML 版本中,不允許使用沒有結束標簽(閉合標簽)的 HTML 元素。

          即使 <br> 在所有瀏覽器中的顯示都沒有問題,使用 <br /> 也是更長遠的保障。

          HTML 輸出 - 有用的提示

          我們無法確定 HTML 被顯示的確切效果。屏幕的大小,以及對窗口的調整都可能導致不同的結果。

          對于 HTML,您無法通過在 HTML 代碼中添加額外的空格或換行來改變輸出的效果。

          當顯示頁面時,瀏覽器會移除源代碼中多余的空格和空行。所有連續的空格或空行都會被算作一個空格。需要注意的是,HTML 代碼中的所有連續的空行(換行)也被顯示為一個空格。

          [demo]

          <html>

          <head>

          <meta charset="UTF-8">

          </head>

          <body>

          <h1>春曉</h1>

          <p>

          春眠不覺曉,

          處處聞啼鳥。

          夜來風雨聲,

          花落知多少。

          </p>

          <p>注意,瀏覽器忽略了源代碼中的排版(省略了多余的空格和換行)。</p>

          </body>

          </html>

          [/demo]

          (這個例子演示了一些 HTML 格式化方面的問題)

          HTML 標簽參考手冊

          標簽 描述

          <p> 定義段落。

          <br /> 插入單個折行(換行)。

          HTML 可定義很多供格式化輸出的元素,比如粗體和斜體字。

          下面有很多例子,您可以親自試試:

          HTML 文本格式化實例

          文本格式化

          [demo]

          <html>

          <head>

          <meta charset="UTF-8">

          </head>

          <body>

          <b>This text is bold</b>

          <br />

          <strong>This text is strong</strong>

          <br />

          <big>This text is big</big>

          <br />

          <em>This text is emphasized</em>

          <br />

          <i>This text is italic</i>

          <br />

          <small>This text is small</small>

          <br />

          This text contains

          <sub>subscript</sub>

          <br />

          This text contains

          <sup>superscript</sup>

          </body>

          </html>

          [/demo]

          預格式文本

          [demo]

          <html>

          <head>

          <meta charset="UTF-8">

          </head>

          <body>

          <pre>

          這是

          預格式文本。

          它保留了 空格

          和換行。

          </pre>

          <p>pre 標簽很適合顯示計算機代碼:</p>

          <pre>

          for i=1 to 10

          print i

          next i

          </pre>

          </body>

          </html>

          [/demo]

          “計算機輸出”標簽

          [demo]

          <html>

          <head>

          <meta charset="UTF-8">

          </head>

          <body>

          <code>Computer code</code>

          <br />

          <kbd>Keyboard input</kbd>

          <br />

          <tt>Teletype text</tt>

          <br />

          <samp>Sample text</samp>

          <br />

          <var>Computer variable</var>

          <br />

          <p>

          <b>注釋:</b>這些標簽常用于顯示計算機/編程代碼。

          </p>

          </body>

          </html>

          [/demo]

          地址

          [demo]

          <!DOCTYPE html>

          <html>

          <head>

          <meta charset="UTF-8">

          </head>

          <body>

          <address>

          Written by <a href="mailto:webmaster@example.com">Donald Duck</a>.<br>

          Visit us at:<br>

          Example.com<br>

          Box 564, Disneyland<br>

          USA

          </address>

          </body>

          </html>

          [/demo]

          縮寫和首字母縮寫

          [demo]

          <html>

          <head>

          <meta charset="UTF-8">

          </head>

          <body>

          <abbr title="etcetera">etc.</abbr>

          <br />

          <acronym title="World Wide Web">WWW</acronym>

          <p>在某些瀏覽器中,當您把鼠標移至縮略詞語上時,title 可用于展示表達的完整版本。</p>

          <p>僅對于 IE 5 中的 acronym 元素有效。</p>

          <p>對于 Netscape 6.2 中的 abbr 和 acronym 元素都有效。</p>

          </body>

          </html>

          [/demo]

          文字方向

          [demo]

          <html>

          <head>

          <meta charset="UTF-8">

          </head>

          <body>

          <p>

          如果您的瀏覽器支持 bi-directional override (bdo),下一行會從右向左輸出 (rtl);

          </p>

          <bdo dir="rtl">

          Here is some Hebrew text

          </bdo>

          </body>

          </html>

          [/demo]

          塊引用

          [demo]

          <html>

          <head>

          <meta charset="UTF-8">

          </head>

          <body>

          這是長的引用:

          <blockquote>

          這是長的引用。這是長的引用。這是長的引用。這是長的引用。這是長的引用。這是長的引用。這是長的引用。這是長的引用。這是長的引用。這是長的引用。這是長的引用。

          </blockquote>

          這是短的引用:

          <q>

          這是短的引用。

          </q>

          <p>

          使用 blockquote 元素的話,瀏覽器會插入換行和外邊距,而 q 元素不會有任何特殊的呈現。

          </p>

          </body>

          </html>

          [/demo]

          刪除字效果和插入字效果

          [demo]

          <html>

          <head>

          <meta charset="UTF-8">

          </head>

          <body>

          <p>一打有 <del>二十</del> <ins>十二</ins> 件。</p>

          <p>大多數瀏覽器會改寫為刪除文本和下劃線文本。</p>

          <p>一些老式的瀏覽器會把刪除文本和下劃線文本顯示為普通文本。</p>

          </body>

          </html>

          [/demo]

          如何查看 HTML 源碼

          您是否有過這樣的經歷,當你看到一個很棒的站點,你會很想知道開發人員是如何將它實現的?

          你有沒有看過一些網頁,并且想知道它是如何做出來的呢?

          要揭示一個網站的技術秘密,其實很簡單。單擊瀏覽器的“查看”菜單,選擇“查看源文件”即可。隨后你會看到一個彈出的窗口,窗口內就是實際的 HTML 代碼。

          文本格式化標簽

          標簽 描述

          <b> 定義粗體文本。

          <big> 定義大號字。

          <em> 定義著重文字。

          <i> 定義斜體字。

          <small> 定義小號字。

          <strong> 定義加重語氣。

          <sub> 定義下標字。

          <sup> 定義上標字。

          <ins> 定義插入字。

          <del> 定義刪除字。

          <s> 不贊成使用。使用 <del> 代替。

          <strike> 不贊成使用。使用 <del> 代替。

          <u> 不贊成使用。使用樣式(style)代替。

          “計算機輸出”標簽

          標簽 描述

          <code> 定義計算機代碼。

          <kbd> 定義鍵盤碼。

          <samp> 定義計算機代碼樣本。

          <tt> 定義打字機代碼。

          <var> 定義變量。

          <pre> 定義預格式文本。

          <listing> 不贊成使用。使用 <pre> 代替。

          <plaintext> 不贊成使用。使用 <pre> 代替。

          <xmp> 不贊成使用。使用 <pre> 代替。

          引用、引用和術語定義

          標簽 描述

          <abbr> 定義縮寫。

          <acronym> 定義首字母縮寫。

          <address> 定義地址。

          <bdo> 定義文字方向。

          <blockquote> 定義長的引用。

          <q> 定義短的引用語。

          <cite> 定義引用、引證。

          <dfn> 定義一個定義項目。

          ue 模板的編譯到渲染,結合源碼的分析介紹從 template 到 AST,到 VNode(虛擬 DOM),再將 VNode 掛載渲染成真是的 DOM。本文從思路流程方面分析模板編譯的整個過程,不著重一字一句的具體代碼解讀。這個過程的代碼比較機械枯燥,可以參看文末的參考鏈接。


          從 vue 模板到渲染成 dom,整個流程如圖:

          整體而言,Vue 的處理方式大致分為三步:

          • 將模板進行解析,得到一棵抽象語法樹 AST(parse / optimize)
          • 根據抽象語法樹 AST 得到虛擬 DOM 樹(generate / render)
          • 將虛擬 DOM 渲染為真實的 DOM

          注:抽象語法樹(AST)是指對源碼進行解析后形成的樹狀的語法結構。通俗地理解,有了 AST 以后,后續處理可以直接在樹結構上進行,不用再處理源碼中的各種書寫格式、括號優先級等問題。

          實現編譯的核心源碼入口:

          // src/compiler/index.js
          export const createCompiler=createCompilerCreator(function baseCompile (
            template: string,
            options: CompilerOptions
          ): CompiledResult {
            const ast=parse(template.trim(), options)
            if (options.optimize !==false) {
              optimize(ast, options)
            }
            const code=generate(ast, options)
            return {
              ast,
              render: code.render,
              staticRenderFns: code.staticRenderFns
            }
          })
          

          步驟一 將模板進行解析為抽象語法樹 AST

          parse() 方法是將源碼轉換成 AST 的方法,它的核心是調用 parseHTML() 方法解析。相關源碼位于 src/compiler/parser/index.js。

          parseHTML() 做的事就是從頭掃描 HTML 字符串,按一定的規則判斷當前字符是什么(標簽、屬性、文本、注釋等等),并調用相應的回調方法,從而完成 HTML 字符串的解析,并返回 AST 樹。

          示例:

          <!-- 模板 template -->
          <div class="counter">
            <div>{{ count }}</div>
            <button @click="increment">+</button>
          </div>
          

          經過 parse / parseHTML 解析后生成的 AST 是這樣的:

          {
              attrsList: [],
              attrsMap: {
                  class: "counter"
              },
              children: [{
                  attrsList: [],
                  attrsMap: {},
                  children: [{
                      end: 37,
                      expression: "_s(count)",
                      start: 26,
                      text: "{{ count }}",
                      tokens: [{
                          @binding: "count"
                      }]
                  }],
                  end: 43,
                  parent: {...},
                  plain: true,
                  rawAttrsMap: {},
                  start: 21,
                  tag: "div",
                  type: 1,
              },{
                  attrsList: [{
                      end: 69,
                      name: "@click",
                      start: 51,
                      value: "increment",
                  }],
                  attrsMap:{
                      @click: "increment",
                  },
                  children: [{
                      end: 71,
                      start: 70,
                      text: "+",
                      type: 3  // text
                  }],
                  end: 80,
                  events:{
                      click:{
                          dynamic: false,
                          end: 69,
                          start: 51,
                          value: "increment"
                      }
                  },
                  hasBindings: true,
                  parent: {...},
                  plain: false,
                  rawAttrsMap:{
                      @click:{
                          end: 69,
                          name: "@click",
                          start: 51,
                          value: "increment",
                      }
                  },
                  start: 43,
                  tag: "button",
                  type: 1
              }],
              end: 86,
              parent: undefined,
              plain: false,
              rawAttrsMap:{
                  class:{
                      end: 20,
                      name: "class",
                      start: 5,
                      value: "counter"
                  }
              }
              start: 0,
              staticClass: "\"counter\"",
              tag: "div",
              type: 1
          }
          

          這一步之后,進行 optimize() 處理。

          optimize() 是對 AST 進行優化的過程,以提升后續渲染性能。這個方法位于 src/compiler/optimizer.js,作用是分析出純靜態的 DOM(不含表達式,可以直接渲染的 DOM),將它們放入常量中,在后續 patch 的過程中可以忽略它們。

          optimize() 處理邏輯,當一個元素有表達式時肯定就不是靜態的,當一個元素是文本節點時,肯定是靜態的,如果子元素是非靜態的,則父元素也是非靜態的。

          optimize() 處理后的 AST:

          {
              attrsList: [],
              attrsMap: {
                  class: "counter"
              },
              children: [{
                  attrsList: [],
                  attrsMap: {},
                  children: [{
                      end: 37,
                      expression: "_s(count)",
                      start: 26,
                      // 看這里
                      static: false,
                      text: "{{ count }}",
                      tokens: [{
                          @binding: "count"
                      }]
                  }],
                  end: 43,
                  parent: {...},
                  plain: true,
                  rawAttrsMap: {},
                  // 看這里
                  static: false,
                  staticRoot: false,
                  start: 21,
                  tag: "div",
                  type: 1,
              },{
                  attrsList: [{
                      end: 69,
                      name: "@click",
                      start: 51,
                      value: "increment",
                  }],
                  attrsMap:{
                      @click: "increment",
                  },
                  children: [{
                      end: 71,
                      start: 70,
                      // 看這里
                      static: true,
                      text: "+",
                      type: 3
                  }],
                  end: 80,
                  events:{
                      click:{
                          dynamic: false,
                          end: 69,
                          start: 51,
                          value: "increment"
                      }
                  },
                  hasBindings: true,
                  parent: {...},
                  plain: false,
                  rawAttrsMap:{
                      @click:{
                          end: 69,
                          name: "@click",
                          start: 51,
                          value: "increment",
                      }
                  },
                  start: 43,
                  // 看這里
                  static: false,
                  staticRoot: false,
                  tag: "button",
                  type: 1
              }],
              end: 86,
              parent: undefined,
              plain: false,
              rawAttrsMap:{
                  class:{
                      end: 20,
                      name: "class",
                      start: 5,
                      value: "counter"
                  }
              }
              start: 0,
              // 看這里
              static: false,
              staticClass: "\"counter\"",
              staticRoot: false,
              tag: "div",
              type: 1
          }
          

          步驟二 將 AST 樹轉化為 VNode (虛擬 DOM 樹)

          實現編譯的核心源碼入口:

          // src/compiler/index.js
          export const createCompiler=createCompilerCreator(function baseCompile (
            template: string,
            options: CompilerOptions
          ): CompiledResult {
            const ast=parse(template.trim(), options)
            if (options.optimize !==false) {
              optimize(ast, options)
            }
            const code=generate(ast, options)
            return {
              ast,
              render: code.render,
              staticRenderFns: code.staticRenderFns
            }
          })
          

          在 parse() 和 optimize() 運行完之后,執行 generate():

          // src\compiler\codegen\index.js
          export function generate (
            ast: ASTElement | void,
            options: CompilerOptions
          ): CodegenResult {
            const state=new CodegenState(options)
            const code=ast ? genElement(ast, state) : '_c("div")'
            return {
              render: `with(this){return ${code}}`,
              staticRenderFns: state.staticRenderFns
            }
          }
          
          export function genElement (el: ASTElement, state: CodegenState): string {
            //對一些標簽屬性的處理
            if (el.staticRoot && !el.staticProcessed) {
              return genStatic(el, state)
            } else if (el.once && !el.onceProcessed) {
              return genOnce(el, state) // 處理v-once
            } else if (el.for && !el.forProcessed) {
              return genFor(el, state) // 處理v-for
            } else if (el.if && !el.ifProcessed) {
              return genIf(el, state)
            } else if (el.tag==='template' && !el.slotTarget) {
              return genChildren(el, state) || 'void 0'
            } else if (el.tag==='slot') {
              return genSlot(el, state)
            } else {
              // component or element
              let code
              //組件的處理
              if (el.component) {
                code=genComponent(el.component, el, state)
              } else {
                //核心的body部分
                //1、生成節點的數據對象data的字符串
                const data=el.plain ? undefined : genData(el, state)
                //2、查找其子節點,生成子節點的字符串
                const children=el.inlineTemplate ? null : genChildren(el, state, true)
                //3、將tag,data,children拼裝成字符串
                code=`_c('${el.tag}'${
                  data ? `,${data}` : '' // data
                }${
                  children ? `,${children}` : '' // children
                })`
              }
              // module transforms
              for (let i=0; i < state.transforms.length; i++) {
                code=state.transforms[i](el, code)
              }
              return code
            }
          

          generate() 返回的 render 表達式結構像這樣:

          _c(
            // 1、標簽
            'div',
            //2、模板相關屬性的數據對象 
            {
             ...  
            },
            //3、子節點,循環其模型
            [
              _c(...)
            ]
          
          <template>
            <div id="app">
              <h1>Hello</h1>
              <span>{{message}}</span>
            </div>
          </template>
          // 上述dom 對應的虛擬 render 表達式
          with(this){
            return _c('div',{
              attrs:{"id":"app"}
            },
            [
              _c('h1',[
                  _v("Hello")
              ]),
              _c('span',[
                  _v(_s(message))
              ])
            ])
          }
          

          示例中出現較多的方法是_c(),即 vm._c(),這個方法本質是 createElement() 的封裝(源碼在src\core\instance\render.js)。除此之外,在 render() 方法中,還有可能出現_v()、_s()、_h()、_m() 等諸多輔助方法。

          // src/core/instance/render-helpers/index.js
          export function installRenderHelpers (target: any) {
            target._o=markOnce // 處理 v-once
            target._n=toNumber // 處理修飾符.number  <input v-model.number="age" type="number">
            target._s=toString // ......
            target._l=renderList
            target._t=renderSlot // 處理 slot
            target._q=looseEqual
            target._i=looseIndexOf
            target._m=renderStatic
            target._f=resolveFilter
            target._k=checkKeyCodes
            target._b=bindObjectProps
            target._v=createTextVNode
            target._e=createEmptyVNode
            target._u=resolveScopedSlots
            target._g=bindObjectListeners
          

          在后續組件進行掛載時,render 方法會被調用,這些輔助方法會將 render 轉化為虛擬 DOM(VNode)。

          虛擬 DOM(VNode)是什么樣的?

          可看一下 VNode 類:

          export default class VNode {
            tag: string | void;
            data: VNodeData | void;
            children: ?Array<VNode>;
            text: string | void;
            elm: Node | void;
            ns: string | void;
            context: Component | void; // rendered in this component's scope
            key: string | number | void;
            componentOptions: VNodeComponentOptions | void;
            componentInstance: Component | void; // component instance
            parent: VNode | void; // component placeholder node
          
            // strictly internal
            raw: boolean; // contains raw HTML? (server only)
            isStatic: boolean; // hoisted static node
            isRootInsert: boolean; // necessary for enter transition check
            isComment: boolean; // empty comment placeholder?
            isCloned: boolean; // is a cloned node?
            isOnce: boolean; // is a v-once node?
            asyncFactory: Function | void; // async component factory function
            asyncMeta: Object | void;
            isAsyncPlaceholder: boolean;
            ssrContext: Object | void;
            fnContext: Component | void; // real context vm for functional nodes
            fnOptions: ?ComponentOptions; // for SSR caching
            devtoolsMeta: ?Object; // used to store functional render context for devtools
            fnScopeId: ?string; // functional scope id support
          
            constructor (
              tag?: string,
              data?: VNodeData,
              children?: ?Array<VNode>,
              text?: string,
              elm?: Node,
              context?: Component,
              componentOptions?: VNodeComponentOptions,
              asyncFactory?: Function
            ) {
              this.tag=tag
              this.data=data
              this.children=children
              this.text=text
              this.elm=elm
              this.ns=undefined
              this.context=context
              this.fnContext=undefined
              this.fnOptions=undefined
              this.fnScopeId=undefined
              this.key=data && data.key
              this.componentOptions=componentOptions
              this.componentInstance=undefined
              this.parent=undefined
              this.raw=false
              this.isStatic=false
              this.isRootInsert=true
              this.isComment=false
              this.isCloned=false
              this.isOnce=false
              this.asyncFactory=asyncFactory
              this.asyncMeta=undefined
              this.isAsyncPlaceholder=false
            }
          
            // DEPRECATED: alias for componentInstance for backwards compat.
            /* istanbul ignore next */
            get child (): Component | void {
              return this.componentInstance
            }
          }
          

          說白了,虛擬 DOM 就是一種使用 JS 數據結構模擬 DOM 元素及其關系的方法。

          DOM 操作之所以慢,主要有兩方面原因:

          • DOM 操作屬于使用 JavaScript 調用瀏覽器提供的接口的過程,并不都是在 JS 引擎中直接完成,中間有不少的性能開銷
          • DOM 本身非常龐大,屬性和方法極多,構建、銷毀、修改都有比較大的性能開銷

          使用 VNode 不再需要關注 DOM 元素所有的屬性和方法,僅僅只需要關注元素類型、屬性、子內容等即可,因此 VNode 可以解決上述兩個導致 DOM 操作慢的問題。

          除此之外,VNode 元素之間也會形成和 DOM 樹類似的樹狀結構,開發者可以將 DOM 元素的對比、變更提前到 VNode 層面去完成,直到 VNode 完成變更以后,計算出發生變動的 VNode,最后再根據這些 VNode 去進行真實 DOM 元素的變更。這樣就可以大大減少需要進行的 DOM 操作,從而提升性能。

          虛擬 DOM(VNode) 因為是純 JavaScript 數據結構,因此具有很好的跨平臺性。

          步驟三 掛載,將虛擬 DOM 渲染為真實的 DOM

          Vue.prototype.

          mount定義在platforms/web/runtime/index.js,mount 本質上是調用了 mountComponent()

          // core/instance/lifecycle.js
          export function mountComponent (
            vm: Component,
            el: ?Element,
            hydrating?: boolean
          ): Component {
            // 省略一大段對render的判斷
          
            callHook(vm, 'beforeMount')
          
            let updateComponent
            updateComponent=()=> {
              vm._update(vm._render(), hydrating)
            }
          
            // 定義Watcher
            new Watcher(vm, updateComponent, noop, {
              before () {
                if (vm._isMounted && !vm._isDestroyed) {
                  callHook(vm, 'beforeUpdate')
                }
              }
            }, true)
          
            // manually mounted instance, call mounted on self
            // mounted is called for render-created child components in its inserted hook
            if (vm.$vnode==null) {
              vm._isMounted=true
              callHook(vm, 'mounted')
            }
            return vm
          }
          

          vm._update() 的第一個參數 render 方法返回的虛擬 DOM,其負責將虛擬 DOM 渲染到真實的 DOM 中。

          // core/instance/lifecycle.js
          // _update() 主要源碼
          const prevVnode=vm._vnode
          vm._vnode=vnode
          if (!prevVnode) {
            // initial render
            vm.$el=vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */)
          } else {
            // updates
            vm.$el=vm.__patch__(prevVnode, vnode)
          }
          

          這段代碼首先判斷了 vm._vnode 是否存在,如果不存在,則說明這個組件是初次渲染,否則說明之前渲染過,這一次渲染是需要進行更新。針對這兩種情況,分別用不同的參數調用了 __patch__() 方法:

          • 如果是初次渲染,第一個參數是真實的 DOM 元素,后續使用 createElm() 根據虛擬 DOM 創建新 DOM。
          • 如果不是初次渲染,第一個參數是前一次渲染的虛擬 DOM,后續調用 patchVnode() 方法,進入虛擬 DOM 對比和更新的流程

          最底層的處理邏輯,還是通過原始的 dom 操作方法 insertBefore、appendChild 等處理渲染的。

          作者:越谷
          鏈接:https://juejin.cn/post/7380241307116748810
          來源:稀土掘金


          主站蜘蛛池模板: 日本人的色道www免费一区| 日本一区二区三区精品中文字幕| 国产精品一区二区四区| 久久精品无码一区二区日韩AV| 亚洲一区二区成人| 国产免费伦精品一区二区三区| 国产成人一区二区三区| 日韩一区二区三区无码影院| 亚洲高清偷拍一区二区三区| 国模精品一区二区三区视频| 亚洲变态另类一区二区三区| 亚洲成在人天堂一区二区| 中文字幕精品亚洲无线码一区应用| 成人精品一区二区三区校园激情| 国产精品夜色一区二区三区| 精品一区二区三区在线成人| 亚洲V无码一区二区三区四区观看| 国产精品免费大片一区二区| 一区二区三区视频网站| 天堂不卡一区二区视频在线观看 | 久久一本一区二区三区| 亚洲熟妇av一区二区三区| 久久国产精品免费一区| 香蕉视频一区二区| 国产亚洲情侣一区二区无码AV | 乱子伦一区二区三区| 制服丝袜一区在线| 精品亚洲AV无码一区二区三区| 无码日韩精品一区二区免费暖暖| 久久久无码精品国产一区| 亚洲日本精品一区二区| 亚洲精品一区二区三区四区乱码| 老熟妇仑乱一区二区视頻| 性色AV一区二区三区天美传媒| 久久精品无码一区二区三区免费| 国精产品一区一区三区有限公司| 国产一区韩国女主播| 色噜噜AV亚洲色一区二区| 亚洲av无码不卡一区二区三区 | 国产福利电影一区二区三区久久老子无码午夜伦不 | 亚洲福利电影一区二区?|