-
JavaScript 表達式(Expression):
- 表達式是可以計算并返回一個值的任何合法的 JavaScript 結構。
- 它們可以是一個簡單的字面量(例如數(shù)字、字符串或布爾值),也可以是復雜的組合,包括算術運算符連接的操作數(shù)、函數(shù)調用、屬性訪問、對象和數(shù)組字面量等。
- 表達式總是會生成一個值,這個值可以被賦給變量、作為參數(shù)傳遞給函數(shù),或者直接參與進一步的計算。
-
JavaScript 代碼(Code):
- JavaScript 代碼通常指的是一個或多個 JavaScript 語句的集合,它們共同構成了一段可執(zhí)行邏輯的單元。
- 語句不一定要返回值,而是用來描述一系列操作,這些操作可以改變程序的狀態(tài),控制流程(如條件語句、循環(huán)語句等)。
簡單來說,一個表達式會產生一個值,而一個代碼塊則會執(zhí)行一系列操作。
MVVM
- M: 模型(Model) : 對應 data 中的數(shù)據
- V: 視圖(View) : 模板
- VM: 視圖模型(ViewModel) : Vue 實例對象
Object.defineProperty()
- 數(shù)據代理:通過一個對象代理對另一個對象中屬性的操作(讀/寫)
- 數(shù)據代理的好處:更加方便的操作數(shù)據
let per = {
name: "張三",
sex: "男",
};
Object.defineProperty(per, "age", {
value: 500,
enumerable: true, // 控制屬性是否可以枚舉,默認值是 false
writable: true, // 控制屬性是否可以被修改,默認值是 false,
configurable: true, // 控制屬性是否可以被刪除,默認值是 false
get() {}, // 用來獲取屬性值的函數(shù)(當有人讀取屬性時,get 函數(shù)(getter)就會被調用,且返回值
set() {}, // 用來設置屬性值的函數(shù)(當有人修改屬性時,set 函數(shù)(setter)就會被調用,
});
Vue 中的數(shù)據代理
-
基本原理:通過 Object.defineProperty()把 data 對象中的所有屬性添加到 vm 上
為每一個添加到 vm 上的屬性,都指定一個 getter/setter
在 getter/setter 中去操作(讀/寫) data 中對應的屬性
Vue 中的事件處理
@click="show" === v-on:click="show($event)"-
事件修飾符:
- .stop:阻止事件冒泡
- .prevent:阻止默認事件
- .once:事件只觸發(fā)一次
- .capture:使用事件捕獲模式
- .self:只有 event.target 是當前操作的元素時才觸發(fā)事件
- .passive:事件的默認行為立即執(zhí)行,無需等待事件回調執(zhí)行完畢
-
按鍵別名:(@keyup.XXX)
- 回車 enter
- 刪除 delete(捕獲“刪除”和“退格”鍵)
- 退出 esc
- 空格 space
- 換行 tab(需配合@keydown 使用)
- 上 up
- 下 down
- 左 left
- 右 right
計算屬性 computed
- 定義:通過已有的屬性進行計算得到的新的屬性
- 優(yōu)勢:與 methods 實現(xiàn)相比,內部有緩存機制(復用),效率更高,調試方便
- data 里面放的是屬性
- computed 里面放的是計算屬性
computed: {
fullName {
// 當fullName屬性被讀取時,get() 方法會被調用,且返回值就作為 fullName 的值
// 初次獲取fullName和所依賴項發(fā)生變化時,都會調用get(依賴項指的是計算屬性中所有用到的屬性)
get(){
return this.firstName + this.lastName;
},
// 當fullName被修改時調用
set(value) {
const arr = value.split(' ')
this.firstName = arr[0]
this.lastName = arr[1]
}
},
// 大多數(shù)情況下計算屬性是不需要修改的,可以簡寫為
fullName() {
return this.firstName + this.lastName;
}
}
監(jiān)視屬性 watch
-
當被監(jiān)視的屬性變化時,回調函數(shù)自動調用,進行相關操作
- 注意
- 監(jiān)視的屬性必須存在(必須在 data 里存在),才能進行監(jiān)視
- 注意
深度監(jiān)視
watch: {
isHot: {
deep: true, // 配置deep: true可以檢測對象內部值的改變
immediate: true, // 初始化時讓handler調用一下
handler(newValue, oldValue) {
onsole.log('isHot被修改了', newValue, oldValue)
}
},
// 如果不需要其他配置項的,可以簡寫成
isHot(newValue, oldValue) {
console.log('isHot被修改了', newValue, oldValue)
}
}
watch 和 computed 的區(qū)別
- computed 存在緩存機制,當他依賴項沒有變化時,不會重新執(zhí)行。而 watch 每次都會執(zhí)行。
- computed 只能是執(zhí)行同步代碼。而 watch 支持異步(也就是可以用 setTimeout)。
- computed 有返回值。而 watch 沒有返回值,需要手動處理數(shù)據。
key 的作用
- key 是給每一個虛擬 DOM 增加的唯一標識,可以根據 key 更準確、更快的找到對應的節(jié)點
VUE 檢測數(shù)據變化的原理
-
VUE 是如何監(jiān)測對象里面數(shù)據改變的?
- 遍歷對象的屬性
- 給屬性添加 getter 和 setter
- 遇到對象嵌套問題,進行遞歸
-
Vue.set & this.$set
- 用于為對象添加響應式屬性
- 語法:Vue.set( target, propertyName/index, value )
- target:要更改的數(shù)據源(可以是對象或者數(shù)組)
- propertyName/index:要更改的具體數(shù)據
- value:重新賦的值
- 注意:Vue.set 只能給 data 里的對象追加屬性而不能給 data 追加
-
VUE 是如何監(jiān)測數(shù)組里面數(shù)據改變的?
- 通過調用數(shù)組的一些方法(push, pop, shift, unshift, splice, sort, reverse)來監(jiān)聽數(shù)組變化,VUE 將這些方法進行了包裹
注意:不能使用數(shù)組索引直接修改
- 通過調用數(shù)組的一些方法(push, pop, shift, unshift, splice, sort, reverse)來監(jiān)聽數(shù)組變化,VUE 將這些方法進行了包裹
v-cloak
- 用于解決網速慢時 vue.js 未能加載出來,頁面出現(xiàn){{xxx}}的問題,配合 css 來提升用戶體驗
[v-cloak]{
display: none;
}
<div v-cloak>{{name}}</div>
VUE 自定義指令
- 需求:定義一個 v-big 指令,和 v-text 功能類似,但會把綁定的數(shù)值放大 10 倍
<span v-big="count"></span>
data: {
count: 1
}
directives: {
// big函數(shù)會在一開始和所綁定的數(shù)據發(fā)生改變時調用
big(element, binding) {
element.innerText = binding.value * 10
}
}
生命周期
-
掛載流程
beforeCreate:無法拿到 data 中的數(shù)據和 methods 中的方法
-
created:可以拿到 data 中的數(shù)據和 methods 中的方法
這個時候 Vue 開始解析模版生成虛擬 DOM,但是頁面還不能顯示解析好的內容
-
beforeMount:頁面呈現(xiàn)的是未經編譯的 DOM,此時對 DOM 的操作
最終不生效這個時候內存中的虛擬 DOM 會轉為真實 DOM 插入頁面,所以在 beforeMount 操作的 DOM 就不奏效了
mounted:頁面呈現(xiàn)的是經過編譯的 DOM,此時可以對 DOM 進行操作(一般在此時進行開啟定時器、發(fā)送網絡請求、訂閱消息、綁定事件等操作)
-
更新流程
- beforeUpdate:操作事件改變數(shù)據后,數(shù)據已更新但頁面尚未與數(shù)據同步
- updated:頁面和數(shù)據同步,保持最新
-
銷毀流程
-
beforeDestroy:此時可以拿到 data 中的數(shù)據和 methods 中的方法,但是對數(shù)據的修改不再觸發(fā)更新(一般在此時解綁事件監(jiān)聽器,清理定時器等)
注意:銷毀后自定義事件會失效,但是原生 DOM 事件依然有效
destroyed:所有指令都被解綁,所有的事件監(jiān)聽器被移除,所有的子實例也都被銷毀。
-
VUE 組件命名規(guī)范
-
一個單詞組成
- 首字母小寫:header
- 首字母大寫:Header
-
多個單詞組成
- kebab-case 命名:goods-list
- CamelCase 命名:GoodsList
VueComponent
- 組件本質是一個名為 VueComponent 的構造函數(shù),且不是程序員定義的,是 Vue.extend 生成的
- 當在代碼中寫入
<component-name/>的時候,Vue 會創(chuàng)建 component-name 組件的實例對象,即執(zhí)行 new VueComponent(options)
注意:每次使用 Vue.extend 返回的都是全新的 VueComponent - 組件配置中
this指的是 VueComponent 實例對象,new Vue(options)中this指的是 Vue 實例對象
腳手架
- 安裝腳手架
npm install -g @vue/cli
- 創(chuàng)建項目
vue create my-project
- 項目目錄
├── node_modules
├── public
│ ├── favicon.ico: 頁簽圖標
│ └── index.html: 主頁面
├── src
│ ├── assets: 存放靜態(tài)資源
│ │ └── logo.png
│ │── main.js: 入口文件
│ │── App.vue: 匯總所有組件
│ │── components: 存放組件
│ │ └── HelloWorld.vue
│ └── views: 存放頁面
│ └── Home.vue
├── .gitignore: git 版本管制忽略的配置
├── babel.config.js: babel 的配置文件
├── package.json: 應用包配置文件
├── package-lock.json: 包版本控制文件
├── README.md: 應用描述文件
└── vue.config.js: vue 腳手架的配置文件
ref 屬性
- 應用在 HTML 標簽上獲取的是真實 DOM 元素,應用在組件標簽上是組件實例對象(vc VueComponent)
props
- 功能:讓組件接收外部傳過來的數(shù)據
export default {
name: "GoodsList",
data() {
return {};
},
// 完整方式
props: {
name: {
type: String,
required: true,
},
price: {
type: Number,
default: 1000,
},
},
};
mixin
- 功能:可以把多個組件共用的配置提取成一個混入對象
// 定義
export const mixin = {
mounted() {
console.log("mixin 的 mounted 被調用了");
},
};
// 使用
import { mixin } from "../mixin";
export default {
name: "GoodsList",
data() {
return {};
},
mixins: [mixin],
};
插件
- 功能:用于增強 Vue
- 本質:包含 install 方法的一個對象,install 的第一個參數(shù)是 Vue,第二個以后的參數(shù)是插件使用者傳遞的數(shù)據
// 定義
export default {
install(Vue, options) {
// 1. 添加全局過濾器
Vue.filter(....)
// 2. 添加全局指令
Vue.directive(....)
// 3. 配置全局混入(合)
Vue.mixin(....)
// 4. 添加實例方法
Vue.prototype.$myMethod = function() {...}
Vue.prototype.$myProperty = xxxx
},
}
// 使用
Vue.use();
組件通信
-
父傳子
- 利用 props
- 父組件將要傳遞的值或者方法通過標簽屬性形式傳遞給子組件
- 子組件利用 props 接收父組件傳遞過來的值或者方法并使用
注意:props 是一個數(shù)組props:[]
-
子傳父
- 利用 props
- 父組件通過標簽屬性形式傳遞一個函數(shù)給子組件
- 子組件通過該函數(shù)將數(shù)據傳遞給父組件
- 利用 $emit
- 父組件通過標簽屬性形式給子組件綁定一個自定義事件
- 子組件通過 $emit 觸發(fā)該事件,并將數(shù)據傳遞給父組件
// 父組件 // 通過父組件給子組件綁定一個自定義事件 <ChildComponent @getData="getChildData"></ChildComponent> methods: { getChildData(data) { console.log(data); } } // 子組件 <button @click="sendData">點擊</button> methods: { sendData() { this.$emit("getData", data); }}, beforeDestroy(){ // 通過$off解綁自定義事件 // 解綁一個 this.$off("getData"); // 解綁多個 this.$off(["getData",...]); // 全部解綁 this.$off(); }- 利用全局事件總線
自定義事件
- 一種組件間通信的方式,適用于:子組件 ===> 父組件
- 具體實現(xiàn):見標題為 《組件通信》 的內容
-
注:如果在組件中使用原生(如 @click)事件,需要寫成
@click.native
全局事件總線
- 一種組件間通信的方式,適用于:任意組件間通信
- 在 new Vue 的時候,通過
beforeCreate生命周期在 Vue 的 prototype 上綁定一個屬性(隨便任何名字),值為 this
new Vue({
// ...
beforeCreate() {
Vue.prototype.$bus = this; // 安裝全局事件總線
},
});
- 在 A 組件中通過
this.$bus.$on來接收數(shù)據
mounted: {
this.$bus.$on("getData", (data) => {
console.log(data);
});
}
beforeDestroy() {
this.$bus.$off("getData"); // 解綁getData事件
}
- 在 B 組件中通過
this.$bus.$emit來發(fā)送數(shù)據
<button @click="sendMsg">發(fā)送信息</button>
data(){
return {
msg: "Hello World"
}
},
methods: {
sendMsg() {
this.$bus.$emit("getData", this.msg);
},
}
消息訂閱與發(fā)布
- 一種組件間通信的方式,適用于:任意組件間通信
- 安裝
pubsub-js
npm install pubsub-js
- 引入
PubSub
import PubSub from 'pubsub-js'
- 使用
注意:接收數(shù)據和發(fā)送數(shù)據的事件名稱必須一致
// 在傳遞數(shù)據的組件中,通過`PubSub.publish`來發(fā)送數(shù)據
PubSub.publish("getMsg", { name: "curry" });
// 在接收數(shù)據的組件中,通過`PubSub.subscribe`來接收數(shù)據(一般是當該組件加載完之后就要先注冊一下接收數(shù)據的事件,所以一般寫在`mounted`生命周期中)
mounted() {
this.pubId = PubSub.subscribe("getMsg", (msg, data) => {
console.log(msg, data, "接收來的數(shù)據");
});
},
beforeDestroy() {
PubSub.unsubscribe(this.pubId); // 組件銷毀前,一定要取消訂閱
}
$nextTick
語法:
this.$nextTick(回調函數(shù))官方解釋:在下一次 DOM 更新結束后執(zhí)行指定的回調函數(shù)
自己解釋:當你修改了數(shù)據之后,Vue 幫你操作完 DOM 之后,把真實的 DOM 放入頁面了,Vue 再幫你調用這個函數(shù)
axios
作用:發(fā)送 ajax 請求
安裝
npm install axios
- 引入
import axios from 'axios'
- 在
vue.config.js配置代理
module.exports = {
// 方式1 配置單個代理
devServer: {
proxy: "http://localhost:3000",
},
// 方式2 配置多個代理
devServer: {
proxy: {
"/api": {
// 前綴 緊跟在端口號后面
target: "http://localhost:3000", // 代理服務器地址
pathRewrite: {
"^/api": "", // 包含api的替換為空
},
ws: true, // 是否啟用websockets
changeOrigin: true, // 用戶控制請求頭中的host值
},
"/foo": {
target: "...",
},
},
},
};
插槽 slot
作用:讓父組件可以向子組件指定位置插入 html 結構,也是一種組件間通信的方式,適用于父組件 ===> 子組件(傳遞的是 html 結構)
-
默認插槽
- 在父組件中傳入內容
<Category title="游戲"> <img src="https://..." /> </Category>- 在子組件中定義
<slot> 我是默認內容,當沒有傳入內容的時候,就展示我 </slot> 具名插槽
- 在父組件中傳入內容
<Category title="游戲">
<img src="https://..." slot="img" />
<a href="#" slot="link">點擊去詳情</a>
</Category>
- 在子組件中定義
<div>
<slot name="img"></slot>
<slot name="link"></slot>
</div>
- 作用域插槽
- 注:作用域插槽中子組件可以向父組件傳數(shù)據,也就是 HTML 結構是父組件來規(guī)定,數(shù)據由子組件來提供(子組件傳給父組件的)
- 子組件
<slot :dataSource="games"></slot>
export default {
data(){
return {
games: ['紅色警戒', '穿越火線', '勁舞團', '超級瑪麗']
}
}
}
- 父組件
<template scope="dataSource" || scope="{games}">
<ul>
<li v-for="item in dataSource.games" :key="item">{{item}}</li>
</ul>
</template>
Vuex
概念:在 Vue 中實現(xiàn)集中式狀態(tài)(數(shù)據)管理的一個 Vue 插件,對 vue 應用中多個組件共享狀態(tài)進行集中式的管理
注意 vue2 中只能使用 vuex 的 3 版本
注意 vue3 中只能使用 vuex 的 4 版本安裝及使用
npm install vuex在 src 下創(chuàng)建 store 文件夾,創(chuàng)建 index.js 文件
-
index.js 的內容
import Vue from "vue"; import Vuex from "vuex"; Vue.use(Vuex); // 準備actions - 用于響應組件中的動作 const actions = { increment(context, value) { console.log("+++", context, value); context.commit("INCREMENT", value); }, }; // 準備mutations - 用于操作數(shù)據(state) const mutations = { INCREMENT(state, value) { state.count += value; }, }; // 準備state - 用于存儲數(shù)據 const state = { count: 0, }; //準備getters - 用于將state中的數(shù)據進行加工 const getters = { powerCouunt(state) { return state.count * state.count; }, }; // 創(chuàng)建store const store = new Vuex.Store({ actions, mutations, getters, state, }); export default store; -
在 main.js 中創(chuàng)建 vue 實例時傳入 store 對象
import store from "./store"; -
在組件中觸發(fā)
methods: { handleClick() { this.$store.dispatch("increment", 5); } } -
在組件中獲取
<h1>{{ $store.state.count }}</h1> <h1>{{ $store.getters.powerCouunt }}</h1> -
mapState
import { mapState } from "vuex"; computed: { // 寫法一:借助mapState生成計算屬性,從state中讀取數(shù)據。(對象寫法) ...mapState({shu:'count',...}) // 寫法二:借助mapState生成計算屬性,從state中讀取數(shù)據。(數(shù)組寫法) ...mapState(['count']) } <h1>{{shu}}</h1> // 寫法一 <h1>{{count}}</h1> // 寫法二 mapGetters
import { mapGetters } from "vuex";
computed: {
// 寫法一:借助mapGetters生成計算屬性,從getters中讀取數(shù)據。(對象寫法)
...mapGetters({zong:'powerCouunt'})
// 寫法二:借助mapGetters生成計算屬性,從getters中讀取數(shù)據。(數(shù)組寫法)
...mapGetters(['powerCouunt'])
}
<h2>{{zong}}</h2> // 寫法一
<h2>{{powerCouunt}}</h2> // 寫法二
- mapMutations
import { mapMutations } from "vuex";
methods: {
// 借助mapMutations生成對應的方法,方法中會調用commit去聯(lián)系mutations(推薦:對象寫法)
...mapMutations({increment:'INCREMENT'})
}
<button @click="increment(3)"> + 3 </button>
- mapActions
import { mapActions } from "vuex";
// 借助mapActions生成對應的方法,方法中會調用dispatch去聯(lián)系actions(推薦:數(shù)組寫法)
methods: {
...mapActions(['increment'])
}
<button @click="increment(3)"> + 3 </button>
- namespace
// 第一步: 在store下的index.js中根據模塊創(chuàng)建對象
const countAbout = {
namespaced: true, // 開啟命名空間
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
// 第二步: 將創(chuàng)建好的模塊導出
const store = new Vuex.Store({
modules: {
countAbout: countAbout,
...
}
})
// 第三步: 在組件中使用
<h1>{{count}}</h1>
import { mapState } from 'vuex'
computed: {
// 根據namespace找對它對應的state中的數(shù)據
// 因為數(shù)據有多個,所以用數(shù)組形式
// 如果有多個命名空間,需要多寫幾個mapState
...mapState('countAbout',['count'])
// ...
}
// 第四步: 跟命名空間相對應的mapActions、mapMutations...都需要修改
...mapMutations('countAbout',{increment:'INCREMENT',...})
...mapState('countAbout',{count:'count',...})
-
總結
11.1. 用戶點擊按鈕,調用 store.dispatch() 方法
11.2. store.dispatch() 方法將 action 對象發(fā)送給 store
11.3. store 中的 action 調用對應的 mutations 中的方法,來操作 store 中的 state
11.4. mutations 中的方法完成并重新渲染頁面注意:
11.5. 如果點擊按鈕后的操作沒有任何邏輯,可以直接通過 commit 調用 mutations 中的方法來修改 state
11.6. 如果當前一個 action 的操作和邏輯過多,可以通過調用 context.dispatch()繼續(xù)執(zhí)行其他 action
不成文的規(guī)定:
11.7. actions 中的方法和 mutations 中的方法名最好相同,但是 mutations 中的方法名最好寫成大寫
路由
注意 vue2 中只能使用 vue-router3 版本
注意 vue3 中只能使用 vue-router4 版本
- 安裝及使用
npm install vue-router@3- 在 src 下創(chuàng)建 router 文件夾,創(chuàng)建 index.js 文件
- index.js 的內容
import VueRouter from "vue-router";
import Home from "../pages/Home";
import About from "../pages/About";
import Message from "../pages/Message";
const router = new VueRouter({
routes: [
{
path: "/home",
component: Home,
},
{
path: "/about",
component: About,
children: [
{
path: "message", // 路由嵌套時,子級路由中的path不要加斜線( / )
component: Message,
},
],
},
],
});
export default router;
- 在 main.js 中引入并使用自己編寫的 router 文件和 VueRouter 插件
import Vue from "vue";
import App from "./App.vue";
import VueRouter from "vue-router";
import router from "./router";
Vue.use(VueRouter);
new Vue({
render: (h) => h(App),
router,
}).$mount("#app");
導航組件用
<router-link to="home">首頁</router-link>標簽包裹,路由組件用<router-view></router-view>標簽來展示內容(類似于 slot)-
路由組件傳參
6.1 query 傳參(好處:不會影響 router 里面的 path)<router-link to="/about/message?id=3"> message </router-link>mounted() { console.log(this.$route); // 通過$route獲取傳參 },6.2 命名路由(作用:路由嵌套層數(shù)過多時,簡化路由的路徑)
// router/index.js const router = new VueRouter({ routes: [ { path: "/about", component: About, children: [ { name: "message", // 命名路由 path: "message", // 路由嵌套時,子級路由中的path不要加斜線( / ) component: Message, }, ], }, ], });<!-- 當路由跳轉的時候,可以直接使用路由的name,不必要寫多層 --> <router-link :to="{ name: "message", query: { id: 3 }, }"> message </router-link> <router-link to="/about/message?id=3"> message </router-link>6.3 params 傳參(注意:使用 params 傳參的對象形式時,to 里面的內容必須得寫成 name 的形式)
<router-link to="/about/message/9/杜蘭特"> message </router-link> <router-link :to="{ name:'message', params: { id:9, name:'杜蘭特' } }" > message </router-link>const router = new VueRouter({ routes: [ { path: "/home", component: Home, }, { path: "/about", component: About, children: [ { name: "message", path: "message/:id/:name", // 使用占位符接收params傳參 component: Message, }, ], }, ], });<p>ID : {{$route.params.id}}</p> <p>NAME : {{$route.params.name}}</p>6.4 路由的 props 配置
const router = new VueRouter({ routes: [ { path: "/home", component: Home, }, { path: "/about", component: About, children: [ { path: "message", component: Message, // 寫法一:對象形式,會以props的形式傳給該組件 // 缺點:數(shù)據只能是死數(shù)據 props: {}, // 寫法二:布爾形式,會把該組件收到的所有params參數(shù)以props形式傳給該組件 // 缺點:只能接收params傳參 props: true, // 寫法三:函數(shù)形式,從$route中拿到傳參 props($route) { return { id: $route.query.id, title: $route.query.title, }; }, }, ], }, ], });export default { props: ["id", "title"], };<p>ID : {{id}}</p> <p>NAME : {{title}}</p> -
router-link 的 replace 屬性
- router-link 默認是 push 模式,只需要在 router-link 的標簽中增加
:replace="true"屬性即可開啟 replace 模式
<router-link to="/about/message" replace> message </router-link> - router-link 默認是 push 模式,只需要在 router-link 的標簽中增加
-
編程式路由
<button @click="gotoMessage('7','durant')">消息</button>methods: { gotoMessage(id,title) { this.$router.replace("/about/message"); this.$router.push({ name:'message', query:{ id, title } }) this.$router.push({ path:'/about/message', params:{ id, title } }) }, }this.$router.back(); // 后退 this.$router.forward(); // 前進 this.$router.go(3); // 前進(傳正數(shù))后退(傳負數(shù)) -
緩存路由組件
- 默認情況下,每次切換路由組件,都會重新渲染
- 可以通過
<keep-alive>標簽包裹需要緩存的組件,只要在<keep-alive>中包裹的組件都會被緩存 - 緩存組件時,需要指定一個 name 屬性(name 對應的值是組件名,指的是
export default { name : Message }),這樣就會將指定的組件緩存起來
<!-- 緩存一個 --> <keep-alive include="Message"> <router-view></router-view> </keep-alive> <!-- 緩存多個 --> <keep-alive :include="['Message','News']"> <router-view></router-view> </keep-alive> -
新的生命周期(路由組件專屬)
export default { activated(){ // 進入組件時調用 } deactivated(){ // 離開組件時調用 } } -
全局路由守衛(wèi)
import VueRouter from "vue-router"; import Home from "../pages/Home"; import About from "../pages/About"; import Message from "../pages/Message"; const router = new VueRouter({ routes: [ { name: "home", path: "/home", component: Home, meta: { title: "首頁" }, }, { name: "about", path: "/about", component: About, meta: { title: "關于" }, children: [ { name: "message", path: "message", component: Message, meta: { // 配置該組件是否需要權限校驗 isAuth: true, title: "消息", }, }, ], }, ], }); router.beforeEach((to, from, next) => { // 判斷當前路由是否需要登錄權限 if (to.meta.isAuth) { // 首先判斷該組件是否需要授權 if (localStorage.getItem("token")) { // 再判斷是否已經登錄過,或者判斷是否包含token等信息 next(); } else { alert("您沒有權限查看該頁面"); next("/home"); } } else { next(); } }); router.afterEach((to, from) => { document.title = to.meta.title || "vue-router"; }); export default router; -
獨享路由守衛(wèi)
import VueRouter from "vue-router"; import Home from "../pages/Home"; import About from "../pages/About"; import Message from "../pages/Message"; const router = new VueRouter({ routes: [ { name: "home", path: "/home", component: Home, meta: { title: "首頁" }, }, { name: "about", path: "/about", component: About, meta: { title: "關于" }, children: [ { name: "message", path: "message", component: Message, meta: { isAuth: true, title: "消息", }, beforeEnter: (to, from, next) => { // 寫法與全局前置路由守衛(wèi)一直 // 需要注意的是,獨享路由守衛(wèi)只有前置 console.log(to, from, next); }, }, ], }, ], }); export default router; -
組件內路由守衛(wèi)(一般不用這個)
export default { // 通過路由規(guī)則進入該組件時被調用 beforeRouteEnter(to, from, next) {}, // 通過路由規(guī)則離開該組件時被調用 beforeRouteLeave(to, from, next) {}, }; -
history 和 hash 模式的區(qū)別
const router = new VueRouter({ mode: "history", // 默認是 hash routes: [...], });14.1 hash 在 url 中有#,history 沒有
14.2 hash 的兼容性比 history 好
14.3 history 模式需要后端配合,否則刷新頁面后會 404,而 hash 模式不需要