Vue開發者必會的基礎知識盤點



下面是Vue的一些基本知識點相關學習跟應用,差缺補漏吧。Vue.js官網好好看一遍還是很香的。

 

Vue中的數據和DOM已經被關聯起來,所有的東西都是響應式的。注意我們不再和HTML直接交互。一個Vue應用會將其掛載到DOM元素上然后對齊進行完全的控制,那個HTML是我們的入口,但是其他的都會發生在新創建的Vue實例內部。詳情可見MVVM原理極其實現

 

Vue實例

1、實例聲明周期鈎子函數

8個聲明周期函數

 

模板語法

1、插值

①、 v-once 指令,你也能執行一次性地插值,當數據改變時,插值處的內容不會更新。

②、可以使用js表達式但是不能使用語句和流控制(if判斷語句)

 
1 {{ ok ? 'YES' : 'NO' }}
2  {{ message.split('').reverse().join('') }}
3  ​
4  <!-- 這是語句,不是表達式 -->
5  {{ var a = 1 }}
6  <!-- 流控制也不會生效,請使用三元表達式 -->
7  {{ if (ok) { return message } }}

 

 

 

2、指令

①、動態參數 -2.60新增

可以使用動態參數為一個動態的事件名綁定處理函數:

約束:為某些字符,如空格和引號,放在 HTML attribute 名里是無效的。會觸發警告。

1  <a v-on:[eventName]="doSomething"> ... </a>

 

當 eventName 的值為 "focus" 時,v-on:[eventName] 將等價於 v-on:focus

 

3、修飾符

在移動端最好的應用就是

①、 .stop 阻止事件冒泡

②、 .prevent (@touchmove.prevent 禁止底層頁面滑動)

 

計算屬性和偵聽器

模板中不應該放入過多的邏輯,會讓模板過重且難以維護,所以對於任何復雜邏輯,都應該使用計算屬性

基礎例子

 

 
 1 <div id="example">
 2    <p>Original message: "{{ message }}"</p>
 3    <p>Computed reversed message: "{{ reversedMessage }}"</p>
 4  </div>
 5  var vm = new Vue({
 6    el: '#example',
 7    data: {
 8      message: 'Hello'
 9    },
10    computed: {
11      // 計算屬性的 getter
12      reversedMessage: function () {
13        // `this` 指向 vm 實例
14        return this.message.split('').reverse().join('')
15      }
16    }
17  })
18  // Original message: "Hello"
19 20  // Computed reversed message: "olleH"

 

我們聲明了一個計算屬性 reversedMessage。Vue 知道 vm.reversedMessage 依賴於 vm.message,因此當 vm.message 發生改變時,,所有依賴 vm.reversedMessage 的綁定也會更新。

 

計算屬性緩存 vs 方法

我們通過表達式中調用方法可以同樣達到效果:

1  <p>Reversed message: "{{ reversedMessage() }}"</p>
2  // 在組件中
3  methods: {
4    reversedMessage: function () {
5      return this.message.split('').reverse().join('')
6    }
7  }

 

兩種方式的最終結果確實是完全相同的。然而,不同的是計算屬性是基於它們的響應式依賴進行緩存。只在相關響應依賴發生改變時它們才會重新計算求值。這就意思只要message還沒有改變,多次訪問reversedMessage 計算屬性會立即返回之前的計算結果,而不必再次執行函數

注:這也同樣意味着下面的計算屬性將不再更新,因為 Date.now() 不是響應式依賴:

 
1 computed: {
2    now: function () {
3      return Date.now()
4    }
5  }

 

如你不希望有緩存,請用方法來替代。

 

計算屬性 vs 偵聽屬性

Vue 提供了一種更通用的方式來觀察和響應 Vue 實例上的數據變動:偵聽屬性

但是有些時候可以使用computed代替watch

 

計算屬性的 setter

