主题
创建路由对应的组件与实现路由一(Lesson9 2/2)
本页对应 Lesson09,共 5 段视频,约 2 小时 21 分。
学习目标
- 能说明跨域产生的原因,并在 Vue 开发服务器中配置代理,将指定前缀请求转发到目标服务,验证浏览器请求自身开发服务器且数据成功返回。
- 能正确使用
changeOrigin、pathRewrite等代理选项处理来源与路径重写,并能排查代理不生效问题(如修改配置后重启服务、前缀匹配、路由与代理优先级)。 - 能解释 JavaScript 引用类型在数组/对象修改中的影响,复现通过
map/遍历修改对象属性对原数组的影响,并使用替换新数组或事件方式触发 Vue 更新,说明深度监听的性能代价。 - 能创建路由对应组件并配置
path、component、redirect、alias、通配 404 等路由规则,实现首页、新闻列表、商品列表、个人中心及重定向和别名访问。 - 能配置
hash/history路由模式、base基础地址,并使用命名视图与多路由出口实现单页面多路由渲染。 - 能将路由配置从
main.js抽离到独立的router/index.js并导出使用,验证抽离后路由功能与抽离前一致。
知识点
本节要做什么
这一节的目标很明确:先不要急着写路由表,而是把路由要用到的页面组件先建出来。转写稿里先提出需求:访问 / 或 /home 显示首页,访问 /newslist 或 /news 显示新闻列表,访问 /goodslist 显示商品列表,访问 /my 显示个人中心,其他地址显示 404。需求拆完后,第一步就是“每个路由对应一个组件”。为什么需要先建组件?因为路由配置的本质是“地址匹配后使用哪个组件”,组件不存在,路由表就没法写。怎么想?先按页面维度拆成 5 个文件,统一放到 src/pages 下。怎么做?逐个创建并写最小模板。易错点:路由级页面组件不要和普通小组件混在一起;Vue 2 模板要保证单根节点;name 与文件名保持一致,调试时更清楚。
创建 Home 组件
为什么需要:首页是默认入口,后续 / 要映射到它。怎么想:先写最小可识别内容,不堆业务。怎么做:在 src/pages/Home.vue 中写标题。易错点:<style scoped> 先留空可以,但不要漏掉 export default。
vue
<template>
<div>
<h3>Home</h3>
</div>
</template>
<script>
export default {
name: "Home"
}
</script>
<style scoped>
</style>创建 NewsList 组件
为什么需要:新闻列表是独立页面,后面可能对应 /newslist,转写稿还要求 /news 也能显示同一组件。怎么想:一个页面一个组件,地址别名后面在路由里配。怎么做:在 src/pages/NewsList.vue 写列表页占位。易错点:不要把“新闻列表”写成普通组件名,页面组件命名要能直接对应路由。
vue
<template>
<div>
<h3>新闻列表界面</h3>
</div>
</template>
<script>
export default {
name: "NewsList"
}
</script>
<style scoped>
</style>创建 GoodsList 组件
为什么需要:商品列表与新闻列表结构相似,但业务不同,必须拆成两个组件。怎么想:路由地址 /goodslist 对应 GoodsList。怎么做:在 src/pages/GoodsList.vue 写占位。易错点:文件名大小写要和 import 时一致,避免 Linux 环境下找不到文件。
vue
<template>
<div>
<h3>商品列表界面</h3>
</div>
</template>
<script>
export default {
name: "GoodsList"
}
</script>
<style scoped>
</style>创建 My 组件
为什么需要:个人中心是独立路由页面。怎么想:地址 /my 对应 My。怎么做:在 src/pages/My.vue 写占位。易错点:转写稿里曾出现 /my 被代理规则拦截,导致路由页面不出现;这不是组件写错,而是代理优先级问题,后面配置代理时要注意。
vue
<template>
<div>
<h3>我的个人中心界面</h3>
</div>
</template>
<script>
export default {
name: "My"
}
</script>
<style scoped>
</style>创建 NotFound 组件
为什么需要:地址写错时不能白屏,要给出 404 提示。怎么想:最后用通配地址 * 匹配它。怎么做:在 src/pages/NotFound.vue 写提示。易错点:404 路由通常放在路由表最后,否则可能提前匹配。
vue
<template>
<div>
<h3>404,您找的界面不存在!</h3>
</div>
</template>
<script>
export default {
name: "NotFound"
}
</script>
<style scoped>
</style>组件如何接到路由上
为什么需要:只有组件文件,页面不会自动出现,必须让地址和组件建立映射。怎么想:转写稿里的做法是引入 VueRouter、Vue.use(VueRouter),再写 routes 数组,每项包含 path 和 component。怎么做:先按转写稿配置 /、/home 重定向、/newslist 与别名 /news、/goodslist、/my、*。易错点:component 的值是组件对象,不是字符串;redirect 是重定向,alias 是别名,两者不要混。
js
const routes = [
{ path: '/', component: Home },
{ path: '/home', redirect: '/' },
{ path: '/newslist', component: NewsList, alias: '/news' },
{ path: '/goodslist', component: GoodsList },
{ path: '/my', component: My },
{ path: '*', component: NotFound }
]router-view 与调试过程
为什么需要:路由匹配到组件后,必须告诉 Vue“在哪里渲染”。怎么想:转写稿中在 App.vue 里放 <router-view>,它占的位置就是路由组件的出口。怎么做:main.js 挂载 App,App.vue 中写 <router-view></router-view>。易错点:转写稿里一开始挂载写成了 #root,控制台报错,检查后发现模板里是 #app,要改为 #app;路由不显示时,先查 router-view 有没有写、路由是否注册、控制台是否报错。
模式、重定向、别名与抽离
为什么需要:默认 hash 模式地址带 #,转写稿演示了 mode: 'history' 可去掉 #;重定向用于 /home 回 /;别名让 /news 和 /newslist 共用一个组件;base 可统一加前缀。怎么做:在 new VueRouter({ routes, mode: 'history' }) 中配置。转写稿最后把路由配置抽到 src/router/index.js,导出 router,再在 main.js 引入,避免主文件越来越乱。易错点:改 vue.config.js 或代理后要重启服务;代理规则可能优先于路由,如 /my 被代理拦截时页面就出不来。
先看目标:把地址映射到组件
为什么需要:单页应用只有一张 HTML,页面切换不能靠刷新,而要靠“地址变化 → 显示不同组件”。这就是前端路由的核心。
怎么想:先把需求拆成地址:/ 首页、/newsList 新闻、/goodsList 商品、/my 个人中心、找不到则 404。每个地址先对应一个页面组件。
怎么做:在 src/pages 下准备 Home、NewsList、GoodsList、My、NotFound,以及单页面多路由要用的 MyHeader、MyMain、YouFooter。转写稿里先创建组件、再在 main.js 引入,顺序不要反。
易错点:转写稿调试时出现过 #root 报错,根实例挂载点应是项目里的 #app;组件路径、文件名大小写要一致。
安装路由并挂载根实例
为什么需要:VueRouter 是插件,必须先 Vue.use 安装,才能使用 router-view、$route 等能力。
怎么想:固定三步:引入 vue-router → Vue.use(VueRouter) → 在根实例传入 router 配置。routes 是数组,每个对象就是一条路由配置。
怎么做:完整 src/main.js 如下:
js
import Vue from "vue";
// 1- 引入模块vue-router
import VueRouter from "vue-router";
import App from "@/App";
import Home from "@/pages/Home";
import NewsList from "@/pages/NewsList";
import GoodsList from "@/pages/GoodsList";
import My from "@/pages/My";
import NotFound from "@/pages/NotFound";
import MyHeader from "@/pages/MyHeader";
import MyMain from "@/pages/MyMain";
import YouFooter from "@/pages/YouFooter";
// 2- 安装路由
Vue.use(VueRouter);
new Vue({
render: h => h(App),
// 3- 应用配置
// 接收的是一个对象,对象中的routes数组,数组中的每个元素(对象)即是路由配置信息对象
router: new VueRouter({
// 配置路由信息
routes: [
{
path: "/",// 指定路由地址
component: Home// 当请求地址与路由地址匹配时,那么会使用组件Home
}, {
// 支持的请求地址除/newsList以及,还支持/news
path: "/newsList",
alias: "/news",// 为地址起别名
component: NewsList
}, {
path: "/goodsList",
// 可以设置为数组,起多个别名
alias: ["/first", "/daoLang", "/wangFei"],
component: GoodsList
}, {
path: "/my",
// 单页面多路由(了解)
components: {
one:MyHeader,
main:MyMain,
footer:YouFooter,
default:My
}
}, {
path: "*",
component: NotFound
}, {
// redirect:重定向--》当请求地址为/home,被重定向至地址/
path: "/home",
redirect: "/"
}
],
// 指定路由模式:默认为hash
// 1- history
// 2- hash
mode: "history",
// 支持地址以m开头
// base:"m"
})
}).$mount("#app");易错点:routes 不是 routers;component 是单组件,components 才是多视图;改完配置要重启开发服务。
路由表细节:别名、重定向、404
为什么需要:一个页面可能希望有多个访问地址;旧地址要回到首页;错误地址要有兜底页面。
怎么想:alias 是“同一组件多地址”;redirect 是“访问 A 跳到 B”;path:"*" 是“其余都匹配”。
怎么做:如 /news 与 /newsList 同组件;/first、/daoLang、/wangFei 都进商品列表;/home 重定向到 /;* 对应 NotFound。
易错点:别名可写字符串或数组;通配路由通常放在最后;重定向写目标 path,不要误写成组件。
用 router-view 指定出口与命名视图
为什么需要:配置了路由还不够,必须告诉 Vue“匹配到的组件显示在哪里”。
怎么想:普通路由用 <router-view> 占位;单页面多路由用 components 配多个名字,再在 router-view 上写 name。
怎么做:完整 src/App.vue 如下:
vue
<template>
<div>
<!--指定路由呈现的位置:为路由组件占位-->
<!-- components->one->组件-->
<router-view name="one"></router-view>
<!-- components->main->组件-->
<router-view name="main"></router-view>
<!-- components->footer->组件-->
<router-view name="footer"></router-view>
<hr/>
<!--在单页面多路由中,router-view省略name,那么会使用components->default->组件-->
<router-view></router-view>
<router-view></router-view>
<router-view></router-view>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "App.vue"
}
</script>
<style scoped>
</style>易错点:name="one" 必须和 components 里的键一致;省略 name 时使用 default;多写多个 router-view 会重复渲染。
路由模式与 base,注意和代理的冲突
为什么需要:默认 hash 地址带 #;history 地址更自然。base 可给地址加统一前缀。
怎么想:mode:"history" 后地址不再带 #;base:"m" 表示地址支持以 m 开头。
怎么做:在 new VueRouter({...}) 中配置 mode,需要时再打开 base。转写稿调试时发现:开发代理若以 /m 开头,会抢在路由前匹配,导致 /my 个人中心异常;应避免代理前缀覆盖路由,或调整代理前缀后重启。
易错点:代理匹配优先于前端路由;mode、base 改动后要重启;先保证 /、/newsList、/goodsList、/my、404 都能单独访问,再叠加多视图配置。
先把本节目标说清楚
这一节是在“实现路由一”的基础上,把 src/main.js 里的路由配置补完整。为什么需要这一步?因为只会写 path + component 只能完成最基础跳转;真实项目里还会遇到“同一个页面多个地址”“旧地址跳新地址”“一个地址同时渲染多块组件”“404 页面”“去掉地址栏的 #”等需求。怎么想?先把路由实例的配置项按职责拆开:routes 管匹配规则,mode 管地址形式,base 管统一前缀。怎么做?直接看本节笔记代码:
js
import Vue from "vue";
// 1- 引入模块vue-router
import VueRouter from "vue-router";
import App from "@/App";
import Home from "@/pages/Home";
import NewsList from "@/pages/NewsList";
import GoodsList from "@/pages/GoodsList";
import My from "@/pages/My";
import NotFound from "@/pages/NotFound";
import MyHeader from "@/pages/MyHeader";
import MyMain from "@/pages/MyMain";
import YouFooter from "@/pages/YouFooter";
// 2- 安装路由
Vue.use(VueRouter);
// 3- 应用配置
// 接收的是一个对象,对象中的routes数组,数组中的每个元素(对象)即是路由配置信息对象
const router = new VueRouter({
// 配置路由信息
routes: [
{
path: "/",// 指定路由地址
component: Home// 当请求地址与路由地址匹配时,那么会使用组件Home
}, {
// 支持的请求地址除/newsList以及,还支持/news
path: "/newsList",
alias: "/news",// 为地址起别名
component: NewsList
}, {
path: "/goodsList",
// 可以设置为数组,起多个别名
alias: ["/first", "/daoLang", "/wangFei"],
component: GoodsList
}, {
path: "/my",
// 单页面多路由(了解)
components: {
one:MyHeader,
main:MyMain,
footer:YouFooter,
default:My
}
}, {
path: "*",
component: NotFound
}, {
// redirect:重定向--》当请求地址为/home,被重定向至地址/
path: "/home",
redirect: "/"
}
],
// 指定路由模式:默认为hash
// 1- history
// 2- hash
mode: "history",
// 支持地址以m开头
// base:"m"
});
new Vue({
render: h => h(App),
// 3- 应用配置
// 接收的是一个对象,对象中的routes数组,数组中的每个元素(对象)即是路由配置信息对象
router
}).$mount("#app");引入、安装、创建实例
为什么需要?Vue.use(VueRouter) 是把路由能力挂到 Vue 上;new VueRouter({...}) 才是创建路由实例。怎么想?固定三步:引入、安装、把实例交给根 Vue。怎么做?注意 router 要作为根实例选项传入,否则 <router-view> 不工作。易错点:转写稿里反复强调“固定写法,不要想太多”;漏写 Vue.use 或根实例没传 router,页面不会按地址切换。
routes 数组与 path/component
为什么需要?路由本质是“地址匹配哪个组件”。怎么想?routes 是数组,每个元素是一个配置对象。怎么做?path 写匹配地址,component 写对应组件。易错点:笔记里是 component 单数组件;后面 /my 用的是 components 多视图,两个单词别混。转写稿调试时发现页面不出现,先检查控制台和 router-view 是否写了。
alias:同一组件多个地址
为什么需要?比如新闻列表既要 /newsList 又要 /news。怎么想?别名不是跳转,而是“这个地址也匹配我”。怎么做?alias: "/news",也可写成数组:alias: ["/first", "/daoLang", "/wangFei"]。易错点:转写稿里“编名”是同音,正确是“别名”;别名不会改变地址栏,也不会像 redirect 那样把 A 改成 B。
redirect:地址改道
为什么需要?旧地址 /home 要回到首页 /。怎么想?redirect 是“请求 A,最终去 B”。怎么做?{ path: "/home", redirect: "/" }。易错点:redirect 和 alias 容易混:alias 是同一组件的另一个名字;redirect 是换地址。转写稿说“重钉项”应纠正为“重定向”。
components:单页面多路由
为什么需要?/my 页面要同时出现头部、主体、底部和个人中心默认内容。怎么想?一个地址可以对应多个命名视图。怎么做?用 components: { one, main, footer, default: My },模板里用 <router-view name="one"> 等占位。易错点:这是“了解”项,普通页面仍用 component;命名视图要和 name 对上。
404、mode 与 base
为什么需要?未知地址要兜底;地址栏想不要 #。怎么想?path: "*" 放最后匹配 404;mode: "history" 使用 history 模式,默认是 hash。怎么做?按笔记写 NotFound 和 mode。base: "m" 是注释项,表示统一前缀,启用后地址要以 m 开头。易错点:改完配置要重启开发服务;转写稿还提到代理前缀可能先匹配,若 /my 被代理拦截,检查 Network 请求地址,必要时调整代理前缀,别误判成路由坏了。
为什么要把路由从 main.js 抽离
为什么需要:路由配置一多,main.js 会同时承担“创建根实例”和“配置地址与组件映射”两件事,文件越来越长,阅读性变差,后面再加路由也不方便定位。
怎么想:转写稿里的推导是,先把 new VueRouter(...) 的返回值抽成一个 router 变量,让 main.js 只负责引入;再把与路由相关的 Vue.use(VueRouter)、routes、mode、base 整体挪到 src/router/index.js,最后导出给入口使用。
怎么做:新建 src/router/index.js,在其中创建并 export default 路由实例;main.js 只 import router from "@/router",再挂到 Vue 实例上。
易错点:export default 和 import router from "@/router" 要对应;Vue.use(VueRouter) 应放在路由模块中执行一次;不要把 routes 写成 routers。
抽离后的入口文件 main.js
为什么需要:入口文件应尽量薄,只做根实例创建和挂载,路由细节交给路由模块。
怎么想:转写稿中抽离后,main.js 里不再出现 routes 数组,只保留 router 的引入和挂载。
怎么做:
js
import Vue from "vue";
import App from "@/App";
import router from "@/router";
new Vue({
render: h => h(App),
router
}).$mount("#app");这里的 @/router 会找到 src/router/index.js。new Vue 配置里的 router 是让整个应用接入路由,$mount("#app") 对应页面中的挂载点。
易错点:忘记在 new Vue 中写 router,会导致路由组件无法正常显示;#app 要和 index.html 中的 id 一致。
路由配置文件 router/index.js 的完整写法
为什么需要:把地址与组件的对应关系集中管理,后续新增页面只改路由文件。
怎么想:先安装插件 Vue.use(VueRouter),再创建 new VueRouter({ routes, mode, base })。routes 中每一项描述“什么地址使用什么组件”。
怎么做:
js
import Vue from "vue";
import VueRouter from "vue-router";
import Home from "@/pages/Home";
import NewsList from "@/pages/NewsList";
import GoodsList from "@/pages/GoodsList";
import MyHeader from "@/pages/MyHeader";
import MyMain from "@/pages/MyMain";
import YouFooter from "@/pages/YouFooter";
import My from "@/pages/My";
import NotFound from "@/pages/NotFound";
Vue.use(VueRouter);
export default new VueRouter({
// 配置路由信息
routes: [
{
path: "/",// 指定路由地址
component: Home// 当请求地址与路由地址匹配时,那么会使用组件Home
}, {
// 支持的请求地址除/newsList以及,还支持/news
path: "/newsList",
alias: "/news",// 为地址起别名
component: NewsList
}, {
path: "/goodsList",
// 可以设置为数组,起多个别名
alias: ["/first", "/daoLang", "/wangFei"],
component: GoodsList
}, {
path: "/my",
// 单页面多路由(了解)
components: {
one: MyHeader,
main: MyMain,
footer: YouFooter,
default: My
}
}, {
path: "*",
component: NotFound
}, {
// redirect:重定向--》当请求地址为/home,被重定向至地址/
path: "/home",
redirect: "/"
}
],
// 指定路由模式:默认为hash
// 1- history
// 2- hash
mode: "history",
// 支持地址以m开头
// base:"m"
});alias 用于给同一路由起别名,可写字符串或数组;components 用于单页面多路由,配合命名视图使用;redirect 是访问 /home 时跳到 /;path:"*" 兜底 404。转写稿调试时还提到:mode:"history" 后地址不再带 #,默认是 hash;base 可给地址加统一前缀,如 base:"m" 后地址以 /m 开头。
易错点:单个组件用 component,多个命名视图用 components;alias 不要写成 alias 数组却仍按单值理解;redirect 写目标路径;若 base 前缀与开发代理前缀冲突,转写稿中明确代理优先级更高,可能把路由请求先拦走,需检查代理配置。
调试与检查清单
转写稿的调试过程是:先把路由配置留在 main.js,验证 /、/newsList、/news、/goodsList、/my、404 和 /home 重定向;再把 new VueRouter 抽成 const router,最后整体抽到 src/router/index.js 并导出。抽离后刷新页面,地址与组件仍能对应,说明导出和引入正确。
易错点检查:src/router/index.js 是否默认导出;main.js 是否引入并挂载;Vue.use(VueRouter) 是否执行;routes 拼写;mode 与 base 是否符合预期;使用 base:"m" 时留意与代理前缀的优先级。
笔记中记录的接口地址原样保留:
https://i.maoyan.com/api/mmdb/movie/v3/list/hot.json?ct=上海&ci=10&channelId=4
https://api.github.com/search/repositories?q=r&sort=stars
https://api.github.com/search/users?q=r&sort=stars
课堂画面





