好文章备忘录:

转自:https://segmentfault.com/a/1190000009160934?_ea=1849098


demo源码:https://github.com/1590123375...

demo未安装依赖,下载完成,npm install后再npm run dev运行。

利用vue-cli配合vue-router搭建一个完整的spa流程(一)

前言
Ⅰ. demo所用vue-router的一些基本操作。vue-router中文文档,快速浏览一遍即可 http://router.vuejs.org/zh-cn/
Ⅱ. 整个demo所用到的技术栈 vueJS(2.0) vue-cli vue-resource es6
Ⅲ. 所需构建工具 nodeJS Git

第一步:安装

OK,正题开始,首先保证nodeJS,Git,webpack已安装完毕。打开项目文件夹,安装vue-cli。


全局安装 vue-cli
$ npm install --global vue-cli

创建一个基于webpack的模板
vue init webpack my-project
创建过程中,vue-router为必须,其他语法检测,单元测试等按需求安装。

创建完成后进入项目文件夹,安装依赖
$ npm install

安装到此结束,运行如下代码,显示为图片所示,则安装成功。
$ npm run dev


第二步:项目文件及运行流程

Ⅰ: 项目文件

打开已经创建好的模板

如图所示,只会用到,src,static,index.html这三个文件。首先解释一下三个文件的作用:
Ⅰ: src 存放路由JS,模板.vue文件,入口JS,以及一个入口.vue文件
Ⅱ: static 存放静态文件
Ⅲ: index 入口html文件

这里解释一下xxx.vue文件是什么,官网叫其为单文件组件,通过webpack源码转换,会全部转换为对应的文件。
说白了就是一个包裹,里边含有三部分 一部分模板template,一部分样式style,一部分JSjavascript,他们封装在一起。
如下图所示:

Ⅱ: 运行流程

写起来比较麻烦,做了一张图,直截了当。

第三步:搭建基本路由框架

项目文件明了之后,我们开始搭建一个简单的SPA路由构架:
Ⅰ: 页面中有俩个及俩个以上的分类
Ⅱ: 每个分类中可以点击进入到详情页面
Ⅲ: URL输入错误后展示404页面
Ⅳ: 在页面中刷新,根据URL重新获取数据,渲染页面

根据基础框架创建对应的文件。

文件详解:
Ⅰ: src中components文件夹里新建三个xxx.vue文件,
①error.vue 此为404页面
②showone.vue 此为第一个分类页面
③showtwo.vue 此为第二个分类页面

Ⅱ: src中zjapp.vue这是路由入口文件

Ⅲ: static中img为详情页面大图,thumbnail为分类页面缩略图

Ⅳ: 俩个JSON文件,分别代表分类一和分类二的数据来源

Ⅴ: bootstrap.css 样式CSS

到此路由的基本框架搭建完成,后面开始代码的填充。

第四步:主页面代码编写

Ⅰ: index.html

作为页面入口文件,先引入Bootstrap.CSS,如果是本地文件放在static文件夹里。可以使用CDN或者npm安装。
为了方便后面阅读将id="app"更改为id="index"。当然,也可以不更改,main.js中有多个为app的名字,避免混淆。

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>spa-vue-demo</title>
  6. <link rel="stylesheet" href="static/bootstrap.min.css" />
  7. </head>
  8. <body>
  9. <div id="index"></div>
  10. <!-- built files will be auto injected -->
  11. </body>
  12. </html>

Ⅱ: main.js

main.js为入口JS文件,Vue的实例在这里书写。el 挂载在 index.html 中 id="index" 的标签上。

  1. import Vue from 'vue'
  2. import App from './zjapp'
  3. import router from './router'
  4. Vue.config.productionTip = false
  5. new Vue({
  6. el: '#index',
  7. router,
  8. template: '<App/>',
  9. components: { App }
  10. })

Vue 开始渲染时,加载 components: { App } 组件替换生成在 id="index" 内的 <App></App> 标签,那么{ App }来自哪里呢?

答案在 import App from './zjapp' 这里是ES6语法,引入zjapp.vue模块中暴露出来的接口,后缀可以不写。