計算屬性默認只有 getter,不過在需要時你也可以提供一個 setter:

 1  computed: {
 2    fullName: {
 3      // getter
 4      get: function () {
 5        return this.firstName + ' ' + this.lastName
 6      },
 7      // setter
 8      set: function (newValue) {
 9        var names = newValue.split(' ')
10        this.firstName = names[0]
11        this.lastName = names[names.length - 1]
12      }
13    }
14  }

 

現在再運行 vm.fullName = 'John Doe' 時,setter 會被調用,vm.firstNamevm.lastName 也會相應地被更新。

偵聽器

當數據變化要執行異步或者開銷較大的操作,watch 是最有用的選擇。

 

Class於Style綁定

綁定HTML Class

對象語法

①、我們可以傳給 v-bind:class 一個對象,以動態地切換 class:

 
1 <div v-bind:class="{ active: isActive }"></div>

 

是否渲染取決於isActive是 true或false

 

②、你可以在對象中傳入更多字段來動態切換多個 class。此外,v-bind:class 指令也可以與普通的 class attribute 共存。當有如下模板:

 1  <div
 2    class="static"
 3    v-bind:class="{ active: isActive, 'text-danger': hasError }"
 4  ></div>
 5  6  // data定義如下
 7  data: {
 8    isActive: true,
 9    hasError: false
10  }
11 12  // 渲染結果
13  // <div class="static active"></div>

 

 

③、綁定的數據對象不必內聯定義在模板里:

 
1 <div v-bind:class="classObject"></div>
2  data: {
3    classObject: {
4      active: true,
5      'text-danger': false
6    }
7  }

 

 

④、這是一個常用且強大的模式,我們也可以在這里綁定一個返回對象的計算屬性

 <div v-bind:class="classObject"></div>
 data: {
   isActive: true,
   error: null
 },
 computed: {
   classObject: function () {
     return {
       active: this.isActive && !this.error,
       'text-danger': this.error && this.error.type === 'fatal'
     }
   }
 }

 

 

數組語法

①、我們可以把一個數組傳給 v-bind:class,以應用一個 class 列表:

1  <div v-bind:class="[activeClass, errorClass]"></div>
2  data: {
3    activeClass: 'active',
4    errorClass: 'text-danger'
5  }
6  // 渲染為:
7  // <div class="active text-danger"></div>

 

 

②、 數組語法中也可以使用對象語法:

1  <div v-bind:class="[{ active: isActive }, errorClass]"></div>

 

 

用在組件上

當在一個自定義組件上使用 class 時,這些 class 將被添加到該組件的根元素上面。這個元素上已經存在的 class 不會被覆蓋。

你聲明了這個組件:

 
1 Vue.component('my-component', {
2    template: '<p class="foo bar">Hi</p>'
3  })
4  <!-- 在使用它的時候添加一些 class: -->
5  <my-component class="baz boo"></my-component>
6 7  <!-- HTML 將被渲染為: -->
8  <p class="foo bar baz boo">Hi</p>

 

 

 

綁定內聯樣式

對象語法

v-bind:style 的對象語法十分直觀——看着非常像 CSS,但其實是一個 JavaScript 對象。CSS property 名可以用駝峰式 (camelCase) 或短橫線分隔 (kebab-case,記得用引號括起來) 來命名:

 
 1 <div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
 2  3  <!-- 直接綁定到一個樣式對象通常更好,這會讓模板更清晰: -->
 4  <div v-bind:style="styleObject"></div>
 5  data: {
 6    activeColor: 'red',
 7    fontSize: 30
 8  }
 9 10  // 綁定對象
11  data: {
12    styleObject: {
13      color: 'red',
14      fontSize: '13px'
15    }
16  }

 

同樣的,對象語法常常結合返回對象的計算屬性使用。

多重值

從 2.3.0 起你可以為 style 綁定中的 property 提供一個包含多個值的數組,常用於提供多個帶前綴的值,例如:

1  <div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>

 

 

