本篇完成如下场景:

1、系统包含首页、客户信息查询、登录三个模块

2、默认进入系统首页,如果要进行用户查询,则需要进行登录授权

3、查询用户后点击列表项,则进入详情页面

基于上述场景需求描述,在客户端我们考虑,需要设计如下组件:Home组件、客户列表组件、客户详情组件、登录组件

在服务器端考虑需要:用户认证服务;客户列表查询服务、客户详情查询服务。

ok,现在我们从上往下,先创建我们的基本目录结构,

当前目录结构如下:

app.js node web 启动文件

node_modules node模块文件(关于node模块安装这里不再介绍)

public 存放静态文件比如index.html 浏览器端执行的css或者js文件、图片、文字等等。当前包含两个文件 index.html,app.js (组件定义等文件)

router 后端路由文件,比如可以把portal部分进行抽象到路由文件夹

middleware 中间件 文件夹,我们会定义鉴权中间件

package.json npm包配置文件

由我们的客户端开始设计,构建我们的组件:

首先Home组件,Home组件,简单的potal信息展示,这里为了演示,就直接显示一串基本信息,在public/app.js中添加如下代码:

var HomeComponent = {
template: `<div>
<h1>Home 页面,portal页</h1>
<h2>以下数据来自服务端</h2>
{{stat}}
</div>`,
data:function(){
return {
stat:''//代表相关统计信息等
}
},
methods:{
getStat:function(){
return axios.get('/portal');
}
},
created:function(){
this.getStat().then(res=>{
this.stat=JSON.stringify(res.data);
}).catch(err=>{
console.log(err);
})
}
}

这里一个新的知识axios,这是一个vue的Ajax库,由于vue-resource已不再更新,官方推荐使用axios;上述代码逻辑很简单,在组件初始化时,请求后端数据,返回后进行简单的数据绑定;对应的后端接口(数据只是模拟),在/app.js下添加如下代码:

var express = require("express");

var app = express();

app.use(express.static('public'));
app.get('/portal',function(req,res){
res.json({
data:[
{
visits:12,
clicks:100
},
{
location:'BeiJing',
total:17
}
]
})
}) app.listen(8110,function(){
console.log("port 8110 is listenning!!!");
});

这里就是最基础的express代码了,只是做了两件事情,第一,设置静态目录为public,设置路由/portal,对应前端请求。

为了让程序运行起来,我们修改我们的/public/index.html代码如下:

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>demo3</title>
<script src="https://cdn.bootcss.com/vue/2.4.1/vue.js"></script>
<script src="https://cdn.bootcss.com/vue-router/2.7.0/vue-router.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script> </head> <body>
<div id="app"> </div>
<script src="./app.js"></script>
</body> </html>

在public/app.js中为组件Home设置路由,并启用路由配置:

var router = new VueRouter({
//TODO:各种路由定义;
routes: [{
name: 'home', path: '/home', component: HomeComponent
} ]
});
var app = new Vue({
router: router,
template: `
<div>
<router-view></router-view>
</div>
`,
el: '#app'
});

打开控制台,进入到项目根目录,执行node app.js 启动后台服务,在浏览器打开http://localhost:8110/#/home ,可以看到如下效果:

接下来,在public/app.js文件中添加我们的另外三个组件:客户列表组件,详情组件和登录组件,并配置路由,最终代码如下:

