1. VUE特點(diǎn)
輕量
使用gzip最小壓縮后有20kb,react有35kb,angular有60kb漸進(jìn)式框架
你不需要完全了解他,就可以用,各取所需,只是個(gè)輕量視圖而已響應(yīng)式的更新機(jī)制
數(shù)據(jù)改變后,視圖會(huì)自動(dòng)更新,而不像react那樣用shouldComponentUpdate進(jìn)行性能優(yōu)化學(xué)習(xí)成本低
模板語法是基于html,容易上手
2. 生命周期

Vue的所有生命周期函數(shù)都是自動(dòng)綁定到this的上下文上,所以不需要用到箭頭函數(shù)。
頁面加載大致過程:
- beforeCreate:無法獲取到prop的data
- created: 經(jīng)過數(shù)據(jù)初始化,此時(shí)可以獲取prop和data,但是組件尚未掛載;
- beforeMount: 開始創(chuàng)建虛擬dom,如果組件中有子組件,先遞歸掛載子組件,再掛載根組件的
- mounted: 將虛擬dom渲染為真實(shí)dom。
- 數(shù)據(jù)更新
更新前:beforeUpdates
更新后: updated - 頁面銷毀
銷毀前:beforeDestory
銷毀后: destoryed
4. Vue 的父組件和子組件生命周期鉤子函數(shù)執(zhí)行順序
(1)加載渲染過程
beforeCreated(父) ->>created(父)->> beforeMounted(父) ->>
子組件渲染:beforeCreated(子) ->> created(子)->> beforeMounted(子) ->> mounted(子)
--> mounted(父)
(2)子組件更新
beforeUpdate(父) --> beforeUpdate(子) -> updated( 子) -> updated(父)
(3)父組件更新
beforeUpdate(父) --> updated(父)
(4)銷毀
beforeDestroy(父) -> beforeDestroy (子)-> destroyed(子) -> destroyed(父)
3. vue基本指令
v-show
當(dāng)條件為true時(shí)候display: block,否則是display: none;無論什么條件都會(huì)被渲染出來,渲染之后只是css屬性的切換,渲染時(shí)候有一定的開銷,適合頻繁切換的場景。v-if
根據(jù)條件來渲染,如果是false,那一開始就不會(huì)渲染,但是切換條件時(shí)會(huì)觸發(fā)銷毀和掛載,所以在切換時(shí)候開銷比較大,不適合頻繁切換的場景v-for
<li v-for="(item, index) in items" :key="item.message">
{{index}} {{ item.message }}
</li>
- v-model
v-model其實(shí)是一個(gè)語法糖
v-model會(huì)忽略所有表單元素的value、checked、selectedattribute 的初始值而總是將 Vue 實(shí)例的數(shù)據(jù)作為數(shù)據(jù)來源。你應(yīng)該通過 JavaScript 在組件的data選項(xiàng)中聲明初始值。
<input v-model="name"></input>
//等價(jià)于
<input
v-bind:value="name"
v-bind:input="name = arguments[0]"
></input>
就是一種雙向綁定的過程,視圖影響數(shù)據(jù),數(shù)據(jù)影響視圖,說明視圖是可交互的,一般和表單有關(guān)系
- v-on簡寫@ 綁定事件
- v-bind:簡寫: 綁定屬性
- v-text顯示文本
- v-pre不編譯雙花括號,直接顯示字符串
- v-html可以顯示html字符串
4. 組件的三大核心概念
(1)屬性
? ① 自定義屬性props,表示組件props中聲明的屬性
? ②原生屬性,比如<Test title="測試"></Test>,默認(rèn)在組件中的根元素上就會(huì)有title="測試"的屬性;
? 在Test組件中設(shè)置inheritAttrs: false就可以關(guān)閉自動(dòng)掛載
? ③特殊屬性,style, class掛載到組件根元素上
(2)事件
? ①普通事件
- @click
- @change
- @input
- @xxx
子組件通過this.$emit("xxx", 參數(shù)1, 參數(shù)2, 參數(shù)...)
? ②修飾符事件
@input.trim (去掉兩端空格)
@click.stop(阻止冒泡事件或者在事件中使用e.stopPropagation)
-
@submit.prevent(去除默認(rèn)事件)
一般用于原生html的行為
(3)插槽
? ① 普通插槽
//老語法
<template slot="xxx"> ...<template>
//2.6版本語法
<template v-slot:xxx> ...<template>
② 作用域插槽
可以獲取屬性
<template slot="xxx" slot-scope="props">{{props}}</template>
<template v-slot:xxx="props">{{props}}</template>
組件:
<template>
<div>
<slot name="xxx" />
<slot v-bind="{value: 'value'}" />
</div>
</template>
5. MVVM和MVC模式的區(qū)別
- MVC
MVC是最經(jīng)典的模型,即Model(模型)、Controller(控制器)、View(視圖)
當(dāng)用戶操作頁面時(shí),view層會(huì)發(fā)出指令到controller,controller去通知model更新數(shù)據(jù)。一旦model發(fā)生改變,就通知視圖更新。
- MVVM
MVVM即Model-View-ViewModel,實(shí)現(xiàn)了view和model的自動(dòng)同步,ViewModel 通過雙向數(shù)據(jù)綁定把 View 層和 Model 層連接了起來。VM起到了雙向綁定的作用,View(視圖) 和 Model(數(shù)據(jù)) 無法直接通訊,在它們之間存在著 ViewModel 中間介充當(dāng)觀察者角色。當(dāng)用戶操作 View(視圖),ViewModel 感知到變化,然后通知 Model 發(fā)生相應(yīng)改變;反之當(dāng) Model(數(shù)據(jù)) 發(fā)生改變,ViewModel 也能感知到變化,使 View 作出相應(yīng)更新。
6. 單向數(shù)據(jù)流和雙向綁定
雙向綁定:
model更新會(huì)觸發(fā)view更新;
view的更新會(huì)觸發(fā)model更新;
單向數(shù)據(jù)流:
model更新會(huì)觸發(fā)view更新;
view的更新和model沒有關(guān)系
vue是單向數(shù)據(jù)流,不是雙向綁定,vue的雙向綁定不過是語法糖,而Object.defineProperty是用來做響應(yīng)式更新的,對屬性設(shè)置set函數(shù),當(dāng)屬性改變時(shí)候,就會(huì)觸發(fā)這個(gè)函數(shù)
實(shí)現(xiàn)過程:
vue自定義v-model
一個(gè)組件的v-model默認(rèn)會(huì)有prop: value,event: input,但是我們可以自定義
//定義子組件
Vue.component('Child', {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean
},
template: <input type="checkbox" :checked="checked" @change="$emit('change', $event.target.checked)">
})
//在父組件中使用
<Child v-model="data" />
此時(shí)data的值會(huì)被傳遞到子組件中,為checked屬性
7. vue中sync修飾符
.sync是為了方便父子之間通信,當(dāng)子組件想要改變父組件傳遞進(jìn)來的屬性時(shí),比如一個(gè)控制modal是否顯示的屬性,子組件就要使用$emit('xxx', 'xxx')
vue提供update: propertyName模式觸發(fā)事件
//子組件更改屬性
this.$emit("update:visible", false)
//父組件
<Child :visible="show" @update:visible="val => show = val" />
那么為了簡化寫法,出現(xiàn)了sync修飾符
//子組件更改屬性
this.$emit("update:visible", false)
//父組件
<Child :visible.sync="show" />
父組件不需要定義,默認(rèn)存在@update:visible="val => show = val"
8. 組件更新
組件更新的條件
①屬性需要在data里面聲明,這樣才能做響應(yīng)式
②如果data中聲明一個(gè)對象
data() {
return {
info: {}
}
}
//這種不會(huì)觸發(fā)更新
this.info.name = "a"
修改為:
data() {
return {
info: { name: undefined }
}
}
③如果在模板中沒有用到某個(gè)屬性,那么修改這個(gè)屬性也不會(huì)觸發(fā)組件更新
④如果data中有一個(gè)數(shù)組屬性
直接push也會(huì)觸發(fā)組件更新
那么vue是如何進(jìn)行組件更新的呢?
當(dāng)vue進(jìn)行實(shí)例化時(shí)候,會(huì)使用Object.defineProperty對data中的屬性設(shè)置set和get方法,相當(dāng)于代理層;
將模板中需要用到的屬性放到watch,如果修改了屬性,在set函數(shù)中會(huì)去通知watch,然后watch去觸發(fā)組件的更新。

