Vue 系列一 之 Vue 基礎

jsliang發表於2019-01-13

Create by jsliang on 2018-11-8 13:34:30
Recently revised in 2019-1-12 19:23:17

Hello 小夥伴們,如果覺得本文還不錯,記得給個 star , 你們的 star 是我學習的動力!GitHub 地址

推薦通過 目錄 以及使用 返回目錄 按鈕,獲得更好的閱讀體驗。

Vue 系列一 之 Vue 基礎

一 目錄

不折騰的前端,和鹹魚有什麼區別~

目錄
一 目錄
二 正文
2.1 初識 Vue
2.2 掛載資料 - data
2.3 進一步優化 el
2.4 插值表示式 - {{ }}
2.5 指令 - v-*
2.6 事件 - methods
2.7 模板 - template
  2.7.1 初識元件
  2.7.2 父子元件通訊
  2.7.3 共用元件
2.8 過濾器 - filter
  2.8.1 區域性過濾
  2.8.2 全域性過濾
2.9 監聽資料
  2.9.1 偵聽屬性 - watch
  2.9.2 計算屬性 - computed
  2.9.3 watch、computed 與 methods 對比
2.10 傳遞 DOM - slot
  2.10.1 slot 單個傳遞
  2.10.2 具名 slot
2.11 Vue 元件生命週期
  2.11.1 beforeCreate & created
  2.11.2 beforeMount & mounted
  2.11.3 beforeUpdate & updated
  2.11.4 beforeDestory & destory
  2.11.5 activated & deactivated
2.12 獲取 DOM 元素
  2.12.1 單個 DOM 元素獲取
  2.12.2 元件 DOM 元素獲取
  2.12.3 Vue.nextTick()
三 實戰
四 總結

二 正文

返回目錄

飲水思源:Vue 官方文件

Vue (讀音 /vjuː/,類似於 view) 是一套用於構建使用者介面的漸進式框架。與其它大型框架不同的是,Vue 被設計為可以自底向上逐層應用。Vue 的核心庫只關注檢視層,不僅易於上手,還便於與第三方庫或既有專案整合。另一方面,當與現代化的工具鏈以及各種支援類庫結合使用時,Vue 也完全能夠為複雜的單頁應用提供驅動。

學習版本:v2.5.21
編寫時間:2019-1-10

如版本更迭太大或者時間小夥伴們看到這篇文章太久沒更新,小夥伴們請檢視 Vue 官方文件學習最新的 Vue。

2.1 初識 Vue

返回目錄

那麼,Vue 是怎麼折騰的呢?

話不多說,我們直接來看程式碼實現:

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  
  <title>Vue 學習</title>

</head>

<body>

  <!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裡操作到實際渲染 -->
  <!-- 簡單理解為 jQuery 的拼接字串(並不全是) -->
  <div id="app"></div>

  <!-- 1. 引用 Vue -->
  <!-- Vue CDN - 提供 Vue 服務 -->
  <script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
  <!-- Vue Router CDN - 管理路由 -->
  <script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
  <!-- Axios CDN - 呼叫介面 -->
  <script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
  
  <script>

    new Vue({
      // 3. el - 掛載目標,即渲染在哪個掛載點
      el: '#app',
      // 4. template - 模板,即渲染到掛載點的內容
      // 最外層必須有一層包裹,例如 <div>
      template: `
        <div>
          <p>Hello World</p>
        </div>
      `
    })

  </script>
</body>

</html>
複製程式碼

現在,我們解析下程式碼執行:

  1. 首先,建立一個空白的 html 模板檔案,通過 CDN 引用 Vue:

Vue 一般分兩個版本:
開發版本:開發中有友好的錯誤提示。
生產版本:上線部署使用的版本,程式碼包比較小

index.html 程式碼片段

<!-- 1. 引用 Vue -->
<!-- Vue CDN - 提供 Vue 服務 -->
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
複製程式碼
  1. 然後,我們編寫一個掛載點,即我們的 Vue,最終會在哪個 DOM 裡面進行操作:
<!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裡操作到實際渲染 -->
<!-- 簡單理解為 jQuery 的拼接字串(並不全是) -->
<div id="app"></div>
複製程式碼
  1. 最後,我們通過 New 一個 Vue 例項物件,對我們 id 為 app 的 DOM 節點進行操作:
new Vue({
  // 3. el - 掛載目標,即渲染在哪個掛載點
  el: document.getElementById('app'),
  // 4. template - 模板,即渲染到掛載點的內容。
  // 最外層必須有一層包裹,例如 <div>
  template: `
    <div>
      <p>Hello World</p>
    </div>
  `
})
複製程式碼

這樣,我們最終就顯示了 Vue 的簡單引用,是不是覺得非常簡單:

Vue 系列一 之 Vue 基礎

2.2 掛載資料 - data

返回目錄

如果 Vue 僅僅是隻有 template 這個模板裝載,那麼它跟 jQuery 就顯得沒多大差別了,下面我們使用下 Vue 的 data 進行資料渲染:

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  
  <title>Vue 學習</title>

</head>

<body>

  <!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裡操作到實際渲染 -->
  <!-- 簡單理解為 jQuery 的拼接字串(並不全是) -->
  <div id="app"></div>

  <!-- 1. 引用 Vue -->
  <!-- Vue CDN - 提供 Vue 服務 -->
  <script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
  <!-- Vue Router CDN - 管理路由 -->
  <script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
  <!-- Axios CDN - 呼叫介面 -->
  <script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
  
  <script>

    new Vue({
      // 3. el - 掛載目標,即渲染在哪個掛載點
      el: '#app',
      // 4. template - 模板,即渲染到掛載點的內容
      // 最外層必須有一層包裹,例如 <div>
      template: `
        <div>
          <p>{{ text }}</p>
        </div>
      `,
      // 5. data - 資料,即在操作中需要用到的資料
      // 可以理解為在 jQuery 中 var text = "Hello World!"
      // {{ text }} 為資料渲染到 DOM 的方式之一
      data() {
        return {
          // template 中要使用的資料
          text: 'Hello World!'
        }
      }
    })

  </script>
</body>

</html>
複製程式碼

在這裡,我們可以看到,我們在 template 中加了一個 <p> 標籤,通過 {{ text }} 形式,引入了一個叫 textdata 資料:

<p>{{ text }}</p>
複製程式碼

接著我們在 <scirpt> 中定義了 text 的內容,從而實現資料渲染:

data() {
  return {
    // template 中要使用的資料
    text: 'Hello World!'
  }
}
複製程式碼

這樣,我們就知道了,我們不僅可以通過模板 template 來渲染 <div> 標籤,我們也可以將 js 中定義的資料或者變數,通過操作 data 從而改變 html 裡面的內容。

Vue 系列一 之 Vue 基礎

2.3 進一步優化 el

返回目錄

2.1 章節 及 2.2 章節中,我們使用 el 的方式是:

el: '#app',
複製程式碼

el 掛載形式,在 Vue 內部執行機制中,它會根據你傳入的值,進行查詢:

  • 如果傳入的是 #app,那它就判斷查詢 idapp 的節點;
  • 如果傳入的是 .app,那它就查詢 classapp 的節點;
  • 如果傳入的是節點名 div,那它就查詢節點名……

大家應該清楚,這樣判斷查詢是需要時間的,多執行一個判斷都是罪惡。

所以我們可以:

el: document.getElementById('app'),
複製程式碼

這般操作,使得 Vue 直接將掛載點掛載到 id 上去,從而獲得更好的載入速度。這算是對 el 的一個小優化。

2.4 插值表示式 - {{ }}

返回目錄

如果小夥伴有點印象,應該還記得,我們在章節 2.2 中通過 {{}} 這個插值表示式的使用,在 data 中對其裡面的資料進行操作。

下面,我們進一步講解這個插值表示式 {{}} 還可以進行哪種騷操作:

  • 物件:{{ {name: 'jack'} }}
  • 字串 {{ 'Hello World!' }}
  • 布林值: {{ isTrue == -1 }}
  • 三元表示式: {{ isTrue ? '正確' : '錯誤' }}

光字面理解是不夠的,我們通過程式碼進行操作演示:

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  
  <title>Vue 學習</title>

</head>

