-
JavaScript 表达式(Expression):
- 表达式是可以计算并返回一个值的任何合法的 JavaScript 结构。
- 它们可以是一个简单的字面量(例如数字、字符串或布尔值),也可以是复杂的组合,包括算术运算符连接的操作数、函数调用、属性访问、对象和数组字面量等。
- 表达式总是会生成一个值,这个值可以被赋给变量、作为参数传递给函数,或者直接参与进一步的计算。
-
JavaScript 代码(Code):
- JavaScript 代码通常指的是一个或多个 JavaScript 语句的集合,它们共同构成了一段可执行逻辑的单元。
- 语句不一定要返回值,而是用来描述一系列操作,这些操作可以改变程序的状态,控制流程(如条件语句、循环语句等)。
简单来说,一个表达式会产生一个值,而一个代码块则会执行一系列操作。
MVVM
- M: 模型(Model) : 对应 data 中的数据
- V: 视图(View) : 模板
- VM: 视图模型(ViewModel) : Vue 实例对象
Object.defineProperty()
- 数据代理:通过一个对象代理对另一个对象中属性的操作(读/写)
- 数据代理的好处:更加方便的操作数据
let per = {
name: "张三",
sex: "男",
};
Object.defineProperty(per, "age", {
value: 500,
enumerable: true, // 控制属性是否可以枚举,默认值是 false
writable: true, // 控制属性是否可以被修改,默认值是 false,
configurable: true, // 控制属性是否可以被删除,默认值是 false
get() {}, // 用来获取属性值的函数(当有人读取属性时,get 函数(getter)就会被调用,且返回值
set() {}, // 用来设置属性值的函数(当有人修改属性时,set 函数(setter)就会被调用,
});
Vue 中的数据代理
-
基本原理:通过 Object.defineProperty()把 data 对象中的所有属性添加到 vm 上
-
为每一个添加到 vm 上的属性,都指定一个 getter/setter
-
在 getter/setter 中去操作(读/写) data 中对应的属性
-
Vue 中的事件处理
-
@click="show" === v-on:click="show($event)"
-
事件修饰符:
- .stop:阻止事件冒泡
- .prevent:阻止默认事件
- .once:事件只触发一次
- .capture:使用事件捕获模式
- .self:只有 event.target 是当前操作的元素时才触发事件
- .passive:事件的默认行为立即执行,无需等待事件回调执行完毕
-
按键别名:(@keyup.XXX)
- 回车 enter
- 删除 delete(捕获“删除”和“退格”键)
- 退出 esc
- 空格 space
- 换行 tab(需配合@keydown 使用)
- 上 up
- 下 down
- 左 left
- 右 right
计算属性 computed
- 定义:通过已有的属性进行计算得到的新的属性
- 优势:与 methods 实现相比,内部有缓存机制(复用),效率更高,调试方便
- data 里面放的是属性
- computed 里面放的是计算属性
computed: {
fullName {
// 当fullName属性被读取时,get() 方法会被调用,且返回值就作为 fullName 的值
// 初次获取fullName和所依赖项发生变化时,都会调用get(依赖项指的是计算属性中所有用到的属性)
get(){
return this.firstName + this.lastName;
},
// 当fullName被修改时调用
set(value) {
const arr = value.split(' ')
this.firstName = arr[0]
this.lastName = arr[1]
}
},
// 大多数情况下计算属性是不需要修改的,可以简写为
fullName() {
return this.firstName + this.lastName;
}
}
监视属性 watch
-
当被监视的属性变化时,回调函数自动调用,进行相关操作
- 注意
- 监视的属性必须存在(必须在 data 里存在),才能进行监视
- 注意
-
深度监视
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 的区别
- computed 存在缓存机制,当他依赖项没有变化时,不会重新执行。而 watch 每次都会执行。
- computed 只能是执行同步代码。而 watch 支持异步(也就是可以用 setTimeout)。
- computed 有返回值。而 watch 没有返回值,需要手动处理数据。
key 的作用
- key 是给每一个虚拟 DOM 增加的唯一标识,可以根据 key 更准确、更快的找到对应的节点
VUE 检测数据变化的原理
-
VUE 是如何监测对象里面数据改变的?
- 遍历对象的属性
- 给属性添加 getter 和 setter
- 遇到对象嵌套问题,进行递归
-
Vue.set & this.$set
- 用于为对象添加响应式属性
- 语法:Vue.set( target, propertyName/index, value )
- target:要更改的数据源(可以是对象或者数组)
- propertyName/index:要更改的具体数据
- value:重新赋的值
- 注意:Vue.set 只能给 data 里的对象追加属性而不能给 data 追加
-
VUE 是如何监测数组里面数据改变的?
- 通过调用数组的一些方法(push, pop, shift, unshift, splice, sort, reverse)来监听数组变化,VUE 将这些方法进行了包裹
注意:不能使用数组索引直接修改
- 通过调用数组的一些方法(push, pop, shift, unshift, splice, sort, reverse)来监听数组变化,VUE 将这些方法进行了包裹
v-cloak
- 用于解决网速慢时 vue.js 未能加载出来,页面出现{{xxx}}的问题,配合 css 来提升用户体验
[v-cloak]{
display: none;
}
<div v-cloak>{{name}}</div>
VUE 自定义指令
- 需求:定义一个 v-big 指令,和 v-text 功能类似,但会把绑定的数值放大 10 倍
<span v-big="count"></span>
data: {
count: 1
}
directives: {
// big函数会在一开始和所绑定的数据发生改变时调用
big(element, binding) {
element.innerText = binding.value * 10
}
}
生命周期
-
挂载流程
-
beforeCreate:无法拿到 data 中的数据和 methods 中的方法
-
created:可以拿到 data 中的数据和 methods 中的方法
这个时候 Vue 开始解析模版生成虚拟 DOM,但是页面还不能显示解析好的内容
-
beforeMount:页面呈现的是未经编译的 DOM,此时对 DOM 的操作
最终
不生效这个时候内存中的虚拟 DOM 会转为真实 DOM 插入页面,所以在 beforeMount 操作的 DOM 就不奏效了
-
mounted:页面呈现的是经过编译的 DOM,此时可以对 DOM 进行操作(一般在此时进行开启定时器、发送网络请求、订阅消息、绑定事件等操作)
-
-
更新流程
- beforeUpdate:操作事件改变数据后,数据已更新但页面尚未与数据同步
- updated:页面和数据同步,保持最新
-
销毁流程
-
beforeDestroy:此时可以拿到 data 中的数据和 methods 中的方法,但是对数据的修改不再触发更新(一般在此时解绑事件监听器,清理定时器等)
注意:销毁后自定义事件会失效,但是原生 DOM 事件依然有效
-
destroyed:所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。
-
VUE 组件命名规范
-
一个单词组成
- 首字母小写:header
- 首字母大写:Header
-
多个单词组成
- kebab-case 命名:goods-list
- CamelCase 命名:GoodsList
VueComponent
- 组件本质是一个名为 VueComponent 的构造函数,且不是程序员定义的,是 Vue.extend 生成的
- 当在代码中写入
<component-name/>
的时候,Vue 会创建 component-name 组件的实例对象,即执行 new VueComponent(options)
注意:每次使用 Vue.extend 返回的都是全新的 VueComponent - 组件配置中
this
指的是 VueComponent 实例对象,new Vue(options)中this
指的是 Vue 实例对象
脚手架
- 安装脚手架
npm install -g @vue/cli
- 创建项目
vue create my-project
- 项目目录
├── node_modules
├── public
│ ├── favicon.ico: 页签图标
│ └── index.html: 主页面
├── src
│ ├── assets: 存放静态资源
│ │ └── 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
- 功能:让组件接收外部传过来的数据
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 的第一个参数是 Vue,第二个以后的参数是插件使用者传递的数据
// 定义
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 是一个数组props:[]
-
子传父
- 利用 props
- 父组件通过标签属性形式传递一个函数给子组件
- 子组件通过该函数将数据传递给父组件
- 利用 $emit
- 父组件通过标签属性形式给子组件绑定一个自定义事件
- 子组件通过 $emit 触发该事件,并将数据传递给父组件
// 父组件 // 通过父组件给子组件绑定一个自定义事件 <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(); }
- 利用全局事件总线
自定义事件
- 一种组件间通信的方式,适用于:子组件 ===> 父组件
- 具体实现:见标题为 《组件通信》 的内容
-
注:如果在组件中使用原生(如 @click)事件,需要写成
@click.native
全局事件总线
- 一种组件间通信的方式,适用于:任意组件间通信
- 在 new Vue 的时候,通过
beforeCreate
生命周期在 Vue 的 prototype 上绑定一个属性(随便任何名字),值为 this
new Vue({
// ...
beforeCreate() {
Vue.prototype.$bus = this; // 安装全局事件总线
},
});
- 在 A 组件中通过
this.$bus.$on
来接收数据
mounted: {
this.$bus.$on("getData", (data) => {
console.log(data);
});
}
beforeDestroy() {
this.$bus.$off("getData"); // 解绑getData事件
}
- 在 B 组件中通过
this.$bus.$emit
来发送数据
<button @click="sendMsg">发送信息</button>
data(){
return {
msg: "Hello World"
}
},
methods: {
sendMsg() {
this.$bus.$emit("getData", this.msg);
},
}
消息订阅与发布
- 一种组件间通信的方式,适用于:任意组件间通信
- 安装
pubsub-js
npm install pubsub-js
- 引入
PubSub
import PubSub from 'pubsub-js'
- 使用
注意:接收数据和发送数据的事件名称必须一致
// 在传递数据的组件中,通过`PubSub.publish`来发送数据
PubSub.publish("getMsg", { name: "curry" });
// 在接收数据的组件中,通过`PubSub.subscribe`来接收数据(一般是当该组件加载完之后就要先注册一下接收数据的事件,所以一般写在`mounted`生命周期中)
mounted() {
this.pubId = PubSub.subscribe("getMsg", (msg, data) => {
console.log(msg, data, "接收来的数据");
});
},
beforeDestroy() {
PubSub.unsubscribe(this.pubId); // 组件销毁前,一定要取消订阅
}
$nextTick
-
语法:
this.$nextTick(回调函数)
-
官方解释:在下一次 DOM 更新结束后执行指定的回调函数
-
自己解释:当你修改了数据之后,Vue 帮你操作完 DOM 之后,把真实的 DOM 放入页面了,Vue 再帮你调用这个函数
axios
-
作用:发送 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>
- 作用域插槽
- 注:作用域插槽中子组件可以向父组件传数据,也就是 HTML 结构是父组件来规定,数据由子组件来提供(子组件传给父组件的)
- 子组件
<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 中实现集中式状态(数据)管理的一个 Vue 插件,对 vue 应用中多个组件共享状态进行集中式的管理
注意 vue2 中只能使用 vuex 的 3 版本
注意 vue3 中只能使用 vuex 的 4 版本 -
安装及使用
-
npm install vuex
-
在 src 下创建 store 文件夹,创建 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 - 用于操作数据(state) const mutations = { INCREMENT(state, value) { state.count += value; }, }; // 准备state - 用于存储数据 const state = { count: 0, }; //准备getters - 用于将state中的数据进行加工 const getters = { powerCouunt(state) { return state.count * state.count; }, }; // 创建store const store = new Vuex.Store({ actions, mutations, getters, state, }); export default store;
-
在 main.js 中创建 vue 实例时传入 store 对象
import store from "./store";
-
在组件中触发
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中读取数据。(对象写法) ...mapState({shu:'count',...}) // 写法二:借助mapState生成计算属性,从state中读取数据。(数组写法) ...mapState(['count']) } <h1>{{shu}}</h1> // 写法一 <h1>{{count}}</h1> // 写法二
-
mapGetters
import { mapGetters } from "vuex";
computed: {
// 写法一:借助mapGetters生成计算属性,从getters中读取数据。(对象写法)
...mapGetters({zong:'powerCouunt'})
// 写法二:借助mapGetters生成计算属性,从getters中读取数据。(数组写法)
...mapGetters(['powerCouunt'])
}
<h2>{{zong}}</h2> // 写法一
<h2>{{powerCouunt}}</h2> // 写法二
- mapMutations
import { mapMutations } from "vuex";
methods: {
// 借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(推荐:对象写法)
...mapMutations({increment:'INCREMENT'})
}
<button @click="increment(3)"> + 3 </button>
- mapActions
import { mapActions } from "vuex";
// 借助mapActions生成对应的方法,方法中会调用dispatch去联系actions(推荐:数组写法)
methods: {
...mapActions(['increment'])
}
<button @click="increment(3)"> + 3 </button>
- namespace
// 第一步: 在store下的index.js中根据模块创建对象
const countAbout = {
namespaced: true, // 开启命名空间
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
// 第二步: 将创建好的模块导出
const store = new Vuex.Store({
modules: {
countAbout: countAbout,
...
}
})
// 第三步: 在组件中使用
<h1>{{count}}</h1>
import { mapState } from 'vuex'
computed: {
// 根据namespace找对它对应的state中的数据
// 因为数据有多个,所以用数组形式
// 如果有多个命名空间,需要多写几个mapState
...mapState('countAbout',['count'])
// ...
}
// 第四步: 跟命名空间相对应的mapActions、mapMutations...都需要修改
...mapMutations('countAbout',{increment:'INCREMENT',...})
...mapState('countAbout',{count:'count',...})
-
总结
11.1. 用户点击按钮,调用 store.dispatch() 方法
11.2. store.dispatch() 方法将 action 对象发送给 store
11.3. store 中的 action 调用对应的 mutations 中的方法,来操作 store 中的 state
11.4. mutations 中的方法完成并重新渲染页面注意:
11.5. 如果点击按钮后的操作没有任何逻辑,可以直接通过 commit 调用 mutations 中的方法来修改 state
11.6. 如果当前一个 action 的操作和逻辑过多,可以通过调用 context.dispatch()继续执行其他 action
不成文的规定:
11.7. actions 中的方法和 mutations 中的方法名最好相同,但是 mutations 中的方法名最好写成大写
路由
注意 vue2 中只能使用 vue-router3 版本
注意 vue3 中只能使用 vue-router4 版本
- 安装及使用
npm install vue-router@3
- 在 src 下创建 router 文件夹,创建 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 命名路由(作用:路由嵌套层数过多时,简化路由的路径)
// 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的形式传给该组件 // 缺点:数据只能是死数据 props: {}, // 写法二:布尔形式,会把该组件收到的所有params参数以props形式传给该组件 // 缺点:只能接收params传参 props: true, // 写法三:函数形式,从$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); // 前进(传正数)后退(传负数)
-
缓存路由组件
- 默认情况下,每次切换路由组件,都会重新渲染
- 可以通过
<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(){ // 离开组件时调用 } }
-
全局路由守卫
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;
-
独享路由守卫
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) => { // 写法与全局前置路由守卫一直 // 需要注意的是,独享路由守卫只有前置 console.log(to, from, next); }, }, ], }, ], }); export default router;
-
组件内路由守卫(一般不用这个)
export default { // 通过路由规则进入该组件时被调用 beforeRouteEnter(to, from, next) {}, // 通过路由规则离开该组件时被调用 beforeRouteLeave(to, from, next) {}, };
-
history 和 hash 模式的区别
const router = new VueRouter({ mode: "history", // 默认是 hash routes: [...], });
14.1 hash 在 url 中有#,history 没有
14.2 hash 的兼容性比 history 好
14.3 history 模式需要后端配合,否则刷新页面后会 404,而 hash 模式不需要
网友评论