打个广告:个人网站地址 www.wenghaoping.com
Vue + express + Mongodb构建 请大家多支持一下。
前言
项目地址 本项目将选用一些Vue以及前端周边库
前端相关库
vue-cli,vue-router,axios,vuex,Boostrap2.x,element-ui
后端相关库
NodeJS,Mongodb,express,
-
使用vue-cli创建项目
-
使用vue-router实现单页路由
-
用vuex管理我们的数据流
-
使用axios请求我们的node服务端
-
使用.vue文件进行组件化的开发
-
ps本项目相关版本
-
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
来快活啊,加我啊
:::