<body>

  <!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裡操作到實際渲染 -->
  <!-- 簡單理解為 jQuery 的拼接字串(並不全是) -->
  <div id="app"></div>

  <!-- 1. 引用 Vue -->
  <!-- Vue CDN - 提供 Vue 服務 -->
  <script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
  <!-- Vue Router CDN - 管理路由 -->
  <script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
  <!-- Axios CDN - 呼叫介面 -->
  <script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
  
  <script>

    new Vue({
      // 3. el - 掛載目標,即渲染在哪個掛載點
      el: document.getElementById('app'),
      // 4. template - 模板,即渲染到掛載點的內容
      // 最外層必須有一層包裹,例如 <div>
      template: `
        <div>
          <p>{{ text }}</p>
          <p>{{ {name: 'jack'} }}</p>
          <p>{{ 'Hello World!' }}</p>
          <p>{{ isTrue == -1 }}</p>
          <p>{{ isTrue ? '真' : '假' }}</p>
        </div>
      `,
      // 5. data - 資料,即在操作中需要用到的資料
      // 可以理解為在 jQuery 中 var text = "Hello World!"
      // {{ text }} 為資料渲染到 DOM 的方式之一
      data() {
        return {
          // template 中要使用的資料
          text: 'Hello World!',
          isTrue: true
        }
      }
    })

  </script>
</body>

</html>
複製程式碼

它在瀏覽器的展示為:

Vue 系列一 之 Vue 基礎

關鍵程式碼講解:

<div>
  <!-- 賦值 text 到 <p> 標籤中 -->
  <p>{{ text }}</p>
  
  <!-- 賦值物件到標籤中 -->
  <p>{{ {name: 'jack'} }}</p>
  
  <!-- 直接賦值字串到標籤中 -->
  <p>{{ 'Hello World!' }}</p>

  <!-- 
    直接進行布林判斷,isTrue 在 data 中設定為 true,
    而 -1 轉為 布林值 是 false,所以兩者不相等
    輸出值為 false 
  -->
  <p>{{ isTrue == -1 }}</p>

  <!-- 執行三元表示式,isTrue 為 true,輸出 真 -->
  <p>{{ isTrue ? '真' : '假' }}</p>
</div>
複製程式碼

通過三元表示式的運用,我們可以做到一些判斷:陣列最後一個元素、是否動態顯示隱藏等。

2.5 指令 - v-*

返回目錄

在 Vue 中,如果單單使用 {{}} 這種插值表示式,是滿足不了我們對資料的操作慾望的。所以,Vue 以 v-ifv-bind 等形式,提供了一些對於頁面 + 資料的更為方便的操作:指令

  • v-text
  • v-html
  • v-if
  • v-else-if
  • v-else
  • v-show
  • v-bind
  • v-on
  • v-model
  • v-for

這裡採用一個頁面展示所有指令,如果小夥伴想逐個詳細瞭解指令,推薦去官網檢視學習:Vue 指令

那麼,上面的指令都是怎麼使用的呢?這裡通過一個 index.html 及一張圖向大家演示其基本用法:

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  
  <title>Vue 學習</title>

  <style>
    /* 顏色樣式:紅、綠、藍 */
    .color-red {
      color: red;
    }

    .color-blue {
      color: blue;
    }

    .color-green {
      color: green;
    }
  </style>

</head>

<body>

  <!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裡操作到實際渲染 -->
  <!-- 簡單理解為 jQuery 的拼接字串(並不全是) -->
  <div id="app"></div>

  <!-- 1. 引用 Vue -->
  <!-- Vue CDN - 提供 Vue 服務 -->
  <script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
  <!-- Vue Router CDN - 管理路由 -->
  <script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
  <!-- Axios CDN - 呼叫介面 -->
  <script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
  
  <script>

    new Vue({
      // 3. el - 掛載目標,即渲染在哪個掛載點
      el: document.getElementById('app'),
      // 4. template - 模板,即渲染到掛載點的內容
      // 最外層必須有一層包裹,例如 <div>
      template: `
        <div>

          <p>v-text 演示</p>
          <p v-text='vTextOrHtml'></p>

          <br/>

          <p>v-html 演示</p>
          <p v-html='vTextOrHtml'></p>

          <br/>

          <p>v-if -> v-else-if -> v-else 演示</p>
          <p v-if='vIf == 1'>Hello v-If</p>
          <p v-else-if='vIf == 2'>Hello v-else-if</p>
          <p v-else>Hello v-else</p>

          <br/>

          <p>v-show 演示</p>
          <p v-show='isTrue'></p>

          <br/>

          <p>v-bind:××× -> :××× 演示</p>
          <input v-bind:value="vBind" v-bind:class="colorRed" type="text"/>
          <input v-bind:other1="other1" :other2="other2" :other3=" 'other3' " value="Hello :屬性值" type="text"/><br/>

          <br/>

          <p>v-on:click -> @click 演示</p>
          <button v-on:click=" vBind= 'Hello v-on:click' ">v-on:click - 點選直接改變 vBind 的值</button><br>
          <button @click="changevBindValue">v-on:click - 點選通過事件改變 vBind 的值</button><br>

          <br/>

          <p>v-model 演示</p>
          <input v-model="vModel" type="text" />
          <p>{{ vModel }}</p>

          <br/>

          <p>v-for 演示</p>
          <ul v-for="(item, index) in vFor" :class="item.classStyle">
            <li>{{index+1}}. {{item.name}} - {{item.age}}</li>
          </ul>

        </div>
      `,
      // 5. data - 資料,即在操作中需要用到的資料
      // 可以理解為在 jQuery 中 var text = "Hello World!"
      // {{ text }} 為資料渲染到 DOM 的方式之一
      data() {
        return {
          // template 中要使用的資料

          // v-text 及 v-html 使用資料
          vTextOrHtml: '<span style="color: red">我是紅的</p>',
          
          // v-if 使用資料
          vIf: 2,
          
          // v-show 使用資料
          isTrue: false,
          
          // v-bind 使用資料
          vBind: "Hello v-bind",
          
          // v-bind 通過動態繫結 class 修改樣式
          colorRed: 'color-red',
          
          // v-bind 的 :屬性 的使用形式
          other1: 'other1',
          
          // 同上
          other2: 'other2',
          
          // v-model 使用資料
          vModel: 'Hello v-model',
          
          // v-for 使用資料
          vFor: [{
              name: '張三', // 姓名
              age: 22, // 年齡
              classStyle: "color-red" // 樣式
            },
            {
              name: '李四',
              age: 23,
              classStyle: "color-blue"
            },
            {
              name: '王五',
              age: 24,
              classStyle: "color-green"
            }
          ]
          
        }
      }
    })

  </script>
</body>

</html>
複製程式碼

我們看下頁面:

Vue 系列一 之 Vue 基礎

在這裡,我們對程式碼進行下講解:

<div>
  <!-- 
    1. v-html
    這裡直接將 vTextOrHtml 中的文字
    當成 string 渲染到頁面中去
   -->
  <p v-text='vTextOrHtml'></p>

  <br/>

  <!-- 
    2. v-html
    這裡在渲染 vTextOrHtml 的過程中,
    如果遇到標籤,則對標籤頁進行渲染 
   -->
  <p v-html='vTextOrHtml'></p>

  <br/>

  <!-- 
    3. v-if/v-else-if/v-if
    判斷 data 中 vIf 的值是多少,
    這裡有三種情況:v-if、v-else-if、v-else。
    如果專案中有更多情況,則再新增 v-else-if 即可
  -->
  <p v-if='vIf == 1'>Hello v-If</p>
  <p v-else-if='vIf == 2'>Hello v-else-if</p>
  <p v-else>Hello v-else</p>

  <br/>

  <!-- 
    4. v-show
    判斷 isTrue 是真還是假,
    它不同於 v-if 的方面是:
    v-if 如果是假,則在 Element 中沒有渲染
    v-show 如果是假,則該標籤為 display: none
  -->
  <p v-show='isTrue'></p>

  <br/>

  <!-- 
    5. v-bind
    v-bind 有兩種格式:
    1. v-bind:value - 全寫
    2. :value - 簡寫
    我們還可以通過 v-bind:class 來動態賦值
    v-bind:other1="other1" 在頁面中顯示就是:
    <input other1="other1" />>
   -->
  <input v-bind:value="vBind" v-bind:class="colorRed" type="text"/>
  <input v-bind:other1="other1" :other2="other2" :other3=" 'other3' " value="Hello :屬性值" type="text"/><br/>

  <br/>

  <!-- 
    6. v-on
    v-on:click 有兩種格式:
    1. v-on:click - 全寫
    2. @click - 簡寫
    v-on:click 除了可以直接在裡面寫表示式,還可以填寫方法
   -->
  <button v-on:click=" vBind= 'Hello v-on:click' ">v-on:click - 點選直接改變 vBind 的值</button><br>
  <button @click="changevBindValue">v-on:click - 點選通過事件改變 vBind 的值</button><br>

  <br/>

  <!-- 
    7. v-model
    v-model 是雙向資料繫結,
    在這裡,上面 input 的修改
    會影響到下面 p 顯示的內容
   -->
  <input v-model="vModel" type="text" />
  <p>{{ vModel }}</p>

  <br/>

  <!-- 
    8. v-for
    v-for 迴圈體遍歷輸出
   -->
  <ul v-for="(item, index) in vFor" :class="item.classStyle">
    <li>{{index+1}}. {{item.name}} - {{item.age}}</li>
  </ul>