條件渲染

<template>元素上使用v-if條件渲染分組

因為 v-if 是一個指令,所以必須將它添加到一個元素上。但是如果想切換多個元素呢?此時可以把一個 <template> 元素當做不可見的包裹元素,並在上面使用 v-if。最終的渲染結果將不包含 <template> 元素。

1  <template v-if="ok">
2    <h1>Title</h1>
3    <p>Paragraph 1</p>
4    <p>Paragraph 2</p>
5  </template>

 

v-else-if v-else

類似於 v-elsev-else-if 也必須緊跟在帶 v-if 或者 v-else-if 的元素之后。

 

用key可以管理可復用的元素

Vue 會盡可能高效地渲染元素,通常會復用已有元素而不是從頭開始渲染。這么做除了使 Vue 變得非常快之外,還有其它一些好處。例如,如果你允許用戶在不同的登錄方式之間切換:

 
<template v-if="loginType === 'username'">
   <label>Username</label>
   <input placeholder="Enter your username">
 </template>
 <template v-else>
   <label>Email</label>
   <input placeholder="Enter your email address">
 </template>

 

那么在上面的代碼中切換 loginType 將不會清除用戶已經輸入的內容。因為兩個模板使用了相同的元素,<input> 不會被替換掉——僅僅是替換了它的 placeholder

 

這樣也不總是符合實際需求,所以 Vue 為你提供了一種方式來表達“這兩個元素是完全獨立的,不要復用它們”。只需添加一個具有唯一值的 key attribute 即可:

 
<template v-if="loginType === 'username'">
   <label>Username</label>
   <input placeholder="Enter your username" key="username-input">
 </template>
 <template v-else>
   <label>Email</label>
   <input placeholder="Enter your email address" key="email-input">
 </template>

 

現在,每次切換時,輸入框都將被重新渲染。

v-for和v-if

永遠不要把 v-ifv-for 同時用在同一個元素上。

一般我們在兩種常見的情況下會傾向於這樣做:

  • 為了過濾一個列表中的項目 (比如 v-for="user in users" v-if="user.isActive")。在這種情形下,請將 users 替換為一個計算屬性 (比如 activeUsers),讓其返回過濾后的列表。

  • 為了避免渲染本應該被隱藏的列表 (比如 v-for="user in users" v-if="shouldShowUsers")。這種情形下,請將 v-if 移動至容器元素上 (比如 ulol)。

1  <ul>
2    <li
3      v-for="user in users"
4      v-if="user.isActive"
5      :key="user.id"
6    >
7      {{ user.name }}
8    </li>
9  </ul>

 

當 Vue 處理指令時v-forv-if 具有更高的優先級,哪怕我們只渲染出一小部分用戶數據的元素,也得在每次重新渲染的時候遍歷整個列表,不論活躍用戶是否發生變化,應該使用計算屬性

 

列表渲染

v-for

在v-for中,既可以使用數組也可以使用對象

 

狀態維護

當Vue正在更新使用v-for渲染列表時,它默認使用“就地更新策略”。如果數據項的順序被改變,Vue將不會移動DOM元素來匹配數據項的順序,而是就地更新每一個元素,並確保它們在每個位置索引位置正確渲染。

不要使用對象或數組之類的非基本類型值作為v-for的key。請用字符串或數值型的值。

key的特殊主要用在Vue的虛擬DOM算法,在新舊nodes對比時辨識VNodes。如果不使用key,Vue會使用一種最大限度減少動態元素並且盡可能的嘗試就地修改/復用相同類型元素的算法。而使用key時,它會基於key的變化重新排列元素順序,並且會移除key不存在的元素

 

 

事件處理

內聯處理器的方法

有時也需要在內聯語句處理器中訪問原始的DOM事件。可以使用特殊變量$event把它傳入方法:

 <button v-on:click="warn('Form cannot be submitted yet.', $event)">
   Submit
 </button>
 // ...
 methods: {
   warn: function (message, event) {
     // 現在我們可以訪問原生事件對象
     if (event) {
       event.preventDefault()
     }
     alert(message)
   }
 }

 

 

