Skip to content
On this page

Vue路由基础

学习目标

  • 【掌握】Vue-router入门
  • 【掌握】Vue-router传参
  • 【掌握】编程式导航
  • 【掌握】路由重定向和404
  • 【掌握】路由组件传参
  • 【掌握】历史记录模式

通过之前的学习我们应该了解Vue创建的是一个单页应用,但我们使用的大型Vue项目仍然能够实现页面内容的切换,这是如何实现的呢?这就用到了我们接下来要学习的内容——路由,Vue中的路由跟生活中理解的路由概念其实非常类似,可以理解为是视图和URL的一种匹配关系,它是Vue全家桶生态中一个非常重要的插件,我们会通过学习最新的V4版本来掌握路由中的一些重要概念。

1.路由入门

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来存放我们的路由配置文件。

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

然后需要在主入口中引入路由配置文件,作用到整个项目中。

js
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个组件,最终实现页面的正确跳转。

vue
<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传参

利用查询字符串的形式来进行参数传递。

在刚才的搜索页中,现在希望点击搜索按钮能够跳转到详情页面,此时我们在做路由跳转的时候必须思考一个问题:我必须将我在搜索页种输入的文本内容传递到详情页面。

在路由配置文件中,新增一项配置信息。

js
routes: [
    {
      path: '/search',
      name: 'search',
      component: Search,
    },
    {
      path: '/list',
      name: 'list',
      component: List,
    },
    {
      path: '/detail',
      name: 'detail',
      component: detail,
    },
  ],

然后在搜索按钮那里通过来实现跳转,此时在路径中通过查询字符串的形式来携带参数

vue
<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参数。

vue
<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动态传参。

使用这种方式实现传参的时候在配置路由信息时需要额外处理。

js
{
      path: '/detail/:text', //这里添加了一个:text的占位符 这个占位符名称可以任意指定
      name: 'detail',
      component: Detail,
    },

然后是通过搜索按钮进行跳转时传递参数。注意区分和query传参的格式区别。

vue
<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>

最终在详情页中来接受参数。

vue
<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方法进行路径的跳转。

vue
<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种方式传递参数。

js
// 字符串路径
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 重定向

当我们匹配到某个路径进行页面跳转的时候,希望能够再次跳转到另一个路由地址,可以采用重定向来实现。

在上面的示例中,比如进入首页就希望能够自动跳转到搜索页:

js
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路径的格式。

js
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。

js
const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    ...
    {
      path: '/detail/:text?',
      name: 'detail',
      component: Detail,
      props:true
    },
    ...
  ],
})

在detail页面中,便可以通过props形式来接受这个参数并且放到模板中使用了。

vue
<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 对象模式

当希望给路由组件传递一些静态属性的时候,使用对象形式是更好的选择。

js
const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    ...
    {
      path: '/list',
      name: 'list',
      component: List,
      props:{
      	a:5,
        b:6
      }
    },
    ...
  ],
})
vue
//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中。

js
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 相同的页面。漂亮依旧!

版权声明 鄂ICP备2022000216号-2