</div>
複製程式碼

v-bind 和 v-model 的區別:

  • v-bind:將 Vue 中的資料同步到頁面,即該值大部分用於前端向瀏覽器傳固定資料。v-bind 可以給任何屬性賦值,是從 Vue 到頁面的單向資料流,即 Vue -> html。
  • v-model:雙向資料繫結,前端向瀏覽器傳資料,使用者操作瀏覽器的更改前端可以察覺到。v-model 只能給具有 value 屬性的元素進行雙向資料繫結(必須使用的是有 value 屬性的元素),即 Vue -> html -> Vue

關於 Vue 的指令,這裡我們先對它進行了個全面的簡單瞭解,知道它是如何使用的。
想詳細學習的小夥伴,記得前往官方文件:Vue 文件

2.6 事件 - methods

返回目錄

在上一章 2.5 中,我們通過在 button 中使用 v-on:click 時,給它繫結了事件方法。

但是,在 2.5 中,我們大體講述了事件方法的使用,但是我們只是一知半解。

在這裡,我們抽取出來做下講解:

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  
  <title>Vue 學習</title>

</head>

<body>

  <!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裡操作到實際渲染 -->
  <!-- 簡單理解為 jQuery 的拼接字串(並不全是) -->
  <div id="app"></div>

  <!-- 1. 引用 Vue -->
  <!-- Vue CDN - 提供 Vue 服務 -->
  <script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
  <!-- Vue Router CDN - 管理路由 -->
  <script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
  <!-- Axios CDN - 呼叫介面 -->
  <script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
  
  <script>

    new Vue({
      // 3. el - 掛載目標,即渲染在哪個掛載點
      el: document.getElementById('app'),
      // 4. template - 模板,即渲染到掛載點的內容
      // 最外層必須有一層包裹,例如 <div>
      template: `
        <button @click="addStyle">新增行內樣式</button>
      `,
      // 5. data - 資料,即在操作中需要用到的資料
      // 可以理解為在 jQuery 中 var text = "Hello World!"
      // {{ text }} 為資料渲染到 DOM 的方式之一
      data() {
        return {
          // template 中要使用的資料
        }
      },
      // 6. methods - 方法,即我們的頁面事件
      // 可以理解為在 jQuery 中定義 Function
      methods: {
        addStyle(e) {
          e.toElement.style.background = "red"
        }
      }
    })

  </script>
</body>

</html>
複製程式碼

此時頁面的點選效果如下所示:

Vue 系列一 之 Vue 基礎

此刻我們分析下頁面:

  1. 首先,在上面的 <button> 中,我們通過 @click 繫結了事件 addStyle
<button @click="addStyle">新增行內樣式</button>
複製程式碼
  1. 接著,方法的編寫,需要寫到與 data 同級的 methods 中:
 methods: { // 方法
  addStyle: function(e) {
    e.toElement.style.background = "red"
  }
}
複製程式碼
  1. 然後,我們通過傳遞引數 e,可以獲取到點選的時候的元素,通過查詢,我們發現它的樣式所在的目錄結構如下:
- button
  - toElement
    - style
      - background
複製程式碼
  1. 最後,我們在使用者點選按鈕的時候,直接修改了它的背景。

2.7 元件 - components

返回目錄

敲黑板!敲黑板!敲黑板!

元件是 Vue 學習的重點,元件化的 SPA 或者 SSR 頁面的製作,使得我們開發起來更加隨心應手。

2.7.1 初始元件

返回目錄

在上面的章節中,我們一直使用 template: `` 的形式,編寫 html 標籤。但是,隨著專案的不斷擴大,如果全部程式碼都寫在一個 template 中,那麼我們修改起來就複雜了。所以,我們應該想辦法對它進行劃分,例如將一個頁面劃分為 headercontentfooter 三部分。這樣,我們需要修改 nav 的時候,只需要在 header 中修改就可以了。

頁面結構

- app
 - header
 - content
 - footer
複製程式碼

這樣的思想,在 Vue 中體現為元件(組合起來的部件)。那麼,在 Vue 中,需要如何做,才能比較好的做到元件的劃分呢?

首先,我們捋捋邏輯:

在前面的章節中,在 Vue 的定義上,我們將首個 template 掛載到了 id 為 app 的節點上。然後將 template 劃分為三個塊:headercontentfooter

在這裡,我們將 #apptemplate 叫做父元件,header 等叫子元件,就好比父親下面有三個兒子一樣。

然後,我們嘗試從 new Vue 中抽離單個元件出來:

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  
  <title>Vue 學習</title>

</head>

<body>

  <!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裡操作到實際渲染 -->
  <!-- 簡單理解為 jQuery 的拼接字串(並不全是) -->
  <div id="app"></div>

  <!-- 1. 引用 Vue -->
  <!-- Vue CDN - 提供 Vue 服務 -->
  <script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
  <!-- Vue Router CDN - 管理路由 -->
  <script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
  <!-- Axios CDN - 呼叫介面 -->
  <script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
  
  <script>

    // 宣告入口元件
    var App = {
      template: `<h1>我是入口元件</h1>`
    }

    new Vue({
      // 3. el - 掛載目標,即渲染在哪個掛載點
      el: document.getElementById('app'),
      // 4. template - 模板,即渲染到掛載點的內容
      // 最外層必須有一層包裹,例如 <div>
      template: '<app/>',
      // 5. data - 資料,即在操作中需要用到的資料
      // 可以理解為在 jQuery 中 var text = "Hello World!"
      // {{ text }} 為資料渲染到 DOM 的方式之一
      data() {
        return {
          // template 中要使用的資料
        }
      },
      // 6. methods - 方法,即我們的頁面事件
      // 可以理解為在 jQuery 中定義 Function
      methods: {
        
      },
      // 7. components - 元件名稱
      components: {
        // key 是元件名,value 是元件物件
        app: App
      }
    })

  </script>
</body>

</html>
複製程式碼

這時候頁面如下所示:

Vue 系列一 之 Vue 基礎

接著,我們分析下進行的三部曲:

  1. component 中定義並抽離 App
  2. new Vue 外定義 App
  3. template 中使用 App

這樣,我們就做到了單個元件的抽離,及 new VueApp 的父元件,Appnew Vue 的子元件。

最後,既然上面做到了單個元件的抽離,現在我們實現多個元件的抽離:

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Vue學習</title>
</head>

<body>
  <div id="app"></div>

  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    // 宣告頭部元件
    var MyHeader = {
      template: `<div>我是頭部</div>`
    };
    
    // 宣告內容元件
    var MyContent = {
      template: `<div>我是軀體</div>`
    };

    // 宣告底部元件
    var myFooter = {
      template: `<div>我是底部</div>`
    }

    new Vue({
      el: document.getElementById('app'),
      components: { // 宣告要用的元件們
        // key 是元件名,value 是元件物件
        'my-header': MyHeader,
        'my-content': MyContent,
        'my-footer': myFooter
      },
      template: `
        <div>
          <my-header/>
          <my-content/>
          <my-footer/>
        </div>
      `
    })
  </script>
</body>

</html>
複製程式碼

這樣,我們就做到了元件的抽離。

Vue 系列一 之 Vue 基礎

注意:template 有且只有一個根節點,如果沒有根節點,Vue 會給你報錯。

  template: `
    <my-header/>
    <my-content/>
    <my-footer/>
  `
複製程式碼

上面那種寫法是錯誤的,謹記。

做到這裡,我們又可以愉快玩耍了,而且 myHeadermyContentmyFooter 中是可以跟 new Vue 一樣寫 datamethods 的哦~

例如:

var MyHeader = {
  data() {
    return {
      // ... 定義資料
    }
  },
  template: `<h1>我是頭部</h1>`,
  methods: {
    // 定義方法
  }
};
複製程式碼

2.7.2 父子元件通訊

返回目錄

既然前面章節已經劃分了父子元件,那麼在這裡,我們講件更有趣的事:父子元件通訊。