事件修飾符

以上方法雖然可以實現,但是更好的方式是:方法只有純粹的數據邏輯,而不是去處理DOM事件細節。為了解決這個問題,Vue提供了事件修飾符。

 

 .stop  // 等同於js中的event.stopPropagation(),防止事件冒泡 
 .prevent // 取消默認事件,比如a標簽的鏈接跳轉
 .caputer // 捕獲事件,點擊子節點,由外到內父節點->子節點觸發點擊事件(不加是由內到外)
 .self // 只觸發自己范圍內的事件,不會包含子元素
 .once // 只執行一次點擊
 .passive

【瀏覽器只有等內核線程執行到事件監聽器對應的JavaScript代碼時,才能知道內部是否會調用preventDefault函數來阻止事件的默認行為,所以瀏覽器本身是沒有辦法對這種場景進行優化的。這種場景下,用戶的手勢事件無法快速產生,會導致頁面無法快速執行滑動邏輯,從而讓用戶感覺到頁面卡頓。】

通俗點說就是每次事件產生,瀏覽器都會去查詢一下是否有preventDefault阻止該次事件的默認動作。我們加上passive就是為了告訴瀏覽器,不用查詢了,我們沒用preventDefault阻止默認動作。

 

 

表單輸入綁定

修飾符

.lazy

在默認情況下,v-model 在每次 input 事件觸發后將輸入框的值與數據進行同步 。你可以添加 lazy 修飾符,從而轉為在 change 事件之后進行同步:

 <!-- 在“change”時而非“input”時更新 -->
 <input v-model.lazy="msg">
 
 <!--注:ElementUI的input輸入框不支持 `v-model` 修飾符-->

 

number

可以自動將用戶輸入的值轉換成數值類型:

只有這個值無法被 parsenFloat()解析,則會返回原始的值

 <input v-model.number="age" type="number">

 

 

.trim

過濾用戶輸入的收尾空白字符:

 
1 <input v-model.trim="msg">

 

 

 

組件基礎

通過Prop向子組件傳遞數據

傳入一個對象的所有property

如果想將一個對象的所有property都作為prop傳入,可以不用每個參數分別使用v-bind

 
1 post: {
2    id: 1,
3    title: 'My Journey with Vue'
4  }

 

下面的模板

 
1 <blog-post v-bind="post"></blog-post>
2 3  <!-- 等價於 -->
4  <blog-post
5    v-bind:id="post.id"
6    v-bind:title="post.title"
7  ></blog-post>

 

 

單向數據流

所有的prop傳值都讓父子prop之間形成一個單行下行綁定。每次父組件發生變更時,子組件中所有的prop都將會刷新為最新的值,這說明你不應該在子組件內部改prop(強行做,Vue會有警告)

注:JavaScript中數組和對象是通過引用傳入的,對於一個數組或對象類型的prop來說,在子組件中改變變更這個對象的本身將會影響父組件的狀態

 

Prop驗證

 1  Vue.component('my-component', {
 2      props: {
 3          // 基礎的類型檢查('null' 和 'undefined'會通過任何類型的驗證
 4          propA: Number,
 5          // 多個類型
 6          propB: [Number, String]
 7          // 必填字符串
 8          propC: [
 9              type: String,
10              required: true
11          ]
12      }
13  })

 

 

自定義事件

始終使用 kebab-case 的事件名

 

插槽

編譯作用域

父級模板里的所有內容都是在父級作用域中編譯的;子模板里的所有內容都是在子作用域中編譯的。

具名插槽

作用域插槽

 

 

混入

基礎

混入(mixin)提供了一種非常靈活的方式,來分發Vue組件中的可復用功能。一個混入對象可以包含任意組件選項。當組件使用混入對象時,所有混入對象的選項將被混入該組件本身的選項

