一步一步学Vue(八)

本篇完成如下场景:

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!!!");
});

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏黑泽君的专栏

通过数据库中的表,使用 MyEclipse2017的反向生成工具-->hibernate反转引擎引擎(MyEclipse2017自带的插件) 来反转生成实体类和对应的映射文件

1、在MyEclipse中,Java视图下,新建一个普通的java project,新建该项目的目的是:用来接收反转引擎生成的实体类和对应的映射文件。

18420
来自专栏Jerry的SAP技术分享

在浏览器里使用SAPGUI里的SE80

(1). 在后台找到Fiori catalog page ID: SAP_FIORI_EXTENSIBILITY

35450
来自专栏老马寒门IT

08Vue.js快速入门-Vue综合实战项目

8.1. 前置知识学习 npm 学习 官方文档 推荐资料 npm入门 npm介绍 需要了解的知识点 package.json 文件相关配置选项 ...

44770
来自专栏做全栈攻城狮

采用React+Ant Design组件化开发前端界面(一)

​ antd是基于less开发的,我们使用less可以方便的改变主题色等配置。

32130
来自专栏魏艾斯博客www.vpsss.net

WordPress 手动优化和插件优化 MySQL 数据库的方法

17020
来自专栏ytkah

dedecms网站迁移时记得将安装目录放空 附迁移的正确方法

  这段时间在赶一些新项目,我们建站一般都在本地服务器搭建起来,测试得差不多了才传到网上,这样对蜘蛛也相对友好一些,要不然改来改去变化太大给搜索引擎的第一印象很...

31030
来自专栏木头编程 - moTzxx

PHP 获取网络图片资源并保存

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011415782/article/de...

61710
来自专栏搞前端的李蚊子

Vue.js实现一个SPA登录页面的过程

技术栈 vue.js 主框架 vuex 状态管理 vue-router 路由管理 一般过程 在一般的登录过程中,一种前端方案是: 检查状态:进入页面时或者路...

1.2K120
来自专栏做全栈攻城狮

采用React+Ant Design组件化开发前端界面(一)

注意:在webpack.config.dev.js添加的配置部分,也需要在webpack.config.prod.js中做相同的配置。否则可能导致项目发布上线后...

13220
来自专栏wblearn

代码提示插件Spket

Spket是一个可以在Eclipse及MyEclipse中实现JavaScript代码自动提示、自动校验、自动纠错的插件。

12710

扫码关注云+社区

领取腾讯云代金券