在元件間,我們 new Vue 相當於父親(父元件),他有自己的 data。然後,子元件也會有自己的 data

  • 假如某天,父親找到自己的兒子,想告訴他:“其實你不是我親生的,你的姓名是***”

那麼,在 Vue 中,我們要怎麼做,才能讓它的兒子(子元件),知道它的姓究竟是什麼呢?我們來看程式碼:

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  
  <title>Vue 學習</title>

</head>

<body>

  <!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裡操作到實際渲染 -->
  <!-- 簡單理解為 jQuery 的拼接字串(並不全是) -->
  <div id="app"></div>

  <!-- 1. 引用 Vue -->
  <!-- Vue CDN - 提供 Vue 服務 -->
  <script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
  <!-- Vue Router CDN - 管理路由 -->
  <script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
  <!-- Axios CDN - 呼叫介面 -->
  <script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
  
  <script>

    // 子元件
    var Son = {
      template: `
        <div>我的名字:{{name}}</div>
      `,
      props: ['name']
    }

    new Vue({
      // 3. el - 掛載目標,即渲染在哪個掛載點
      el: document.getElementById('app'),
      // 4. template - 模板,即渲染到掛載點的內容
      // 最外層必須有一層包裹,例如 <div>
      template: `
        <son :name="name"></son>
      `,
      // 5. data - 資料,即在操作中需要用到的資料
      // 可以理解為在 jQuery 中 var text = "Hello World!"
      // {{ text }} 為資料渲染到 DOM 的方式之一
      data() {
        return {
          // template 中要使用的資料
          name: '皮皮蝦'
        }
      },
      // 6. methods - 方法,即我們的頁面事件
      // 可以理解為在 jQuery 中定義 Function
      methods: {
        
      },
      // 7. components - 元件名稱
      components: {
        // key 是元件名,value 是元件物件
        son: Son
      }
    })

  </script>
</body>

</html>
複製程式碼

編寫完程式碼後,我們可以在瀏覽器看到,瀏覽器顯示出了:我的名字:皮皮蝦,這幾個大字。

Vue 系列一 之 Vue 基礎

哦了,原來父親的兒子姓 。同時,我們也就知道了,在父元件中的資料,通過 v-bind:*** 的形式,將父元件中的 data,傳送給子元件。而子元件呢,通過 props 的定義,獲取到了父親的資料。

這樣我們就做到了父元件傳遞資料給子元件。

2.7.3 共用元件

返回目錄

在上面中,我們提到:

- App
 - my-header
 - my-content
 - my-footer
複製程式碼

App 這個元件上,我們掛載了三個子元件:myHeadermyContentmyFooter

  • 但是,如果某天,出現了一個女孩(共有元件),這個女孩的名字叫:beautifulGirl。然後不僅三個兒子(子元件)想追求她,就連父親(父元件)也想追求她(夠瘋狂)。

那麼,在 Vue 中,是通過什麼方式,使父親和兒子都有機會接觸到這個女孩呢?(父子元件如何能夠都可以使用共用元件)

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  
  <title>Vue 學習</title>

</head>

<body>

  <!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裡操作到實際渲染 -->
  <!-- 簡單理解為 jQuery 的拼接字串(並不全是) -->
  <div id="app"></div>

  <!-- 1. 引用 Vue -->
  <!-- Vue CDN - 提供 Vue 服務 -->
  <script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
  <!-- Vue Router CDN - 管理路由 -->
  <script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
  <!-- Axios CDN - 呼叫介面 -->
  <script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
  
  <script>

    // 宣告頭部元件
    var MyHeader = {
      template: `
        <div>我是頭部,我想了解<beautiful-girl></beautiful-girl></div>
      `
    };
    
    // 宣告內容元件
    var MyContent = {
      template: `
        <div>我是內容區,我想了解<beautiful-girl></beautiful-girl></div>
      `
    };

    // 宣告底部元件
    var myFooter = {
      template: `
        <div>我是底部,我想了解<beautiful-girl></beautiful-girl></div>
      `
    }

    // 宣告共用元件
    Vue.component('beautiful-girl', {
      template: `<span>—— 美麗女孩 ——</span>`
    })

    new Vue({
      // 3. el - 掛載目標,即渲染在哪個掛載點
      el: document.getElementById('app'),
      // 4. template - 模板,即渲染到掛載點的內容
      // 最外層必須有一層包裹,例如 <div>
      template: `
        <div>
          <my-header/>
          <my-content/>
          <my-footer/>
        </div>
      `,
      // 5. data - 資料,即在操作中需要用到的資料
      // 可以理解為在 jQuery 中 var text = "Hello World!"
      // {{ text }} 為資料渲染到 DOM 的方式之一
      data() {
        return {
          // template 中要使用的資料
        }
      },
      // 6. methods - 方法,即我們的頁面事件
      // 可以理解為在 jQuery 中定義 Function
      methods: {
        
      },
      // 7. components - 元件名稱
      components: {
        // key 是元件名,value 是元件物件
        'my-header': MyHeader,
        'my-content': MyContent,
        'my-footer': myFooter,
      }
    })

  </script>
</body>

</html>
複製程式碼

在這裡,我們通過 Vue.component('元件名',{ }) 的形式,註冊了個全域性元件 beautiful-girl,這樣,父子元件都可以直接呼叫該元件,從而在瀏覽器顯示為:

Vue 系列一 之 Vue 基礎

現在,父親和兒子都可以和漂亮女孩溝通了。究竟是父親給他們的兒子找了個後媽,還是他們兒子找到自己所愛呢?敬請期待……

2.8 過濾器 - filter

返回目錄

在工作中,我們經常需要對一些後端傳回來的資料進行過濾。例如:我司 Java 小哥傳回來的金錢,就是分進位制的,即:1元 = 100分。所以傳回個 2000,其實是 20 元。那麼,在 Vue 中,我們該如何對資料進行過濾呢?

2.8.1 區域性過濾

返回目錄

話不多說,先上程式碼:

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  
  <title>Vue 學習</title>

</head>

<body>

  <!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裡操作到實際渲染 -->
  <!-- 簡單理解為 jQuery 的拼接字串(並不全是) -->
  <div id="app"></div>

  <!-- 1. 引用 Vue -->
  <!-- Vue CDN - 提供 Vue 服務 -->
  <script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
  <!-- Vue Router CDN - 管理路由 -->
  <script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
  <!-- Axios CDN - 呼叫介面 -->
  <script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
  
  <script>

    // 宣告頭部元件
    var MyHeader = {
      template: `
        <div>我是頭部,我想了解<beautiful-girl></beautiful-girl></div>
      `
    };
    
    // 宣告內容元件
    var MyContent = {
      template: `
        <div>我是內容區,我想了解<beautiful-girl></beautiful-girl></div>
      `
    };

    // 宣告底部元件
    var myFooter = {
      template: `
        <div>我是底部,我想了解<beautiful-girl></beautiful-girl></div>
      `
    }

    // 宣告共用元件
    Vue.component('beautiful-girl', {
      template: `<span>—— 美麗女孩 ——</span>`
    })

    new Vue({
      // 3. el - 掛載目標,即渲染在哪個掛載點
      el: document.getElementById('app'),
      // 4. template - 模板,即渲染到掛載點的內容
      // 最外層必須有一層包裹,例如 <div>
      template: `
        <p>我是錢多多,我有 {{money}} 多一點: ¥{{money | addDot}},跟我混有出息~</p>
      `,
      // 5. data - 資料,即在操作中需要用到的資料
      // 可以理解為在 jQuery 中 var text = "Hello World!"
      // {{ text }} 為資料渲染到 DOM 的方式之一
      data() {
        return {
          // template 中要使用的資料
          money: 1000000
        }
      },
      // 6. methods - 方法,即我們的頁面事件
      // 可以理解為在 jQuery 中定義 Function
      methods: {
        
      },
      // 7. components - 元件名稱
      components: {
        // key 是元件名,value 是元件物件

      },
      // 8. filters - 元件內的過濾器
      filters: {
        addDot(money) {
          return (money / 1000000 + ".000000");
        }
      }
    })

  </script>
</body>

</html>
複製程式碼

在上面,我們通過 filters 中的 addDot 方法,對資料進行了過濾,將 money 的資料,從 10000000 變成了 1.000000

Vue 系列一 之 Vue 基礎

2.8.2 全域性過濾

返回目錄

然後,在嘗試了區域性 filters 的好處之後,我們還可以試試它的全域性過濾器寫法:

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  
  <title>Vue 學習</title>

</head>

