路由切换页面的时候,视图改变了,前端的路径也变了,但是没有重新访问该页面。可以说是视图和url的匹配关系。
vue2对应的是路由的v3版本,vue3对应的是路由的v4版本
vue2路由
选择安装版本时,@3 vue2选择三号版本
npm i vue-router@3
- 新建文件夹,放基础配置,引入vue方法,调用核心方法路由
- 生成实例并导出
- 在实例中生成路由对象
- mode为路由模式,分为History和hash
- 每个路由对象中有最关键的两个属性,它们共同构建了路由映射表
- 在路由映射表头部设置首页默认显示样式
- 在main中引入路由并挂载到vue实例中
- 需要将视图切换的区域最终渲染到模板(app)中(调用VueRouter方法的时候默认注册了router-view组件
- 给按钮包裹跳转组件。跳转组件routerLink可以进行跳转,必须要写to属性,指定跳转的链接地址
- routerLink是一种声明式导航,它的特点:点击被包裹的按钮时,页面跳转时会自动给被跳转的页面添加类名,可以通过这些类名给被选中的页面添加样式。
- hash模式在url多了一个#/,这样是不会发送请求校验给后端的。所以在前端使用时推荐使用History模式。
- 如果我们需要处理不存在的路径(没有在路径列表中匹配到内容),进行404处理,写一个NotFound页面,使用通配符来匹配404路径
- $router实现页面跳转,这种导航形式叫编程式导航。进入到404页面后,开启定时器,定时器结束自动跳转到首页。我们可以在mounted生命周期中,在进入到页面之后,打印this,新增了$route $router ,只有挂载了才会出现,(...)是响应式属性,使用this.$router,在整个项目的路由中调用push方法进行跳转
- push和replace的区别:replace执行的跳转无法记录,也就无法回退,可以进行无痕功能的书写。push可以记录跳转,可以回退,能执行普通功能的编程式导航。
<template>
<div>
<!-- 需要将视图切换的区域最终渲染到模板中,需要一个叫路由的出口 -->
<router-view></router-view>
</div>
</template>
<script>
export default {
data(){
return {
song:"",
}
},
methods:{
search(){ // 做页面跳转
this.$router.push(`/search?song=${this.song}&peiqi=123`)
}
}
}
</script>
import Vue from 'vue'
import App from './App.vue'
import router from './rouder'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
router // 将路由挂载到vue实例上
}).$mount('#app')
// 配置路由_前端路由,是视图和URL的映射关系
import VueRouter from "vue-router";
import Vue from 'vue'
import Home from '../views/Home.vue'
import About from '../views/About.vue'
import Self from '../views/Self.vue'
import NotFound from '../views/NotFound.vue'
import Search from '../views/Search.vue'
// vue需要使用VueRouter
Vue.use(VueRouter)
// 生产一个router实例 传入一个配置对象,这个配置对象表达了视图和URL的映射关系
const router = new VueRouter({
mode: 'history',
// routes是一个数组,这个数组中表达了映射关系
// 两组映射关系,一组/about => About 组件,一组/self => Self组件
// routes是一个对象形式,里面表达映射关系
routes: [
{
path:'/', // 表示首页默认显示
name:'home',
component:Home,
},
{
path: '/about', // 绝对路径,不要加. 对应了一个叫about的组件
name:'about',
component: About,
// 不要加s!!先定义about组件。路由组件不放在components中,放在views中
}, {
path: '/self',
name:'self',
component: Self,
},
{
path:'*',
name:'404',
component:NotFound,
},
{
// 在需要被跳转的页面配置动态占位符
path:'/search/:song/:id',
name:'search',
component:Search,
// props:true // 传参可以用props接收
},
]
})
export default router
<template>
<div>
<!-- <router-link to="/about"><button>About</button></router-link>
<router-link to="/self"> <button>Self</button></router-link> -->
<button @click="$router.push('/about')">About</button>
<button @click="$router.push('/self')">Self</button>
<br/>
<input type="text" placeholder="请搜索" v-model.trim="song"
@keyup.enter="search">
</div>
</template>
<script>
export default {
data(){
return {
song:"",
}
},
methods:{
search(){
// 做页面跳转 查询参数,传递参数
// this.$router.push(`/search?song=${this.song}&peiqi=123`)
// 2 动态参数
this.$router.push(`/search/${this.song}/123`)
/* this.$router.push({
name:'search',
parent:{
song:this.song,
},
}) */
}
}
}
</script>
<style scoped>
.router-link-active button{
background-color: plum;
color: #ccc;
}
</style>
网易云项目
删掉node_modules重新执行npm i
打开之后 node app.js ,不要关闭终端
- 使用搜索功能时,回车后使用编程式导航进行跳转
-
-
- 使用v-model动态绑定输入的内容为song
- 监听enter按下来传递song向下一个页面传递去发送请求
-
- 在第二个页面中,获取到上一个页面中输入的内容,发送ajax请求,得到数据。(路由组件之间如何传参)——查询参数格式
-
- 查询参数 在app的 中 this.$router.push(`/search?song=${this.song}`);
- 这是传参语法格式,可以通过URL传递参数。value是动态变量,所以动态包裹在模板字符串中,在路径上已经能看到传参了
- 可以通过{{ $route.query.song }}来接收传参,也可以在url后面增加其他参数,用&符来连接
-
在search中接收
其中this.$route.query是用来接收参数的,利用传递过来的关键字song发送ajax请求,并将请求得到的数据渲染到页面上。
- 动态参数传参
-
- 在传递的URL直接传参
- 在需要被跳转的页面,添加动态占位符,要传几个参,就配置多少动态占位符
- 在被跳转的页面接收参数,
- 如果传递的是字符串值,建议使用查询参数;如果传递的是数值,建议使用动态参数
- 配置表的时候添加name属性,可以通过name属性传参
- 所以在配置表时,最好为每个页面都添加name属性
- 在传递的URL直接传参
- 如果向path路径传递params参数(传递params参数需要写占位符),不能成功。所以path传递参数,只能用query,不能用params。接收参数的时候书写的方法也需要和传参方法一致,否则无法成功
- 使用props传参(不建议)
-
- 在映射表中开启props
- 在子组件中接收props,并且在页面上渲染接收内容
- 在映射表中开启props
1.vue3路由入门
1.1 安装依赖
在我们的Vite项目中,通过命令来安装Vue-router,vue3版本使用的是最新的Vue-router@4版本。
npm install vue-router
可以在package.json中确认成功安装了依赖。
1.2 配置路由
我们现在有这样一个需求:在页面上有2个button,点击button搜索,可以跳转到一个搜索页面,点击button列表,可以跳到一个列表页面。
稍微分析下,就应该知道这个需求要用路由来实现,我们现在需要2个路由页面(搜索 列表),路由页面其实就是组件。
我们首选需要来在项目中配置一下路由:
在项目的src目录中新建一个router目录,再建立一个index.js来存放我们的路由配置文件。
import { createRouter, createWebHashHistory } from 'vue-router'
import Search from '../components/Search.vue'
import List from '../components/List.vue'
const router = createRouter({
history: createWebHashHistory(),
routes: [
{
path: '/search',
name: 'search',
component: Search,
},
{
path: '/list',
name: 'list',
component: List,
},
],
})
export default router
然后需要在主入口中引入路由配置文件,作用到整个项目中。
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index.js'
createApp(App).use(router).mount('#app')
1.3 内置路由组件使用
在App.vue也就是项目的根组件中,通过Vue-router内置的2个组件和,最终实现页面的正确跳转。
<template>
<div>
<h1>这是首页</h1>
<router-link to="search"><button>搜索页</button></router-link>
<router-link to="list"><button>列表页</button></router-link>
<router-view></router-view>
</div>
</template>
可以理解为路由页面的出口,它可以根据路径来决定具体展示哪个组件 可以理解一个a标签,to属性决定它最终跳转到哪个路径
此时我们已经实现了路由页面的正确跳转。
2.路由传参
当路由跳转到一个页面的时候,往往需要携带一些信息,然后通过这些信息可以向服务端请求数据渲染页面,那如何来实现路由传参呢,Vue给我们提供了2种常见的形式。
2.1 query传参
利用查询字符串的形式来进行参数传递。
在刚才的搜索页中,现在希望点击搜索按钮能够跳转到详情页面,此时我们在做路由跳转的时候必须思考一个问题:我必须将我在搜索页种输入的文本内容传递到详情页面。
在路由配置文件中,新增一项配置信息。
routes: [
{
path: '/search',
name: 'search',
component: Search,
},
{
path: '/list',
name: 'list',
component: List,
},
{
path: '/detail',
name: 'detail',
component: detail,
},
],
然后在搜索按钮那里通过来实现跳转,此时在路径中通过查询字符串的形式来携带参数
<template>
<div>
<input type="text" placeholder="请输入搜索内容" v-model="text" />
<router-link :to="`/detail?text=${text}`"><button>点击搜索</button></router-link>
</div>
</template>
<script setup>
import { ref } from 'vue'
const text = ref('')
</script>
最终在详情页中来接受这个传递过来的数据。
在url中可以直接观测到传递的数据。
通过Vue-router提供了一个hook函数useRoute可以获取到传递过来的query参数。
<template>
<h1>这是搜索的内容:{{ text }}</h1>
</template>
<script setup>
import { onMounted, ref } from 'vue'
import { useRoute } from 'vue-router'
let text = ref('')
onMounted(() => {
text.value = useRoute().query.text
})
</script>
最终页面也能正确显示传递过来的参数。
2.2 params传参
刚才的需求同样可以使用另一种方式来实现,我们称之为params动态传参。
使用这种方式实现传参的时候在配置路由信息时需要额外处理。
{
path: '/detail/:text', //这里添加了一个:text的占位符 这个占位符名称可以任意指定
name: 'detail',
component: Detail,
},
然后是通过搜索按钮进行跳转时传递参数。注意区分和query传参的格式区别。
<template>
<div>
<input type="text" placeholder="请输入搜索内容" v-model="text" />
<!--query传参 <router-link :to="`/detail?text=${text}`"><button>点击搜索</button></router-link> -->
<router-link :to="`/detail/${text}`"><button>点击搜索</button></router-link>
</div>
</template>
最终在详情页中来接受参数。
<template>
<h1>这是搜索的内容:{{ text }}</h1>
</template>
<script setup>
import { onMounted, ref } from 'vue'
import { useRoute } from 'vue-router'
let text = ref('')
onMounted(() => {
// text.value = useRoute().query.text 这是query传参的接受方式
text.value = useRoute().params.text
})
</script>
页面同样能正确显示参数内容。
3.编程式导航
3.1 基本使用
除了使用 <router-link> 创建 a 标签来定义导航链接,我们还可以通过获取router的方式来控制页面的跳转。
上面示例中的跳转都是通过<router-link> 渲染的a标签实现的,如果我们希望页面能够自动跳转呢?具体来说,希望进入到首页后过3S自动进入到搜索页,这种场景下,使用<router-link> 显然无法实现,因为a标签必须手动去点击,我们现在希望通过代码能完成点击,这里就需要使用编程式导航了。
在App.vue中通过useRouter来获取整个router,然后开启一个3s的定时器,通过push方法进行路径的跳转。
<script setup>
import { onMounted } from 'vue'
import { useRouter } from 'vue-router'
onMounted(() => {
const router = useRouter()
setTimeout(() => {
router.push('/search')
}, 3000)
})
</script>
<template>
<div>
<h1>这是首页</h1>
<router-link to="/search"><button>搜索页</button></router-link>
<router-link to="/list"><button>列表页</button></router-link>
<router-view></router-view>
</div>
</template>
当你点击 <router-link> 时,Vue内部其实仍然会调用push这个方法,所以点击 <router-link :to="..."> 相当于调用 router.push(...) ,可以根据实际需求来选用更合理的方式。
3.2 路由传参
和声明式导航类似,编程式导航也可以采用query和params2种方式传递参数。
// 字符串路径
router.push('/users')
// 带有路径的对象
router.push({ path: '/users' })
// 命名的路由,并加上动态参数 同样需要对应地配置路由信息
router.push({ name: 'user', params: { username: 'eduardo' } })
// 带查询参数,结果是 /register?plan=private
router.push({ path: '/register', query: { plan: 'private' } })
3.3 replace,push和go
刚才详细说明了push方法可以实现编程式导航跳转,replace方法同样可以,唯一不同的是,它在导航时不会向 history 添加新记录,正如它的名字所暗示的那样——它取代了当前的条目。
go方法采用一个整数作为参数,表示在history历史中前进或后退多少步,类似于 window.history.go(n)。
4.路由重定向和404
4.1 重定向
当我们匹配到某个路径进行页面跳转的时候,希望能够再次跳转到另一个路由地址,可以采用重定向来实现。
在上面的示例中,比如进入首页就希望能够自动跳转到搜索页:
routes: [
{
path: '/',
redirect: '/search', //配置首页的路由信息时通过redirect属性来实现重定向
},
{
path: '/search',
name: 'search',
component: Search,
},
{
path: '/list',
name: 'list',
component: List,
},
{
path: '/detail/:text?',
name: 'detail',
component: Detail,
},
],
4.2 404
当我们访问一些不存在的路径时,一般都会给出一个404的的页面提示,404也是通过重定向来实现的。
首先可以新建一个404页面组件,当路由路径没有正确匹配的时候,统一重定向到404这个页面中,需要注意path路径的格式。
import { createRouter, createWebHashHistory } from 'vue-router'
import Search from '../components/Search.vue'
import List from '../components/List.vue'
import Detail from '../components/Detail.vue'
import NotFound from '../components/404.vue'
const router = createRouter({
history: createWebHashHistory(),
routes: [
...
{
path: '/404',
name: '404',
component: NotFound,
},
{
path: '/:catchAll(.*)',
redirect: '/404',
},
],
})
export default router
5.路由组件传参
我们之前已经深入学习了如何进行路由组件的参数传递,但之前通过useRoute来获取路由参数的方式耦合度太强,我们希望用我们最习惯的方式props来获取这个参数。
5.1 布尔模式
当 props 设置为 true 时,route.params 将被设置为组件的 props。
回到之前的示例中来实现一下,首先在路由配置信息中添加props这个属性,并设置为true。
const router = createRouter({
history: createWebHashHistory(),
routes: [
...
{
path: '/detail/:text?',
name: 'detail',
component: Detail,
props:true
},
...
],
})
在detail页面中,便可以通过props形式来接受这个参数并且放到模板中使用了。
<template>
<h1>这是搜索的内容:{{ props.text }}</h1>
</template>
<script setup>
import { onMounted, ref } from 'vue'
let text = ref('')
onMounted(() => {
// text.value = useRoute().query.text 这是query传参的接受方式
// text.value = useRoute().params.text 这是params传参的接受方式
})
const props = defineProps(['text'])
</script>
5.2 对象模式
当希望给路由组件传递一些静态属性的时候,使用对象形式是更好的选择。
const router = createRouter({
history: createWebHashHistory(),
routes: [
...
{
path: '/list',
name: 'list',
component: List,
props:{
a:5,
b:6
}
},
...
],
})
//List.vue中
<template>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>{{ a }}</li>
<li>{{ b }}</li>
</ul>
</template>
<script setup>
defineProps(['a', 'b'])
</script>
5.3 函数模式
这种模式大家也可以了解一下,props还可以是一个函数,返回的对象最终会被并入到传递给路由组件的props中。
const routes = [
{
path: '/detail',
component: Detail,
props: route => ({ query: route.query.q })
}
]
URL /detail?q=vue 将传递 {query: 'vue'} 作为 props 传给 Detail组件。
6.历史记录模式
在创建路由器实例时,history 配置允许我们在不同的历史模式中进行选择。
6.1 Hash模式
hash 模式是用 createWebHashHistory() 创建的,我们上面的示例便是采用了这种模式。
js
import { createRouter, createWebHashHistory } from 'vue-router'
const router = createRouter({
history: createWebHashHistory(),
routes
})
它在内部传递的实际 URL 之前使用了一个哈希字符(#)。由于这部分 URL 从未被发送到服务器,所以它不需要在服务器层面上进行任何特殊处理。不过,它在 SEO 中确实有不好的影响。如果你担心这个问题,可以使用 HTML5 模式。
6.2 HTML5 模式
用 createWebHistory() 创建 HTML5 模式,推荐使用这个模式:
js
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(),
routes: [
//...
],
})
当使用这种历史模式时,URL 会看起来很 "正常",没有了那个多余的#。
不过,问题来了(这个问题一般都是后端运维来解决)。由于我们的应用是一个单页的客户端应用,如果没有适当的服务器配置,用户在浏览器中直接访问 https://example.com/user/id,就会得到一个 404 错误。这就丑了。
不用担心:要解决这个问题,你需要做的就是在你的服务器上添加一个简单的回退路由。如果 URL 不匹配任何静态资源,它应提供与你的应用程序中的 index.html 相同的页面。漂亮依旧!