Vue全家桶--10 Vue-Router路由
Vue全家桶--10 Vue-Router路由
10.1 什么是路由
Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得非常简单。
通过根据不同的请求路径,切换显示不同组件进行渲染页面。
10.2 基本路由使用
10.2.1 安装路由
npm install vue-router
10.2.2 引入 vue-router.js
<script src="./node_modules/vue/dist/vue.js"></script> <script src="./node_modules/vue-router/dist/vue-router.js"></script>
10.2.3 HTML 路由切换
<div id="app"> <div class="header"> <h1>header</h1> </div> <div class="left"> <ul> <!-- 方式1:传统方式! --> <li><a href="#/foo">foo</a></li> <li><a href="#/bar">bar</a></li> <!-- 方式2:官方推荐! --> <!-- <router-link> 默认会被渲染成一个 `<a>` 标签, --> <!-- 通过传入 `to` 属性指定跳转链接,不用像上面加 `#` 号 --> <li><router-link to="/foo">Go to Foo</router-link></li> <li><router-link to="/bar">Go to Bar</router-link></li> </ul> </div> <div class="main"> <!-- 路由出口: 路由匹配到的组件将渲染在这里 --> <router-view></router-view> </div> </div>
10.2.4 JS 配置路由
<script src="./node_modules/vue/dist/vue.js"></script> <script src="./node_modules/vue-router/dist/vue-router.js"></script> <script> //1.定义组件 const Foo = { template:`<div>hello Foo</div>` }; const Bar ={ template:`<div>hello Bar</div>` } // 2. 配置路由表:当点击特定的 url 时,显示对应的那个组件。 const router = new VueRouter({ routes:[ //配置每个路由映射一个组件 {path:'/foo',component:Foo}, {path:'/bar',component:Bar} ] }); // 3. 注入路由到实例中 new Vue({ el:'#app', router //router:router }); </script>
10.3 路由案例实战
10.3.1 修改模板
安装路由/axios
npm install vue-router
npm install axios
10.3.2 News组件
**js函数自调用 ;(function(){})()
**windows 全局属性 window.News={} ,这样就可以全局调用组件,否则在该作用域内,外面无法调用到
;(function(){ // const template=`<!--右边主页面区域--> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <div class="header clearfix"> <nav> <ul class="nav nav-pills"> <li class="active"><a href="#">体育</a></li> <li ><a href="#">科技</a></li> </ul> </nav> <hr> </div> <!--体育栏目--> <div> <ul> <li> <a href="#">世界杯开赛啦</a> </li> <li> <a href="#">NBA开赛倒计时</a> </li> </ul> <!--详情--> <div class="jumbotron"> <h2>世界杯开赛啦</h2> <p>世界杯于明晚8点举行开幕式.....</p> </div> </div> <!--科技栏目--> <div> <ul > <li> <span>5G时代到来了 </span> <button class="btn btn-default btn-xs">查看(Push)</button> <button class="btn btn-default btn-xs">查看(replace)</button> </li> <li> <span>互联网大洗牌</span> <button class="btn btn-default btn-xs">查看(Push)</button> <button class="btn btn-default btn-xs">查看(replace)</button> </li> </ul> <!--详情--> <div class="jumbotron"> <h2>世界杯开赛啦</h2> <p>世界杯于明晚8点举行开幕式.....</p> </div> </div> </div>`; window.News={ template } })()
10.3.3 About组件
; (function () { const template = `<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <h1>梦学谷-陪你学习,伴你梦想!</h1> <input /> </div>`; window.About={ template } })()
10.3.4 配置路由
新建router.js文件
; (function () { window.router = new VueRouter({ linkActiveClass: 'active', routes: [ { path: '/', component: AppHome }, { path: '/news', component: News }, { path: '/about', component: About } ] }) })()
10.3.5 注入路由到实例中
在 main.js 中的 Vue 实例中引入 router
var vm = new Vue({ el: '#app', // Vue实例中的template选项中引用了组件后,会将这个组件的渲染结果替换掉 #app 标签的元素 // template: '<app> </app>', template:'<app></app>', router, // 引用路由配置 components:{ App, } });
10.3.6 配置路由渲染组件出口
在 App.js 中配置
; (function () { // 组件模板中,必须包含有且只有一个根元素 const template = ` <div> <!--头部导航区域--> <app-navbar></app-navbar> <!--核心区域:分左右两边--> <div class="container-fluid"> <div class="row"> <!--左边菜单栏区域--> <app-left></app-left> <!--右边主页面区域: 分上下两个区域 <app-home> <h1 slot="dashboard" class="page-header">{{title}}</h1> </app-home> --> <!-- 配置路由渲染组件出口,也就是右边主页面区域 --> <router-view> <h1 slot="dashboard" class="page-header">{{title}}</h1> </router-view> </div> </div> </div> `; window.App = { template, components: { AppNavbar, AppLeft, AppHome }, data() { return { title: '仪表盘', }; }, } })()
10.3.7 修改跳转链接
在 AppLeft.js 中修改跳转链接
; (function () { window.AppLeaf = { template: `<div class="col-sm-3 col-md-2 sidebar"> <ul class="nav nav-sidebar"> <li class="active"> <router-link to="/">首页</router-link> </li> <li> <router-link to="/news">新闻管理</router-link> </li> <li> <router-link to="/about">关于我们</router-link> </li> </ul> </div>` } })()
10.3.8 引入js文件
注意先后顺序
<script src="../node_modules/vue/dist/vue.js"></script>
<!-- vue-router.js要引入在 vue.js 下方--->
<script src="../node_modules/vue-router/dist/vue-router.js"></script> <script src="../node_modules/axios/dist/axios.js"></script> <script src="./components/AppNavbar.js"></script> <script src="./components/AppLeft.js"></script> <script src="./components/Home/DashBoard.js"></script> <script src="./components/Item.js"></script> <script src="./components/Home/HomeList.js"></script> <script src="./components/Home/AppHome.js"></script> <script src="./components/Home/News.js"></script> <script src="./components/Home/About.js"></script> <script src="./router.js"></script> <script src="./App.js"></script> <script src="./main.js"></script>
10.3.9 启动测试
http://127.0.0.1:5500/vue-08-router/02-bootstrap-ajax-router/index.html#/
10.4 样式匹配--高亮显示导航
10.4.1 tag
<router-link> 默认渲染后生成 <a> 标签。
可在 <router-link> 上使用 tag 属性,指定渲染后生成其他标签。
10.4.2 active-class
<router-link> 渲染后生成标签上默认有 CSS 类名: router-link-active 。
可在 <router-link> 上使用 active-class 属性,指定渲染后生成其他类名。
可以通过路由的构造选项 linkActiveClass 来全局配置,不用在每个<router-link> 使用 active-class 指定生成
的类名
10.4.3 exact
默认情况 下,路由地址 / 、/foo 、/bar 都以 / 开头,它们都会去匹配 / 地址的 CSS 类名。
可在 <router-link> 上使用 exact 属性开启 CSS 类名精确匹配。
<!-- 这个链接只会在地址为 / 的时候被激活, --> <router-link to="/" exact>
10.4.4 实现高亮显示导航链接
AppLeft.js
;(function(){ const template=`<div class="col-sm-3 col-md-2 sidebar"> <ul class="nav nav-sidebar"> <!-- router-link 默认渲染出来的是 a 标签, 如果需要让它渲染出来的 是别的标签,则可以使用 tag 属性指定渲染后的标签 2. 可以在每个 router-link 上使用 active-class 来激活 CSS 类名 或者在 VueRouter 实例中,使用 linkActiveClass 全局配置 CSS 类名 3. exact 是精确匹配, 指定在哪个标签上,则这个标签的路径就不会被其他路径模糊匹配 --> <router-link to="/" tag="li" exact><a>首页</a></router-link> <router-link to="/news" tag="li"><a>新闻管理</a></router-link> <router-link to="/about" tag="li"><a>关于我们</a></router-link> </ul> </div>`; window.AppLeft={ template } })()
router.js
; (function () { window.router = new VueRouter({ // 全局配置 router-link 标签生成的 CSS 类名 linkActiveClass: 'active', routes: [ { path: '/', component: AppHome }, { path: '/news', component: News }, { path: '/about', component: About } ] }) })()
10.5 嵌套路由
10.5.1 子路由组件
10.5.2 配置嵌套路由
{ path: '/news', component: News, children: [ // 当匹配到 /news/sport 请求时, // 组件 Sport 会被渲染在 News 组件中的 <router-view> 中 { path: '/news/sport', component: Sport }, // 简写方式,等价于 /news/tech 路径,注意前面没有 / ,有 / 就是根目录了 { path: 'tech', component: Tech }, //点击新闻管理默认选中 新闻, // 就是/news后面没有子路径时, redirect 重定向到 体育 { path: '', redirect: '/news/sport' } ] },
10.5.3 路由跳转链接
<ul class="nav nav-pills"> <router-link to="/news/sport" tag="li"> <a >体育</a> </router-link> <router-link to="/news/tech" tag="li"> <a >科技</a> </router-link> </ul> <!--定义路由出口--> <router-view></router-view>
10.6 嵌套路由案例--新闻管理
10.6.1 封装路由需要的组件 New组件中的Sport和Tech
Sport.js
; (function () { // const template = ` <div> <ul> <li v-for="(sport,index) in sportArr" :key="sport.id"> <a href="#" >{{ sport.title }}</a> </li> </ul> <!--详情--> <div class="jumbotron"> <h2>世界杯开赛啦</h2> <p>世界杯于明晚8点举行开幕式.....</p> </div> </div> `; window.Sport = { template, data() { return { sportArr: [], }; }, created() { this.getSportArr(); }, methods:{ getSportArr(){ axios.get('http://127.0.0.1:5500/vue-08-router/02-bootstrap-ajax-router/db/sport.json').then(response => { console.log(response.data) // 得到返回结果数据 this.sportArr = response.data }).catch(error => { console.log(error.message) }) } } } })()
Tech.js
; (function () { // const template = ` <div> <ul > <li v-for="(tech, index) in techArr" :key="tech.id"> <span> {{tech.title}} </span> <button class="btn btn-default btn-xs">查看(Push)</button> <button class="btn btn-default btn-xs">查看(replace)</button> </li> </ul> <!--详情--> <div class="jumbotron"> <h2>世界杯开赛啦</h2> <p>世界杯于明晚8点举行开幕式.....</p> </div> </div> `; window.Tech = { template, data() { return { techArr: [], }; }, created() { this.getTechArr(); }, methods: { getTechArr() { axios.get('http://127.0.0.1:5500/vue-08-router/02-bootstrap-ajax-router/db/tech.json').then(response => { console.log(response.data) // 得到返回结果数据 this.techArr = response.data }).catch(error => { console.log(error.message) }) } } } })()
10.6.2 配置嵌套路由
; (function () { window.router = new VueRouter({ // 全局配置 router-link 标签生成的 CSS 类名 linkActiveClass: 'active', routes: [ { path: '/', component: AppHome }, { path: '/news', component: News, children: [ { path: '/news/sport', component: Sport }, { // 简写方式,等价于 /news/tech 路径,注意前面没有 / ,有 / 就是根目录了 path: 'tech', component: Tech }, { //点击新闻管理默认选中 新闻, //就是/news后面没有子路径时, redirect 重定向到 体育 path: '', redirect: '/news/sport' } ] }, { path: '/about', component: About } ] }) })()
10.6.3 跳转链接和路由渲染出口
;(function(){ // const template=`<!--右边主页面区域--> <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <div class="header clearfix"> <nav> <ul class="nav nav-pills"> <router-link to="/news/sport" tag="li" exact><a>体育</a></router-link> <router-link to="/news/tech" tag="li" exact><a>科技</a></router-link> </ul> </nav> <hr> </div> <!--定义路由出口--> <router-view></router-view> </div>`; window.News={ template } })()
10.6.4 引入JS
<script src="./components/Home/Sport.js"></script> <script src="./components/Home/Tech.js"></script>
10.7 缓存路由组件与案例
10.7.1 场景与作用
1. 默认情况下,当路由组件被切换后组件实例会销毁,当切换回来时实例会重新创建。
2. 如果可以缓存路由组件实例,切换后不用重新加载数据,可以提高用户体验。
10.7.2 实现缓存路由组件
<keep-alive> 可缓存渲染的路由组件实例
<keep-alive> <router-view></router-view> </keep-alive>
10.7.3 demo
上诉的demo中在App.js中添加缓存路由组件
<!-- 配置路由渲染组件出口,也就是右边主页面区域 --> <keep-alive> <router-view> <h1 slot="dashboard" class="page-header">{{title}}</h1> </router-view> </keep-alive>
10.8 路由组件传递数据
10.8.1 路由传递数据步骤
(1)路由配置
{ path: '/news/sport', component: Sport, children: [ { path: '/news/sport/detail/:id', // :id 路径变量占位符 component: SportDetail } ] }
(2)路由跳转路径
<!-- 要动态拼接值, 则 to 属性值是 JS 表达式, 要写 JS 表达式, 则要使用 v-bind 方式绑定属性 注意 + 前面有单引号 '' --> <router-link :to="'/news/sport/detail/' + sport.id"> {{sport.title}} </router-link>
(3)在路由组件中读取请求参数
this.$route.params.id
10.8.2 DEMO
配置路由
; (function () { window.router = new VueRouter({ // 全局配置 router-link 标签生成的 CSS 类名 linkActiveClass: 'active', routes: [ { path: '/', component: AppHome }, { path: '/news', component: News, children: [ { path: '/news/sport', component: Sport, children: [ // :id 路径变量占位符 { path: '/news/sport/detail/:id', component: SportDetail } ] }, { // 简写方式,等价于 /news/tech 路径,注意前面没有 / ,有 / 就是根目录了 path: 'tech', component: Tech, children:[ {path: '/news/tech/detail/:id', component: TechDetail } ] }, { //点击新闻管理默认选中 新闻, //就是/news后面没有子路径时, redirect 重定向到 体育 path: '', redirect: '/news/sport' } ] }, { path: '/about', component: About } ] }) })()
组件指定路径和渲染出口
; (function () { // const template = ` <div> <ul> <li v-for="(sport,index) in sportArr" :key="sport.id"> <router-link :to="'/news/sport/detail/'+ sport.id" > {{sport.title}} </router-link> </li> </ul> <!--详情--> <!--定义路由出口--> <router-view></router-view> </div> `; window.Sport = { template, data() { return { sportArr: [], }; }, created() { this.getSportArr(); }, methods:{ getSportArr(){ axios.get('http://127.0.0.1:5500/vue-08-router/02-bootstrap-ajax-router/db/sport.json').then(response => { console.log(response.data) // 得到返回结果数据 this.sportArr = response.data }).catch(error => { console.log(error.message) }) } } } })()
详情组件
; (function () { const template = ` <div class="jumbotron"> <h2>{{ sportDetail.title }}</h2> <p>{{ sportDetail.content }}</p> </div> `; window.SportDetail = { template, data() { return { id: null, sportDetail: {} }; }, created() { // 注意: // 1. 是 $route , 最后没有 r 字母 // 2. created 钩子只会调用1次,当切换标题列表的路由时,此钩子不会再次调用, // 所以对应 ID 不会被更新, 可以使用 watch 监听 $route 路由的变化。 this.getItemById(); }, methods: { getItemById() { //将路由路径的变量赋值给本地变量 this.id = this.$route.params.id - 0; var sportItem = []; axios.get('http://127.0.0.1:5500/vue-08-router/02-bootstrap-ajax-router/db/sport.json').then(response => { //console.log(response.data) // 得到返回结果数据 sportItem = response.data; this.sportDetail = sportItem.find(arr => { return arr.id == this.id; }) console.log(this.sportDetail); }).catch(error => { console.log(error.message); }) } }, watch: { // watch 是对象,用于监听属性使用 // 使用 watch 监听 $route 路由的变化,获取 ID 值 '$route': function () { //console.log('$route'); if ((this.$route.params.id - 0) > 0) { //判断是否是详情页路由 this.getItemById() } } } } })()
10.9 编程式路由导航
10.9.1 声明式与编程式路由
**声明式( 直接通过 <a> 标签href指定链接跳转)
<router-link :to="...">
**编程式(采用 js 代码链接跳转,如 localhost.href)
router.push(...)
10.9.2 编程式路由导航 API
this.$router.push(path) 相当于点击路由链接(后退1步,会返回当前路由界面) this.$router.replace(path) 用新路由替换当前路由(后退1步,不可返回到当前路由界面) this.$router.back() 后退回上一个记录路由 this.$router.go(n) 参数 n 指定步数 this.$router.go(-1) 后退回上一个记录路由 this.$router.go(1) 向前进下一个记录路由