<body>

  <!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裡操作到實際渲染 -->
  <!-- 簡單理解為 jQuery 的拼接字串(並不全是) -->
  <div id="app"></div>

  <!-- 1. 引用 Vue -->
  <!-- Vue CDN - 提供 Vue 服務 -->
  <script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
  <!-- Vue Router CDN - 管理路由 -->
  <script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
  <!-- Axios CDN - 呼叫介面 -->
  <script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
  
  <script>

    // 全域性過濾器
    Vue.filter('addDot', function(money) {
      return (money / 1000000 + ".000000");
    })
    
    new Vue({
      // 3. el - 掛載目標,即渲染在哪個掛載點
      el: document.getElementById('app'),
      // 4. template - 模板,即渲染到掛載點的內容
      // 最外層必須有一層包裹,例如 <div>
      template: `
        <p>我是錢多多,我有 {{money}} 多一點: ¥{{money | addDot}},跟我混有出息~</p>
      `,
      // 5. data - 資料,即在操作中需要用到的資料
      // 可以理解為在 jQuery 中 var text = "Hello World!"
      // {{ text }} 為資料渲染到 DOM 的方式之一
      data() {
        return {
          // template 中要使用的資料
          money: 1000000
        }
      },
      // 6. methods - 方法,即我們的頁面事件
      // 可以理解為在 jQuery 中定義 Function
      methods: {
        
      },
      // 7. components - 元件名稱
      components: {
        // key 是元件名,value 是元件物件

      },
      // 8. filters - 元件內的過濾器
      filters: {
        
      }
    })

  </script>
</body>

</html>
複製程式碼

最後在頁面中顯示為:

Vue 系列一 之 Vue 基礎

2.9 監聽資料

返回目錄

Vue 中,我們通過 v-model 做了雙向資料繫結,即在頁面的 <input> 中輸入的值,在我們的 Vue 中可以獲得資料;在 Vue 中定義的資料,也會即時渲染到頁面中。

但是,在程式碼中,我們怎樣才能獲取到它即時輸入的資料呢?

2.9.1 偵聽屬性 - watch

返回目錄

話不多說,先上程式碼:

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  
  <title>Vue 學習</title>

</head>

<body>

  <!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裡操作到實際渲染 -->
  <!-- 簡單理解為 jQuery 的拼接字串(並不全是) -->
  <div id="app"></div>

  <!-- 1. 引用 Vue -->
  <!-- Vue CDN - 提供 Vue 服務 -->
  <script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
  <!-- Vue Router CDN - 管理路由 -->
  <script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
  <!-- Axios CDN - 呼叫介面 -->
  <script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
  
  <script>
    
    new Vue({
      // 3. el - 掛載目標,即渲染在哪個掛載點
      el: document.getElementById('app'),
      // 4. template - 模板,即渲染到掛載點的內容
      // 最外層必須有一層包裹,例如 <div>
      template: `
        <div>
          <input type="text" v-model="money" />
          <span>{{money}}</span>
        </div>
      `,
      // 5. data - 資料,即在操作中需要用到的資料
      // 可以理解為在 jQuery 中 var text = "Hello World!"
      // {{ text }} 為資料渲染到 DOM 的方式之一
      data() {
        return {
          // template 中要使用的資料
          money: ''
        }
      },
      // 6. methods - 方法,即我們的頁面事件
      // 可以理解為在 jQuery 中定義 Function
      methods: {
        
      },
      // 7. components - 元件名稱
      components: {
        // key 是元件名,value 是元件物件

      },
      // 8. filters - 元件內的過濾器
      filters: {
        
      },
      // 9. watch - 偵聽屬性
      watch: {
        // key: data 屬性的屬性名
        money(newVal, oldVal) {
          console.log(newVal, oldVal);
        }
      }
    })

  </script>
</body>

</html>
複製程式碼

這樣,當我們輸入 11 個 1 的過程中,瀏覽器的 Console 對應輸出為:

Vue 系列一 之 Vue 基礎

2.9.2 計算屬性 - computed

返回目錄

在上面,我們講了通過 watch 來監聽 datanumberstring 等欄位的改變。但是,在 Vue 中,為了方便我們的監聽操作,Vue 還定義了個方法:computed,我們可以通過 computed,監控我們在 data 中定義的全部資料。

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Vue學習</title>
</head>

<body>
  <div id="app"></div>

  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>

    new Vue({
      el: document.getElementById('app'),
      template: `
        <div>
          <input type="text" v-model="number1" />
          +
          <input type="text" v-model="number2" />
          *
          <input type="text" v-model="number3" />
          =
          {{result}}
        </div>
      `,
      data: {
        number1: 0,
        number2: 0,
        number3: 0,
        result: '',
      },
      computed: {
        // 如果原值不變,快取不調函式的優化機制
        result: function() {
          // 監視物件,寫在了函式內部,
          // 凡是函式內部有 this. 相關屬性,改變都會觸發當前函式
          let addSum = parseInt(this.number1) + parseInt(this.number2);
          let allSum = addSum * this.number3;
          return allSum;
        }
      }
    })

  </script>
</body>

</html>
複製程式碼

其結果如下面 GIF 圖所示:

Vue 系列一 之 Vue 基礎

2.9.3 watch、computed 與 methods 對比

返回目錄

在上面,我們涉及了兩個知識點:watchcomputed

那麼,又到 “玄學” 的時刻了,都是跟監聽資料打交道,我們平時使用 Vue 的時候,什麼時候使用 watch,什麼時候使用 computed?然後,如果我們在加上 methods,那麼什麼時候我們又用 methods 呢?

首先,我們對比下 computedmethods

  • computed 是根據 data 中的資料變化,而進行的操作。即 this.任意資料 改變了,那麼,computed 就會進行改變;而如果 this.任務資料 不變,那麼 computed 就會執行它的快取策略,不會更新
  • methods 一般是根據點選之類的事件來觸發的,例如使用者通過 @click="方法" 來進行資料的改變。

然後,我們對比下 computedwatch

如果上面章節的 computed 方法換成 watch

index.html 程式碼片段

// 9. watch - 偵聽屬性
watch: {
  // key: data 屬性的屬性名
  result(newVal, oldVal) {
    console.log(newVal, oldVal);
    this.result = this.number1 + this.number2 * this.number3;
  }
},
複製程式碼

你會發現,result 資料不變化了,因為這是 computed 才特有的玩意,如果你需要將上面章節的 computed 方法換成 watch,那麼你需要:

index.html 程式碼片段

// 9. watch - 偵聽屬性
watch: {
  // key: data 屬性的屬性名
  number1(val) {
    this.result = parseInt(this.number1) + parseInt(this.number2) * parseInt(this.number3);
  },
  number2(val) {
    this.result = parseInt(this.number1) + parseInt(this.number2) * parseInt(this.number3);
  },
  number3(val) {
    this.result = parseInt(this.number1) + parseInt(this.number2) * parseInt(this.number3);
  }
},
複製程式碼

如此,小夥伴應該瞭解到,watch 如果需要完成 computed 的功能,那麼,它需要監聽每一個需要改變的屬性。

最後,在這裡,我們大致描述下 watchcomputed 的區分:

  • computed 強調計算,例如 c = a + bb 是外界傳來不斷變化的,因為你只要顯示 c,所以使用 computed。而 watch 屬性強調自身值的變化前後的動作,如果需要完成 c = a + b,那麼你需要 watch 資料 ab 的變化,在這兩者變化的時候,在方法中執行 c = a + b
  • watch 在處理非同步操作或者開銷較大的操作上有優勢。
    • 執行非同步操作不能序列返回結果,使用 watch
    • 開銷較大的操作,避免堵塞主執行緒,使用 watch
    • 簡單且序列返回的,使用 computed
  • computed 對繫結的值有依賴,如果每次操作的值不變化,則不進行計算,具有快取特性。watch 會偵聽前後變化的狀態,無論操作的值是否變化,都會執行定義的函式體,所以會有 data(newVal, oldVal)。

如果小夥伴們較真上了,那麼請檢視官方文件:計算屬性和偵聽器

2.10 傳遞 DOM - slot

返回目錄

在日常工作中,我們對一些常用的功能,例如:側邊欄、頂部導航欄等,會進行常用的封裝,等我們想用的時候,就可以直接引用。那麼,在 Vue 中,想實現這類功能,我們還需要了解什麼?

2.10.1 slot 單個傳遞

返回目錄

話不多說,先上程式碼:

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  
  <title>Vue 學習</title>

</head>

