下面是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 }
現在再運作時,setter 會被調用,
vm.fullName = \'John Doe\'
和
vm.firstName
也會相應地被更新。
vm.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-else
,
v-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-if
和
v-for
同時用在同一個元素上。
一般我們在兩種常見的情況下會傾向于這樣做:
- 為了過濾一個清單中的項目 (比如
)。在這種情形下,請将v-for="user in users" v-if="user.isActive"
替換為一個計算屬性 (比如users
),讓其傳回過濾後的清單。activeUsers
- 為了避免渲染本應該被隐藏的清單 (比如
)。這種情形下,請将v-for="user in users" v-if="shouldShowUsers"
移動至容器元素上 (比如v-if
、ul
)。ol
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-for
具有更高的優先級,哪怕我們隻渲染出一小部分使用者資料的元素,也得在每次重新渲染的時候周遊整個清單,不論活躍使用者是否發生變化,應該使用計算屬性
v-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\'];