阅读目录javascript
一:vue-router是什么?html
四:理解vue设置路由导航的两种方法。html5
五:理解动态路由和命名视图java
六:理解嵌套路由node
七:在nginx上部署vue项目(history模式)webpack
八:vue-router 之 keep-alivenginx
一. vue-router是什么?git
vue-router是vue.js官方的路由插件,它和vue.js是集成的。它用于构建单页面应用,vue的单页面应用是基于路由和组件的,路由是用于设定访问路径的,而且路径和组件会产生映射起来。在vue-router单页面应用中,路径之间的切换,能够理解为组件的切换,路由模块的本质:是创建起url和页面之间的映射关系。
二:vue-router的实现原理
vue-router是用于构建单页面的,单页面的核心是更新视图而不会从新请求页面,这也就是为何在页面中不用a标签的缘由,由于页面只有一个index.html。那么它在实现单页面前端路由时,提供了两种模式,hash模式和History模式。默认状况下是使用hash模式。
2.1 hash模式
hash是URL的锚点(#), 表明网页中的一个位置,若是只改变#后的部分,浏览器会滚动到相应的位置,而不会从新加载网页,而且每次改变#后的部分,都会在浏览器的访问历史中增长一条记录,当咱们使用后退按钮的时候,就能够返回到上一个位置。所以hash模式经过锚点值的改变,根据不一样的值,渲染指定DOM位置的不一样数据。
2.2 history模式
上面是经过hash模式的,页面的地址就会加上 # 号,好比咱们的地址相似这样的:http://localhost:8080/#/,咱们使用history的话,那么访问页面的时候就和日常同样,不带井号的;以下地址也能够访问 http://localhost:8080/ ,使用路由history模式的话,只须要在配置路由规则时,加入 'mode': 'history'便可,它是利用html5中的 history.pushState的API来完成的URL跳转,无需从新加载页面的。
不过这种配置须要后台开发支持一下的,具体怎么配置,下面会详细讲到。
三:vue-router使用及代码配置
在vue-router中,定义了两个标签<router-link>和<router-view>来对应点击和显示,<router-link>是点击的部分,<router-view>是定义显示的部分,当咱们点击以后,路由匹配组件的内容后会在<router-view>显示出来,<router-link>还须要一个属性 to, 它的含义就是到哪里去的意思。
好比 <router-link to="/home">111</router-link> 的含义是当咱们点击111的时候,它会找到home相对应的组件,而后会在 <router-view>中显示出来。
理解配置路由
路由通常使用两个部分组成,path和component,path指路径,component指的是组件,它是一个对象,好比 { path: '/home', component: home }
好比咱们这边定义两条路由,以下代码:
const routes = [ { path: '/home', component: Home }, { path: '/xxx', component: XXX } ];
2. 建立router管理
建立router对路由进行管理,它是由构造函数 new vueRouter()建立,接收上面的routes参数。以下代码:
const router = new vueRouter({ routes: routes });
3. 实列注入到vue根实列中
咱们接着把上面router实列注入待vue根实列中,咱们就可使用路由了。以下代码:
new Vue({ el: '#app', router: router, render: h => h(Index) });
在配置代码以前,咱们仍是看看咱们的项目整个目录结构以下:(基于第十三篇文章的基础之上再进行构建的)。
### 目录结构以下: demo1 # 工程名 | |--- dist # 打包后生成的目录文件 | |--- node_modules # 全部的依赖包 | |--- app | | |---index | | | |-- views # 存放全部vue页面文件 | | | |-- components # 存放vue公用的组件 | | | |-- app.js # vue入口配置文件 | | | |-- router.js # 路由配置文件 | |--- views | | |-- index.html # html文件 | |--- webpack.config.js # webpack配置文件 | |--- .gitignore | |--- README.md | |--- package.json | |--- .babelrc # babel转码文件
在app/index/views 新建home.vue 和 xxx.vue 文件。
1. home.vue 代码以下:
<style lang='stylus'> .home-container width 100% </style> <template> <div class="home-container"> <h1>欢迎来到Home</h1> <p>{{msg}}</p> </div> </template> <script type="text/javascript"> export default { data() { return { msg: '我是Home组件' } } } </script>
xxx.vue 代码以下:
<style lang='stylus'> .xxx-container width 100% </style> <template> <div class="xxx-container"> <h1>欢迎来到xxx</h1> <p>{{msg}}</p> </div> </template> <script type="text/javascript"> export default { data() { return { msg: '我是XXX组件' } } } </script>
2. 接着在 app/index/views 新建index.vue, 代码以下:
<style lang="stylus"> </style> <template> <div id="app"> <header> <router-link to='/home'>Home</router-link> <router-link to='/xxx'>XXX</router-link> </header> <!-- 对应组件的内容渲染到router-view中 --> <router-view></router-view> </div> </template> <script type="text/javascript"> export default { data() { return { } } } </script>
3. 在 app/index/router.js定义router,路径到组件的映射。 添加以下代码:
import Vue from 'vue'; import VueRouter from 'vue-router'; // 引入组件 import home from './views/home'; import xxx from './views/xxx'; // 告诉 vue 使用 vueRouter Vue.use(VueRouter); const routes = [ { path: '/home', component: home }, { path: '/xxx', component: xxx }, { path: '*', // 其余没有的页面都重定向到 home页面去 redirect: '/home' } ] var router = new VueRouter({ routes: routes }); export default router;
固然上面引入组件的方法,咱们还能够懒加载的方式加载,懒加载引入的优势是:当咱们访问页面的时候才会去加载相关的资源,这样的话,能提升页面的访问速度。
好比以下这样:component: resolve => require(['@/views/HelloWorld'], resolve) // 使用懒加载
所以咱们能够把上面的代码写成以下:
import Vue from 'vue'; import VueRouter from 'vue-router'; /* // 引入组件 import home from './views/home'; import xxx from './views/xxx'; */ // 告诉 vue 使用 vueRouter Vue.use(VueRouter); const routes = [ { path: '/home', component: resolve => require(['./views/home'], resolve) // 使用懒加载 }, { path: '/xxx', component: resolve => require(['./views/xxx'], resolve) // 使用懒加载 }, { path: '*', // 其余没有的页面都重定向到 home页面去 redirect: '/home' } ] var router = new VueRouter({ base: '/app/index', // 配置单页应用的基路径 routes: routes }); export default router;
如上base的含义:应用的基路径,好比整个单页应用服务在 /app/index 下,那么base就应该设置为 /app/index.
4. 实列注入到vue根实列中。
把路由注入到根实列中,启动路由,咱们在app/index/app.js 入口文件添加以下代码:
import Vue from 'vue'; import Index from './views/index'; // 引入路由 import router from './router'; new Vue({ el: '#app', router: router, render: h => h(Index) });
所以要运行上面代码以前,咱们先要 下载 vue-router 到咱们项目中来,以下代码命令:
npm i vue-router --save
下载完成后,咱们再来运行打包命令,npm run dev 后,就能够启动页面了。
在页面访问以下
四:理解vue设置路由导航的两种方法。
vue设置路由导航的两种方法有 <router-link :to=''> 和 router.push().
4.1 to的值能够是一个字符串路径,或者一个描述地址的对象。好比以下都是能够的。
// 字符串 <router-link to='/home'>Home</router-link> // 对象 <router-link :to="{path: '/home'}">Home</router-link> // 命名路由 <router-link :to="{name: 'home'}">Home</router-link> /* 若是是命名路由的话,须要在router.js 加上name字段,以下代码: const routes = [ { path: '/home', name: 'home', component: resolve => require(['./views/home'], resolve) // 使用懒加载 }, { path: '/xxx', name: 'xxx', component: resolve => require(['./views/xxx'], resolve) // 使用懒加载 }, { path: '*', // 其余没有的页面都重定向到 home页面去 redirect: '/home' } ] */ // 直接路由带查询参数query,地址栏就变成 /home?id=1 <router-link :to="{path: 'home', query: {id: 1 }}">Home</router-link> // 若是是path的话,路由带参数params的话,params是不会生效的。以下代码 params的参数是不会在地址栏中显示的。 <router-link :to="{path: 'home', params: {id: 1 }}">Home</router-link> // 命名路由带路由参数params,地址栏仍是 /home, 可是能够经过 this.$route.params.id拿到值的 <router-link :to="{name: 'home', params: {id: 1 }}">Home</router-link>
4.2 router.push()方法
// 支持字符串 this.$router.push('xxx'); // 支持对象 this.$router.push({ path: 'xxx' }); // 支持命名路由方式 this.$router.push({ name: 'xxx' }); // 直接路由带查询参数 query, 地址栏变成 /xxx?id=1 this.$router.push({ path: 'xxx', query: { id: 1 } }); // 命名路由带查询参数query,地址栏变成 /xxx?id=1 this.$router.push({ name: 'xxx', query: { id: 1 } }); // 若是提供了path,直接路由带参数params, params不会生效,在xxx页面经过 // console.log(this.$route.params.id) 是获取不到值的。 this.$router.push({ path: 'xxx', params: { id: 1 } }); // 命名路由带路由参数params,地址栏是/xxx。在xxx页面经过 console.log(this.$route.params.id) 是能够获取到值的。 this.$router.push({ name: 'xxx', params: { id: 1 } });
总结:1. 不管是直接路由path仍是命名路由name,带查询参数query,地址栏会变成 /url?查询参数名=查询参数值
2. 直接路由path带路由参数params,params不生效。在xxx页面经过 console.log(this.$route.params.id) 是获取不到值的。
3. 命名路由name带路由参数params地址栏保持是 /url/路由参数值。在xxx页面经过 console.log(this.$route.params.id) 是能够获取到值的。
五:理解动态路由和命名视图
5.1 动态路由
动态路由也能够叫作路由传参。
在前面咱们介绍了路由导航功能是不能传递参数的,咱们能够叫他们静态路由,而能传递参数的路由模式,而且对应的路由数量是不肯定的,所以咱们能够叫他动态路由。
应用场景:当咱们的多个页面或组件都要被屡次重复利用的时候,咱们的路由都指向同一个组件,这时候从不一样的地方进入相同的组件的时候,咱们根据传递的参数不一样,来渲染不一样的数据。
好比以下代码:
const routes = [ { path: '/xxx/:id', // 动态路由信息 name: 'xxx', component: resolve => require(['./views/xxx'], resolve) // 使用懒加载 } ];
如上代码 path: /xxx/:id, 这种形式,这样定义以后,vue-router将会匹配全部的 /xxx/1, /xxx/2,.....
好比我如今有多个页面须要进入xxx组件内,这时候咱们能够在配置路由路径后加个:id。index.vue 改为以下代码:
<template> <div id="app"> <header> <router-link to="home">Home</router-link> <router-link to='xxx/on'>XXX</router-link> </header> <!-- 对应组件的内容渲染到router-view中 --> <router-view></router-view> </div> </template>
当我点击 XXX 时候,会进入xxx组件内,那么在xxx.vue组件内,能够经过 this.$route.params.id 获取传的参数值了。
以下图所示:
5.2 理解命名视图
有时候咱们想同时显示多个视图,好比一个单页应用页面,有侧导航(sidebar) 和 头部(header) 和 main(主内容)等三个视图,这个时候命名视图就派上用场了。
咱们能够在页面中拥有多个单独命名的视图,而不是和咱们上面同样只有一个单独的视图。若是 router-view 没有设置名字,那么默认为default。
如今咱们能够在 app/index/components 新建文件夹为sidebar, header, main, 及在各对应的目录下新建index.vue.
如今咱们的项目的目录结构变成以下了:
### 目录结构以下: demo1 # 工程名 | |--- dist # 打包后生成的目录文件 | |--- node_modules # 全部的依赖包 | |--- app | | |---index | | | |-- views # 存放全部vue页面文件 | | | | |-- home.vue | | | | |-- index.vue | | | | |-- xxx.vue | | | |-- components # 存放vue公用的组件 | | | | |--- header | | | | | |-- index.vue # 公用的头部组件 | | | | |--- main | | | | | |-- index.vue # 主体组件 | | | | |--- sidebar | | | | | |-- index.vue # 侧导航公用的组件 | | | | | | | | |-- app.js # vue入口配置文件 | | | |-- router.js # 路由配置文件 | |--- views | | |-- index.html # html文件 | |--- webpack.config.js # webpack配置文件 | |--- .gitignore | |--- README.md | |--- package.json | |--- .babelrc # babel转码文件
app/index/components/header/index.vue 代码以下:
<style lang="stylus"> * {margin: 0; padding: 0} .header-container width 100% height 50px background #000 div font-size 16px color #fff text-align center </style> <template> <div class="header-container"> <div>个人头部导航</div> </div> </template> <script type="text/javascript"> export default { data() { return { } } } </script>
app/index/components/sidebar/index.vue 代码以下:
<style lang="stylus"> .sidebar-container width 200px height 100% min-height 500px background red float left div font-size 12px color #fff text-align center </style> <template> <div class="sidebar-container"> <div>个人左侧导航</div> </div> </template> <script type="text/javascript"> export default { data() { return { } } } </script>
app/index/components/main/index.vue 代码以下:
<style lang="stylus"> .main-container margin-left 200px height 100% min-height 500px background green div font-size 12px color #fff text-align center </style> <template> <div class="main-container"> <div>个人主体部分</div> </div> </template> <script type="text/javascript"> export default { data() { return { } } } </script>
框架搭建完成后,咱们须要在index.vue 代码变成以下:
<style lang="stylus"> </style> <template> <div id="app"> <!-- <header> <router-link to="/home">Home</router-link> <router-link to='/xxx/on'>XXX</router-link> </header> --> <router-view name="Header"></router-view> <router-view name="Sidebar"></router-view> <router-view name="Main"></router-view> <!-- 对应组件的内容渲染到router-view中 --> <router-view></router-view> </div> </template> <script type="text/javascript"> export default { data() { return { } } } </script>
接着咱们须要在router.js下配置代码以下:
import Vue from 'vue'; import VueRouter from 'vue-router'; // 引入组件 import home from './views/home'; import xxx from './views/xxx'; // 告诉 vue 使用 vueRouter Vue.use(VueRouter); const routes = [ { path: '/home', name: 'home', components: { default: resolve => require(['./views/home'], resolve), // 使用懒加载 Header: resolve => require(['./components/header/index'], resolve), // 使用懒加载 Sidebar: resolve => require(['./components/sidebar/index'], resolve), // 使用懒加载 Main: resolve => require(['./components/main/index'], resolve) // 使用懒加载 } }, { path: '/xxx/:id', name: 'xxx', components: { default: resolve => require(['./views/xxx'], resolve), // 使用懒加载 Header: resolve => require(['./components/header/index'], resolve), // 使用懒加载 Sidebar: resolve => require(['./components/sidebar/index'], resolve), // 使用懒加载 Main: resolve => require(['./components/main/index'], resolve) // 使用懒加载 } }, { path: '*', // 其余没有的页面都重定向到 home页面去 redirect: '/home' } ] var router = new VueRouter({ base: '/app/index', // 配置单页应用的基路径 routes: routes }); export default router;
而后打包运行下,在浏览器上能够看到以下图所示的结构。
如上能够看到,咱们可使用 命名视图 来搭建咱们网站的框架,这能够理解命名视图的做用了。
六:理解嵌套路由
什么是嵌套路由?好比咱们进入到咱们home页面的时候,它下面还有分类,好比叫 java书籍,node书籍等,那么当我点击各个类目的时候,就对应到相应的组件。好比首先我进入的是 /home 这个路由,而后当我进入 /home下面的分类的 java书籍的话,那么咱们的路由就是 /home/java, 若是进入分类的是 node书籍的话,那么路由就是 /home/node 了。所以 vue提供了 childrens这个属性来作这件事,它也是一组路由。
首先咱们在 app/index/views 下 新建 java.vue 和 node.vue.
java.vue代码以下:
<style lang='stylus'> .java-container width 100% </style> <template> <div class="java-container"> <h1>欢迎来到java类书籍</h1> <p>{{msg}}</p> </div> </template> <script type="text/javascript"> export default { data() { return { msg: '我是java组件' } }, methods: { } } </script>
node.vue 代码以下:
<style lang='stylus'> .node-container width 100% </style> <template> <div class="node-container"> <h1>欢迎来到node类书籍</h1> <p>{{msg}}</p> </div> </template> <script type="text/javascript"> export default { data() { return { msg: '我是node组件' } }, methods: { } } </script>
app/index/router.js 代码就改为以下:
import Vue from 'vue'; import VueRouter from 'vue-router'; // 引入组件 import home from './views/home'; import xxx from './views/xxx'; // 告诉 vue 使用 vueRouter Vue.use(VueRouter); const routes = [ { path: '/home', name: 'home', component: resolve => require(['./views/home'], resolve), // 子路由 children: [ { path: 'java', component: resolve => require(['./views/java'], resolve) }, { path: 'node', component: resolve => require(['./views/node'], resolve) } ] }, { path: '/xxx/:id', name: 'xxx', component: resolve => require(['./views/xxx'], resolve) }, { path: '*', // 其余没有的页面都重定向到 home页面去 redirect: '/home' } ] var router = new VueRouter({ base: '/app/index', // 配置单页应用的基路径 routes: routes }); export default router;
app/index/views/index.vue 代码以下:
<style lang="stylus"> </style> <template> <div id="app"> <header> <router-link to="/home" tag='li'>Home</router-link> <router-link to="/home/java">java</router-link> <router-link to="/home/node">node</router-link> <router-link to='/xxx/on'>XXX</router-link> </header> <!-- <router-view name="Header"></router-view> <router-view name="Sidebar"></router-view> <router-view name="Main"></router-view> --> <!-- 对应组件的内容渲染到router-view中 --> <router-view></router-view> </div> </template> <script type="text/javascript"> export default { data() { return { } } } </script>
如上代码增长完成后,进行打包,编译都正常,可是点击java或node的时候,子路由一直没有渲染到对应的组件,网上不少资料说,子路由多写了 /, 可是我router.js里面也没有这些东西的,可是通过搜索,发现问题并非在这里,而是说在嵌套的子模块里面引用子路由的时候,也须要加上 <router-view></router-view> 这句代码,以下是home.vue 代码:
<template> <div class="home-container"> <h1>欢迎来到Home</h1> <p>{{msg}}</p> <p @click="func">进入index页面</p> <router-view></router-view> </div> </template>
注意:路由嵌套的真正的含义是:点击子路由的时候,父级组件仍是会显示的,子组件也会显示的,这才是使用子路由嵌套的用途。
若是仅仅想显示子组件的话,不想显示父组件的话,那就不要使用路由嵌套,直接使用兄弟路由,写死路径便可。
好比
const router = [ { path: '/home', name: 'home', component: resolve => require(['./views/home'], resolve), }, // 兄弟路由 { path: '/home/java', name: 'home', component: resolve => require(['./views/java'], resolve), } ]
github源码 webpack+vue+router