vue2.0构建全栈项目(前后分离实践)【1】

525 阅读6分钟

打个广告:个人网站地址 www.wenghaoping.com

Vue + express + Mongodb构建 请大家多支持一下。

前言

项目地址 本项目将选用一些Vue以及前端周边库

前端相关库

vue-cli, vue-router, axios, vuex, Boostrap2.x, element-ui

后端相关库

NodeJS, Mongodb, express,

  1. 使用vue-cli创建项目

  2. 使用vue-router实现单页路由

  3. 用vuex管理我们的数据流

  4. 使用axios请求我们的node服务端

  5. 使用.vue文件进行组件化的开发

  6. ps本项目相关版本

  7. vue 2.5.2, vue-router 3.0.1, vuex 3.0.1, axios 0.17.1,bootstrap 3.3.7, element-ui 2.0.5

最后我们会做成一个Demo,

本文根据 github.com/wenghaoping… 大神框架,一步一步简化并且搭建,当做练手,也把整个逻辑思路理一遍,希望帮助入门vue有所帮助,也帮助自己学习大神的架构

安装

1.我们将会使用webpack去为我们的模块打包,预处理,热加载。如果你对webpack不熟悉,它就是可以帮助我们把多个js文件打包为1个入口文件,并且可以达到按需加载。这就意味着,我们不用担心由于使用太多的组件,导致了过多的HTTP请求,这是非常有益于产品体验的。但我们并不只是为了这个而使用webpack,我们需要用webpack去编译.vue文件,如果没有使用一个loader去转换我们.vue文件里的style、js和html,那么浏览器就无法识别。

2.模块热加载是webpack的一个非常碉堡的特性,将会为我们的单页应用带来极大的便利。 通常来说,当我们修改了代码刷新页面,那应用里的所有状态就都没有了。这对于开发一个单页应用来说是非常痛苦的,因为需要重新在跑一遍流程。如果有模块热加载,当你修改了代码,你的代码会直接修改,页面并不会刷新,所以状态也会被保留。

3.Vue也为我们提供了CSS预处理,所以我们可以选择在.vue文件里写LESS或者SASS去代替原生CSS。

4.我们过去通常需要使用npm下载一堆的依赖,但是现在我们可以选择Vue-cli。这是一个vue生态系统中一个伟大创举。这意味着我们不需要手动构建我们的项目,而它就可以很快地为我们生成。

首先,安装vue-cli。(确保你有node和npm)

npm i -g vue-cli

然后创建一个webpack项目并且下载依赖

vue init webpack vue-story

cd vue-story

npm install

安利一下淘宝镜像

npm install -g cnpm --registry=https://registry.npm.taobao.org

使用cnpm会更快,

接着使用 npm run dev 在热加载中运行我们的应用

这一行命令代表着它会去找到package.json的scripts对象,执行node bulid/dev-server.js。在这文件里,配置了Webpack,会让它去编译项目文件,并且运行服务器,我们在localhost:8080即可查看我们的应用。

顺便解释下package.json中的一些简单意义

1.name为你本次的项目的项目名称

2.version为版本号

3.description为简介

4.scripts为命令好简写,比如npm run dev其实运行的是这里dev下面对应的代码

这些都准备好后,我们需要为我们的路由、XHR请求、数据管理下载三个库,我们可以从vue的官网中找到他们。另外我们使用bootstrap作为我的UI库,主要为了制作响应式

npm i axios vue-router vuex bootstrap element-ui--save

初始化(main.js)

查看我们的应用文件,我们可以在src目录下找到App.vue和main.js。main.js将会作为我们应用的入口文件而App.vue会作为我们应用的初始化组件。先让我们来完善下main.js

// src/main.js
import Vue from 'vue'
import router from './router' // 路由
import store from './store' // vuex管理器
import * as filters from './filters' // 全局filter
import ElementUI from 'element-ui' // element引入
import 'element-ui/lib/theme-chalk/index.css' // elelemtCSS
import App from './App.vue' // 最上层组件
import 'bootstrap/dist/css/bootstrap.css' // boostrap样式
Vue.use(ElementUI)

// register global utility filters.
Object.keys(filters).forEach(key => {
  Vue.filter(key, filters[key])
})
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  template: '<App/>',
  store,
  components: { App }
})

可以发现我们在main.js里使用了两个组件App.vue,稍后让我们具体实现它们的内容。

而我们的index.html只需要保留

即可,我们的Vue在实例化时设置了el : '#app' 所以会替换这标签,为我们App组件的内容

//index.html
<div id="app"></div>

我们的初始化就到这结束了,接下来让我们开始创建组件。

创建首页组件

首先我们在App.vue里为我们的应用写个顶部导航组件。 全局公用组件,我们放在 src/components目录下