選項合並

當組件和混入對象有同名選項是, 數據對象在內部會進行遞歸合並,並且在發生沖突時以組件數據優先

 
 1 var mixin = {
 2      data() {
 3          return {
 4              message: 'hello',
 5              foo: 'abc'
 6          }
 7      }
 8  }
 9 10  new Vue({
11      mixin: [mixin],
12      data() {
13          return {
14              message: 'goodbye',
15              bar: 'def'
16          }
17      },
18      created() {
19          console.log(this.$data)
20          // => {message: 'goodbye', foo:'adc', bar: 'def'}
21      }
22  })

 

 

同名鈎子函數將合並為一個數組,因此都將被調用。只是混入對象的鈎子將在組件自身鈎子之前調用

值為對象的選項,例如methods、components和directives,將別合並成同一個對象。兩個對象鍵名沖突時,取組件對象的鍵值對

 

自定義選項合並策略

自定義選項將使用默認策略,即簡單地覆蓋已有值。如果想要自定義選項以自定義邏輯合並,可以向 Vue.config.optionMergeStrategies添加一個函數

 

自定義指令

鈎子函數

鈎子函數參數

動態指令參數

對象字面量

如果指令需要多個值,可以傳入一個JavaScript對象字面量。指令函數可以接受所有合法的JavaScript表達式

1  <div v-demo="{ color: 'white', text: 'hello!' }"></div>
2  Vue.directive('demo', function (el, binding) {
3    console.log(binding.value.color) // => "white"
4    console.log(binding.value.text)  // => "hello!"
5  })

 

 

 

渲染函數 & JSX

看懂百分之30%,過段時間再看

 

路由

編程式導航和聲明式導航

 1  //  聲明式
 2  <router-link :to="....">
 3  4  // 編程式
 5  router.push(...)
 6  // ex:       
 7  // 字符串
 8  router.push('home')
 9  // 對象
10  router.push({ path: 'home' })
11  // 命名的路由
12  router.push({ name: 'user', params: { userId: '123' }})
13  // 帶查詢參數,變成 /register?plan=private
14  router.push({ path: 'register', query: { plan: 'private' }})

 

 

導航守衛

全局前置守衛

router.beforeEach

全局解析守衛

router.beforeResolve

全局后置鈎子

 router.afterEach((to, from) => {
   // ...
 })

路由獨享守衛

  beforeEnter: (to, from, next) => {
         // ...
  }

 

組件內的守衛

① beforeRouteEnter

② beforeRouteUpdate

③ beforeRouteLeave

 
 1  beforeRouteEnter (to, from, next) {
 2      // 在渲染該組件的對應路由被 confirm 前調用
 3      // 不!能!獲取組件實例 `this`
 4      // 因為當守衛執行前,組件實例還沒被創建。
 5       next(vm => {
 6           // 通過`vm`訪問組件實例
 7       })
 8    },
 9    beforeRouteUpdate (to, from, next) {
10      // 在當前路由改變,但是該組件被復用時調用
11      // 舉例來說,對於一個帶有動態參數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉       的時候,
12      // 由於會渲染同樣的 Foo 組件,因此組件實例會被復用。而這個鈎子就會在這個情況下被調       用。
13      // 可以訪問組件實例 `this`
14    },
15    beforeRouteLeave (to, from, next) {
16      // 導航離開該組件的對應路由時調用
17      // 可以訪問組件實例 `this`
18    }

 

完整的導航解析流程

1.導航被觸發。 2.在失活的組件里調用 beforeRouterLeave守衛。 3.調用全局的 beforeEach守衛。 4.在重用的組件里調用 beforeRouterUpdate守衛。 5.在路由配置里調用 beforeEnter 6.解析異步路由組件。 7.在被激活的組件里調用 beforeRouterEnter 8.調用全局的 beforeResolve守衛。 9.導航被確認。 10.調用全局 afterEach鈎子。 11.觸發DOM更新。 12.用創建好的實例調用 beforeRouteEnter 守衛中傳給 next的回調函數。

 