Vue 实例中的 router 属性也是ES6中对象的字面量写法,等于router:router。同理 import router from './router' 这里引入router。

因为,router中index.js暴露接口时没有署名,这里也可以改一个名字,比如:

  1. import Vue from 'vue'
  2. import App from './zjapp'
  3. //修改名字一样可以。
  4. import changeES6 from './router'
  5. Vue.config.productionTip = false
  6. new Vue({
  7. el: '#index',
  8. //修改在这里
  9. router:changeES6,
  10. template: '<App/>',
  11. components: { App }
  12. })

最后,可能有人会问 Vue.config.productionTip = false 是做什么用的,其实这里是关闭了生产模式即部署到服务器后给出的提示。

Ⅲ: zjapp.vue

这个文件是 Vue 一开始渲染组件时的文件,首先贴出全部代码,很多,但是会全部讲解作用,含义。

  1. <template>
  2. <div class="container">
  3. <div class="row">
  4. <div id="index" class="col-xs-12 col-lg-12 col-md-12" style="padding: 0;">
  5. <transition name='animate' appear mode='out-in'>
  6. <router-view v-bind:router-data="allData" v-bind:key="change"></router-view>
  7. </transition>
  8. <transition name='btn' appear mode='out-in'>
  9. <div class="app-btn" v-show="allData.mainShow">
  10. <button class="btn btn-success app-btn-back" v-show="back==0?false:true" v-bind:key="back" v-on:click="dosom('back')">上一页</button>
  11. <button class="btn btn-success app-btn-next" v-show="next==0?false:true" v-bind:key="next" v-on:click="dosom('next')">下一页</button>
  12. </div>
  13. </transition>
  14. <div class="app-loading" v-show="loading">
  15. <img src="../static/loading/loading.gif" style="margin:0 auto;display: block;" alt="loading" />
  16. </div>
  17. </div>
  18. </div>
  19. </div>
  20. </template>
  21. <script>
  22. import router from './router'
  23. export default{
  24. data(){
  25. return{
  26. allData:{
  27. showData:null,
  28. detailedData:{},
  29. num:0,
  30. mainShow:true
  31. },
  32. loading:false,
  33. change:true,
  34. back:0,
  35. next:1,
  36. }
  37. },
  38. created(){
  39. this.routePath();
  40. },
  41. watch:{
  42. "$route"(to){
  43. this.routePath();
  44. }
  45. },
  46. methods:{
  47. buttonToggle(){
  48. var nowNum=this.allData.num;
  49. this.back=nowNum;
  50. this.next=2-nowNum;
  51. },
  52. dosom(str){
  53. str=="next"?this.allData.num++:this.allData.num--;
  54. this.buttonToggle();
  55. //当前user/当前页面/当前页面路由
  56. router.push(this.$route.path.slice(0,8)+this.allData.num);
  57. },
  58. routePath(){
  59. if(this.$route.fullPath=="/"){
  60. router.push("/user/0/0");
  61. this.load();
  62. }
  63. else if(this.$route.fullPath.length==9 || this.$route.fullPath.length==20){
  64. this.load();
  65. }
  66. else{
  67. router.push("/user/error");
  68. this.back=0;
  69. this.next=0;
  70. }
  71. },
  72. load(){
  73. var numData=null,
  74. listData=null;
  75. // /user/lisData/numData
  76. numData=this.$route.path.slice(8,9);
  77. listData=this.$route.path.slice(6,7);
  78. // 初始化
  79. this.allData.num=numData;
  80. this.buttonToggle();
  81. this.change=!this.change;
  82. if(this.$route.path.indexOf("con")>0){
  83. //获取list中第几个
  84. var typeData=this.$route.query.type;
  85. this.$nextTick(e=>{
  86. this.$http.get("static/data-"+listData+".json").then(rea=>{
  87. this.loading=true;
  88. setTimeout(e=>{
  89. //vue-resource加载数据存在于data.body中
  90. var listNum=rea.body.allData.slice(numData*6,numData*6+6);
  91. //详细显示页面数据来源
  92. this.allData.detailedData=listNum.slice(typeData,typeData+1)[0];
  93. this.loading=false;
  94. },700);
  95. });
  96. });
  97. this.allData.mainShow=false;
  98. }else{
  99. this.$nextTick(e=>{
  100. this.loading=true;
  101. setTimeout(e=>{
  102. this.$http.get("static/data-"+listData+".json").then(rea=>{
  103. this.allData.showData=rea.body.allData.slice(numData*6,numData*6+6);
  104. this.loading=false;
  105. });
  106. },700);
  107. });
  108. this.allData.mainShow=true;
  109. }
  110. }
  111. }
  112. }
  113. </script>
  114. <style>
  115. /*切换中动画*/
  116. .animate-enter-active,.animate-leave-active{
  117. transition: all 0.5s ease;
  118. }
  119. .animate-enter{
  120. transform: translateX(-80px);
  121. opacity: 0;
  122. }
  123. .animate-leave-active{
  124. transform: translateX(80px);
  125. opacity: 0;
  126. }
  127. /*底部按钮简单动画*/
  128. .btn-enter-active,.btn-leave-active{
  129. transition: all 1s ease;
  130. }
  131. .btn-enter{
  132. opacity: 0;
  133. }
  134. .btn-leave-active{
  135. opacity: 0;
  136. }
  137. /*back,next btn-class*/
  138. .app-btn{
  139. overflow: hidden;
  140. width: 140px;
  141. height: 34px;
  142. position: relative;
  143. margin-top: 15px;
  144. }
  145. /*back btn-class*/
  146. .app-btn-back{
  147. position: absolute;
  148. top: 0;
  149. left: 0;
  150. }
  151. /*next btn-class*/
  152. .app-btn-next{
  153. position: absolute;
  154. bottom: 0;
  155. right: 0;
  156. }
  157. /*loading*/
  158. .app-loading{
  159. background-color: tan;
  160. position: fixed;
  161. height: 100%;
  162. width: 100%;
  163. left: 0;
  164. top:0;
  165. }
  166. </style>