// src/components/topNav.vue

<template>
  <nav class="navbar navbar-inverse">
    <div class="container-fluid">
      <div class="navbar-header">
        <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
          <span class="sr-only">Toggle navigation</span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
        </button>
        <div class="navbar-brand">主页</div>
      </div>
      <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
        <ul class="nav navbar-nav">
          <li class="active"><a href="#">记事本<span class="sr-only">(current)</span></a></li>
        </ul>
      </div>
    </div>
  </nav>
</template>

创建侧边栏组件

// src/components/sider.vue

<template>
  <div class="panel panel-primary">
    <div class="panel-heading">
      <h1 class="text-center">总件</h1>
    </div>
    <div class="panel-body">
      <h1 class="text-center">{{planIndex}}件</h1>
    </div>
  </div>
</template>

js部分 在sider.vue我们需要通过store去获取总件数,我们的总件数是共享事件

<script type="text/ecmascript-6">
    export default {
      props: [],
      data () {
        return {};
      },
      computed: {
        planIndex () {
          return this.$store.state.list.length;
        }
      },
      mounted () {},
      // 组件
      components: {},
      methods: {},
      // 当dom一创建时
      created () {},
      watch: {}
    };
</script>

创建展示页 当前首页作为展示页,数据从vuex中去取

// src/views/index/index.vue
<template>
  <div class="index">
    <el-button type="primary" round @click="creatPlan">创建</el-button>
    <ul class="list-group" style="margin-top: 10px;">
      <li class="list-group-item" v-for="(plan, index) in plans" :key="index">
        <div class="row">
          <div class="col-sm-2 user-details">
            <img :src="plan.avatar" class="avatar img-circle img-responsive" />
            <p class="text-center">
              <strong>
                {{ plan.name }}
              </strong>
            </p>
          </div>
          <div class="col-sm-4 text-center">
            <p class="label label-primary text-center">
              <i class="glyphicon glyphicon-calendar"></i>
              {{ plan.date }}
            </p>
          </div>
          <div class="col-sm-4 text-left">
            {{ plan.introduce }}
          </div>
          <div class="col-sm-1">
            <el-button icon="el-icon-circle-close" type="danger" round @click="deletePlan(plan,index)"></el-button>
          </div>
        </div>
      </li>
    </ul>
  </div>
</template>

JS部分

<script type="text/ecmascript-6">
  export default {
    props: [],
    data () {
      return {
        loading: false
      };
    },
    computed: {
      plans () {
        // 从store中取出数据
        return this.$store.state.list;
      }
    },
    mounted () {},
    // 组件
    components: {},
    methods: {
      deletePlan (plan, index) {
        // 删除该事件
        this.$store.dispatch('deletePlan', index);
      },
      creatPlan () {
          // 路由去创建页面
        this.$router.push({name: 'creatPlan', query: {}});
      }
    },
    // 当dom一创建时
    created () {},
    watch: {}
  };
</script>

最后为APP.vue页面

<template>
  <div id="app">
    <top-nav></top-nav>
    <div class="container">
      <div class="col-sm-3">
        <sider></sider>
      </div>
      <div class="col-sm-9">
        <transition :name="transitionName">
          <router-view class="child-view">

          </router-view>
        </transition>
      </div>
    </div>
  </div>
</template>

JS部分,在路由切换加上特效,看下面的watch

<script type="text/ecmascript-6">
import topNav from '@/components/topNav.vue';
import sider from '@/components/sider.vue';
export default {
  data () {
    return {
      transitionName: 'slide-left'
    };
  },
  components: {
    topNav,
    sider
  },
  watch: {
    '$route' (to, from) { // 为了给路由切换加上特效
      if (to) {
        this.transitionName = 'slide-right';
      } else {
        this.transitionName = 'slide-left';
      }
    }
  }
};
</script>

less部分

<style lang="less" scoped>
  #app {
  /* 路由切换动效 */
    .slide-left-enter, .slide-right-leave-active {
      opacity: 0;
      -webkit-transform: translate(100%, 0);
      transform: translate(100%, 0);
      transition: 0.3s;
    }
    .slide-left-leave-active, .slide-right-enter {
      opacity: 0;
      -webkit-transform: translate(-100%, 0);
      transform: translate(-100%, 0);
      transition: 0.3s;
    }
    .child-view {
      position: absolute;
      left: 0;
      width: 100%;
      height: 100%;
      /*transition: all .2s ease;*/
      transition: all .3s cubic-bezier(.55,0,.1,1);
    }
  }
</style>

以下是整个文件夹的分布

到此为止,所有的页面搭建完毕,请看下一篇关于VUEX的设置,以及相关工具类,路由,和过滤器等的运用

::: hljs-center

来快活啊,加我啊

:::