var LoginComponent = {
template: ` <div class="login" >
username:<input type="text" v-model="user.username" />
password:<input type="password" v-model="user.password" />
<input type="button" @click="login()" value="login" />
</div>
`,
data: function () {
return {
user: {
username: '',
password: ''
}
}
},
methods: { login: function () {
axios.post('/login',{params: this.user})
.then(function (res) {
if (res.success) {
localStorage.setItem('token', res.token);
}
})
.catch(function (error) {
console.log(error);
}); }
}
} var CustomerListComponent = {
template: `
<div>
<div>
<input type="text" v-model="keyword" /> <input type="button" @click="getCustomers()" value="search" />
</div>
<ul>
<router-link v-for="c in customers" tag="li" :to="{name:'detail',params:{id:c.id}}" :key="c.id">{{c.name}}</router-link>
</ul>
</div>
`,
data: function () {
return {
customers: [],
keyword: ''
}
},
created: function () {
this.getCustomers();
},
methods: {
getCustomers: function () {
axios.get('/api/getCustomers', { params: { keyword: this.keyword } })
.then(res => { this.customers = res.data; console.log(res) })
.catch(err => console.log(err));
}, }
} var CustomerComponent = {
template: `
<div>
{{customer}}
</div>
`,
data: function () {
return {
customer: {}
}
},
created: function () {
var id = this.$route.params.id;
this.getCustomerById(id);
},
watch: {
'$route': function () {
console.log(this.$route.params.id);
}
},
methods: {
getCustomerById: function (id) {
axios.get('/api/customer/'+id)
.then(res => this.customer = res.data)
.catch(err => console.log(err));
}
}
} var HomeComponent = {
template: `<div>
<h1>Home 页面,portal页</h1>
<h2>以下数据来自服务端</h2>
{{stat}}
</div>`,
data: function () {
return {
stat: ''//代表相关统计信息等
}
},
methods: {
getStat: function () {
return axios.get('/portal');
}
},
created: function () {
this.getStat().then(res => {
this.stat = JSON.stringify(res.data);
}).catch(err => {
console.log(err);
})
}
} var router = new VueRouter({
//TODO:各种路由定义;
routes: [{
name: 'home', path: '/home', component: HomeComponent
},
{
name: 'customers', path: '/customers', component: CustomerListComponent, },
{
name: 'detail', path: '/detail/:id', component: CustomerComponent, },
{
name: 'login', path: '/login', component: LoginComponent
}
]
}); //注册全局事件钩子
//TODO:会在下一篇中详细分析
// router.beforeEach(function (to, from, next) {
// if (to.matched.some(r => r.meta.auth)) {
// if (!localStorage.getItem('token')) {
// console.log("需要登录");
// next({
// path: '/login',
// query: { to: to.fullPath }
// })
// } else {
// next();
// }
// } else {
// next()
// }
// }); var app = new Vue({
router: router,
template: `
<div>
<router-link :to="{name:'home'}" >Home</router-link>
<router-link :to="{name:'customers'}" >Customers</router-link>
<router-view></router-view>
</div>
`,
el: '#app'
});

后台根据接口添加如下路由,在router文件夹中,添加customers.js文件,加入如下代码:

var router = require("express").Router();
var db = require('./fakeData'); router.get('/getCustomers', function (req, res) {
var list = db.data; list = list.filter(v => v.name.indexOf(req.query.keyword) !== -1); res.json(list);
}); router.get('/customer/:id',function(req,res){
var list=db.data; var obj=list.filter(v=>v.id==req.params.id)[0]; res.json(obj);
}) module.exports = router;

同时在/app.js中修改代码如下:

var express = require("express");

var authMiddleware=require('./middleware/authMiddleware');
var customerRouter=require('./router/customers'); var app = express(); app.use(express.static('public'));
app.get('/portal',function(req,res){
res.json({
data:[
{
visits:12,
clicks:100
},
{
location:'BeiJing',
total:17
}
]
})
})
//TOOD:下一篇会详细讲,先忽略
// app.use(authMiddleware); app.use('/api',customerRouter); app.listen(8110,function(){
console.log("port 8110 is listenning!!!");
});

重新执行node app.js,刷新浏览器,看到最终效果如下:

上述vue的代码,我们在前面几篇都有所提及,没有陌生格式的代码,大家有疑问的可以提comment。下一篇中会加入授权,包括前端路由控制以及后端接口访问控制,今天就到这里吧,最近比较忙,更新进度有点慢,下一篇完善权限,在本部分代码中已加入todo标示,有兴趣的可以考虑一下()。

本篇完整代码如下:

public/index.html

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>demo3</title>
<script src="https://cdn.bootcss.com/vue/2.4.1/vue.js"></script>
<script src="https://cdn.bootcss.com/vue-router/2.7.0/vue-router.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script> </head> <body>
<div id="app"> </div>
<script src="./app.js"></script>
</body> </html>

public/app.js