Ⅰ: HTML部分(即template)

大体分为三部个分

第一部分:

  1. <transition name='animate' appear mode='out-in'>
  2. <router-view v-bind:router-data="allData" v-bind:key="change"></router-view>
  3. </transition>

第一部分为页面中内容路由入口,其中:
v-bind:router-data="allData" 是对模板中传输数据用的
v-bind:key="change" 是页面切换动画绑定的变值,用来使页面被复用时触发切换动画

第二部分:

  1. <transition name='btn' appear mode='out-in'>
  2. <div class="app-btn" v-show="allData.mainShow">
  3. <button class="btn btn-success app-btn-back" v-show="back==0?false:true" v-on:click="dosom('back')">上一页</button>
  4. <button class="btn btn-success app-btn-next" v-show="next==0?false:true" v-on:click="dosom('next')">下一页</button>
  5. </div>
  6. </transition>

第二部分为页面中上一页,下一页按钮部分,其中:
v-show="allData.mainShow" 是控制俩个按钮显示,隐藏(详情页隐藏)
v-show="back==0?false:true" 是控制单个按钮显示,隐藏(最后一页时,下一页按钮隐藏)
v-on:click="dosom('back')" 是绑定的点击事件

第三部分:

  1. <div class="app-loading" v-show="loading">
  2. <img src="../static/loading/loading.gif" style="margin:0 auto;display: block;" alt="loading" />
  3. </div>

第三部分为页面中内容更新数据时loading画面,其中:
v-show="loading" 是用来显示,隐藏 loading 动画

好了,到此主要的HTML模块已经布局完毕,现在开始JS功能的开发

Ⅱ: javascript

JS这里的整体流程:watch router.path的变化,从URL中读取数据,从新获取数据。(因为本地JSON文件,获取JSON后对JSON进行剪切)

import router from './router' ES6语法,引入router模块下暴露的接口,这里引入router实例为后续编写编程式导航铺垫。

  1. data(){
  2. return{
  3. allData:{
  4. showData:null,
  5. detailedData:{},
  6. num:0,
  7. mainShow:true
  8. },
  9. loading:false,
  10. change:true,
  11. back:0,
  12. next:1,
  13. }
  14. }

