利用vue-cli配合vue-router搭建一个完整的spa流程 第一步:安装 第二步:项目文件及运行流程 第三步:搭建基本路由框架 第四步:主页面代码编写

好文章备忘录:

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


利用vue-cli配合vue-router搭建一个完整的spa流程
第一步:安装
第二步:项目文件及运行流程
第三步:搭建基本路由框架
第四步:主页面代码编写


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为必须,其他语法检测,单元测试等按需求安装。
利用vue-cli配合vue-router搭建一个完整的spa流程
第一步:安装
第二步:项目文件及运行流程
第三步:搭建基本路由框架
第四步:主页面代码编写

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

安装到此结束,运行如下代码,显示为图片所示,则安装成功。
$ npm run dev
利用vue-cli配合vue-router搭建一个完整的spa流程
第一步:安装
第二步:项目文件及运行流程
第三步:搭建基本路由框架
第四步:主页面代码编写


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

Ⅰ: 项目文件

打开已经创建好的模板
利用vue-cli配合vue-router搭建一个完整的spa流程
第一步:安装
第二步:项目文件及运行流程
第三步:搭建基本路由框架
第四步:主页面代码编写

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

这里解释一下xxx.vue文件是什么,官网叫其为单文件组件,通过webpack源码转换,会全部转换为对应的文件。
说白了就是一个包裹,里边含有三部分 一部分模板template,一部分样式style,一部分JSjavascript,他们封装在一起。
如下图所示:
利用vue-cli配合vue-router搭建一个完整的spa流程
第一步:安装
第二步:项目文件及运行流程
第三步:搭建基本路由框架
第四步:主页面代码编写

Ⅱ: 运行流程

写起来比较麻烦,做了一张图,直截了当。
利用vue-cli配合vue-router搭建一个完整的spa流程
第一步:安装
第二步:项目文件及运行流程
第三步:搭建基本路由框架
第四步:主页面代码编写

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

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

根据基础框架创建对应的文件。
利用vue-cli配合vue-router搭建一个完整的spa流程
第一步:安装
第二步:项目文件及运行流程
第三步:搭建基本路由框架
第四步:主页面代码编写

文件详解:
Ⅰ: 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安装。
为了方便后面阅读将。当然,也可以不更改,main.js中有多个为app的名字,避免混淆。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>spa-vue-demo</title>
    <link rel="stylesheet" href="static/bootstrap.min.css" />
  </head>
  <body>
    <div id="index"></div>
    <!-- built files will be auto injected -->
    </body>
</html>

Ⅱ: main.js

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

import Vue from 'vue'
import App from './zjapp'
import router from './router'

Vue.config.productionTip = false

new Vue({
  el: '#index',
  router,
  template: '<App/>',
  components: { App }
})

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

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

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

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

import Vue from 'vue'
import App from './zjapp'

//修改名字一样可以。
import changeES6 from './router'

Vue.config.productionTip = false

new Vue({
  el: '#index',

  //修改在这里
  router:changeES6,

  template: '<App/>',
  components: { App }
})

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

Ⅲ: zjapp.vue

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

<template>
    <div class="container">
        <div class="row">
            <div id="index" class="col-xs-12 col-lg-12 col-md-12" style="padding: 0;">
                <transition name='animate' appear mode='out-in'>
                    <router-view v-bind:router-data="allData" v-bind:key="change"></router-view>
                </transition>
                <transition name='btn' appear mode='out-in'>
                    <div class="app-btn" v-show="allData.mainShow">
                        <button class="btn btn-success app-btn-back" v-show="back==0?false:true" v-bind:key="back" v-on:click="dosom('back')">上一页</button>
                        <button class="btn btn-success app-btn-next" v-show="next==0?false:true" v-bind:key="next" v-on:click="dosom('next')">下一页</button>
                    </div>
                </transition>
                <div class="app-loading" v-show="loading">
                    <img src="../static/loading/loading.gif" style="margin:0 auto;display: block;" alt="loading" />
                </div>
            </div>
        </div>
    </div>
</template>
<script>
    import router from './router'
    export default{
        data(){ 
            return{
                allData:{
                    showData:null,
                    detailedData:{},
                    num:0,
                    mainShow:true
                },
                loading:false,
                change:true,
                back:0,
                next:1,
            }
        },
        created(){
            this.routePath();
        },
        watch:{
            "$route"(to){
                this.routePath();
            }
        },
        methods:{
            buttonToggle(){
                var nowNum=this.allData.num;
                this.back=nowNum;
                this.next=2-nowNum;
            },
            dosom(str){
                str=="next"?this.allData.num++:this.allData.num--;
                this.buttonToggle();
                //当前user/当前页面/当前页面路由
                router.push(this.$route.path.slice(0,8)+this.allData.num);
            },
            routePath(){
                if(this.$route.fullPath=="/"){
                    router.push("/user/0/0");
                    this.load();
                }
                else if(this.$route.fullPath.length==9 || this.$route.fullPath.length==20){
                    this.load();
                }
                else{
                    router.push("/user/error");
                    this.back=0;
                    this.next=0;
                }
            },
            load(){
                var numData=null,
                    listData=null;
                    
                // /user/lisData/numData
                numData=this.$route.path.slice(8,9);
                listData=this.$route.path.slice(6,7);
                
                // 初始化
                this.allData.num=numData;
                this.buttonToggle();
                this.change=!this.change;
                if(this.$route.path.indexOf("con")>0){
                    //获取list中第几个
                    var typeData=this.$route.query.type;
                    this.$nextTick(e=>{
                        this.$http.get("static/data-"+listData+".json").then(rea=>{
                            this.loading=true;
                            setTimeout(e=>{
                                
                                //vue-resource加载数据存在于data.body中
                                var listNum=rea.body.allData.slice(numData*6,numData*6+6);
                                
                                //详细显示页面数据来源
                                this.allData.detailedData=listNum.slice(typeData,typeData+1)[0];
                                
                                this.loading=false;
                            },700);
                        });
                            
                    });
                    this.allData.mainShow=false;
                }else{
                    this.$nextTick(e=>{
                        this.loading=true;
                        setTimeout(e=>{
                            this.$http.get("static/data-"+listData+".json").then(rea=>{
                                
                                this.allData.showData=rea.body.allData.slice(numData*6,numData*6+6);
                                this.loading=false;
                            });
                        },700);
                    });
                    this.allData.mainShow=true;
                }
            }
        }
    }
</script>
<style>
    /*切换中动画*/
    .animate-enter-active,.animate-leave-active{
        transition: all 0.5s ease;
    }
    .animate-enter{
        transform: translateX(-80px);
        opacity: