vue2基础第一天
1.vue指令
实质上就是特殊的 html 标签属性, 特点: v- 开头
插值表达式
在dom标签中, 直接插入内容,又叫声明式渲染/文本插值
语法: {{ 表达式 }}
dom中插值表达式赋值, vue的变量必须在data里声明
2.vue指令-v-bind
动态给标签属性设置vue变量的值
语法:v-bind:属性名="vue变量"
简写::属性名="vue变量"
<!-- vue指令-v-bind属性动态赋值 -->
<a v-bind:href="url">我是a标签</a>
<img :src="imgSrc">
3.vue指令-v-on
给标签绑定事件
- 语法
- v-on:事件名="要执行的==少量代码=="
- v-on:事件名="methods中的函数"
- v-on:事件名="methods中的函数(实参)"
- 简写: @事件名="methods中的函数"
v-on事件对象
语法:
- 无传参, 通过形参直接接收
- 传参, 通过$event指代事件对象传给事件处理函数
<template>
<div>
<a @click="one" href="http://www.baidu.com">阻止百度</a>
<hr>
<a @click="two(10, $event)" href="http://www.baidu.com">阻止去百度</a>
</div>
</template>
<script>
export default {
methods: {
one(e){
e.preventDefault()
},
two(num, e){
e.preventDefault()
}
}
}
</script>
v-on修饰符
语法:
- @事件名.修饰符="methods里函数"
- .stop - 阻止事件冒泡
- .prevent - 阻止默认行为
- .once - 程序运行期间, 只触发一次事件处理函数
<template>
<div @click="fatherFn">
<!-- vue对事件进行了修饰符设置, 在事件后面.修饰符名即可使用更多的功能 -->
<button @click.stop="btn">.stop阻止事件冒泡</button>
<a href="http://www.baidu.com" @click.prevent="btn">.prevent阻止默认行为</a>
<button @click.once="btn">.once程序运行期间, 只触发一次事件处理函数</button>
</div>
</template>
<script>
export default {
methods: {
fatherFn(){
console.log("father被触发");
},
btn(){
console.log(1);
}
}
}
</script>
v-on按键修饰符
给键盘事件, 添加修饰符
语法:
- @keyup.enter - 监测回车按键
- @keyup.esc - 监测返回按键
<template>
<div>
<input type="text" @keydown.enter="enterFn">
<hr>
<input type="text" @keydown.esc="escFn">
</div>
</template>
<script>
export default {
methods: {
enterFn(){
console.log("enter回车按键了");
},
escFn(){
console.log("esc按键了");
}
}
}
</script>
4.vue指令 v-model
把表单标签value属性和vue数据变量, 双向绑定到一起
语法: v-model="vue数据变量"
双向数据绑定
- 数据变化 -> 视图自动同步
- 视图变化 -> 数据自动同步
绑定在普通表单标签上:
<input type="text" v-model="username" />
绑定在下拉菜单select上:
<select v-model="from">
<option value="北京市">北京</option>
<option value="南京市">南京</option>
<option value="天津市">天津</option>
</select>
绑定在单选框上:
<input type="radio" value="男" name="sex" v-model="gender">男
<input type="radio" value="女" name="sex" v-model="gender">女
绑定在文本域上:
<textarea v-model="intro"></textarea>
绑定在复选框上:
特别注意: v-model
, 在input[checkbox]
的多选框状态
变量为非数组, 则绑定的是checked
的属性(true/false) - 常用于: 单个绑定使用
变量为数组, 则绑定的是他们的value
属性里的值 - 常用于: 收集勾选了哪些值
<input type="checkbox" v-model="hobby" value="抽烟">抽烟
<input type="checkbox" v-model="hobby" value="喝酒">喝酒
<input type="checkbox" v-model="hobby" value="写代码">写代码
v-model修饰符
v-model.修饰符="vue数据变量"
- .number 以parseFloat转成数字类型
- .trim 去除首尾空白字符
- .lazy 在change时触发而非inupt时
<template>
<div>
<div>
<span>年龄:</span>
<input type="text" v-model.number="age">
</div>
<div>
<span>人生格言:</span>
<input type="text" v-model.trim="motto">
</div>
<div>
<span>自我介绍:</span>
<textarea v-model.lazy="intro"></textarea>
</div>
</div>
</template>
<script>
export default {
data() {
return {
age: "",
motto: "",
intro: ""
}
}
}
</script>
5.vue指令 v-text和v-html
更新DOM对象的innerText/innerHTML
- 语法:
- v-text="vue数据变量"
- v-html="vue数据变量"
- 注意: 会覆盖插值表达式
<template>
<div>
<p v-text="str"></p>
<p v-html="str"></p>
</div>
</template>
<script>
export default {
data() {
return {
str: "<span>我是一个span标签</span>"
}
}
}
</script>
6.vue指令 v-show和v-if
控制标签的隐藏或出现
- 语法:
- v-show="vue变量"
- v-if="vue变量"
- 原理
- v-show 用的display:none隐藏 (频繁切换使用)
- v-if 直接从DOM树上移除
- 高级
- v-else使用
<template>
<div>
<h1 v-show="isOk">v-show的盒子</h1>
<h1 v-if="isOk">v-if的盒子</h1>
<div>
<p v-if="age > 18">我成年了</p>
<p v-else>还得多吃饭</p>
</div>
</div>
</template>
<script>
export default {
data() {
return {
isOk: true,
age: 15
}
}
}
</script>
7.vue指令-v-for
循环生成结构命令
口诀: 让谁循环生成, v-for就写谁身上
-
语法
- v-for="(值, 索引) in 目标结构"
- v-for="值 in 目标结构"
-
目标结构:
- 可以遍历数组 / 对象 / 数字 / 字符串 (可遍历结构)
-
注意:
v-for的临时变量名不能用到v-for范围外
避免v-for和v-if在一起使用: Vue 处理指令时,v-for 比 v-if 具有更高的优先级, 虽然用起来也没报错好使, 但是性能不高, 如果你有5个元素被v-for循环, v-if也会分别执行5次.
vue2基础第二天
1.v-for更新
数组改变, v-for会监测到并更新页面
数组不改变, v-for不会更新页面
vue2通过数组下标修改数组的值的方式 虽然修改了数组 不会触发v-for 不会同步修改视图
vue2 解决方案:this.$set 更新数据的时候,还会更新视图
语法: this.$set(要设置的原数据, 数组下标, 新的值)
vue3没有这个bug
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
这些方法不会触发v-for更新
slice()
filter()
concat()
2.动态class
语法:
- :class="{类名: 布尔值}"
3.动态style
此种方式生成的是标签的行内样式
语法
- :style="{css属性: 值}"
4.计算属性computed
基本概念
一个数据, 依赖另外一些数据计算而来的结果
注意:1.计算属性和data属性都是变量-不能重名
2.计算属性会根据依赖项的变化而自动重新计算
3.计算属性定义的时候是一个函数,使用到的其实是个变量
4.计算属性变量的值就是return返回的数据
简便写法:
computed: {
"计算属性名" () {
return "值"
}
}
计算属性的缓存
计算属性相比函数,具有缓存优势,计算属性对应函数执行后, 会把return值缓存起来
依赖项不变, 多次调用都是从缓存取值,依赖项值变化, 函数会"自动"重新执行并缓存新的值
比普通方法性能更高
计算属性-完整写法
计算属性也是变量,如果要给计算属性赋值 , 需要使用完整写法
computed: {
"属性名": {
set(值){
},
get() {
return "值"
}
}
}
5.侦听器-watch
简单侦听
可以侦听data/computed属性值改变
简便写法: 只能侦听到简单数据类型的变化
watch: {
"被侦听的属性名" (newVal, oldVal){
// newVal: 当前最新值
// oldVal: 上一刻值
// 变量名对应值改变这里自动触发
}
}
深度侦听
侦听复杂类型, 和立即执行侦听
watch: {
"要侦听的属性名": {
// 变量名对应值改变这里自动触发
immediate: true, // 立即侦听(网页打开handler执行一次)
deep: true, // 深度侦听复杂类型内变化 对象里面层的值改变
handler (newVal, oldVal) {
}
}
}
vue2基础第三天
1.组件
组件是可复用的 Vue 实例,封装的思想,把页面上 可重用的部分
封装为 组件
,从而方便项目的 开发 和 维护
组件内template只能有一个根标签
组件内data必须是一个函数, 独立作用域
2.组件全局注册
全局入口在main.js, 在new Vue之上注册
//引入组件
import Pannel from './components/Pannel'
//全局注册组件
Vue.component("PannelG", Pannel)
//使用组件
<PannelG></PannelG>
<PannelG/>
<pannel-g></pannel-g>
3.组件局部注册
import 组件对象 from 'vue文件路径'
export default {
components: {
"组件名": 组件对象
}
}
4.父子组件通讯
父组件向子组件传值
<Product title="好贵的北京烤鸭" price="290" :intro="str"></Product>
export default {
data(){
return {
str: "好贵啊, 快来啊, 好吃"
}
},
}
子组件接收数据
export default {
props: ['title', 'price', 'intro']
}
单向数据流
在vue中需要遵循单向数据流原则
单向数据流:从父到子的单向数据流动
1. 父组件的数据发生了改变,子组件会自动跟着变
2. 子组件不能直接修改父组件传递过来的props props是只读的
==父组件传给子组件的是一个对象,子组件修改对象的属性,是不会报错的,对象是引用类型, 互相更新==
子通过自定义事件通知父修改数据
子: this.$emit("自定义事件名", 传值) - 通知父执行父methods里函数代码
父:@自定义事件名="父methods函数"
vue2基础第四天
1.生命周期钩子函数
Vue 框架内置函数,随着组件的生命周期阶段,自动执行
4大阶段8个方法
初始化 beforeCreate created
挂载 beforeMount mounted
更新 beforeUpdate updated
销毁 beforeDestroy destroyed
初始化阶段
beforeCreate
--此时拿不到data函数和methods中的数据
created
--data和methods已初始化,此时可以拿到data函数和methods中的数据,应用场景:网络请求,注册全局事件
挂载阶段
beforeMount
--此时拿不到真实dom元素
mounted
--可以拿到真实dom元素
更新阶段
data函数里有数据改变才执行的钩子函数,data数据改变重复执行beforeUpdate
和updated
钩子函数
beforeUpdate
--data里数据更新之前, DOM更新之前执行
updated
--data数据更新之后,且虚拟dom重新渲染并打补丁到真实dom之后执行的钩子函数
销毁阶段
当$destroy()被调用 – 比如组件DOM被移除(例v-if)执行销毁钩子函数
beforeDestroy
--dom元素或组件销毁前执行 场景: 移除全局事件, 移除当前组件, 计时器, 定时器, eventBus移除事件$off方法
destroyed
--dom元素或组件销毁后执行
2.$refs-获取DOM和vue实例
获取dom元素
获取dom元素时,webapi获取方式和this.$refs获取方式获取到同一个对象
<h1 id="h" ref="myH">我是一个孤独可怜又能吃的h1</h1>
export default {
mounted() {
console.log(document.getElementById("h")); // h1
console.log(this.$refs.myH); // h1
},
};
获取组件对象
目标是组件时,webapi获取方式获取到dom元素,this.$refs获取到vue实例
this.$refs可以拿到组件 甚至可以修改组件内部的数据,但是一般不会这么做 这样做会造成后期维护困难 一般只会拿到组件调用组件的方法
3.$nextTick使用
Vue更新DOM异步的,点击count++, 马上通过"原生DOM"拿标签内容, 无法拿到新值
解决: this.$nextTick()
过程: DOM更新完会挨个触发$nextTick里的函数体
this.$nextTick(() => {
console.log(this.$refs.myP.innerHTML);
})
扩展: await取代回调函数 $nextTick()原地返回Promise对象
this.$nextTick(() => { await this.$nextTick()
this.$refs.myInp.focus() ===> this.$refs.myInp.focus()
})
4.组件name属性使用
可以用组件的name属性值, 来注册组件名字
我们封装的组件-可以自己定义name属性组件名-让使用者有个统一的前缀风格
components/Com.vue
<template>
<div>
<p>我是一个Com组件</p>
</div>
</template>
<script>
export default {
name: "ComNameHaHa" // 可以定义组件自己的名字
}
</script>
App.vue - 注册和使用
<template>
<div>
<ComNameHaHa></ComNameHaHa>
</div>
</template>
<script>
import Com from './components/Com'
export default {
components: {
[Com.name]: Com
// "ComNameHaHa": Com
}
}
</script>
拓展: [这里还可以放表达式]
const obj={
}
等价于====>obj={ ab:1}
vue2基础第五天
1.动态组件component
vue内置component组件, 配合is属性, 设置要显示的组件名字
挂载点: <component :is="变量"></component>
组件切换会导致组件被频繁销毁和重新创建, 性能不高
2.组件缓存keep-alive
使用Vue内置的keep-alive组件, 可以让包裹的组件保存在内存中不被销毁
<div style="border: 1px solid red;">
<!-- Vue内置keep-alive组件, 把包起来的组件缓存起来 -->
<keep-alive>
<component :is="comName"></component>
</keep-alive>
</div>
总结:keep-alive可以提高组件的性能, 内部包裹的标签不会被销毁和重新创建, 触发激活和非激活的生命周期方法
补充生命周期钩子方法:
activated - 激活时触发
deactivated - 失去激活状态触发
3.组件插槽slot
组件内用<slot></slot>占位
使用组件时<Son></Son>夹着的地方, 传入标签替换slot
Son.vue
<template>
<div class="box">
<!-- 坑位 -->
<slot>
<section>子组件默认内容</section>
</slot>
</div>
</template>
<script>
export default {};
</script>
App.vue
<template>
<div>
<Son>
<h3>你好儿子</h3>
<a href="#">链接</a>
</Son>
</div>
</template>
<script>
import Son from './components/Son.vue'
export default {
components: { Son },
}
</script>
<style></style>
插槽默认内容---<slot>夹着内容默认显示内容, 如果不给插槽slot传东西, 则使用<slot>夹着的内容在原地显示
4.具名插槽
当一个组件内有2处以上需要外部传入标签的地方
slot
的name
属性起插槽名, 使用组件时, template
配合v-slot:插槽名
传入具体标签
Son.vue
<template>
<div class="box">
<slot name="title">
<h2>我是子组件标题</h2>
</slot>
<!-- 坑位 -->
<slot name="content">
<section>子组件默认内容</section>
</slot>
</div>
</template>
<script>
export default {};
</script>
<style scoped>
.box {
border: 1px solid #000;
margin: 20px;
}
</style>
App.vue
<template>
<div>
<Son>
<template v-slot:title>
<h3>你好儿子</h3>
</template>
<template v-slot:content>
<a href="#">链接</a>
</template>
</Son>
</div>
</template>
<script>
import Son from './components/Son.vue'
export default {
components: { Son },
}
</script>
v-slot:
可以简化成#
使用
v-bind
可以省略成:
v-on:
可以省略成@
v-slot:
可以简化成#
5.作用域插槽
子组件里值, 在给插槽赋值时在父组件环境下使用
1.子组件, 在slot上绑定自定义属性和子组件内的值
2.使用组件,用template配合v-slot="自定义变量名"
3.自定义变量会收集slot身上属性和值形成对象
Pannle.vue
<template>
<div class="box">
<!-- 作用域插槽可以看做:子传父 -->
<slot :row="defaultObj"></slot>
</div>
</template>
<script>
export default {
data() {
return {
defaultObj: {
defaultOne: '无名氏',
defaultTwo: '小传同学',
},
}
},
}
</script>
<style scoped>
.box {
border: 1px solid #000;
margin: 20px;
padding: 20px;
}
</style>
App.vue
<template>
<div>
<!--
作用域插槽的使用
1、子组件,<slot :属性名="值"></slot> 传值
2、父组件,通过 v-slot="变量名" 接收
PS:作用域插槽相当于是插槽的子传父。
-->
<Pannle>
<!-- 父组件接收:v-slot="变量名" -->
<template v-slot="scope">
<h2>{{ scope }}</h2>
<h3>{{ scope.row.defaultTwo }}</h3>
</template>
</Pannle>
</div>
</template>
<script>
import Pannle from './components/Pannle.vue'
export default {
components: {
Pannle,
},
}
</script>
6.自定义指令
你需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令
自定义指令作用:可以获取标签,扩展功能
自定义指令全局注册
在main.js用 Vue.directive()方法来进行注册, 然后项目中所有.vue文件里都可以直接用自定义指令
Vue.directive('color', {
// 挂载时触发 只触发一次 相当于mounted钩子函数
inserted(el) {
console.log(el);
}
});
自定义指令局部注册
只能在当前组件.vue文件中使用的自定义指令
使用指令:v-指令名称
<template>
<div id="app">
<!-- 自定义指令 -->
<input type="text" autofocus v-abc />
<h2 v-color="'red'">我是大标题</h2>
</div>
</template>
<script>
export default {
data() {
return {};
},
methods: {},
// 自定义指令局部注册
directives: {
abc: {
// 挂载到页面后触发, 相当于mounted钩子函数
// el表示使用指令时的标签
inserted(el) {
console.log(el);
},
},
},
};
</script>
自定义指令-传值
定义自定义指令时定义接收参数
binding为使用自定义指令时传进来的对象
// 全局注册自定义指令-传值
Vue.directive('color', {
// 挂载时触发 只触发一次 相当于mounted钩子函数
inserted(el, binding) {
el.style.color = binding.value;
},
// 每次更新后触发 相当于updated钩子函数
update(el, binding) {
el.style.color = binding.value;
}
});
使用自定义指令时传递参数
<template>
<div>
<!-- 使用指令时传值:v-指令名称="变量" -->
<!-- 使用指令时传值:v-指令名称="'字符串'" -->
<h2 v-color="'red'">我是二标题-什么颜色呢?</h2>
<h3 v-color="myColor">我是三标题-什么颜色呢?</h3>
<button @click="myColor = 'green'">改颜色变量</button>
</div>
</template>
<script>
export default {
data() {
return {
myColor: "pink",
};
},
};
</script>
vue2基础第六天
1.路由
前端中定义
路径和组件的映射关系或接口和服务的映射关系
作用
实现单页面应用(SPA): 所有功能在一个html页面上实现
实现业务场景切换
路由的优点
整体不刷新页面,用户体验更好
数据传递容易, 开发效率高
路由的缺点
开发成本高(需要学习专门知识)
首次加载会比较慢一点,不利于seo
2.vue-router
定义:vue官方提供的路由系统功能模块包
作用:在Vue项目中集成路由
vue-router提供2个内置全局组件 router-link router-view
注意:vue-router@4
不兼容vue2
vue2项目中要下载vue-router@3
3.vue-router使用步骤
在main.js中配置
1.安装
yarn add vue-router@3
2.导入路由
import VueRouter from 'vue-router'
3.使用路由插件
// 在vue中,使用使用vue的插件,都需要调用Vue.use()
Vue.use(VueRouter)
4.1导入组件
import Find from '@/views/Find.vue';
import My from '@/views/My.vue';
import Part from '@/views/Part.vue';
import NotFound from '@/views/NotFound.vue';
4.2创建路由规则数组
const routes = [
{
// 默认页面重定向为Find页
path: '/',
redirect: '/find'
},
{
path: "/find",
component: Find,
// 嵌套路由:二级路由
children: [
// main.js中二级路由路径书写无需 / 开头
// path为空表示默认打开的页面
{
path: '',
// 重定向
redirect: 'recommend'
},
{
path: 'recommend',
component: Recommend
},
{
path: 'ranking',
component: Ranking
},
{
path: 'songlist',
component: SongList
}
]
},
{
path: "/my",
name: 'mypage',
component: My
},
{
path: "/part/:id",
component: Part
},
// 404页面
{
path: '*',
component: NotFound
}
];
5.创建路由对象 - 传入规则
const router = new VueRouter({
routes,
//默认hash模式
//history模式url地址栏上没有#号
mode: 'history' //设置history模式,路由上线需要服务器端支持, 否则找的是文件夹
})
6.关联到vue实例
new Vue({
router
})
7.使用路由
使用路由页面components换成router-view
使用router-view挂载点显示切换的路由
<router-view></router-view>
4.声明式导航
基本使用
用全局组件router-link来替代a标签
router-link配合to, 实现点击切换路由
router-link实质上最终会渲染成a链接 to属性等价于提供 href属性
router-link提供了声明式导航高亮的功能(router-link-exact-active router-link-active)
router-link自带的2个类名
router-link-exact-active (精确匹配) url中hash值路径, 与href属性值完全相同, 设置此类名
router-link-active (模糊匹配) url中hash值, 包含href属性值这个路径, 设置此类名
<template>
<div id="app">
<ul>
<!-- 声明式导航 -->
<!-- 声明式导航也可以传对象 此时to前要绑定: -->
<!-- <li><router-link to="/find">发现页</router-link></li> -->
<li><router-link :to="{ path: '/find' }">发现页</router-link></li>
<li><router-link to="/my?id=123">我的主页</router-link></li>
<li><router-link to="/part/456">我的分页</router-link></li>
</ul>
<!-- 路由挂载点 -->
<router-view></router-view>
</div>
</template>
<script>
export default {};
</script>
<style scoped lang=less>
.router-link-exact-active {
color: aqua;
}
</style>
声明式导航传参
方案1: 传值---to="/path?参数名=值"
接收---`$route.query`
方案2: 传值---to="/path/值"
(需要在路由规则数组中配置 /path/:参数名)
接收---`$route.params`
两种方案二选一即可,选择哪种看团队习惯
拓展: 声明式导航也可以传对象 此时to前面要绑定:
<router-link :to="{ path: '/find'}">发现页</router-link>
等价于
<router-link to="/find">发现页</router-link>
5.vue路由 - 重定向
定义:匹配path后, 强制切换到目标path上
网页打开url默认hash值是/路径
redirect是设置要重定向到哪个路由路径
强制重定向后, 还会重新来数组里匹配一次规则
//网页默认打开, 匹配路由"/", 强制切换到"/find"上
const routes = [
{
path: "/", // 默认hash值路径
redirect: "/find" // 重定向到/find
// 浏览器url中#后的路径被改变成/find-重新匹配数组规则
}
]
6.404页面
如果路由hash值, 没有和数组里规则匹配,默认给一个404页面
放在路由规则数组最后, path匹配*(任意路径) – 前面不匹配就命中最后这个, 显示对应组件页面
7.编程式导航
用JS代码来进行跳转,大多数情况使用声明式导航,当需要在导航前判断是就要使用编程式导航
基础使用
<template>
<div id="app">
<!-- 编程式导航 -->
<button @click="btnFn">编程式导航</button>
<!-- 路由挂载点 -->
<router-view></router-view>
</div>
</template>
<script>
export default {
methods: {
btnFn() {
// 方式1 使用 name
// 方式1需要在路由数组里, 给路由起名字
this.$router.push("Find");
// 方式2 使用 path
this.$router.push("/find");
},
},
};
</script>
跳转传参
方式1: query方式传参 搭配path 接收参数用 $route.query
方式2: params方式传参 搭配name 接收参数用 $route.params
注意: vue2固有的bug 编程式导航跳转相同的页面 会报错
<template>
<div id="app">
<!-- 编程式导航 -->
<button @click="btnFn">编程式导航</button>
<!-- 路由挂载点 -->
<router-view></router-view>
</div>
</template>
<script>
export default {
methods: {
btnFn() {
// 进阶使用:传对象的形式,适用于参数较多的情况
// name 和path选其中一个就好
//传参 params搭配name传参
//格外注意: 使用path会自动忽略params
this.$router.push({
/*name: "part",
params: {
id: 123,
aaa: "rose",
bbb: "flower",
}, */
path: "/my",
query: {
id: 1234444,
aaa: "aaa",
bbb: "15dsaaf",
},
});
},
},
};
</script>
<style scoped lang=less>
.router-link-exact-active {
color: aqua;
}
</style>
8.路由嵌套
规则
main.js
继续配置2级路由
一级路由path从/开始定义
二级路由往后path直接写名字, 无需/开头
嵌套路由在上级路由的children
数组里编写路由信息对象
main.js展示
// 导入二级路由
import Recommend from '@/views/second/Recommend';
import SongList from '@/views/second/SongList';
import Ranking from '@/views/second/Ranking';
const routes = [
{
// 默认页面重定向为Find页
path: '/',
redirect: '/find'
},
{
path: "/find",
component: Find,
// 嵌套路由:二级路由
children: [
// main.js中二级路由路径书写无需 / 开头
// path为空表示默认打开的页面
{
path: '',
// 重定向
redirect: 'recommend'
},
{
path: 'recommend',
component: Recommend
},
{
path: 'ranking',
component: Ranking
},
{
path: 'songlist',
component: SongList
}
]
},
// 404页面
{
path: '*',
component: NotFound
}
];
二级路由展示
跳转时, 要去的路由路径从一级开始写,需要/
开头
<template>
<div>
find页面
<!-- 二级路由挂载点 -->
<ul>
<!-- 注意点:页面中 to 属性的每一级路径都需要写/开头 如:/一级/二级 / -->
<li>
<router-link to="/find/recommend">发现音乐页/ 推荐页面</router-link>
</li>
<li>
<router-link to="/find/ranking">发现音乐页 / 排行榜页面</router-link>
</li>
<li>
<router-link to="/find/songlist">发现音乐页 / 歌单页面</router-link>
</li>
</ul>
<router-view></router-view>
</div>
</template>
<script>
export default {};
</script>
<style scoped>
/* 精确匹配类名 */
.router-link-exact-active {
color: red;
}
</style>
9.全局前置守卫
路由跳转之前, 先执行一次前置守卫函数, 判断是否可以正常跳转
在main.js中得到路由对象router
之后书写代码
// 语法: router.beforeEach((to, from, next)=>{//路由跳转"之前"先执行这里, 决定是否跳转})
// 参数1: 要跳转到的路由 (路由对象信息) 目标
// 参数2: 从哪里跳转的路由 (路由对象信息) 来源
// 参数3: 函数体 - next()才会让路由正常的跳转切换, next(false)在原地停留, next("强制修改到另一个路由路径上")
// 注意: 如果不调用next, 页面留在原地
// 例子: 判断用户是否登录, 是否决定去"我的音乐"/my
const isLogin = false; // 登录状态(未登录)
router.beforeEach((to, from, next) => {
if (to.path === "/my" && isLogin === false) {
alert("请登录")
next(false) // 阻止路由跳转
} else {
next() // 正常放行
}
})