showData 为当前页面渲染数据,即router-view被替换为showone.vue模板中的数据来源,每次点击下一页等操作导致router.path变化时,此数据更新对应的子模板中(showone.vue)数据也更新。(后面讲到路由页面时会解释)

detailedData 为详情页面渲染数据,即router-view被替换为showtwo.vue模板中的数据来源,同上。

num 这个是用来每次打开或者刷新页面时读取当前为第几页的number,因为这个数值用了很多次,故将它放到了初始化函数里

mainShow 控制俩个按钮(下一页,上一页)总体显示,隐藏

loading 控制loading动画的显示,隐藏

change 页面复用时的Key值

back 返回按钮的number,因为按钮的判断为v-show="back==0?false:true"当为0是隐藏

next 同上


以上为这个demo中数据的含义,下面是方法的解释,从methods开始说起:

  1. buttonToggle(){
  2. var nowNum=this.allData.num;
  3. this.back=nowNum;
  4. this.next=2-nowNum;
  5. }

这是俩个按钮的控制函数,因为JSON数据不多,一个分类中只有2页数据,所以 this.next=2-nowNum; 最后一页时隐藏。

  1. dosom(str){
  2. str=="next"?this.allData.num++:this.allData.num--;
  3. this.buttonToggle();
  4. // http://localhost:8080/#/user/0/1
  5. // http://localhost:8080/#/user/0/this.allData.num
  6. router.push(this.$route.path.slice(0,8)+this.allData.num);
  7. }

这是按钮点击时触发的方法,点击后判断是上一页,还是下一页,因为会动态的隐藏按钮所以不用关注++或者--的上下界。随后进行url的更改(url更改后会触发watch,watch中执行的函数为 routePath() ,下一个说到)

  1. routePath(){
  2. if(this.$route.fullPath=="/"){
  3. router.push("/user/0/0");
  4. this.load();
  5. }
  6. else if(this.$route.fullPath.length==9 || this.$route.fullPath.length==20){
  7. this.load();
  8. }
  9. else{
  10. router.push("/user/error");
  11. this.back=0;
  12. this.next=0;
  13. }
  14. }

this.$route.fullPath 返回的是全部 url 字符串,这是当前url判断函数:

当读取到的url为“/”时,此为第一次打开页面,跳转到首页也就是 http://localhost:8080/#/user/0/0 然后 执行load()方法,load() 方法下一个说到。

当读取到this.$route.fullPath.length==9 || this.$route.fullPath.length==20,其实就是 this.$route.fullPath 为/user/x/x 的主页面中,或者为 /user/x/x/con?type=x 的详情页面中,此时直接进行 load() 方法更新数据即可

最后其他任何 url 都被认为是错误的 http 请求,返回404页面,当然俩个翻页按钮隐藏。

  1. load(){
  2. var numData=null,
  3. listData=null;
  4. // /user/lisData/numData
  5. listData=this.$route.path.slice(6,7);
  6. numData=this.$route.path.slice(8,9);
  7. // 初始化num值
  8. this.allData.num=numData;
  9. this.buttonToggle();
  10. // 页面复用时Key值
  11. this.change=!this.change;
  12. if(this.$route.path.indexOf("con")>0){
  13. // 获取list中第几个
  14. var typeData=this.$route.query.type;
  15. this.$nextTick(e=>{
  16. this.$http.get("static/data-"+listData+".json").then(rea=>{
  17. this.loading=true;
  18. setTimeout(e=>{
  19. //vue-resource加载数据存在于data.body中
  20. var listNum=rea.body.allData.slice(numData*6,numData*6+6);
  21. //详细显示页面数据来源
  22. this.allData.detailedData=listNum.slice(typeData,typeData+1)[0];
  23. this.loading=false;
  24. },700);
  25. });
  26. });
  27. this.allData.mainShow=false;
  28. }else{
  29. this.$nextTick(e=>{
  30. this.loading=true;
  31. setTimeout(e=>{
  32. this.$http.get("static/data-"+listData+".json").then(rea=>{
  33. this.allData.showData=rea.body.allData.slice(numData*6,numData*6+6);
  34. this.loading=false;
  35. });
  36. },700);
  37. });
  38. this.allData.mainShow=true;
  39. }
  40. }

这个方法的作用是交互数据,demo 有俩个分类,首页,和第一页,所以对应的数据也是俩个JSON。定时器的作用是模拟数据请求延时。

以上就是 methods 方法里全部函数,下面解释一下Vue实例里其他的方法。

  1. created(){
  2. this.routePath();
  3. }

这是一个生命周期钩子代表Vue实例被创建好了,创建好之后进行url解析,这是初始化的步骤,第一次打开这个demo执行的函数。官方文档:Vue生命周期

  1. watch:{
  2. "$route"(to){
  3. this.routePath();
  4. }
  5. }

说到 watch 了这是监控url变化时触发的函数,说白了就是执行 router.path("/user/x/x") 
之后Vue会检测到变化,从而进行回调函数,这里执行 routerPath() 分析 url 是属于哪个页面从而进行数据更新。

好了,javascript的编写到此结束,主要部分还是在 routerPath() 这个函数,再通过 url 重新获取数据。


style 部分就不说了,简单的css3动画

利用vue-cli配合vue-router搭建一个完整的spa流程(二)

在(一)中写到了主要页面的编写,现在开始三个路由页面的编写。

第一步: 路由实例index.js

先贴出代码。

  1. import Vue from 'vue'
  2. import Router from 'vue-router'
  3. import VueResource from 'vue-resource'
  4. import tem from '@/components/showone'
  5. import tem_cont from '@/components/showtwo'
  6. import tem_error from '@/components/error'
  7. //安装插件
  8. Vue.use(Router)
  9. Vue.use(VueResource)
  10. export default new Router({
  11. routes:[
  12. {
  13. path:"/user/:list/:listNum",
  14. component:tem,
  15. children:[
  16. {
  17. path:"con",
  18. component:tem_cont
  19. }
  20. ]
  21. },
  22. {
  23. path:"/user/error",
  24. component:tem_error
  25. }
  26. ]
  27. })

代码很短,一一解释下。

  1. import Vue from 'vue'
  2. import Router from 'vue-router'
  3. import VueResource from 'vue-resource'
  4. import tem from '@/components/showone'
  5. import tem_cont from '@/components/showtwo'
  6. import tem_error from '@/components/error'

↑ 这里是引入所有使用的数据,参数。

  1. //安装插件
  2. Vue.use(Router)
  3. Vue.use(VueResource)

↑ 这里说下 vue-resource 这个一开始没有安装,打开项目右键打开Git 键入 npm install vue-resource --save
这是一个ajax插件,使用起来比较方便而且很简单。

  1. routes:[
  2. {
  3. path:"/user/:list/:listNum",
  4. component:tem,
  5. children:[
  6. {
  7. path:"con",
  8. component:tem_cont
  9. }
  10. ]
  11. },
  12. {
  13. path:"/user/error",
  14. component:tem_error
  15. }
  16. ]

↑ 路由配置,详情页面是主页面的子路由。

第二部: 三个路由xxxx.vue文件编写

Ⅰ: showone.vue