代码示例
示例一:创建路由对应的 5 个页面组件
vue
<!-- src/pages/Home.vue -->
<template>
<div>
<h3>Home</h3>
</div>
</template>
<script>
export default {
name: "Home"
}
</script>
<style scoped>
</style>vue
<!-- src/pages/NewsList.vue -->
<template>
<div>
<h3>新闻列表界面</h3>
</div>
</template>
<script>
export default {
name: "NewsList"
}
</script>
<style scoped>
</style>vue
<!-- src/pages/GoodsList.vue -->
<template>
<div>
<h3>商品列表界面</h3>
</div>
</template>
<script>
export default {
name: "GoodsList"
}
</script>
<style scoped>
</style>vue
<!-- src/pages/My.vue -->
<template>
<div>
<h3>我的个人中心界面</h3>
</div>
</template>
<script>
export default {
name: "My"
}
</script>
<style scoped>
</style>vue
<!-- src/pages/NotFound.vue -->
<template>
<div>
<h3>404,您找的界面不存在!</h3>
</div>
</template>
<script>
export default {
name: "NotFound"
}
</script>
<style scoped>
</style>要点解释与易错点
- 路由级组件统一放在
src/pages(或src/views)下,和普通业务组件区分开,这是笔记中明确强调的目录习惯。 name属性与文件名保持一致,便于调试时在 Vue Devtools 中定位组件。- 每个组件模板必须是单根节点(外层
<div>),Vue 2 中多根节点会直接报编译错误。 <style scoped>加scoped是为了让样式只作用于当前组件,避免多个页面组件样式互相污染。- 组件里先只写占位标题即可,路由跑通后再填业务内容,符合转写稿中“先创建组件,再实现路由”的顺序。
示例二:路由配置文件 src/router/index.js(含 alias、redirect、404、history 模式、单页面多路由)
js
import Vue from "vue";
import VueRouter from "vue-router";
import Home from "@/pages/Home";
import NewsList from "@/pages/NewsList";
import GoodsList from "@/pages/GoodsList";
import MyHeader from "@/pages/MyHeader";
import MyMain from "@/pages/MyMain";
import YouFooter from "@/pages/YouFooter";
import My from "@/pages/My";
import NotFound from "@/pages/NotFound";
// 安装路由插件,必须在 new VueRouter 之前执行
Vue.use(VueRouter);
export default new VueRouter({
// 配置路由信息:routes 是数组,数组中的每个元素(对象)即是一条路由配置信息
routes: [
{
path: "/", // 指定路由地址
component: Home // 地址匹配时使用 Home 组件
}, {
// 支持的请求地址除 /newsList 以外,还支持 /news
path: "/newsList",
alias: "/news", // 为地址起别名
component: NewsList
}, {
path: "/goodsList",
// 可以设置为数组,起多个别名
alias: ["/first", "/daoLang", "/wangFei"],
component: GoodsList
}, {
path: "/my",
// 单页面多路由(了解)
components: {
one: MyHeader,
main: MyMain,
footer: YouFooter,
default: My
}
}, {
// 通配符,匹配不到任何已配置地址时走这里
path: "*",
component: NotFound
}, {
// redirect:当请求地址为 /home,被重定向至地址 /
path: "/home",
redirect: "/"
}
],
// 指定路由模式:默认为 hash
// 1- history 2- hash
mode: "history",
// 支持地址以 m 开头
// base: "m"
});要点解释与易错点
Vue.use(VueRouter)是固定写法,漏写会在new VueRouter时报 “not a constructor” 类错误。- 每个路由对象用
path指定地址、component指定组件,component是单数;只有单页面多路由才用components复数,写成复数却配单个组件是常见错误。 alias是“同一个组件多地址”,不是重定向:地址栏仍然显示/news;redirect是地址栏会变成目标地址,两者别混用。path: "*"必须写在数组末尾(Vue Router 3 按顺序匹配,写在前面会吃掉所有路由)。mode: "history"去掉 URL 中的#,但上线后需要服务端把 404 回退到 index.html,否则刷新子路径会 404;base用于给所有地址加统一前缀。- 转写稿中提到的一个坑:如果
devServer.proxy里配了/my之类的代理,代理优先级高于路由,会出现“路由配了但页面出不来”,需要换代理前缀。
示例三:入口 src/main.js + 根组件 src/App.vue(抽出 router 后的最终形态)
js
// src/main.js
import Vue from "vue";
import App from "@/App";
import router from "@/router";
new Vue({
render: h => h(App),
router
}).$mount("#app");vue
<!-- src/App.vue -->
<template>
<div>
<!-- 指定路由呈现的位置:为路由组件占位 -->
<!-- components -> one -> 组件 -->
<router-view name="one"></router-view>
<!-- components -> main -> 组件 -->
<router-view name="main"></router-view>
<!-- components -> footer -> 组件 -->
<router-view name="footer"></router-view>
<hr/>
<!-- 单页面多路由中,router-view 省略 name,会使用 components -> default -> 组件 -->
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "App.vue"
}
</script>
<style scoped>
</style>要点解释与易错点
router是router: router的 ES6 简写,new Vue({ router })把路由实例注入根实例,所有子组件才能用router-view。router-view是占位符:地址匹配到哪条路由,就在这个位置渲染对应组件;不写router-view页面永远是空白,这是新手最常见的“路由配好了却没反应”。router-view的name必须和路由配置里components的 key 严格对应,省略name就走default。- 笔记里 App.vue 重复写了 4 个无名
router-view,是为了演示“同一个组件会在每个无名占位处重复渲染”;实际项目只保留一个即可,多写会导致页面内容重复出现。 - 从笔记 15-3 到 15-5 的演进路径:路由配置先写在
main.js→ 抽成const router变量 → 再抽到src/router/index.js并export default,main.js只负责import router from "@/router",这样后续新增路由只改路由文件,main.js不用动。
常见错误
- 现象:改完
vue.config.js代理后仍跨域或请求未走代理→原因:devServer 未重启,代理配置未生效→修法:停止服务后重新npm run serve,并确认改的是devServer.proxy。 - 现象:请求仍跨域或代理不匹配→原因:Ajax 地址没有以代理键前缀开头→修法:统一改为
/api/...等前缀,在 Network 面板核对最终请求 URL。 - 现象:代理后最终地址多前缀/少前缀导致 404→原因:
pathRewrite与请求前缀不匹配,或changeOrigin未按目标服务要求设置→修法:先看 Network 最终 URL,再按前缀写pathRewrite,必要时设changeOrigin: true。 - 现象:
mode: "history"后直接刷新/newsList等子路由 404→原因:history 模式需要服务端回退到入口页→修法:开发环境配historyApiFallback,生产环境配 Nginxtry_files,或暂用 hash 模式。 - 现象:访问别名地址以为会跳转,结果 URL 不变或误判失败→原因:
alias只是同一组件的可访问地址,不是重定向→修法:需要 URL 改变用redirect;只需多地址访问用alias。 - 现象:
/my页面空白或只显示部分区域→原因:components的键与router-view的name不对应,或default没有无名router-view承接→修法:逐一核对name,保留一个无名router-view承接default。 - 现象:代理前缀与路由路径冲突,访问
/my被代理走→原因:devServer 代理前缀优先匹配,代理前缀覆盖了路由路径→修法:代理改用/api、/proxy等独立前缀,避免与路由前缀重合。 - 现象:
map中直接改item.checked后原数组数据也被改→原因:item是原数组对象的引用→修法:返回新对象或生成新数组后再替换/emit,不要直接改原对象属性。
练习
- 在
vue.config.js配置/api代理到猫眼热门接口,页面用 Axios 请求/api/mmdb/movie/v3/list/hot.json?...;验收:Network 中请求本机/api,响应有数据,无 CORS 报错。 - 将路由配置从
main.js抽离到src/router/index.js,main.js只引入 router;验收:/、/newsList、/goodsList、/my、任意错误地址均正常。 - 用
alias让/news与/newsList使用同一组件,用redirect让/home跳到/;验收:说明哪些地址 URL 会变、哪些不会变。 - 为
/my实现单页面多路由:one/main/footer/default四个命名视图;验收:四个区域分别渲染对应组件,删掉无名router-view后能解释default消失现象。 - 给商品列表加“选中”功能:用
map生成新数组修改指定 id 的选中状态;验收:原数组不被污染,视图更新,并说明直接改item.checked为什么会改原数据。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 自定义代理 | 14:45 |
| 2 | 代理配置mp4 | 1:06:02 |
| 3 | 引用 | 10:41 |
| 4 | 实现路由一mp4 | 38:48 |
| 5 | 实现路由二三 | 11:18 |
小结
- 路由配置先跑通再抽离,抽离后要保证
export default与import router from "@/router"一致。 history模式不是前端单独能完全解决的,必须考虑服务端回退配置。alias解决“多地址访问同一组件”,redirect解决“地址跳转”,两者不要混用。- 单页面多路由的核心是
components键与router-view name一一对应,default必须有无名视图承接。 - 代理配置修改后必须重启 devServer;调试代理先看 Network 最终请求 URL,再看响应。
pathRewrite决定最终转发地址,changeOrigin只影响目标服务看到的来源,不要指望它替代 CORS 处理。- 代理前缀应避开路由前缀,否则代理会优先拦截页面路由请求。
- 修改数组内对象属性会污染原数据;需要可追踪更新时,优先生成新对象/新数组再替换。