Vuex

State

state 提供唯一的公共數據源。所有共享的數據要統一放到Store的State中進行儲存

組件訪問State中數據的第一種方式:

1  this.$store.state.全局數據名稱

 

組件訪問State中數據的第二種方式:

 
1 // 1.從Vuex中按需導入`mapState`函數
2  import { mapState } from 'vuex'
3 4  // 2.將全局數據,映射為當前組件的計算屬性
5  computed: {
6      ...mapState(['count'])
7  }

 

 

Mutation

Mutation用於變更Store中的數據。

① 只能通過muntation變更Store數據,不可以直接操作Store中的數據。

② 通過這種方式雖然操作起來稍微繁瑣一些,但是可以集中監控所有數據的變化。

 
 1 // 定義motation
 2  mutations: {
 3      add(state) {
 4          // 變更狀態
 5          state.count++
 6      },
 7      // 傳參
 8      addN(state,n) {
 9          state.count+=n
10      }
11  }
12 13  //組件中觸發mutation
14  methods: {
15      handle() {
16          // 觸發mutations 的第一種方式
17          this.$store.commit('add')
18          // 觸發mutations傳參
19          this.$store.commit('addN', 3)
20      }
21  }

 

 

this.$store.commit()是觸發mutations的第一種方式,觸發mutations的第二種方式:

 

1  // 1.從vuex中按需導入`mapMutations`函數
2  import { mapMutations } from 'vuex'
3 4  // 2.將指定的 mutations函數,映射為當前組件的 methods函數
5  methods: {
6      ...mapMutations(['add','addN'])
7  }

 

 

Action

Action用於處理異步任務。

如果通過異步變更數據,必須通過Action,而不能使用Mutation,但是在Action中還是要通過觸發Mutation的方式間接變更數據。

 
// 定義Action
 actions: {
     // context 第一個形參可以理解為當前new 的實例
     addAsync(context,n) {
         setTimeout(() => {
             context.commit('addN',n)
         },1000)
     }
 }
 ​
 // 觸發Action
 methods: {
     handle: {
         // 觸發actions 的第一種方式
         // 攜帶參數
         this.$store.dispath('addAsync', 5)
     }
 }

 

 

this.$store.dispatch()是觸發actions的第一種方式,觸發actions的第二種方式

1  // 1.從vuex中按需導入`mapActions`函數
2  import { mapActions } from 'vuex'
3 4  // 2.將指定的actions函數,映射為當前組件的methods函數
5  methods: {
6      ...mapActions(['addAsync', 'addNAsync'])
7  }

 

 

Getter

Getter用於對Store中的數據進行加工處理形成新的數據。

① Getter可以對Store中已有的數據加工處理之后形成新的數據,類似Vue的計算屬性

② Store中數據發生變化,Getter的數據也會跟着變化。

 
 1 // 定義Getter
 2  const strore = new Vuex.Store({
 3      state: {
 4          count: 0
 5      },
 6      getters: {
 7          showNum: state => {
 8              return '當前最新的數量是【'+ state.count +'】'
 9          }
10      }
11  })

 

使用getters的第一種方式:

 
1 this.$store.getters.名稱

 

使用getters的第二種方式:

 
1 import { MapGetters } from 'vuex'
2 3  computed: {
4      ...mapGetters(['showNum'])
5  }

 

 

namespaced

這個屬性是用來解決不同模塊命名沖突的問題:

1  // 不同頁面引入getter、actions、mutations時,要加上模塊名
2  // ex
3  ...mapGetters('BadInfo', ['DialogDate'])
4 5  // 第二種寫法
6  this.$store.commit('XXX/SETXXX',sth);
7  this.$store.getters['XXX/getXXX'];

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM