webpack
webpack.config.js
//导入node.js中专门操作路径的模块
const path = require("path");
//导入HTML插件,得到一个构造函数
const HtmlPlugin = require('html-webpack-plugin');
//创建HTML插件的实例对象
const htmlPlugin = new HtmlPlugin({
//指定原文件的存放路径
template: './src/index.html',
//指定生成的文件的存放路径
filename: './index.html'
})
module.exports = {
mode: "development",
//打包入口文件路径
entry: path.join(__dirname, "./src/index.js"),
output: {
//输出文件的存放路径
path: path.join(__dirname, "./dist"),
//输出文件的名称
filename: "bundle.js",
},
//通过plugins节点,使htmlPlugin插件生效
plugins:[htmlPlugin],
devServer: {
//初次打包完成后,自动打开浏览器
open:true,
//实时打包所使用的主机地址
host: '127.0.0.1',
//实时打包所使用的端口号
port: 80
}
};
mode的可选值
- development
- 开发环境
- 不会对打包生成的文件进行代码压缩和性能优化
- 打包速度快,适合在开发阶段使用
- production
- 生产环境
- 会对打包生成的文件进行代码压缩和性能优化
- 打包速度很慢,仅适合项目发布阶段使用
自定义打包的入口和出口
- 默认值:
- 默认的打包入口文件为
src->index.js
- 默认的输出文件路径为
dist->main.js
- 默认的打包入口文件为
- 自定义:在webpack.config.js配置文件中,通过entry节点指定打包的入口。通过output节点指定打包的出口
entry: path.join(__dirname, "./src/index.js"),
output: {
//输出文件的存放路径
path: path.join(__dirname, "./dist"),
//输出文件的名称
filename: "bundle.js",
},
webpack插件
- webpack-dev-server
- 类似于node.js阶段用到的nodemon工具
- 每当修改了源代码,webpack会自动进行项目的打包和构建
- html-webpack-plugin
- webpack中的HTML插件(类似于一个模板引擎插件)
- 可以通过此插件自定制index.html页面内容
webpack-dev-server
会启动一个实时打包的http服务器
webpack5和webpack-dev-server@4有兼容问题
- 安装:
npm i webpack-dev-server@3.11.0 -D
- 配置
- 修改
"scripts": { "dev": "webpack serve" },
- 再运行
npm run dev
命令,重新进行项目的打包 - 在浏览器中访问
http://localhost:8080
地址,查看打包效果
打包生成的文件哪儿去了?
- 不配置webpack-dev-server的情况下,webpack打包生成的文件,会存放到实际的物理磁盘上
- 严格遵守开发者在webpack.config.js中指定配置
- 根据output节点指定路径进行存放
- 配置webpack-dev-server的情况下,打包生成的文件,会存放到内存上
- 不再根据output节点指定的路径,存放到实际的物理磁盘上
- 提高了实时打包输出的性能,因为内存比物理磁盘速度快很多
生成到内存中的文件该如何访问
webpack-dev-server生成到内存中的文件,默认放到了项目的根目录中,而且是虚拟的、看不见的
http://localhost:8080/xxx
/xxx
html-webpack-plugin
webpack5和html-webpack-plugin@4有兼容问题
- 安装:
npm i html-webpack-plugin@5.5.0 -D
- 配置:
//导入HTML插件,得到一个构造函数
const HtmlPlugin = require('html-webpack-plugin');
//创建HTML插件的实例对象
const htmlPlugin = new HtmlPlugin({
//指定原文件的存放路径
template: './src/index.html',
//指定生成的文件的存放路径
filename: './index.html'
})
module.exports = {
mode: "development",
//通过plugins节点,使htmlPlugin插件生效
plugins:[htmlPlugin],
};
- 通过HTML插件复制到项目根目录中的index.html页面,也被放到了内存中
- HTML插件在生成index.html页面底部,自动注入了打包的bundle.js文件
devServer节点
在webpack.config.js配置文件中,可以通过devServer节点对webpack-dev-server插件进行更多的配置
devServer: {
//初次打包完成后,自动打开浏览器
open:true,
//实时打包所使用的主机地址
host: '127.0.0.1',
//实时打包所使用的端口号
port: 80
}
loader
webpack5 loader配置链接 在时间开发过程中,webpack默认只能打包处理以.js后缀名结尾的模块。其他非.js后缀名结尾的模块,webpack默认处理不了,需要调用loader加载器才可以正常打包,否则就会报错
loader加载器的作用
协助webpack打包处理特定的文件模块
- css-loader 可以打包处理.css相关文件
- less-loader 可以打包处理.less相关文件
- babel-loader 可以打包处理webpack无法处理的高级JS语法
style-loader和css-loader
- 安装:
npm i style-loader css-loader -D
- 配置:"style-loader", "css-loader"的位置不能写反
module: {
rules: [{ test: /\.css$/, use: ["style-loader", "css-loader"] }],
},
- use数组中指定的loader顺序是固定的
- 多个loader的调用顺序是:从后往前调用
less-loader
- 安装:
npm i less-loader less -D
- 配置: less是内置依赖项,不需要显示调用
module: {
rules: [{ test: /\.less$/, use: ["style-loader", "css-loader","less-loader"] }],
},
url-loader和file-loader
在webpack5中file-loader和url-loader已经被弃用,要使用它俩时,将模块类型设置为Javascript/auto 打包处理样式表中与url路径相关的文件
- 安装:
npm i url-loader file-loader -D
- 配置:file-loader是url-loader的内置依赖项,不需要显示配置
module: {
rules: [{ test: /\.jpg|png|gif$/, use: 'url-loader?limit=22229' }],
},
或者
module: {
rules: [
{
test: /\.jpg|png|gif$/,
use: {
loader: "url-loader",//通过loader属性指定要调用的loader
options: {//通过options属性指定参数项
limit: 22229,
},
},
},
],
},
- ?后面的limit
- limit用来指定图片的大小,单位是字节(byte)
- 只有≦limit大小的图片,才会被转为base64格式的图片
babel-loader
打包处理js文件中的高级语法
- 安装:
npm i babel-loader@8.2.1 @babel/core@7.12.3 @babel/plugin-proposal-class-properties@7.12.1 -D
把js文件统一生成到js目录中
配置:
entry: path.join(__dirname, "./src/index.js"),
output: {
//输出文件的存放路径
path: path.join(__dirname, "./dist"),
//输出文件的名称
filename: "js/bundle.js",
},
把图片统一放到image目录下
module: {
rules: [
{
test: /\.jpg|png|gif$/,
use: {
loader: "url-loader",//通过loader属性指定要调用的loader
options: {//通过options属性指定参数项
limit: 22229,
},
outputPath: 'image'
},
},
],
},
自动·清理dist目录下的旧文件
Source-Map
Source Map 就是一个信息文件,里面存储着位置信息。也就是说,Source Map文件中存储着代码压缩混淆前后的对应关系
问题
开发环境下默认生成的Source Map,记录的是生成后的代码的位置。会导致运行时报错的行数与源代码的行数不一致的问题
解决
eval-source-map仅限在开发模式下使用,不建议在“生产环境”下使用, 此选项生成的Source Map 能够保证“运行时报错的行数”与“源代码的行数”保持一致
module.exports = {
mode: 'development',
devtool: 'eval-source-map'
}
webpack生产环境下的Source Map
在生产环境下,如果省略了devtool选项,则最终生成的文件中不包含Source Map。这能防止源代码通过Source Map的形似暴露给别有所图的人
只定位行数不暴露代码
module.exports = {
mode: 'development',
devtool: 'nosources-source-map'
}
只定位行数不暴露代码
module.exports = {
mode: 'development',
devtool: 'source-map'
}
Vue
全局注册和局部注册
全局
import xxx from 'yyy'
app.component('xxx',xxx)
局部
<script>
import xxx from './components/xxx.vue'
export default {
name: 'App',
components: {
xxx
}
}
组件注册时的大小写
kebab-case
命名法(短横线命名法):使用时必须使用短横线命名来使用PascalCase
命名法(帕斯卡命名法或大驼峰命名法):可以用大驼峰命名法使用,也可以转短横线命名法使用- 可以把组件name作为注册时的名称
app.component(xxx.name,xxx)
组件样式冲突问题
问题描述
默认情况下,写在.vue
组件中的样式会全局生效,因此很容易造成多个组件之间的样式冲突问题。导致组件之间样式冲突的根本原因是:
- SPA(单页面应用),所有组件的DOM结构,都是基于唯一的index.html页面进行展示的
- 每个组件中的样式,都会影响整个index.html页面中的DOM元素
问题解决 解决原理:为每一个标签分配唯一的自定义属性
- style节点的
scoped
属性,为了提高开发效率和开发体验,vue为style节点提供了scoped属性,从而防止组件之间样式冲突的问题 - style节点的scoped属性,用来自动为每一个组件分配唯一的自定义属性, 并自动为当前组件的DOM标签和style样式应用这个自定义属性,防止组件的样式冲突
<style scoped>
...
</style>
/deep/
样式穿透,加了scoped之后想让某些样式对子组件生效,可以使用/deep/深度选择器
基本语法
指令
- 指令绑定:
v-on:xxx="方法名",@xxx="方法名"
@xxx="语句"
- 方法如果没有传参,可以接收到参数e,就是
事件触发源(就是那个标签,按钮,输入框啥的)
$event
是vue提供的特殊变量,用来表示原生的事件参数对象event。$event
可以解决事件对象event被覆盖的问题
事件修饰符
使用:
<template>
<a href="http://www.baidu.com" @click.prevent="onClick">百度</a>
</template>
<script>
export default {
name: '',
methods:{
onClick(){
window.alert(12)
}
}
}
</script>
<style scoped lang='less'>
</style>
按钮修饰符
在监听键盘事件时,我们经常需要判断详细的按键。此时,可以为键盘相关的事件添加按键修饰符
<template>
<input type="text" @keyup.enter="onKey">
</template>
<script>
export default {
name: '',
methods:{
onKey(e){
console.log(e.target.value);
}
}
}
</script>
<style scoped lang='less'>
</style>
v-model指令的修饰符
为了方便对用户输入的内容进行处理,vue为v-model提供了三个修饰符:
v-if和v-show的区别
-
实现原理不同:
- v-if指令会动态的创建或移除DOM元素,从而控制元素在页面上的显示和隐藏
- v-show指令会动态为元素添加或移除
style="display:none"
的样式,从而控制元素的显示和隐藏
-
性能消耗不同:v-if有更高的切换开销,而v-show有更高的初始渲染开销
- 如果需要非常频繁地切换,则使用v-show比较好
- 如果在运行时条件很少改变,则使用v-if比较好
使用key维护列表的状态
当列表的数据变化时,默认情况下,vue尽可能的复用已存在的DOM元素,从而提升渲染的性能。但这种默认的性能优化策略,会导致有状态的列表无法被正确更新
为了给vue一个提示,以便它能跟踪每个节点的身份,从而在保证有状态的列表被正确更新的前提下,提升渲染的性能。此时,需要为每项提供一个唯一的key属性
key的注意事项
- key的值只能是字符串或数字类型
- key的值必须具有唯一性(不重复)
- 建议把数据项id属性的值作为key值
- 使用index的值当作key的值没有任何意义(index不具有唯一性)
- 建议使用v-for指令时一定要指定key的值
props
一个组件需要显式声明它所接受的 props,这样 Vue 才能知道外部传入的哪些是 props,哪些是透传 attribute
props命名
虽然理论上你也可以在向子组件传递 props
时使用 camelCase
形式 (使用 DOM 模板时例外),但实际上为了和 HTML attribute
对齐,我们通常会将其写为 kebab-case
形式:
props声明
- 字符串数组:
props: ['foo']
- 对象:
props: { title: String, likes: Number }
单向数据流
所有的 props
都遵循着单向绑定原则,props
因父组件的更新而变化,自然地将新的状态向下流往子组件,而不会逆向传递。这避免了子组件意外修改父组件的状态的情况,不然应用的数据流将很容易变得混乱而难以理解。
props验证
export default {
props: {
// 基础类型检查
//(给出 `null` 和 `undefined` 值则会跳过任何类型检查)
propA: Number,
// 多种可能的类型
propB: [String, Number],
// 必传,且为 String 类型
propC: {
type: String,
required: true
},
// Number 类型的默认值
propD: {
type: Number,
default: 100
},
// 对象类型的默认值
propE: {
type: Object,
// 对象或者数组应当用工厂函数返回。
// 工厂函数会收到组件所接收的原始 props
// 作为参数
default(rawProps) {
return { message: 'hello' }
}
},
// 自定义类型校验函数
propF: {
validator(value) {
// The value must match one of these strings
return ['success', 'warning', 'danger'].includes(value)
}
},
// 函数类型的默认值
propG: {
type: Function,
// 不像对象或数组的默认,这不是一个工厂函数。这会是一个用来作为默认值的函数
default() {
return 'Default function'
}
}
}
}
计算属性
- 计算属性默认是只读的。当你尝试修改一个计算属性时,你会收到一个运行时警告。只在某些特殊场景中你可能才需要用到“可写”的属性,你可以通过同时提供 getter 和 setter 来创建
自定义事件
在调用 this.$emit()
方法触发自定义事件时,可以通过第2个参数为自定义事件传参,可以通过事件处理函数的形参接收到
watch监听器
值也可以是一个方法名称的字符串 (通过 methods 声明),或包含额外选项的对象。当使用对象语法时,回调函数应被声明在 handler 中。额外的选项包含
export default {
data() {
return {
a: 1,
b: 2,
c: {
d: 4
},
e: 5,
f: 6
}
},
watch: {
// 侦听根级属性
a(val, oldVal) {
console.log(`new: ${val}, old: ${oldVal}`)
},
// 字符串方法名称
b: 'someMethod',
// deep: true,该回调将会在被侦听的对象的属性改变时调动,无论其被嵌套多深
c: {
handler(val, oldVal) {
console.log('c changed')
},
deep: true
},
// 侦听单个嵌套属性:
'c.d': function (val, oldVal) {
// do something
},
// immediate: true,该回调将会在侦听开始之后立即调用
e: {
handler(val, oldVal) {
console.log('e changed')
},
immediate: true
},
// 你可以传入回调数组,它们将会被逐一调用
f: [
'handle1',
function handle2(val, oldVal) {
console.log('handle2 triggered')
},
{
handler: function handle3(val, oldVal) {
console.log('handle3 triggered')
}
/* ... */
}
]
},
methods: {
someMethod() {
console.log('b changed')
},
handle1() {
console.log('handle 1 triggered')
}
},
created() {
this.a = 3 // => new: 3, old: 1
}
}
this.$watch()
我们也可以使用组件实例的 $watch()
方法来命令式地创建一个侦听器:
export default {
created() {
this.$watch('question', (newQuestion) => {
// ...
})
}
}
停止侦听器
const unwatch = this.$watch('foo', callback)
// ...当该侦听器不再需要时
unwatch()
生命周期
created()
:在组件实例处理完所有与状态相关的选项后调用。mounted()
:在组件被挂载之后调用。(第一次被渲染到页面上)unmounted()
:在一个组件实例被卸载之后调用。updated()
:在组件因为一个响应式状态变更而更新其 DOM 树之后调用。
数据共享
父向子
v-bind,props
子向父
自定义事件
父子数据双向绑定
v-model,props,emits:['update:xxx'])
兄弟组件之间进行通话
兄弟组件之间实现数据共享的方案是 EventBus
,可以借助1第三方包 mitt
来创建 eventBus
对象,从而实现兄弟组件之间的数据共享
后代组件之间的通信
provide和inject
父节点使用 provide
向下共享数据时,可以结合 computed
函数向下共享响应式的数据。
provide(){
return{
color:computed(()=>this.color)
}
}
如果父节点共享的是响应式数据,则子孙节点必须以 .value
的形式进行使用
全局配置axios
在 main.js
入口文件中,通过 app.config.globalProperties
全局挂载 axios
ref获取DOM元素
this.$ref.xxx
在父组件的子组件上绑定ref,通过this.$ref.xxx.methods
方法调用子组件上的 methods
方法
动态组件
<!-- currentTab 改变时组件也改变 -->
<component :is="currentTab"></component>
keep-alive保持状态
当使用 <component :is="...">
来在多个组件间作切换时,被切换掉的组件会被卸载。我们可以通过 <KeepAlive>
组件强制被切换掉的组件仍然保持“存活”的状态。
<keep-alive>
<component :is="comName"></component>
</keep-alive>
插槽
具名插槽
如果在封装组件时需要预留多个插槽节点,则需要为每个<slot>
插槽指定具体的name名称。这种带具体名称的插槽叫做具名插槽
没有指定名称的插槽name默认为default
如果我们想在父组件没有提供任何插槽内容时在 <button>
内渲染“Submit”,只需要将“Submit”写在 <slot>
标签之间来作为默认内容:
<button type="submit">
<slot>
Submit <!-- 默认内容 -->
</slot>
</button>
简写:v-slot:header
等同于#header
作用域插槽
在封装组件的过程中,可以预留的 <slot>
插槽绑定props数据,这种带有props数据的 <slot>
叫做"作用域插槽"
!!!不一定命名为scope,甚至可以写成解构赋值的形式{xxx,xxx}
<!-- 子 -->
<slot :info="info" :msg="msg"></slot>
<!-- 父 -->
<template v-slot:default="scope">
<p>{{scope}}</p>
</template>
自定义指令
指令钩子
const myDirective = {
// 在绑定元素的 attribute 前
// 或事件监听器应用前调用
created(el, binding, vnode, prevVnode) {
// 下面会介绍各个参数的细节
},
// 在元素被插入到 DOM 前调用
beforeMount(el, binding, vnode, prevVnode) {},
// 在绑定元素的父组件
// 及他自己的所有子节点都挂载完成后调用
mounted(el, binding, vnode, prevVnode) {},
// 绑定元素的父组件更新前调用
beforeUpdate(el, binding, vnode, prevVnode) {},
// 在绑定元素的父组件
// 及他自己的所有子节点都更新后调用
updated(el, binding, vnode, prevVnode) {},
// 绑定元素的父组件卸载前调用
beforeUnmount(el, binding, vnode, prevVnode) {},
// 绑定元素的父组件卸载后调用
unmounted(el, binding, vnode, prevVnode) {}
}
!!! 在vue2中,mounted->bind,updated->update
指令参数
指令的钩子会传递以下几种参数:
-
el
:指令绑定到的元素。这可以用于直接操作 DOM。 -
binding
:一个对象,包含以下属性。value
:传递给指令的值。例如在v-my-directive="1 + 1"
中,值是2
。oldValue
:之前的值,仅在beforeUpdate
和updated
中可用。无论值是否更改,它都可用。arg
:传递给指令的参数 (如果有的话)。例如在v-my-directive:foo
中,参数是"foo"
。modifiers
:一个包含修饰符的对象 (如果有的话)。例如在v-my-directive.foo.bar
中,修饰符对象是{ foo: true, bar: true }
。instance
:使用该指令的组件实例。dir
:指令的定义对象。
-
vnode
:代表绑定元素的底层 VNode。 -
prevNode
:之前的渲染中代表指令所绑定元素的 VNode。仅在beforeUpdate
和updated
钩子中可用。
全局指令
app.directive('focus',{
mounted(el){
el.focus();
}
})
函数简写
如果mounted和updated函数中的逻辑完全相同,则可以简写为
app.directive('focus',()=>{
el.focus();
})
Vue-Router
基本使用
安装:npm i vue-router@next -S
- 新建
router.js
import { createRouter, createWebHashHistory } from "vue-router";
const router = createRouter({
history: createWebHashHistory(),
routes: [
{ path: "/", redirect: "/home" },
{ path: "/home", component: () => import("./Home.vue") },
{ path: "/msg", component: () => import("./msg.vue") },
],
});
export default router
- 在
main.js
中调用
import { createApp } from 'vue'
import App from './App.vue'
import router from './components/vuerouter/router'
const app = createApp(App)
app.use(router)
app.mount('#app')
- 在
App.vue
中使用
<template>
<router-link to="/home">home</router-link>
<router-link to="/msg">msg</router-link>
<router-view></router-view>
</template>
设置高亮
- 被激活的路由链接,默认会应用一个叫做
router-link-active
的类名。开发者可以使用此类名选择器,为激活的路由链接设置高亮效果 - 在创建路由的实例对象时,开发者可以基于linkActiveClass属性,自定义路由链接被激活时所应用的类名:
const router = createRouter({
history: createWebHashHistory(),
linkActiveClass:'xxxx',
routes: [
{ path: "/", redirect: "/home" },
{ path: "/home", component: () => import("./Home.vue") },
],
});
export default router
嵌套路由
//App.vue
<router-link to="/home/home1">home</router-link>
//router.js
{
path: "/home",
component: () => import("./Home.vue"),
//在进入'/home'会重定向到'/home/home1'
redirect:'/home/home1'
children: [
{
path: "/home1",
component: () => import("./Home.vue"),
},
],
},
动态路由链接
动态路由指的是:把Hash地址中可变的部分定义为参数项,从而提高路由规则的复用性。在vue-router中使用:
来定义路由的参数项
{ path: "/msg/:id", component: () => import("./msg.vue") }
- 使用props接收动态路由参数:
- 声明props:true:
{ path: "/msg/:id", component: () => Msg, props: true },
- 组件内接收:
props:['id']
- 声明props:true:
编程式导航
this.$router.push('hash地址')
this.$router.go(数值n)
this.$router.push
// 字符串路径
router.push('/users/eduardo')
// 带有路径的对象
router.push({ path: '/users/eduardo' })
// 命名的路由,并加上参数,让路由建立 url
router.push({ name: 'user', params: { username: 'eduardo' } })
// 带查询参数,结果是 /register?plan=private
router.push({ path: '/register', query: { plan: 'private' } })
// 带 hash,结果是 /about#team
router.push({ path: '/about', hash: '#team' })
如果提供了 path
,params
会被忽略,上述例子中的 query
并不属于这种情况。取而代之的是下面例子的做法,你需要提供路由的 name
或手写完整的带有参数的 path
const username = 'eduardo'
// 我们可以手动建立 url,但我们必须自己处理编码
router.push(`/user/${username}`) // -> /user/eduardo
// 同样
router.push({ path: `/user/${username}` }) // -> /user/eduardo
// 如果可能的话,使用 `name` 和 `params` 从自动 URL 编码中获益
router.push({ name: 'user', params: { username } }) // -> /user/eduardo
// `params` 不能与 `path` 一起使用
router.push({ path: '/user', params: { username } }) // -> /user
this.$router.replace
router.push({ path: '/home', replace: true })
// 相当于
router.replace({ path: '/home' })
this.$router.go
// 向前移动一条记录,与 router.forward() 相同
router.go(1)
// 返回一条记录,与 router.back() 相同
router.go(-1)
// 前进 3 条记录
router.go(3)
// 如果没有那么多记录,静默失败
router.go(-100)
router.go(100)
命名路由
<router-link :to="{ name: 'user', params: { username: 'erina' }}">
User
</router-link>
等同于
router.push({ name: 'user', params: { username: 'erina' } })
命名视图
//App.vue
<router-view class="view left-sidebar" name="LeftSidebar"></router-view>
<router-view class="view main-content"></router-view>
<router-view class="view right-sidebar" name="RightSidebar"></router-view>
//router.js
const router = createRouter({
history: createWebHashHistory(),
routes: [
{
path: '/',
components: {
default: Home,
// LeftSidebar: LeftSidebar 的缩写
LeftSidebar,
// 它们与 `<router-view>` 上的 `name` 属性匹配
RightSidebar,
},
},
],
})
导航守卫
//router.js
router.beforeEach((to,from,next)=>{
...
})
to
:目标路由对象from
:当前导航正要离开的路由对象next
:next是一个函数,表示放行- 不声明next,则默认允许用户访问每一个路由
- 声明next,则必须调用 next() 函数,否则不允许用户访问任何一个路由
- 直接放行:
next()
- 强制停留在当前页面:
next(false)
- 强制跳转到登陆页面:
next('/xxx')
- 直接放行:
不声明next,使用return进行是否跳转的判断
- false:取消当前的导航。如果浏览器的
URL
改变了(可能是用户手动或者浏览器后退按钮),那么URL
地址会重置到from
路由对应的地址 - 路由地址:通过一个路由地址跳转到一个不同的地址,就像你调用
router.push()
一样,你可以设置诸如replace: true
或name: 'home'
之类的配置。当前的导航被中断,然后进行一个新的导航,就和from
一样。 - 如果什么都没有,
undefined
或返回true
,则导航是有效的,并调用下一个导航守卫
router.beforeEach(async (to, from) => {
if (
// 检查用户是否已登录
!isAuthenticated &&
// ❗️ 避免无限重定向
to.name !== 'Login'
) {
// 将用户重定向到登录页面
return { name: 'Login' }
}
})
路由元信息
有时,你可能希望将任意信息附加到路由上,如过渡名称、谁可以访问路由等。这些事情可以通过接收属性对象的 `meta` 属性来实现,并且它可以在路由地址和导航守卫上都被访问到。定义路由的时候你可以这样配置 `meta` 字段
声明
//router.js
const router = createRouter({
routes: [
{
path: "/home",
component: () => import("./Home.vue"),
meta:{isActive:true}
},
],
});
export default router;
访问
//Home.vue
<p>{{$route.meta.isActive}}</p>
组合式API(setup)
import { useRouter, useRoute } from 'vue-router'
export default {
setup() {
const router = useRouter()
const route = useRoute()
function pushWithQuery(query) {
router.push({
name: 'search',
query: {
...route.query,
},
})
}
},
}