先贴出代码,有些复杂,慢慢解释。

  1. <template>
  2. <div style='cursor:pointer;height: 867px;' >
  3. <div v-show='routerData.mainShow'>
  4. <nav class='navbar navbar-default'>
  5. <div class='container' style="padding: 0;">
  6. <div class='collapse navbar-collapse' style="padding: 0;">
  7. <ul class='nav navbar-nav userNav'>
  8. <li><a v-bind:class="{activeBg:isActive==0}" v-on:click='link(0)'>首页</a></li>
  9. <li><a v-bind:class="{activeBg:isActive==1}" v-on:click='link(1)'>页面一</a></li>
  10. </ul>
  11. </div>
  12. </div>
  13. </nav>
  14. <div class='media' v-for='(item,index) in routerData.showData' v-on:click='go(item,index)'>
  15. <div>
  16. <div class='media-left'>
  17. <img class='media-object' v-bind:src='item.thumbnail'>
  18. </div>
  19. <div class='media-body'>
  20. <h2 class='media-heading' v-text='item.title'></h2>
  21. <span style='font-size:25px;color:#ccc'>{{item.content | more}}</span>
  22. </div>
  23. </div>
  24. </div>
  25. </div>
  26. <router-view v-bind:router-nesting='routerData'></router-view>
  27. </div>
  28. </template>
  29. <script>
  30. import router from '.././router'
  31. export default{
  32. props:["routerData"],
  33. data(){
  34. return {
  35. isActive:this.$route.path.slice(6,7)
  36. }
  37. },
  38. methods:{
  39. go(obj,index){
  40. router.push({path:this.$route.path+"/con",query:{type:index}});
  41. },
  42. link(num){
  43. var listNum=this.$route.path.slice(6,7);
  44. if(listNum!=num){
  45. router.push("/user/"+num+"/0");
  46. this.isActive=this.$route.path.slice(6,7);
  47. }
  48. }
  49. },
  50. filters:{
  51. more(value){
  52. var newMessage=value.slice(0,40)+"........点击查看更多";
  53. return newMessage;
  54. }
  55. }
  56. }
  57. </script>
  58. <style>
  59. .activeBg{
  60. background-color: teal;
  61. color: white !important;
  62. transition: 0.5s all ease-in;
  63. }
  64. .userNav :hover{
  65. background-color: cornsilk;
  66. color: black !important;
  67. }
  68. </style>

template有俩部分组成:

  1. <div v-show='routerData.mainShow'>
  2. <nav class='navbar navbar-default'>
  3. <div class='container' style="padding: 0;">
  4. <div class='collapse navbar-collapse' style="padding: 0;">
  5. <ul class='nav navbar-nav userNav'>
  6. <li><a v-bind:class="{activeBg:isActive==0}" v-on:click='link(0)'>首页</a></li>
  7. <li><a v-bind:class="{activeBg:isActive==1}" v-on:click='link(1)'>页面一</a></li>
  8. </ul>
  9. </div>
  10. </div>
  11. </nav>
  12. <div class='media' v-for='(item,index) in routerData.showData' v-on:click='go(item,index)'>
  13. <div>
  14. <div class='media-left'>
  15. <img class='media-object' v-bind:src='item.thumbnail'>
  16. </div>
  17. <div class='media-body'>
  18. <h2 class='media-heading' v-text='item.title'></h2>
  19. <span style='font-size:25px;color:#ccc'>{{item.content | more}}</span>
  20. </div>
  21. </div>
  22. </div>
  23. </div>

↑ 这是第一部分,包含导航与当前分类中全部内容的一个列表。

①: v-show='routerData.mainShow' 这个控制整体部分显示隐藏,与 上一页,下一页按钮为相同的控制数据,因为二者显示,隐藏逻辑是一样的。都是在详情页隐藏,主页显示。

②: v-on:click='link(0)' 导航按钮跳转绑定的函数。

③: v-for='(item,index) in routerData.showData' 循环数据,渲染列表。

④: v-on:click='go(item,index)' 每个列表绑定跳转到详情页的函数。

⑤: {{item.content | more}} 渲染简介,并且通过一个过滤器使内容中数字过多时,进行剪切


  1. <router-view v-bind:router-nesting='routerData'></router-view>

↑ 这是第二部分,子路由入口。v-bind:router-nesting='routerData' 给子路有中渲染页面的数据。

接下来是script部分

首先引入router实例 import router from '.././router'
再接收 zjapp.vue 传输过来的数据 props:["routerData"]


methods方法里函数解释:

  1. go(obj,index){
  2. router.push({path:this.$route.path+"/con",query:{type:index}});
  3. }

