一.MVVM
MVVM 是 Model-View-ViewModel 的縮寫。
Model
代表資料模型,也可以在Model中定義資料修改和操作的業務邏輯。View
代表UI 元件,它負責將資料模型轉化成UI 展現出來。ViewModel
監聽模型資料的改變和控制檢視行為、處理使用者互動,簡單理解就是一個同步View 和 Model的物件,連線Model和View。
在MVVM架構下,View 和 Model 之間並沒有直接的聯絡,而是通過ViewModel進行互動,Model 和 ViewModel 之間的互動是雙向的, 因此View 資料的變化會同步到Model中,而Model 資料的變化也會立即反應到View 上。
ViewModel 通過雙向資料繫結把 View 層和 Model 層連線了起來,而View 和 Model 之間的同步工作完全是自動的,無需人為干涉,因此開發者只需關注業務邏輯,不需要手動操作DOM, 不需要關注資料狀態的同步問題,複雜的資料狀態維護完全由 MVVM 來統一管理。
注意, MVVM模型中, Model和View是不會直接連線的,而ViewModel則會以雙向連線的形式連線Model和View。
二.Vue和React的區別
Vue的優點
- 輕量級的框架
- 雙向資料繫結
- 指令
- 外掛化
與React的對比
兩者具有許多的相似之處
- 使用 Virtual DOM
- 提供了響應式 (Reactive) 和元件化 (Composable) 的檢視元件。
- 將注意力集中保持在核心庫,而將其他功能如路由和全域性狀態管理交給相關的庫。
Vue與React的不同之處
- 元件的重渲染 React中元件的重渲染需要通過
shouldComponentUpdate
來避免不必要的子元件的重渲染,而Vue中元件的依賴是在渲染過程中自動追蹤的,所以系統能精確知曉哪個元件確實需要被重渲染。 - JSX vs Template 在 React 中,所有的元件的渲染功能都依靠 JSX。JSX 是使用 XML 語法編寫 JavaScript 的一種語法糖。Vue預設推薦使用Vue模板(更適用於表現類),但Vue也支援JSX。
- 元件的重渲染 React中元件的重渲染需要通過
元件作用域的CSS 在React中,CSS 作用域是通過 CSS-in-JS 的方案實現的 (比如 styled-components、glamorous 和 emotion),而Vue則有更好的解決方案,如下:
<style scoped> @media (min-width: 250px) { .list-container:hover { background: orange; } } </style>複製程式碼
這個可選
scoped
屬性會自動新增一個唯一的屬性 (比如data-v-21e5b78
) 為元件內 CSS 指定作用域,編譯的時候.list-container:hover
會被編譯成類似.list-container[data-v-21e5b78]:hover
,這樣就可以控制CSS只在這個元件內生效。
三.VUE知識點
1. Vue的生命週期
- beforeCreate
- created
- beforeMount
- mounted
- beforeUpdated
- updated
- beforeDestroy
- destroyed
大致過程就是
- 資料初始化(1~2)
完成資料觀測、屬性和方法的運算載入,event/wather時間回撥。 - dom掛載階段(3~4)
el被新建立的vm.$el替換並掛載到例項上去,之後呼叫鉤子函式。 - 資料更新階段(5~6)
資料更新,虛擬dom重渲染 - 元件解除安裝階段(7~8)
銷燬例項及子例項
2. Vue實現資料雙向繫結的原理
Vue實現這種資料雙向繫結的效果,需要三大模組:
- Observer:能夠對資料物件的所有屬性進行監聽,如有變動可拿到最新值並通知訂閱者。
- Compile:對每個元素節點的指令進行掃描和解析,根據指令模板替換資料,以及繫結相應的更新函式
- Watcher:作為連線Observer和Compile的橋樑,能夠訂閱並收到每個屬性變動的通知,執行指令繫結的相應回撥函式,從而更新檢視
Observer
Observer的核心是通過Obeject.defineProperty()
來監聽資料的變動,這個函式內部可以定義setter
和getter
,每當資料發生變化,就會觸發setter
。這時候Observer
就要通知訂閱者,訂閱者就是Watcher
。
Watcher
Watcher
訂閱者作為Observer
和Compile
之間通訊的橋樑,主要做的事情是:
- 在自身例項化時往屬性訂閱器(dep)裡面新增自己
- 自身必須有一個
update()
方法 - 待屬性變動
dep.notice()
通知時,能呼叫自身的update()方法,並觸發Compile
中繫結的回撥
Compile
Compile
主要做的事情是解析模板指令,將模板中的變數替換成資料,然後初始化渲染頁面檢視,並將每個指令對應的節點繫結更新函式,新增監聽資料的訂閱者,一旦資料有變動,收到通知,更新檢視。
vue資料雙向繫結原理詳解在這裡剖析Vue原理&實現雙向繫結MVVM
3.vue-router
Vue Router 是vue官方推建的路由管理器。它和 Vue.js 的核心深度整合,讓構建單頁面應用變得易如反掌。包含的功能有:
- 巢狀的路由/檢視表
- 模組化的、基於元件的路由配置
- 路由引數、查詢、萬用字元
- 基於 Vue.js 過渡系統的檢視過渡效果
- 細粒度的導航控制
- 帶有自動啟用的 CSS class 的連結
- HTML5 歷史模式或 hash 模式,在 IE9 中自動降級
- 自定義的滾動條行為
(1)動態路由匹配
一個“路徑引數”使用冒號 :
標記。當匹配到一個路由時,引數值會被設定到 this.$route.params
,可以在每個元件內使用。
const router = new VueRouter({
routes: [
// 動態路徑引數 以冒號開頭
{ path: '/user/:id', component: User }
]
})複製程式碼
使用$route.params和$route.query獲取路由中的引數。
(2)巢狀路由
在專案的開發中常常在一個父路由下新增若干的字路由,也可以在子路由中新增後代路由,即路由的巢狀。
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User,
children: [
{
path: 'profile',
component: UserProfile
},
{
path: 'posts',
component: UserPosts
}
]
}
]
})複製程式碼
要注意,以 /
開頭的巢狀路徑會被當作根路徑。 這讓你充分的使用巢狀元件而無須設定巢狀的路徑。
(3).程式設計式導航(跳轉)
router-link: 路由標籤實現前端路由的跳轉,本質上是$router.push(),通過tag渲染成目標標籤,to轉到目的路由。
<router-link tag='div' to='./user'></router-link>複製程式碼
router.push: 想要導航到不同的 URL,則使用 router.push
方法。這個方法會向 history 棧新增一個新的記錄,所以,當使用者點選瀏覽器後退按鈕時,則回到之前的 URL。
router.replace: 跟 router.push
很像,唯一的不同就是,它不會向 history 新增新記錄,而是跟它的方法名一樣 —— 替換掉當前的 history 記錄。
router.go(n): 這個方法的引數是一個整數,意思是在 history 記錄中向前或者後退多少步,類似 window.history.go(n)
。
(4)路由重定向和路由模式
重定向:通過redirect屬性,將目的路由指向對應路由
路由模式:hash路由和history路由(通過設定mode的值來改變路由模式)
vue-router
預設 hash 模式 —— 使用 URL 的 hash 來模擬一個完整的 URL,於是當 URL 改變時,頁面不會重新載入,但是會在URL後新增’#‘號,不是很美觀。
http://www.rosenwang.xyz:8080/#/home ----hash
複製程式碼
history路由則顯得更加符合要求,但是需要後端的支援,如何直接使用,上線後訪問會出現404.
http://www.rosenwang.xyz:8080/home -history複製程式碼
(5)導航守衛
全域性守衛:beforeEach,afterEach
路由獨享守衛:beforeEnter,afterEnter
元件內守衛:beforeRouterEnter,beforeRouterUpdate,beforeRouterLeave
每個守衛方法接收三個引數:
to: Route
: 即將要進入的目標 路由物件from: Route
: 當前導航正要離開的路由next: Function
: 一定要呼叫該方法來 resolve 這個鉤子。執行效果依賴next
方法的呼叫引數。
確保要呼叫 next
方法,否則鉤子就不會被 resolved。
(6)路由懶載入
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')複製程式碼
4.父子元件
(1)父元件向子元件傳參
父元件通過標籤上定義傳值,子元件通過props
方法接受資料
<parent>
<child :child-msg="msg"></child> //這裡必須要用 - 代替駝峰
</parent>
props: {
childMsg: {
type: Array, //傳入的型別
default: [] //預設值
}
}複製程式碼
(2)子元件向父元件傳遞資料
子元件通過$emit
方法傳遞引數,父元件通過v-on
(簡寫為@
)來監聽DOM事件,並在觸發時接收資料執行js函式。
//子元件
testClick() {
this.$emit('test','123');
//$emit(even,value)even 是一個函式,value 是傳給父元件的值
}
//父元件
<div>
<child @test="change" :msg="msg"></child> //監聽子元件觸發的test事件,然後呼叫change方法
</div>
methods: {
change(val) {
this.msg = val; // val: 123
}
}複製程式碼
(3)非父子元件資料傳遞
通過vuex統一實現狀態管理,實現了非父子元件內的資料通訊
5. Vue響應資料變化的幾種做法
- methods: 每次獲取都會重新計算求值
- computed(計算屬性,有快取): 基於資料依賴進行快取,只有當資料變化時,才會重新求值。(計算屬性只有 getter,可以在需要的時候自己設定 setter)。computed 擅長處理的情景:一個資料受多個資料影響。
- watch: 當需要在資料變化時執行非同步操作或者消耗較大的操作時,比較有效。watch 擅長處理的情景:一個資料影響多個資料。
- v-model: 基於資料雙向繫結(對於 v-for 迴圈列表中的項,需要使用鍵值)
6. Vue的條件渲染
v-if
是真正的條件渲染,它會適當地銷燬和重建DOM達到讓元素顯示和隱藏的效果。
v-show 通過修改元素的display的CSS屬性讓其顯示或者隱藏,元素始終會被渲染並保留在DOM中。
v-if vs v-show
一般來說,v-if
有更高的切換開銷,而 v-show
有更高的初始渲染開銷。因此,如果需要非常頻繁地切換,則使用 v-show
較好;如果在執行時條件很少改變,則使用 v-if
較好。