9. compute和watch屬性的區(qū)別
計(jì)算屬性compute
作用:
① 減少模板中計(jì)算邏輯
② 緩存數(shù)據(jù)
③ 依賴固定的數(shù)據(jù)類型,不會(huì)重新再計(jì)算,只有在數(shù)據(jù)變化時(shí)候才會(huì)計(jì)算
對比:
<p>{{reverseStr}}</p>
<p>{{reverseStr2}}</p>
computed: {
reverseStr: function() {
this.str.split("").reverse.join("")
}
}
data() {
reverseStr2: function() {
this.str.split("").reverse.join("")
}
}
$forceUpdate刷新頁面,str沒變化時(shí)候,reverseStr不會(huì)執(zhí)行計(jì)算,reverseStr2會(huì)被調(diào)用
監(jiān)聽屬性watch
監(jiān)聽數(shù)據(jù)的變化
data() {
a:1,
b: {
c: 2
},
d: {
e: {
f: 3
}
}
}
//各個(gè)屬性監(jiān)聽方式,
watch: {
a(val, old) {},
"b.c": function(val, old),
// d及以下的所有屬性都會(huì)被監(jiān)聽,deep表示深度監(jiān)聽;immediate表示是否在第一次渲染就執(zhí)行這個(gè)監(jiān)聽
d: {
handler: function(val, old) {},
deep: true,
immediate: true
}
}
如果一個(gè)數(shù)據(jù)需要經(jīng)過復(fù)雜計(jì)算就用 computed;
如果一個(gè)數(shù)據(jù)需要被監(jiān)聽并且對數(shù)據(jù)做一些操作就用 watch
10. vue組件通信方式
①props和$emit父子組件通信
這個(gè)是最基礎(chǔ)的組件通信,父組件通過v-bind:xxx="xx"傳遞屬性,v-on:xxx="xx"綁定事件;
子組件通過props獲取,$emit觸發(fā)父組件傳遞的事件。
//父組件
<template>
<div>
<Child :msg="message" @changeStates="change"></child>
</div>
</template>
//子組件
<template>
{{msg}}
<button @click="clickHandle">點(diǎn)擊</button>
</template>
<script>
import Child from "./Child";
export default {
name: "Child",
props: ["msg"],
components:{
Child
},
methods: {
clickHandle() {
this.$emit("changeStates", "變了");
}
}
};
</script>
②ref
ref如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子組件上,引用就指向組件實(shí)例。
//父組件
<template>
<div>
<child ref="son"></child>
</div>
</template>
//子組件
<template>
<div>
<input ref="inputRef" type="text" value="hi"></child>
</div>
</template>
// 獲取子組件的屬性和方法
//獲取子組件input框的內(nèi)容
this.$refs.son.$refs.inputRef.value
③children
直接使用,但是建議少用
父組件:
<template>
<div>
<child></child>
</div>
</template>
<script>
export default {
name: 'parent',
data: () => ({
msg: "Hi, I am your father"
}),
mounted() {
console.log(this.$children[0].msg)
}
}
</script>
子組件:
<template>
<div>Hello Boy</div>
</template>
<script>
export default {
name: "child",
data: () => ({
msg: "hi"
}),
mounted() {
console.log(this.$parent.msg); //
}
};
</script>
④EventBus中央數(shù)據(jù)總線,
on
通過創(chuàng)建一個(gè)空的vue實(shí)例作為中央事件總線,用于觸發(fā)和監(jiān)聽事件,類型于addListener
⑤
listeners隔代組件通信
$attrs 里存放的是父組件中綁定的非 Props 屬性;
$listeners里存放的是父組件中綁定的非原生事件;
// 父組件
<template>
<div>
<child-a
:name="name"
:age="age"
:job="job"
title="This is a title"
@click="post"
></child-a>
</div>
</template>
// 子組件child-a中
<template>
<div>
<child-b v-bind="$attrs" v-on="$listeners"></child-b>
</div>
</template>
this.$attrs
// {name: "name", age: "28", job: "worker", title: "This is a title"}
this.$listeners.click()
// hello
// 子組件child-b中
<template>
<div>
<p>B-listeners: {{ this.$listeners.click() }}</p>
</div>
</template>
<script>
export default {
props: ["name"], // name 作為props屬性綁定
inheritAttrs: false, // 可以關(guān)閉自動(dòng)掛載到組件根元素上的沒有在props聲明的屬性
created() {
console.log(this.$attrs);
// {age: "28", job: "worker", title: "This is a title"}
console.log(this.$listeners.click()); // hello
}
};
</script>
⑥provide和inject
祖先組件中通過 provider 來提供變量,然后在子孫組件中通過 inject 來注入變量。
provide 和 inject 主要在開發(fā)高階插件/組件庫時(shí)使用
除此之外,還有vuex狀態(tài)管理,如下所示
11. Vuex狀態(tài)管理
vuex類似于react的redux,當(dāng)開發(fā)大型單頁應(yīng)用,多個(gè)視圖組件依賴同一個(gè)狀態(tài),比如登錄狀態(tài),用戶信息等。當(dāng)狀態(tài)更新時(shí)候,這些使用過狀態(tài)的組件都要更新。針對這種情況,可以使用vuex來解決。
特點(diǎn):
(1)狀態(tài)存儲(chǔ)是響應(yīng)式的,組件從store中讀取狀態(tài),如果狀態(tài)發(fā)生變化,則會(huì)自動(dòng)更新到組件
(2)不能直接修改store中的狀態(tài)
使用方式:
import vue from 'vue';
import vuex from 'vuex';
const store = new Vuex.Store({
state: {},
getters: {}
mutations: {},
actions: {}
})
// 通過根組件直接注入,這樣所有的組件都可以使用store
new Vue({
e1: "#app",
store
})
組成部分:
-
state
作為模塊唯一數(shù)據(jù)源,包含了所有的狀態(tài),訪問state方式:
this.$store.state.xxx
mapState簡化方式訪問:
import { mapState } from 'vuex';
export default {
computed: mapState({
count: state => state.count,
myCount: 'count',
// 和當(dāng)前的數(shù)據(jù)操作
add(state) {
return state.count + this.nowCount
}
})
}
store中的變量名和當(dāng)前組件中要使用的變量名相同
import { mapState } from 'vuex';
export default {
computed: mapState([
'count'
])
}
最常用的就是對象展開符的方式:
import { mapState } from 'vuex';
export default {
computed: {
...mapState([
'count'
])
other(){}
}
}
-
getters
當(dāng)我們不滿足直接使用store中state數(shù)據(jù),比如篩選計(jì)算等處理,如果多個(gè)組件都需要這種,那么最好的方式是在store中定義:
getters: {
toDo : state => {
return state.toDo.filter(i => i.toDoThings)
}
}
視圖中訪問方式:
this.$store.getters.toDo
mapGetters簡化的方式:
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters([
'tODo',
])
}
}
//訪問方式: this.tODo
-
mutation
這個(gè)用于修改state屬性,調(diào)用的必須是同步的事件
mutations: {
increment(state, num) {
state.count = state.count + num
}
}
調(diào)用方式:
this.$store.commit('increment', 10)
mapMutations簡化方式:
import { mapMutations } from 'vuex'
export default {
// ...
methods: {
...mapMutations([
'increment', // 將 `this.increment()` 映射為 `this.$store.commit('increment')`
]),
...mapMutations({
add: 'increment' // 將 `this.add()` 映射為 `this.$store.commit('increment')`
})
}
}
-
action
類似于mutation,可以提交mutation修改state
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
//或者通過參數(shù)解構(gòu)
actions: {
increment ({ commit }) {
commit('increment')
}
}
})
處理異步的業(yè)務(wù)
actions: {
increment ({ commit, state }, payload) {
// ...
}
}
觸發(fā):
this.$store.dispatch('increment')
mapAtions簡化方式
import { mapMutations } from 'vuex'
export default {
// ...
methods: {
...mapActions([
'increment', // 將 `this.increment()` 映射為 `this.$store.commit('increment')`
]),
...mapActions({
add: 'increment' // 將 `this.add()` 映射為 `this.$store.commit('increment')`
})
}
}