即Model-View-ViewModel。vue
Vue是以數據爲驅動的,Vue自身將DOM和數據進行綁定,一旦建立綁定,DOM和數據將保持同步,每當數據發生變化,DOM會跟着變化。ios
ViewModel是Vue的核心,它是Vue的一個實例。Vue實例時做用域某個HTML元素上的,這個HTML元素能夠是body,也能夠是某個id所指代的元素。ajax
DOM Listeners和Data Bindings是實現雙向綁定的關鍵。vue-router
DOM Listeners監聽頁面全部View層DOM元素的變化,當發生變化,Model層的數據隨之變化;Data Bindings監聽Model層的數據,當數據發生變化,View層的DOM元素隨之變化。vuex
beforeCreate階段: vue實例的掛載元素$el和數據對象data都爲undefined,還爲初始化。
created階段:vue實例的數據對象data有了,$el尚未
beforeMount階段:vue實例的$el和data都初始化了,但仍是掛載以前爲虛擬的DOM節點,data還沒有替換。
mounted階段:vue實例掛載完成,data成功渲染。
beforeUpdate/updated階段:
當data變化時,會觸發beforeUpdate和updated方法。這兩個不經常使用,不推薦使用。
beforeDestory/destoryed階段:
beforeDestory是在vue實例銷燬前觸發,通常在這裏要經過removeEventListener解除手動綁定的事件。實例銷燬後,觸發的destroyed。
複製代碼
vue.js 是採用數據劫持結合發佈者-訂閱者模式的方式,經過Object.defineProperty()來劫持各個屬性的setter,getter,在數據變更時發佈消息給訂閱者,觸發相應的監聽回調。json
具體步驟:axios
第一步:須要observe的數據對象進行遞歸遍歷,包括子屬性對象的屬性,都加上 setter和getter 這樣的話,給這個對象的某個值賦值,就會觸發setter,那麼就能監聽到了數據變化後端
第二步:compile解析模板指令,將模板中的變量替換成數據,而後初始化渲染頁面視圖,並將每一個指令對應的節點綁定更新函數,添加監聽數據的訂閱者,一旦數據有變更,收到通知,更新視圖api
第三步:Watcher訂閱者是Observer和Compile之間通訊的橋樑,主要作的事情是: 一、在自身實例化時往屬性訂閱器(dep)裏面添加本身 二、自身必須有一個update()方法 三、待屬性變更dep.notice()通知時,能調用自身的update()方法,並觸發Compile中綁定的回調,則功成身退。緩存
第四步:MVVM做爲數據綁定的入口,整合Observer、Compile和Watcher三者,經過Observer來監聽本身的model數據變化,經過Compile來解析編譯模板指令,最終利用Watcher搭起Observer和Compile之間的通訊橋樑,達到數據變化 -> 視圖更新;視圖交互變化(input) -> 數據model變動的雙向綁定效果。
由於組件是用來複用的,JS 裏對象是引用關係,這樣做用域沒有隔離,而 new Vue 的實例,是不會被複用的,所以不存在引用對象的問題。
答:能夠實現雙向綁定,指令(v-class、v-for、v-if、v-show、v-on)。vue的model層的data屬性。綁定事件:<input @click=doLog() />
v-show指令是經過修改元素的displayCSS屬性讓其顯示或者隱藏
v-if指令是直接銷燬和重建DOM達到讓元素顯示和隱藏的效果
將當前組件的<style>
修改成<style scoped>
<keep-alive></keep-alive>
的做用是什麼?<keep-alive></keep-alive>
包裹動態組件時,會緩存不活動的組件實例,主要用於保留組件狀態或避免從新渲染。
提供一個在頁面上已存在的 DOM 元素做爲 Vue 實例的掛載目標.能夠是 CSS 選擇器,也能夠是一個 HTMLElement 實例
答:全局定義指令:在vue對象的directive方法裏面有兩個參數,一個是指令名稱,另一個是函數。組件內定義指令:directives
鉤子函數:bind(綁定事件觸發)、inserted(節點插入的時候觸發)、update(組件內相關更新)
鉤子函數參數:el、binding
若是請求來的數據是否是要被其餘組件公用,僅僅在請求的組件內使用,就不須要放入vuex 的state裏。
若是被其餘地方複用,這個很大概率上是須要的,若是須要,請將請求放入action裏,方便複用.
computed 是計算屬性,依賴其餘屬性計算值,而且 computed 的值有緩存,只有當計算值變化纔會返回內容。
watch 監聽到值的變化就會執行回調,在回調中能夠進行一些邏輯操做。因此通常來講須要依賴別的屬性來動態得到值的時候可使用 computed,對於監聽到值的變化須要作一些複雜業務邏輯的狀況可使用 watch。
問題: obj.b已經成功添加,可是視圖並未刷新
緣由:緣由在於在Vue實例建立時,obj.b並未聲明,所以就沒有被Vue轉換爲響應式的屬性,天然就不會觸發視圖的更新,這時就須要使用Vue的全局api $set()
方法:$set()方法至關於手動的去把obj.b處理成一個響應式的屬性,此時視圖也會跟着改變了
父組件與子組件傳值
父組件傳給子組件:子組件經過props方法接受數據;
子組件傳給父組件:$emit方法傳遞參數
非父子組件間的數據傳遞,兄弟組件傳值
eventBus,就是建立一個事件中心,至關於中轉站,能夠用它來傳遞事件和接收事件。項目比較小時,用這個比較合適。
只用來讀取的狀態集中放在store中; 改變狀態的方式是提交mutations,這是個同步的事物; 異步邏輯應該封裝在action中。
在main.js引入store,注入。新建了一個目錄store,….. export 。
場景有:單頁應用中,組件之間的狀態、音樂播放、登陸狀態、加入購物車 圖片描述
state
Vuex 使用單一狀態樹,即每一個應用將僅僅包含一個store 實例,但單一狀態樹和模塊化並不衝突。存放的數據狀態,不能夠直接修改裏面的數據。
mutations
mutations定義的方法動態修改Vuex 的 store 中的狀態或數據。
getters
相似vue的計算屬性,主要用來過濾一些數據。
action
actions能夠理解爲經過將mutations裏面處裏數據的方法變成可異步的處理數據的方法,簡單的說就是異步操做數據。view 層經過 store.dispath 來分發 action。
const store = new Vuex.Store({ //store實例
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})
複製代碼
const User = {
template: '<div>User</div>'
}
const router = new VueRouter({
routes: [
// 動態路徑參數 以冒號開頭
{ path: '/user/:id', component: User }
]
})
一個「路徑參數」使用冒號 : 標記。當匹配到一個路由時,參數值會被設置到 this.$route.params,能夠在每一個組件內使用。
複製代碼
提醒一下,當使用路由參數時,例如從 /user/foo 導航到 /user/bar,原來的組件實例會被複用。由於兩個路由都渲染同個組件,比起銷燬再建立,複用則顯得更加高效。不過,這也意味着組件的生命週期鉤子不會再被調用。
複用組件時,想對路由參數的變化做出響應的話,你能夠簡單地 watch (監測變化) $route 對象:
const User = {
template: '...',
watch: {
'$route' (to, from) {
// 對路由變化做出響應...
}
}
}
複製代碼
全局前置守衛
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
to: Route: 即將要進入的目標 路由對象
from: Route: 當前導航正要離開的路由
next: Function: 必定要調用該方法來 resolve 這個鉤子。執行效果依賴 next 方法的調用參數。
複製代碼
全局後置鉤子
router.afterEach((to, from) => {
// ...
})
複製代碼
路由獨享的守衛
你能夠在路由配置上直接定義 beforeEnter 守衛:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
複製代碼
組件內的守衛
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// 在渲染該組件的對應路由被 confirm 前調用
// 不!能!獲取組件實例 `this`
// 由於當守衛執行前,組件實例還沒被建立
},
beforeRouteUpdate (to, from, next) {
// 在當前路由改變,可是該組件被複用時調用
// 舉例來講,對於一個帶有動態參數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候,
// 因爲會渲染一樣的 Foo 組件,所以組件實例會被複用。而這個鉤子就會在這個狀況下被調用。
// 能夠訪問組件實例 `this`
},
beforeRouteLeave (to, from, next) {
// 導航離開該組件的對應路由時調用
// 能夠訪問組件實例 `this`
}
}
複製代碼
結合 Vue 的異步組件和 Webpack 的代碼分割功能,輕鬆實現路由組件的懶加載。
這就是如何定義一個可以被 Webpack 自動代碼分割的異步組件。
const Foo = () => import('./Foo.vue')
在路由配置中什麼都不須要改變,只須要像往常同樣使用 Foo:
const router = new VueRouter({
routes: [
{ path: '/foo', component: Foo }
]
})
複製代碼
第一步: 路由 多添加一個自定義字段 requireAuth
path: '/repository',
name: 'repository',
meta: {
requireAuth: true, // 添加該字段,表示進入這個路由是須要登陸的
},
component: Repository
複製代碼
第二步:
router.beforeEach((to, from, next) => {
if (to.meta.requireAuth) { // 判斷該路由是否須要登陸權限
if (store.state.token) { // 經過vuex state獲取當前的token是否存在
next();
}
else {
next({
path: '/login',
query: {redirect: to.fullPath} // 將跳轉的路由path做爲參數,登陸成功後跳轉到該路由
})
}
}
else {
next();
}
複製代碼
第三步
// 建立axios實例
let server=axios.create({
baseURL: process.env.BASE_URL, // api的base_url
timeout: 5000 // 請求超時時間
})
// axios實例建立好以後,開始使用request攔截器對axios請求配置作統一處理,具體以下:
server.interceptors.request.use(config => {
config.method === 'post'
? config.data = qs.stringify({...config.data})
: config.params = {...config.params};
config.headers['Content-Type'] = 'application/json';
if (store.state.token) { // 判斷是否存在token,若是存在的話,則每一個http header都加上token
config.headers.Authorization = `token ${store.state.token}`;
}
return config;
},error => {
// 返回錯誤處理
Promise.reject(error);
});
// 而後是對response作統一處理
server.interceptors.response.use(response => {
//這裏根據後端提供的數據進行對應的處理
if (response.data.result === 'TRUE') {
return response.data;
} else {
//常規錯誤處理
}
},error => {
let text = error.response.status;
switch (text) {
case 401:
// 返回 401 清除token信息並跳轉到登陸頁面
store.commit(types.LOGOUT);
router.replace({
path: 'login',
query: {redirect: router.currentRoute.fullPath}
})
}
return Promise.reject(error)
})
複製代碼