npm init vite
npm i
npm i vue-router
npm i sass -D
在main.js中
import router from './router'
createApp(App).use(router).mount('#app')
在index中配置路由
import {createRouter,createWebHistory} from 'vue-router'
import Home from '../view/Home.vue'
import Search from '../view/Search.vue'
const router = createRouter ({
history:createWebHistory(),
routes:[
{
path:'/',
name:'home',
component:Home
},
{
path:'/search',
name:'search',
component:Search
}
]
})
export default router
写一个顶部的导航栏TopNav.vue在component文件夹中
useRoute和useRouter的区别,一个是获取全局路由,一个是获取当前页面的路由
在app中,将样式引入,并且去掉
在获取网易云数据的api中note app.js
在项目中
npm i axios
获取搜索的接口,放在search中,把连接板包裹在axios把获取的song.value拼接到链接后面,然后发axios请求
const route = useRoute()
const song = ref("")
const lists = ref([])
song.value = route.query.song
axios.get(`http://localhost:3000/search?keywords=${song.value}`).then((res) => {
lists.value = res.data.result.songs
})
查询到数据得到一个30长度的array
将array中需要的数据渲染到页面
-
{{ item.name }}
{{ _item.name }}
{{ _index + 1 < item.artists.length ? "/" : "" }}
{{ item.album.name }}
{{ format(item.duration) }}
得到的歌手不换行,超出的部分省略号,给innerspan添加三个样式即可
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
给每个歌手添加后斜杠,如果索引值+1小于数组长度就加斜杠,如果索引值+1不小于数组长度就不加斜杠{{_index + 1 < item.artists.length ? "/" : ""}}
给li添加斑马条纹样式和鼠标hover样式
定义方法format用来毫秒值转分秒
分钟和秒如果不足10需要在前面添加字符串0。如果秒只有一位,获取秒数时只截取一位,然后添加字符串0;如果多于10,则截取前两位,后面多余的不要。
需要监听song,如果song变化,需要重新发送请求,再把参数传给lists
封装axios请求为方法init(song)
在第一次加载的时候先运行一次init(song.value)
需要监听route.query.song的变化,变化了重新执行init
route.query是一个响应式对象,但route.query.song是一个响应式对象里的值,如果要对这个值进行监听,需要写一个函数包装他,并返回值,这样就不会出现报错了
封装了之后,axios请求中包裹的动态字符中的.value需要删除,因为监听已经直接针对song
const route = useRoute()
const song = ref("")
const lists = ref([])
song.value = route.query.song
function init(song) {
axios.get(`http://localhost:3000/search?keywords=${song}`).then((res) => {
lists.value = res.data.result.songs
})
}
init(song.value) // 第一次加载的时候执行
watch(
() => route.query.song,
(newValue) => {
song.value = newValue
init(song.value)
})
this is login
router.beforeEach((to,from) => {
// 如果进入了页面不是login,或者isLogin不是true,则强制回到login
if(to.name !== 'login' && !localStorage.getItem("isLogin")){
return {
name: "login"
}
}
})
router是全局路由,如果想精细化定制不同页面的跳转效果,可以在路由导航列表的对象里面书写路由导航守卫
localStorage.getItem("isLogin")需要用JSON包裹,否则可能会出现不能识别的情况
{
path: '/detail',
name: 'detail',
component: Detail,
// 单个路由对象的前置导航守卫
beforeEnter (to, from) {
if (to.name !== "/login" &&
!JSON.parse(localStorage.getItem("isLogin"))
) {
return {
name: "login"
}
}
}
},
前置导航守卫可以设置单个,但后置导航守卫可以设置全局的
前置导航守卫可以写在router的全局、局部,或者写在组件内部。推荐写在router
setup语法糖无法触发beforeRouteEnter钩子函数,需要写完整格式
顾名思义,路由导航守卫可以让每个页面完成跳转前后进行一些逻辑实现。vue-router提供了多种导航守卫:全局的,单个路由独享的,或者组件级的。现在来逐一说明。
路由导航守卫的详细说明
你可以使用 router.beforeEach 注册一个全局前置守卫,这样在匹配每个路由路径的时候都会进行一次进入前的"拦截",在某些需要验证登录状态的业务场景下应用极广。
我们仍然用示例来演示全局前置守卫的使用:
现在有3个页面,分别是登录页,首页,列表页。进入任何页面前都需要进行身份验证,必须本地存储中isLogin的字段为true时才可以进入,否则统一回到登录页。按照之前学习的内容快速完成路由信息的相关配置。
在配置完路由信息后,通过router.beforeEach 注册一个全局前置守卫,其中的守卫方法接受2个参数
前置守卫中通过返回的路由对象实现重定向。
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../components/Home.vue'
import Detail from '../components/Detail.vue'
import Login from '../components/Login.vue'
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
name: 'home',
components: Home,
},
{
path: '/detail',
name: 'detail',
components: Detail,
},
{
path: '/login',
name: 'login',
components: Login,
},
],
})
router.beforeEach((to, from) => {
if (!localStorage.getItem('isLogin') && to.name !== 'login') {
return {
name: 'login',
}
}
})
export default router
在之前版本的路由中,还提供了第三个可选参数next,通过调用next方法也能进入到即将进入的路由页面,但新版本中不推荐这么做了。
和全局前置守卫类似,同样可以注册全局后置守卫,沿用上面的示例,在离开每个页面之前,都弹出一个提示框。
router.afterEach((to, from) => {
alert('要离开此页面咯')
})
除了定义全局的路由守卫,还可以针对单个路由对象定义守卫:
{
path: '/detail',
name: 'detail',
component: Detail,
beforeEnter: (to, from) => {
if (!localStorage.getItem('isLogin') && to.name !== 'login') {
return {
name: 'login',
}
}
},
},
除开在路由配置信息中定义导航守卫,还可以在组件内部定义守卫:
meta叫路由元信息,可以存储当前路由对象的一些信息
可以将任意信息添加到路由对象上,比如页面标题,鉴权认证等,Vue中的路由提供了一个meta字段,可以通过给每个路由对象配置meta字段来添加信息。
{
path: '/',
name: 'home',
component: Home,
meta: {
title: '首页',
},
},
在组件的生命周期中,可以将meta信息合理地调用出来。
//Home中 组件挂载完毕后 将页面的标题内容改为meta中存放的信息
这里需要写setup语法糖,但是组件内守卫不要写。虽然最好也不要写组件内守卫啦
某些复杂的组件关系存在层级更深的路由,这是可以利用路由嵌套来实现,给需要添加二级路由的路由对象添加children属性来配置二级路由,同样使用来渲染出口。
现在给Detail路由页面添加二级子路由,能够显示用户详情和头像详情,在对应的路由配置中添加children属性
// 不要忘记最上面的引入!!!
{
path: '/detail',
name: 'detail',
component: Detail,
meta: {
title: '详情页',
},
children: [
{ path: 'users', name: 'users', component: Users },
{ path: 'profile', name: 'profile', component: Profile },
],
},
建立好对应的路由组件后,需要在Detail中添加二级路由的出口:
这是详情页
// 记得渲染出口
嵌套路由的使用规则跟一级路由保持一致,当然如果你的业务足够复杂,还可以嵌套三级,四级路由。
切换路由的过程中,VueRouter还提供了操作滚动条行为的方法,通过scrollBehavior方法可以在路由配置中规定滚动条行为
const router = createRouter({
history: createWebHashHistory(),
routes: [...],
scrollBehavior (to, from, savedPosition) {
// return 期望滚动到哪个的位置
return {
top:30 //滚动到距离顶部30
}
}
})
当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就会更加高效。
首页不用做懒加载,除开首页对所有的路由都使用动态导入。
Vue Router 支持开箱即用的动态导入,这意味着你可以用动态导入代替静态导入:
const Detail = () => import('../components/Detail.vue')
const router = createRouter({
// ...
routes: [{ path: '/detail',name:'detail', component: Detail }],
})
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../view/Home.vue'
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/login',
name: 'login',
component: ()=>import('../view/Login.vue'), // 改为懒加载
meta: {
title: '登录',
},
},
在登录页点击登录后,button新增了一个vip的button,可以进入vip页面。登录之后,才能在路由映射关系中加上vip对象(不能是控制按钮显示隐藏
对路由的添加通常是通过 配置routes来完成的,但是在某些情况下,你可能想在应用程序已经运行的时候添加或删除路由。例如在处理一些路由权限的场景下就需要动态增加路由。
动态增加路由主要依靠router.addRoute()方法实现,获取到router实例后,可以在合理时机注册新的路由对象,
例如在登陆后新增一个Vip路由:
const login = () => {
localStorage.setItem('isLogin', true)
isVip.value = true
router.addRoute({
path: '/vip',
name: 'vip',
component: Vip,
})
}
动态删除路由最常用的方法是通过使用 router.removeRoute() 按名称删除路由,所以注册路由信息时添加name属性是一个好习惯,大家务必养成。
我们示例中登录退出希望将Vip路由删除掉:
const out = () => {
localStorage.clear()
isVip.value = false
router.removeRoute('vip')
}
最终Login组件的页面代码会显得比较丰富完整:
Vue Router 提供了两个功能来查看现有的路由:
this is login