↑ 这是列表中内容点击时执行的函数,从 template 中传过来 index 值,添加到 url 中,从而获取这是列表中第几个。

  1. link(num){
  2. var listNum=this.$route.path.slice(6,7);
  3. if(listNum!=num){
  4. router.push("/user/"+num+"/0");
  5. this.isActive=this.$route.path.slice(6,7);
  6. }
  7. }

↑ link(num)函数是导航点击绑定的函数,通过传志 num 将 url 转换为对应的分类,从而触发 watch 重新获取数据。这里加了一个判断,重复点击,无效。

  1. filters:{
  2. more(value){
  3. var newMessage=value.slice(0,40)+"........点击查看更多";
  4. return newMessage;
  5. }
  6. }

↑ 过滤器,剪切字数。


style就不解释了

Ⅱ: showtwo.vue

这个是文件是详情页面,即主页面中的列表内容点击后,跳转的页面。

  1. <template>
  2. <div style='height:700px;padding-top:100px'>
  3. <div>
  4. <img v-bind:src='routerNesting.detailedData.src' style='display:block;margin:0 auto;width:500px'>
  5. <br>
  6. <h2 v-text='routerNesting.detailedData.title'></h2>
  7. <p>{{routerNesting.detailedData.content}}</p>
  8. <button v-on:click='back' class='btn btn-success'>返回</button>
  9. </div>
  10. </div>
  11. </template>
  12. <script>
  13. import router from '.././router'
  14. export default{
  15. props:["routerNesting"],
  16. methods:{
  17. back(){
  18. router.push(this.$route.path.slice(0,9));
  19. }
  20. }
  21. }
  22. </script>
  23. <style></style>

↑ 数据与showone.vue相似,routerNesting数据是通过ziapp.vue->showone.vue->showtwo.vue传递过来的。
back() 函数将url从/user/0/0/con?type=2跳转到/user/0/0 触发watch更新数据。

Ⅲ: error.vue

  1. <template>
  2. <div style="margin-top: 150px;">
  3. <h1 style="text-align: center;">遥远的404!</h1>
  4. <div style="width: 150px;margin: 50px auto;">
  5. <button v-on:click="jump(0)" class="btn btn-primary">首页</button>
  6. <button v-on:click="jump(1)" class="btn btn-primary">第一页</button>
  7. </div>
  8. </div>
  9. </template>
  10. <script>
  11. import router from '.././router'
  12. export default{
  13. methods:{
  14. jump(num){
  15. num==0?router.push("/user/0/0"):router.push("/user/1/0");
  16. }
  17. }
  18. }
  19. </script>
  20. <style></style>

↑ 嗯~ o( ̄▽ ̄)o,这个比较简单,不做解释了。


结语

至此,全部都解清楚了,按照步骤来的话一个简单的spa也初见其形。

整体思想:通过watch监控url的变化,变化后执行routerPath()函数,随后重新获取数据。