var LoginComponent = {
template: ` <div class="login" >
username:<input type="text" v-model="user.username" />
password:<input type="password" v-model="user.password" />
<input type="button" @click="login()" value="login" />
</div>
`,
data: function () {
return {
user: {
username: '',
password: ''
}
}
},
methods: { login: function () {
axios.post('/login', this.user)
.then(function (res) {
if (res.success) {
localStorage.setItem('token', res.token);
}
})
.catch(function (error) {
console.log(error);
}); }
}
} var CustomerListComponent = {
template: `
<div>
<div>
<input type="text" v-model="keyword" /> <input type="button" @click="getCustomers()" value="search" />
</div>
<ul>
<router-link v-for="c in customers" tag="li" :to="{name:'detail',params:{id:c.id}}" :key="c.id">{{c.name}}</router-link>
</ul>
</div>
`,
data: function () {
return {
customers: [],
keyword: ''
}
},
created: function () {
this.getCustomers();
},
methods: {
getCustomers: function () {
axios.get('/api/getCustomers', { params: { keyword: this.keyword } })
.then(res => { this.customers = res.data; console.log(res) })
.catch(err => console.log(err));
}, }
} var CustomerComponent = {
template: `
<div>
{{customer}}
</div>
`,
data: function () {
return {
customer: {}
}
},
created: function () {
var id = this.$route.params.id;
this.getCustomerById(id);
},
watch: {
'$route': function () {
console.log(this.$route.params.id);
}
},
methods: {
getCustomerById: function (id) {
axios.get('/api/customer/'+id)
.then(res => this.customer = res.data)
.catch(err => console.log(err));
}
}
} var HomeComponent = {
template: `<div>
<h1>Home 页面,portal页</h1>
<h2>以下数据来自服务端</h2>
{{stat}}
</div>`,
data: function () {
return {
stat: ''//代表相关统计信息等
}
},
methods: {
getStat: function () {
return axios.get('/portal');
}
},
created: function () {
this.getStat().then(res => {
this.stat = JSON.stringify(res.data);
}).catch(err => {
console.log(err);
})
}
} var router = new VueRouter({
//TODO:各种路由定义;
routes: [{
name: 'home', path: '/home', component: HomeComponent
},
{
name: 'customers', path: '/customers', component: CustomerListComponent, },
{
name: 'detail', path: '/detail/:id', component: CustomerComponent, },
{
name: 'login', path: '/login', component: LoginComponent
}
]
}); //注册全局事件钩子
//TODO:会在下一篇中详细分析
// router.beforeEach(function (to, from, next) {
// if (to.matched.some(r => r.meta.auth)) {
// if (!localStorage.getItem('token')) {
// console.log("需要登录");
// next({
// path: '/login',
// query: { to: to.fullPath }
// })
// } else {
// next();
// }
// } else {
// next()
// }
// }); var app = new Vue({
router: router,
template: `
<div>
<router-link :to="{name:'home'}" >Home</router-link>
<router-link :to="{name:'customers'}" >Customers</router-link>
<router-view></router-view>
</div>
`,
el: '#app'
});

router/customers.js

var router = require("express").Router();
var db = require('./fakeData'); router.get('/getCustomers', function (req, res) {
var list = db.data; list = list.filter(v => v.name.indexOf(req.query.keyword) !== -1); res.json(list);
}); router.get('/customer/:id',function(req,res){
var list=db.data; var obj=list.filter(v=>v.id==req.params.id)[0]; res.json(obj);
}) module.exports = router;

middleware/authMiddleware.js

module.exports=function(req,res,next){
if(req.path="/login"){
res.json({
success:true
})
}
next();
}

app.js

var express = require("express");

var authMiddleware=require('./middleware/authMiddleware');
var customerRouter=require('./router/customers'); var app = express(); app.use(express.static('public'));
app.get('/portal',function(req,res){
res.json({
data:[
{
visits:12,
clicks:100
},
{
location:'BeiJing',
total:17
}
]
})
})
//TOOD:下一篇会详细讲,先忽略
// app.use(authMiddleware); app.use('/api',customerRouter); app.listen(8110,function(){
console.log("port 8110 is listenning!!!");
});

