本篇完成如下场景:
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!!!"); });