利用vue-cli配合vue-router搭建一个完整的spa流程的更多相关文章

  1. [Vue CLI 3] vue inspect 的源码设计实现

    首先,请记住: 它在新版本的脚手架项目里面非常重要 它有什么用呢? inspect internal webpack config 能快速地在控制台看到对应生成的 webpack 配置对象. 首先它是 ...

  2. 手把手搭建一个完整的javaweb项目

    手把手搭建一个完整的javaweb项目 本案例使用Servlet+jsp制作,用MyEclipse和Mysql数据库进行搭建,详细介绍了搭建过程及知识点. 下载地址:http://download.c ...

  3. react全家桶从0搭建一个完整的react项目(react-router4、redux、redux-saga)

    react全家桶从0到1(最新) 本文从零开始,逐步讲解如何用react全家桶搭建一个完整的react项目.文中针对react.webpack.babel.react-route.redux.redu ...

  4. 搭建一个完整的Java开发环境

    搭建一个完整的Java开发环境 作为一个Java程序员,配置一个java开发环境是必备的技能,今天给广大菜鸟初学者补上一课.环境的配置,大概就分三个1,JDK 2,Tomcat(或者其他的)3,ecl ...

  5. asp.netmvc 三层搭建一个完整的项目

    接下来用 asp.net mvc 三层搭建一个完整的项目: 架构图: 使用的数据库: 一张公司的员工信息表,测试数据 解决方案项目设计: 1.新建一个空白解决方案名称为Company 2.在该解决方案 ...

  6. 11. 搭建一个完整的K8S集群

    11. 搭建一个完整的Kubernetes集群 1. kubectl的命令遵循分类的原则(重点) 语法1: kubectl 动作 类 具体的对象 例如: """ kube ...

  7. vue入门(三)----使用vue-cli搭建一个单页富应用

    上面两节我们说了vue的一些概念,其实说的知识一点基础,这部分知识我觉得更希望大家到官网进行学习,因为在这里说的太多我觉得也只是对官网的照搬照抄而已.今天我们来学习一下vue-cli的一些基础知识,并 ...

  8. vue/cli 3.0脚手架搭建

    在vue 2.9.6中,搭建vue-cli脚手架的流程是这样的: 首先 全局安装vue-cli,在cmd中输入命令: npm install --global vue-cli  安装成功:  安装完成 ...

  9. Vue-cli安装步骤,搭建一个完整的 Vue 项目

    安装node环境下载 node.js 官网地址:https://nodejs.org/en/ 下载完成后打开然后一路next安装完成后打开 dos 窗口输入命令:node -v 回车会输出node的版 ...

随机推荐

  1. Android(java)学习笔记197:ContentProvider使用之内容观察者02

    下面通过3个应用程序之间的交互说明一下内容观察者: 一. 如下3个应用程序为相互交互的: 二.交互逻辑图: 三.具体代码: 1.   16_数据库工程: (1)数据库帮助类BankDBOpenHelp ...

  2. 使用Latex插入数学公式(二)

    初级运算 关系运算符 希腊字母 集合运算符逻辑运算符 空格问题 矩阵格式 矩阵格式有三种: 无括号的矩阵 matrix 是 Latex 的矩阵命令,矩阵命令中每一行以 \\ 结束,矩阵的元素之间用 & ...

  3. 德尔福 XE5 安卓调试

    https://stackoverflow.com/questions/2604727/how-can-i-connect-to-android-with-adb-over-tcp?page=2&am ...

  4. eclipse如何导出WAR包

    WAR包是用于将java项目部署在中间件上的,例如部署在Tomcat,Weblogic,WebSphere等等,那么如何使用eclipse导出WAR包呢? 工具/原料 eclipse 方法/步骤   ...

  5. 排序算法小结:C++实现

    #include<vector> #include<iostream> //排序算法的稳定性:对于相同的关键字,排序之前的位置和排序之后的位置相同,则称为稳定排序,否则不稳定排 ...

  6. Eclipse(MyEclipse)使用技巧——修改注释字体大小

    Eclipse在安装完成后,注释的字体大小远远小于代码的大小,按照网上查的相关信息 窗口——首选项——常规——外观——颜色和字体——基本——文本字体——编辑 Window -->Preferen ...

  7. 笔试算法题(24):找出出现次数超过一半的元素 & 二叉树最近公共父节点

    出题:数组中有一个数字出现的次数超过了数组长度的一半,请找出这个数字: 分析: 解法1:首先对数组进行排序,时间复杂度为O(NlogN),由于有一个数字出现次数超过了数组的一半,所以如果二分数组的话, ...

  8. php代码中注释的含义

    最近在梳理和优化手上的项目代码,这个项目已经走过好几任了,每一任的开发人员多多少少都有一些差异和各自的习惯,所以代码逻辑和写法上都有点[乱]. 在代码中,注释是一个非常重要的信息,更何况是接手其他人的 ...

  9. 【thinking in java】反射

    前言 反射是框架设计的灵魂,使用的前提条件:必须先得到字节码的Class,Class类用于表示字节码,字节码即是.class文件 概述 JAVA反射机制:在程序运行的过程中,对于任意一个类,都可以知道 ...

  10. Go:工厂模式

    Go的结构体没有构造函数,通常可以使用工厂模式来解决这个问题. 一个结构体的声明是这样的: package model type Student struct { Name string } 因为 S ...