一步一步学Vue(八)的更多相关文章

  1. 一步一步学Vue(六)https://www.cnblogs.com/Johnzhang/p/7242640.html

    一步一步学Vue(六):https://www.cnblogs.com/Johnzhang/p/7237065.html  路由 一步一步学Vue(七):https://www.cnblogs.com ...

  2. 一步一步学Vue(九) 路由元数据

    一步一步学Vue(九):https://www.cnblogs.com/Johnzhang/p/7260888.html

  3. 一步一步学Vue(四)

    接上篇.上篇中给出了代码框架,没有具体实现,这一篇会对上篇定义的几个组件进行分别介绍和完善: 1.TodoContainer组件 TodoContainer组件,用来组织其它组件,这是react中推荐 ...

  4. 一步一步学Vue(十二)

    为了提升代码的逼格,之后代码改为Vue文件组件,之前代码虽然读起来容易理解,而且适合在小的项目中使用,但是有如下缺点: 全局定义(Global definitions) 强制要求每个 componen ...

  5. 一步一步学Vue(六)

    本篇继续介绍vue-router,我们需要要完成这样个demo:<分页显示文章列表>:这里我们以博客园首页列表为例简化处理: 按照上图框选所示,简单分为蓝色部分文章组件(ArticleIt ...

  6. 一步一步学ROP之linux_x64篇

    一步一步学ROP之linux_x64篇 一.序 **ROP的全称为Return-oriented programming(返回导向编程),这是一种高级的内存攻击技术可以用来绕过现代操作系统的各种通用防 ...

  7. (转载)一步一步学Linq to sql系列文章

    现在Linq to sql的资料还不是很多,本人水平有限,如果有错或者误导请指出,谢谢. 一步一步学Linq to sql(一):预备知识 一步一步学Linq to sql(二):DataContex ...

  8. 一步一步学ZedBoard & Zynq(四):基于AXI Lite 总线的从设备IP设计

    本帖最后由 xinxincaijq 于 2013-1-9 10:27 编辑 一步一步学ZedBoard & Zynq(四):基于AXI Lite 总线的从设备IP设计 转自博客:http:// ...

  9. 【DG】[三思笔记]一步一步学DataGuard

    [DG][三思笔记]一步一步学DataGuard 它有无数个名字,有人叫它dg,有人叫它数据卫士,有人叫它data guard,在oracle的各项特性中它有着举足轻理的地位,它就是(掌声)..... ...

  10. 一步一步学习Vue(十一)

    本篇继续学习vuex,还是以实例为主:我们以一步一步学Vue(四)中讲述的例子为基础,对其改造,基于vuex重构一遍,这是原始的代码: todolist.js ; (function () { var ...

随机推荐

  1. Java基础——抽象类和接口

    之所以将抽象类和接口放在一起做笔记,是因为他们之间很难区分又各自独立.在学习完Java程序设计的三大特点(封装.继承.多态)之后,我最大的收获是,慢慢理解了Java语言这种面向对象程序设计的优越性,它 ...

  2. 解决(防止)DDOS攻击的另一种思想

    本方案适合作最后的处理方案. 在服务器遭到DDOS攻击后,防火墙.高防盾或者其他的方案都已经失去了效力,这时运维人员无任何方案可以处理,并且只能任由DDOS攻击或关闭服务器时,该方案可以有限的抵挡大部 ...

  3. Python:Anaconda安装虚拟环境到指定路径

    1 曾经的困扰 有段时间,想使用基于不同python版本的anaconda,就直接从官网下载了两个不同的anaconda版本进行安装.刚开始的时候,还觉得也没啥问题.用了一小段时间,在安装其他的第三方 ...

  4. Tomcat、JBOSS、WebSphere、WebLogic、Apache等技术概述

    Tomcat:应用也算非常广泛的web服务器,支持部分j2ee,免费,出自apache基金组织   JBoss:开源的应用服务器,比较受人喜爱,免费(文档要收费)   Weblogic:应该说算是业界 ...

  5. Java学习笔记--反射API

    反射API 1.反射API的介绍 通过反射API可以获取Java程序在运行时刻的内部结构.比如Java类中包含的构造方法.域和方法等元素,并可以与这些元素进行交换.     按照 一般地面向对象的设计 ...

  6. bc计算A股上市新股依次涨停股价

    几年的股市可谓惨不忍睹,不提也罢.唯有打新中签的时候,心里稍微有那么一点点的补偿,于是内心就YY可以30板吗,可以40板吗.于是就写了个连板的bc程序,每次中签的时候就运行一下,然后尽情的YY,然而每 ...

  7. 【Android Developers Training】 65. 应用投影和相机视图

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  8. USACO The Castle

    首先看一下题目. The CastleIOI'94 - Day 1 In a stroke of luck almost beyond imagination, Farmer John was sen ...

  9. HybridApp Exception

    HybridApp Exception [创建安卓虚拟机失败]CPU acceleration status:HAXM must be updated(version 1.1.1<6.0.1) ...

  10. 序列、视图、索引(面试看这个就GO了)

    oracle内置对象 序列.视图.索引 序列 create sequence aaa start with 1; 使用 视图 创建好之后 然后直接用 就OK了 有了视图可以代替子查询,使得sql简洁 ...