<body>

  <!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裡操作到實際渲染 -->
  <!-- 簡單理解為 jQuery 的拼接字串(並不全是) -->
  <div id="app"></div>

  <!-- 1. 引用 Vue -->
  <!-- Vue CDN - 提供 Vue 服務 -->
  <script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
  <!-- Vue Router CDN - 管理路由 -->
  <script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
  <!-- Axios CDN - 呼叫介面 -->
  <script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
  
  <script>
    
    var myLi = {
      template: `
        <li><slot></slot></li>
      `
    };

    Vue.component('my-li', myLi);

    var App = {
      template: `
        <div>
          <ul>
            <my-li><button>我是第一行 button 按鈕</button></my-li>
            <my-li><h3>我是第二行 h3 標籤</h3></my-li>
            <my-li><a href="javascript:void(0)">我是第三行 a 導航</a></my-li>
            <my-li><span>我是第四行 span 標籤</span></my-li>
          </ul>
        </div>
      `
    };

    new Vue({
      // 3. el - 掛載目標,即渲染在哪個掛載點
      el: document.getElementById('app'),
      // 4. template - 模板,即渲染到掛載點的內容
      // 最外層必須有一層包裹,例如 <div>
      template: `
        <app/>
      `,
      // 5. data - 資料,即在操作中需要用到的資料
      // 可以理解為在 jQuery 中 var text = "Hello World!"
      // {{ text }} 為資料渲染到 DOM 的方式之一
      data() {
        return {
          // template 中要使用的資料

        }
      },
      // 6. methods - 方法,即我們的頁面事件
      // 可以理解為在 jQuery 中定義 Function
      methods: {
        
      },
      // 7. components - 元件名稱
      components: {
        // key 是元件名,value 是元件物件
        app: App
      },
      // 8. filters - 元件內的過濾器
      filters: {
        
      },
      // 9. watch - 偵聽屬性
      watch: {
        // key: data 屬性的屬性名

      },
      // 10. computed - 計算屬性
      computed: {
        // 如果原值不變,computed 會執行快取,即不呼叫方法
        
      }
    })

  </script>
</body>

</html>
複製程式碼

其結果如下圖所示:

Vue 系列一 之 Vue 基礎

那麼,上面程式碼中,我們幹了什麼?

首先,如上程式碼及其結果圖,我們的 new Vue 中掛載了一個元件 App

new Vue({
  el: document.getElementById('app'),
  components: {
    app: App
  },
  template: `
    <app/>
  `
})
複製程式碼

然後,該 App 的目的,是想動態引用一個 li 元件

var App = {
  template: `
    <div>
      <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
      </ul>
    </div>
  `
};
複製程式碼

接著,我們在全域性定義 myLi 元件的同時,通過 <slot></slot> 插槽,使它能夠動態地載入 dom 節點。

var myLi = {
  template: `
    <li><slot></slot></li>
  `
};

Vue.component('my-li', myLi);
複製程式碼

最後,我們在 App 中,傳遞給它不同的 dom 節點,從而動態生成 App

var App = {
  template: `
    <div>
      <ul>
        <my-li><button>我是第一行 button 按鈕</button></my-li>
        <my-li><h3>我是第二行 h3 標籤</h3></my-li>
        <my-li><a href="javascript:void(0)">我是第三行 a 導航</a></my-li>
        <my-li><span>我是第四行 span 標籤</span></my-li>
      </ul>
    </div>
  `
};
複製程式碼

這樣,我們就思路清晰地知道,如何通過 <slot></slot> 來動態地載入 dom 節點,對我們 Vue 開發又有了更好的幫助。

2.10.2 具名 slot

返回目錄

在上面中,我們談論到了單個插槽 slot 的用法。但是,如果元件想根據父元件是否傳遞某個變數來存放插槽的數量,要怎麼做呢?

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  
  <title>Vue 學習</title>

</head>

<body>

  <!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裡操作到實際渲染 -->
  <!-- 簡單理解為 jQuery 的拼接字串(並不全是) -->
  <div id="app"></div>

  <!-- 1. 引用 Vue -->
  <!-- Vue CDN - 提供 Vue 服務 -->
  <script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
  <!-- Vue Router CDN - 管理路由 -->
  <script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
  <!-- Axios CDN - 呼叫介面 -->
  <script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
  
  <script>
    
    var mySlot = {
      template: `
        <ul>
          <li>
            <slot></slot>
          </li>
          <li>
            <slot name="one"></slot>
          </li>
          <li>
            <slot name="two"></slot>
          </li>
          <li>
            <slot name="three"></slot>
          </li>
        </ul>
      `
    };

    Vue.component('my-slot', mySlot);

    var App = {
      template: `
        <div>
          <my-slot>
            <p>Helo World!</p>
            <button slot="one">按鈕</button>
            <a href="javascript:void(0)" slot="two">連結</a>
          </my-slot>
        </div>
      `
    };

    new Vue({
      // 3. el - 掛載目標,即渲染在哪個掛載點
      el: document.getElementById('app'),
      // 4. template - 模板,即渲染到掛載點的內容
      // 最外層必須有一層包裹,例如 <div>
      template: `
        <app/>
      `,
      // 5. data - 資料,即在操作中需要用到的資料
      // 可以理解為在 jQuery 中 var text = "Hello World!"
      // {{ text }} 為資料渲染到 DOM 的方式之一
      data() {
        return {
          // template 中要使用的資料

        }
      },
      // 6. methods - 方法,即我們的頁面事件
      // 可以理解為在 jQuery 中定義 Function
      methods: {
        
      },
      // 7. components - 元件名稱
      components: {
        // key 是元件名,value 是元件物件
        app: App
      },
      // 8. filters - 元件內的過濾器
      filters: {
        
      },
      // 9. watch - 偵聽屬性
      watch: {
        // key: data 屬性的屬性名

      },
      // 10. computed - 計算屬性
      computed: {
        // 如果原值不變,computed 會執行快取,即不呼叫方法
        
      }
    })

  </script>
</body>

</html>
複製程式碼

效果圖如下:

Vue 系列一 之 Vue 基礎

下面我們分析下,我們在程式碼中做了啥:

首先,我們通過下面程式碼可以知道,第一個 lislot 是未命名的預設 slot,所以它在頁面中展示為 p 的資料。

var mySlot = {
  template: `
    <ul>
      <li>
        <slot></slot>
      </li>
    </ul>
  `
};

var App = {
  template: `
    <div>
      <my-slot>
        <p>Helo World!</p>
        <button slot="one">按鈕</button>
        <a href="javascript:void(0)" slot="two">連結</a>
      </my-slot>
    </div>
  `
};
複製程式碼

然後,再觀察下 App 中的程式碼 <button slot="one">按鈕</button><a href="javascript:void(0)" slot="two">連結</a>,發現它們使用了 slot="***",這說明了它指定了要求元件中 <slot name="***"></slot> 的程式碼接收。所以第二行第三行顯示為按鈕和連結。

最後,由於最後一個 li<slot name="three"></slot>,這個 name="three"App 元件中沒有用到,所以它表現為空。

2.11 Vue 元件生命週期

返回目錄

在 Vue 中,什麼時候進行虛擬 dom 渲染成 dom,或者什麼時候銷燬程式碼,都是有對應的鉤子的:


  • beforeCreate
  • created

  • beforeMount
  • mounted

  • beforeUpdate
  • updated

  • activated
  • deactivated

  • beforeDestory
  • destory

關於生命週期,Vue 官方文件是有相關圖示及文件的:官方文件 - Vue 生命週期

Vue 系列一 之 Vue 基礎

下面我們通過程式碼演示,講解這 5 組生命週期的用法。

2.11.1 beforeCreate & created

返回目錄

話不多說,先上程式碼:

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  
  <title>Vue 學習</title>

</head>

<body>

  <!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裡操作到實際渲染 -->
  <!-- 簡單理解為 jQuery 的拼接字串(並不全是) -->
  <div id="app"></div>

  <!-- 1. 引用 Vue -->
  <!-- Vue CDN - 提供 Vue 服務 -->
  <script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
  <!-- Vue Router CDN - 管理路由 -->
  <script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
  <!-- Axios CDN - 呼叫介面 -->
  <script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
  
  <script>
    
    var lifeCycle = {
      template: `
        <div>
          我是生命週期元件
        </div>
      `,
      data: function() {
        return {
          text: 'Hello World!'
        }
      },
      beforeCreate: function() {
        // 元件建立之前
        console.log(this.text); // [Console] undefined
      },
      created: function() {
        // 元件建立之後
        console.log(this.text); // [Console] Hello World!
      }

      /*
        * 使用 lifeCycle 元件,就會觸發以上的事件函式(鉤子函式)
        * created 中可以運算元據,並且可以實現 Vue -> 頁面 的影響
        * 應用:發起 ajax 請求
      */
    }

    var App = {
      components: {
        'life-cycle': lifeCycle
      },
      template: `
        <div>
          <life-cycle></life-cycle>
        </div>
      `
    }

    new Vue({
      el: document.getElementById('app'),
      components: {
        app: App
      },
      template: `
        <app/>
      `
    })
    
  </script>
</body>

</html>
複製程式碼

在程式碼中可以看到,我們在 App 中引用了 lifeCycle 這個元件。

我們通過鉤子函式 beforeCreate(元件建立之前) 與 created(元件建立之後),結合 console 發現,這兩個鉤子函式對於 data 來說,一個在 data 掛載前(beforeCreate),所以列印出來的是:undefined,而另外一個發生在 data 掛載後,所以列印出來的是:Hello World!

Vue 系列一 之 Vue 基礎

2.11.2 beforeMount & mounted

返回目錄

話不多說,先上程式碼:

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  
  <title>Vue 學習</title>

</head>

<body>

  <!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裡操作到實際渲染 -->
  <!-- 簡單理解為 jQuery 的拼接字串(並不全是) -->
  <div id="app"></div>

  <!-- 1. 引用 Vue -->
  <!-- Vue CDN - 提供 Vue 服務 -->
  <script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
  <!-- Vue Router CDN - 管理路由 -->
  <script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
  <!-- Axios CDN - 呼叫介面 -->
  <script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
  
  <script>
    
    var lifeCycle = {
      template: `
        <div>
          我是生命週期元件
        </div>
      `,
      data: function() {
        return {
          text: 'Hello World!'
        }
      },
      beforeMount: function() {
        // Vue 起作用之前
        console.log(document.body.innerHTML);
      },
      mounted: function() {
        // Vue 起作用,裝載資料到 DOM 之後
        console.log(document.body.innerHTML);
      }
    }

    var App = {
      components: {
        'life-cycle': lifeCycle
      },
      template: `
        <div>
          <life-cycle></life-cycle>
        </div>
      `
    }

    new Vue({
      el: document.getElementById('app'),
      components: {
        app: App
      },
      template: `
        <app/>
      `
    })

  </script>
</body>

</html>
複製程式碼

那麼,雖說它們的作用,一個是 Vue 起作用之前,一個是 Vue 起作用,裝載資料到 DOM 之後。

我們應該怎樣才能觀察到它的作用?

Vue 系列一 之 Vue 基礎

看到上圖的紅框,也許你會恍然大悟:“喔,beforeMount 就是我裝載之前的鉤子函式,而 mounted 是我裝載之後的鉤子函式,它是 Vue 作用以後的 DOM”

2.11.3 beforeUpdate & updated

返回目錄

話不多說,先上程式碼:

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  
  <title>Vue 學習</title>

</head>

<body>

  <!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裡操作到實際渲染 -->
  <!-- 簡單理解為 jQuery 的拼接字串(並不全是) -->
  <div id="app"></div>

  <!-- 1. 引用 Vue -->
  <!-- Vue CDN - 提供 Vue 服務 -->
  <script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
  <!-- Vue Router CDN - 管理路由 -->
  <script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
  <!-- Axios CDN - 呼叫介面 -->
  <script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
  
  <script>
    
    var lifeCycle = {
      template: `
        <div id="update">
          <p>我是生命週期元件</p>
          <p>{{text}}</p>
          <button @click="text = '!dlroW olleH'">點選改變 text</button>
        </div>
      `,
      data: function() {
        return {
          text: 'Hello World!'
        }
      },
      // 基於資料改變,影響頁面
      beforeUpdate: function() {
        // 改變前
        console.log(document.getElementById('update').innerHTML);
      },
      updated: function() {
        // 改變後
        console.log(document.getElementById('update').innerHTML);
      }

      /*
        * 在日常工作中,我們可以在事件前後拿到它的 DOM,從而做一些我們想要的操作
      */
    }

    var App = {
      components: {
        'life-cycle': lifeCycle
      },
      template: `
        <div>
          <life-cycle></life-cycle>
        </div>
      `
    }

    new Vue({
      el: document.getElementById('app'),
      components: {
        app: App
      },
      template: `
        <app/>
      `
    })

  </script>
</body>

</html>
複製程式碼

在解析程式碼前,我們先檢視它的輸出:

Vue 系列一 之 Vue 基礎

可以看出,beforeUpdate 可以獲取原 DOM,而 updated 可以獲取新 DOM。

它們在上面程式碼中變現為:獲取 <button> 按鈕觸發的事件前後 DOM 的變化,通過這個變化,我們可以在當中做一些操作,從而更好的滿足我們的業務需求。

  • 小結:( beforeMount & mounted ) VS ( beforeUpdate & updated

那麼問題來了,beforeMount 這組和 beforeUpdate 都能監控到 DOM 的變化,它們有什麼區別呢?

答案是,一般我們如果需要在頁面載入的時候,監控 DOM 的變化,那就使用 beforeMountmounted;但是,如果我們想監控使用者的操作(點選事件等),那麼,我們就需要使用 beforeUpdateupdated,因為它們不像 beforeMountmounted 只會在頁面掛載初期執行一次,它們可以根據使用者的操作被執行多次。

2.11.4 beforeDestory & destory

返回目錄

話不多說,先上程式碼:

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  
  <title>Vue 學習</title>

</head>

<body>

  <!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裡操作到實際渲染 -->
  <!-- 簡單理解為 jQuery 的拼接字串(並不全是) -->
  <div id="app"></div>

  <!-- 1. 引用 Vue -->
  <!-- Vue CDN - 提供 Vue 服務 -->
  <script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
  <!-- Vue Router CDN - 管理路由 -->
  <script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
  <!-- Axios CDN - 呼叫介面 -->
  <script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
  
  <script>
    
    var lifeCycle = {
      template: `
        <div id="update">
          <p>我是生命週期元件</p>
        </div>
      `,
      // 對應父元件 v-if == false 的時候,就產生下面鉤子函式,銷燬當前元件
      beforeDestroy: function() { 
        // 銷燬之前
        console.log('例項銷燬之前呼叫。在這一步,例項仍然完全可用。');
      },
      destroyed: function() {
        // 銷燬之後
        console.log('Vue 例項銷燬後呼叫。呼叫後,Vue 例項指示的所有東西都會解繫結,所有的事件監聽器會被移除,所有的子例項也會被銷燬。');
      }
    }

    var App = {
      components: {
        'life-cycle': lifeCycle
      },
      data: function() {
        return {
          isExist: true
        }
      },
      template: `
        <div>
          <life-cycle v-if="isExist"></life-cycle>
          <button @click="isExist = !isExist">點選改變 子元件 狀態</button>
        </div>
      `
    }

    new Vue({
      el: document.getElementById('app'),
      components: {
        app: App
      },
      template: `
        <app/>
      `
    })

  </script>
</body>

</html>
複製程式碼

在這裡,我們在點選 <button> 的時候,控制檯顯示為:

Vue 系列一 之 Vue 基礎

可以看出,當我們點選 <button> 的時候,我們的 isExist 狀態(第一次時)被改變為 false,從而觸發了 lifeCycle 的銷燬鉤子函式,在控制檯列印了上面兩行話。

相應的,如果是當 isExist 狀態變為 true 的時候,會觸發我們的 beforeCreatecreated 這兩個鉤子函式,有興趣的小夥伴可以嘗試一下,這裡不做過多演示。

2.11.5 activated & deactivated

返回目錄

經過長期的工作,我們知道,如果頻繁的操作 DOM,進行影響到鉤子函式 beforeCreatecreatedbeforeDestorydestory 的操作,是對我們的效能會產生影響的。我們要如何防止某部分程式碼的頻繁操作 DOM,並且監聽到它的操作呢?

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  
  <title>Vue 學習</title>

</head>

<body>

  <!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裡操作到實際渲染 -->
  <!-- 簡單理解為 jQuery 的拼接字串(並不全是) -->
  <div id="app"></div>

  <!-- 1. 引用 Vue -->
  <!-- Vue CDN - 提供 Vue 服務 -->
  <script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
  <!-- Vue Router CDN - 管理路由 -->
  <script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
  <!-- Axios CDN - 呼叫介面 -->
  <script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
  
  <script>
    
    var lifeCycle = {
      template: `
        <div id="update">
          <p>我是生命週期元件</p>
        </div>
      `,
      activated: function() {
        console.log("元件被啟用了");
      },
      deactivated: function() {
        console.log("元件被停用了");
      }
    }

    var App = {
      components: {
        'life-cycle': lifeCycle
      },
      data: function() {
        return {
          isExist: true
        }
      },
      template: `
        <div>
          <keep-alive>
            <life-cycle v-if="isExist"></life-cycle>
          </keep-alive>
          <button @click="isExist = !isExist">點選改變 子元件 狀態</button>
        </div>
      `
    }

    new Vue({
      el: document.getElementById('app'),
      components: {
        app: App
      },
      template: `
        <app/>
      `
    })

  </script>
</body>

</html>
複製程式碼

在程式碼中,我們通過 <keep-alive></keep-alive> 這個 Vue 的內建元件,對我們子元件進行了包裹。

然後,當我們進入頁面和點選按鈕時,做到了 activateddeactivated 這兩個鉤子函式的觸發:

Vue 系列一 之 Vue 基礎

可以看出,當我們進來頁面的時候,它就告訴我們,該元件被啟用了。當我們第一次點選 <button> 按鈕的時候,isExist 的狀態變成了 false,即該元件被停用了。最後,我們再次點選了 <button>,這時候控制檯再次列印 元件被啟用了

  • 小結:這時候,希望小夥伴回到生命週期章節的開頭,看官方關於生命週期的解析圖,它將有助於我們更加理解宣告週期。如果還是不夠清晰,可以點選圖片旁邊的按鈕,進入官方文件,檢視官方關於生命週期的解析。【返回加深學習】

2.12 獲取 DOM 元素

返回目錄

在日常開發中,可能有小夥伴會想到操作 DOM 元素。如果用原生的 document.getElementById 吧,可能太 low 了,所以,有沒有類似於 jQuery 的 $("#id") 之類的呢?

2.12.1 單個 DOM 元素獲取

返回目錄

話不多說,先上程式碼:

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  
  <title>Vue 學習</title>

</head>

<body>

  <!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裡操作到實際渲染 -->
  <!-- 簡單理解為 jQuery 的拼接字串(並不全是) -->
  <div id="app"></div>

  <!-- 1. 引用 Vue -->
  <!-- Vue CDN - 提供 Vue 服務 -->
  <script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
  <!-- Vue Router CDN - 管理路由 -->
  <script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
  <!-- Axios CDN - 呼叫介面 -->
  <script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
  
  <script>
    
    var App = {
      template: `
        <div>
          <button ref="btn">按鈕</button>
        </div>
      `,
      beforeCreate: function() {
        // 這裡不能運算元據,只是初始化了事件等……
        console.log(this.$refs.btn); // [Console] undefined
      },
      created: function() {
        // 可以運算元據了
        console.log(this.$refs.btn); // [Console] undefined
      },
      beforeMount: function() {
        // new Vue 發生裝載,替換 <div id="app"></div> 之前
        console.log(this.$refs.btn); // [Console] undefined
      },
      mounted: function() {
        // 裝載資料之後
        console.log(this.$refs.btn.innerHTML); // [Console] 按鈕
      }
    }

    new Vue({
      el: document.getElementById('app'),
      components: {
        app: App
      },
      template: `<app/>`
    })

  </script>
</body>

</html>
複製程式碼

我們先檢視下頁面:

Vue 系列一 之 Vue 基礎

首先,我們在元件的 DOM 部分(<button>),寫上 ref = "btn"。

然後,我們發現只有在 mounted 資料裝載之後這個鉤子函式中,通過元件物件 this.$refs.btn 可以獲取到元素

這樣,我們就知道在一些場景,如何可以方便地通過 Vue 獲取到 DOM 元素了。

2.12.2 元件 DOM 元素獲取

返回目錄

在上面,我們獲取到了單個 DOM 節點的部分,假如我們需要獲取到整個子元件,那麼要怎麼做呢?

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  
  <title>Vue 學習</title>

</head>

<body>

  <!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裡操作到實際渲染 -->
  <!-- 簡單理解為 jQuery 的拼接字串(並不全是) -->
  <div id="app"></div>

  <!-- 1. 引用 Vue -->
  <!-- Vue CDN - 提供 Vue 服務 -->
  <script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
  <!-- Vue Router CDN - 管理路由 -->
  <script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
  <!-- Axios CDN - 呼叫介面 -->
  <script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
  
  <script>
    
    var tempComponent = {
      template: `
        <div>我是臨時元件</div>
      `
    }

    Vue.component('temp', tempComponent);

    var App = {
      template: `
        <div>
          <temp ref="temp" />
        </div>
      `,
      mounted: function() {
        // 裝載資料之後
        console.log(this.$refs.temp.$el);
      }
    }

    new Vue({
      el: document.getElementById('app'),
      components: {
        app: App
      },
      template: `<app/>`
    })

  </script>
</body>

</html>
複製程式碼

我們先不急著分析,先看控制檯列印出了什麼;

Vue 系列一 之 Vue 基礎

在這裡可以看到它列印出了一堆關於該元件的東西,其中

  • $children - 當前元件的子元件
  • $el - 當前元件的元素節點
  • $parent - 當前元件的父元件
  • $root - 獲取 new Vue 例項

然後發現元素 $el是 DOM 節點的內容,我們嘗試列印出來看一下:

console.log(this.$refs.temp.$el);
複製程式碼

Console

<div>我是臨時元件</div>
複製程式碼

通過 Console 可以看出,$el 就可以列印出其中的 <button> 元素了。

2.12.3 Vue.nextTick()

返回目錄

當然,我們有時候操作 DOM,是想在 data 資料變更的時候進行操作,如果是使用上面方法,有些時候是搞不定的。

那麼,我們應該怎麼做呢?

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  
  <title>Vue 學習</title>

</head>

<body>

  <!-- 2. Vue 掛載點 - Vue 的虛擬 DOM 在這裡操作到實際渲染 -->
  <!-- 簡單理解為 jQuery 的拼接字串(並不全是) -->
  <div id="app"></div>

  <!-- 1. 引用 Vue -->
  <!-- Vue CDN - 提供 Vue 服務 -->
  <script src="https://cdn.bootcss.com/vue/2.5.21/vue.js"></script>
  <!-- Vue Router CDN - 管理路由 -->
  <script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.js"></script>
  <!-- Axios CDN - 呼叫介面 -->
  <script src="https://cdn.bootcss.com/axios/0.18.0/axios.js"></script>
  
  <script>
    
    var App = {
      template: `
        <div>
          <input v-if="isShow" ref="input" />
        </div>
      `,
      data: function() {
        return {
          isShow: true
        }
      },
      mounted: function() {
        // 希望在 Vue 真正渲染 DOM 到頁面之後進行下面操作
        this.$nextTick(function() {
          this.$refs.input.focus();
        })
      }
    }

    new Vue({
      el: document.getElementById('app'),
      components: {
        app: App
      },
      template: `<app/>`
    })

  </script>
</body>

</html>
複製程式碼

如上,通過 Vue 的全域性 API Vue.nextTick(),我們在下次 DOM 更新迴圈結束之後執行延遲迴調。在修改資料之後立即使用這個方法,獲取更新後的 DOM。

這個操作我們可想象下 Promise 的執行流程,會獲得更好的體驗。

三 實戰

返回目錄

那麼,學到這裡,我們應該進行一個簡單的操練,來回顧我們所學知識了:

Vue 系列一 之 Vue 基礎

四 總結

返回目錄

如上,我們入門了基礎的 Vue,可能小夥伴們會覺得還是很暈。

但是,沒關係,我們接下來在講解 VueRouter、VueCli 的時候還是會使用 Vue 基礎語法的,正如那句話:萬丈高樓平地起,地基還得自己起

多實操,多做筆記,總能熟練上去的,加油~


後記

如果小夥伴需要存放 jsliang.top 這樣的純靜態頁面或者 company.jsliang.top 這樣的具有 Node 後端支援的頁面,推薦購買雲伺服器來存放。

如果小夥伴們不知道該怎麼選擇雲伺服器,可以檢視 詳細介紹 或者加 jsliang QQ:1741020489 諮詢。

知識共享許可協議

jsliang 的文件庫 由 樑峻榮 採用 知識共享 署名-非商業性使用-相同方式共享 4.0 國際 許可協議 進行許可。
基於 github.om/LiangJunron… 上的作品創作。
本許可協議授權之外的使用許可權可以從 creativecommons.org/licenses/by… 處獲得。

相關文章