Vue.js进阶【4-1】Vue+Node+MongoDB+前后端分离实现登录界面
下面分三个部分来介绍:〇 根目录创建1 创建项目目录文件夹,我们的服务端和客户端都会以独立的文件夹形式存在于这个根文件夹中先在自己喜欢的位置 创建项目目录文件夹 classweb比如:D:\classweb注:打开命令行的简单方法:在文件夹中按住 shift 鼠标右键 点击“在此处打开命令行” / "在此处打开powershell窗口"一、服务端1安装cnpmc...
下面分三个部分来介绍:
〇 根目录创建
1 创建项目目录文件夹,我们的服务端和客户端都会以独立的文件夹形式存在于这个根文件夹中
先在自己喜欢的位置 创建项目目录文件夹 classweb
比如:D:\classweb
注:打开命令行的简单方法:在文件夹中按住 shift 鼠标右键 点击“在此处打开命令行” / "在此处打开powershell窗口"
一、服务端
1 安装cnpm
cnpm是阿里提供的,和npm一样,只是不用访问外网,可以提供速度保障
npm install -g cnpm
2 生成服务器端项目目录
进入目录,运行 express server 生成服务器端项目(server是我们服务端项目的名字) (这里注意,得提前安装node express-generator)
D:\classweb>cnpm install -g express-generator
D:\classweb>express server
D:\classweb>cd server
D:\classweb\server>
D:\classweb\server>cnpm install
这样就生成了服务端目录和项目文件,并安装了依赖项
注:cnpm install
z.1 解析当前项目中的package.json中依赖项,并将这些依赖项(如果还没下载到本目录)下载到当前目录的node_modules中;
z.2 其实出了node_modules中的大量下载的库文件,其他文件夹里才是项目文件,没几个文件;
z.3 如果你的项目移动了目录,node_modules中的内容将过期,这时候删除该目录,重新执行cnpm install即可
3 启动服务端
D:\classweb\server>npm start
浏览器打开:http://localhost:3000/
以后每次要在命令行操作服务端目录,都要先停掉服务端服务(按两次Ctrl+C),再执行控制台命令
4 安装MongoDB并启动
见本人写的另一篇文章:https://blog.csdn.net/calmreason/article/details/82683912
4.0 Robo 3T客户端连接MongoDB服务
Robo 3 使用简明教程:https://www.cnblogs.com/dacongge/p/7346037.html
4.1 创建MongoDB数据库表数据
创建数据库:Create DataBase
Database Name:classweb
Create Collection:user
添加一条用户数据:
{
"_id" : ObjectId("5b988192469dc3ff0faa6dd2"),
"name" : "admin",
"phone" : "888",
"password" : "4QrcOUm6Wau+VuBX8g+IPg=="
}
4.2 服务端连接MongoDB
停止Node端服务,安装mongodb
D:\classweb\server>cnpm install mongodb@2.2.33 --save
5 安装express-session
停止服务端Node端服务
D:\classweb\server>cnpm install express-session --save
6 服务端访问MongoDB:dbhandler.js
先在routes中创建dbhandler.js文件,写入下面我们封装好的mongodb操作方法。
文件内容如下:
var mongo=require("mongodb");
var MongoClient = mongo.MongoClient;
var assert = require('assert');
var url = require('url');
var host="localhost";
var port="27017";
var Urls = 'mongodb://localhost:27017/classweb';
// classweb ===> 自动创建一个
//add一条数据
var add = function(db,collections,selector,fn){
var collection = db.collection(collections);
collection.insertMany([selector],function(err,result){
try{
assert.equal(err,null)
}catch(e){
console.log(e);
result = [];
};
fn(result);
db.close();
});
}
//delete
var deletes = function(db,collections,selector,fn){
var collection = db.collection(collections);
collection.deleteOne(selector,function(err,result){
try{
assert.equal(err,null);
assert.notStrictEqual(0,result.result.n);
}catch(e){
console.log(e);
result.result = "";
};
fn( result.result ? [result.result] : []); //如果没报错且返回数据不是0,那么表示操作成功。
db.close;
});
};
//find
var find = function(db,collections,selector,fn){
//collections="hashtable";
var collection = db.collection(collections);
collection.find(selector).toArray(function(err,result){
//console.log(docs);
try{
assert.equal(err,null);
}catch(e){
console.log(e);
result = [];
}
fn(result);
db.close();
});
}
//update
var updates = function(db,collections,selector,fn){
var collection = db.collection(collections);
collection.updateOne(selector[0],selector[1],function(err,result){
try{
assert.equal(err,null);
assert.notStrictEqual(0,result.result.n);
}catch(e){
console.log(e);
result.result = "";
};
fn( result.result ? [result.result] : []); //如果没报错且返回数据不是0,那么表示操作成功。
db.close();
});
}
var methodType = {
// 项目所需
login:find,
// type ---> 不放在服务器上面
// 放入到服务器
// 请求---> 根据传入进来的请求 数据库操作
// req.query req.body
show:find, //后台部分
add:add,
update:updates,
delete:deletes,
updatePwd:updates,
//portal部分
showCourse:find,
register:add
};
//主逻辑 服务器 , 请求 --》
// req.route.path ==》 防止前端的请求 直接操作你的数据库
module.exports = function(req,res,collections,selector,fn){
MongoClient.connect(Urls, function(err, db) {
assert.equal(null, err);
console.log("Connected correctly to server");
// 根据 请求的地址来确定是什么操作 (为了安全,避免前端直接通过请求url操作数据库)
methodType[req.route.path.substr(1)](db,collections,selector,fn);
db.close();
});
};
7 修改users.js
var express = require('express');
var router = express.Router();
var handler = require('./dbhandler.js');
var crypto = require('crypto');
/* POST users listing. */
//登录
router.post('/login', function(req, res, next) {
var md5 = crypto.createHash('md5');
var password = md5.update(req.body.password).digest('base64');
handler(req, res, "user", {name: req.body.username},function(data){
if(data.length===0){
res.end('{"err":"抱歉,系统中并无该用户,如有需要,请向管理员申请"}');
}else if(data[0].password !== password){
res.end('{"err":"密码不正确"}');
}else if(data.length!==0&&data[0].password===password){
req.session.username = req.body.username; //存session
req.session.password = password;
res.end('{"success":"true"}');
}
});
});
module.exports = router;
8 修改app.js
支持跨域访问
这样请求的代码就写完了,但是跨域请求 需要在node中也作配置才可以请求到
修改app.js,在11行左右找到 var app= express(),在其后面添加如下代码
第二段代码是服务器端存session的,直接使用express-session模块(后面会带着大家安装),然后添加配置项即可(配置项的说明在备注中)
//跨域 后期删
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "http://localhost:8080"); //为了跨域保持session,所以指定地址,不能用*
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header('Access-Control-Allow-Headers', 'Content-Type');
res.header('Access-Control-Allow-Credentials', true);
next();
});
//session
var session=require('express-session');
app.use(session({
secret:'classweb531234', //设置 session 签名
name:'classweb',
cookie:{maxAge:60*1000*60*24}, // 储存的时间 24小时
resave:false, // 每次请求都重新设置session
saveUninitialized:true
}));
重启服务端Node
二、客户端
1 vue-cli安装
这里注意,我们最好是另外开一个命令行 来执行,因为开发时前面的Node项目和vue项目要同时运行
先全局安装vue-cli
D:\classweb>cnpm install -g vue-cli
2 创建 vue项目
D:\classweb>vue init webpack vueclient
控制台安装过程中下面三个选择:N
? Use ESLint to lint your code? No
? Set up unit tests No
? Setup e2e tests with Nightwatch? No
3 启动Vue项目
D:\classweb>cd vueclient
D:\classweb\vueclient>npm run dev
浏览器打开:http://localhost:8080/
4 实现登录功能
使用Sublime打开文件夹:D:\classweb\vueclient
修改:D:\classweb\vueclient\src\App.vue的内容 这是项目的入口页面
4.1 创建登录login.vue文件
注:此时你还可以先了解一下原始的.vue文件的作用和组织方式 http://www.php.cn/js-tutorial-384094.html
你可以理解为一个.vue文件是一个完整的组件,这个组件里包括了原来三个文件(HTML、js、CSS)中的内容。当然这个文件不是浏览器认识的,需要vue-cli安装vue-loader插件解析之后才能使用的,当然这些都被自动处理了。
<template>
<div class="backlogin">
<div class="login_box">
<div class="title">后台登录</div>
<div>
<input class="myinput" type="text" placeholder="手机号/用户名" v-model="username" />
</div>
<div>
<input @keyup.13="login" class="myinput" type="password" placeholder="口令" v-model="password" />
</div>
<div class="login_other">
<a href="javascript:;">找回密码</a>
<input type="checkbox" id="remenberme" /><label for="remenberme">记住我</label>
</div>
<button :disabled="disablebtn" class="login" @click="login">{{loginText}}</button>
</div>
</div>
</template>
<script>
export default {
name: 'backlogin',
data () {
return {
username:"admin",/*TODO:先预存测试值,以免手动输入*/
password:"123456",
disablebtn:false,
loginText:"登录"
}
},
methods:{
login(){
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.header{
height: 60px;
box-shadow: 0 1px 5px rgba(13,62,73,0.2) ;
}
.header img{
width: 170px;
margin-top: 12px;
margin-left: 15px;
float: left;
}
.header span{
float: left;
color: #566a80;
margin: 21px 0 0 20px;
}
.login_box{
width: 320px;
margin: 50px auto;
}
.login_box .myinput{
width: 100%;
border: 1px solid #cad3de;
height: 40px;
line-height: 40px;
margin: 5px 0 10px;
border-radius: 3px;
padding: 0 10px;
outline: none;
box-sizing: border-box;
}
.login_box .myinput:focus{
border: 1px solid #4289dc;
}
.login_other{
overflow: hidden;
}
.login_other a{
float: right;
color: #727f8f;
}
.login_other a:hover{
color: #273444;
}
.login_other input, .login_other label{
float: left;
color: #727f8f;
}
.login_other input{
margin: 4px 5px 0 0;
}
.login{
box-sizing: border-box;
border: none 0;
height: 44px;
line-height: 44px;
width: 100%;
background:#4187db;
font-size: 16px;
border-radius: 3px;
margin-right: 40px;
transition: all 0.5s ease;
cursor: pointer;
outline: none;
color: #fff;
margin-top: 15px;
}
.login:hover{
background: #2668b5;
}
.login[disabled]{
opacity: 0.8;
}
.login[disabled]:hover{
background:#4187db;
}
.title{
color: #273444;
font-size: 1.5em;
text-align: center;
margin: 0 0 20px 0;
}
@media only screen and (max-width: 768px) {
.login_box{
width: 280px;
margin: 50px auto;
}
}
</style>
关于export default的介绍参考:https://www.cnblogs.com/xiaotanke/p/7448383.html
4.2 引用login.vue文件
然后修改router文件夹下的index.js文件来配置首页访问的组件是login.vue (这里获取组件的时候 @表示src文件夹路径 所有vue文件的引入都不需要vue后缀,import后的赋值最好统一给大写)。
此时,可以看到浏览器页面内容自动刷新了
4.3 客户端ajax请求
vue中请求数据,这里我们使用第三方库axios,这也是vue作者推荐的,比自带的http好用很多。
先安装axios
把原来的服务ctrl+c两次停掉,然后 运行 cnpm install axios --save 安装,安装完成再重新启动服务。
注:这里为什么要用 --save呢,因为使用save的话,这个包就会集成到package.json中的,我们上线的时候就能通过npm install去直接安装了。
D:\classweb\vueclient>cnpm install axios --save
D:\classweb\vueclient>npm run dev
此时的package.json中就有了axios的引用了
4.4 跨域请求
然后我们在main.js中添加如下代码 引入axios,并配置基础路径(因为是跨域请求node端,所以所有请求前面都需要添加node端的基础地址,以后打包上线的时候需要合并的时候再把这个地址删掉),文件位置和修改后的代码如下图
由于是跨域请求,我们需要配置withCredentials为true,这样避免每次都被识别为新的请求。
说明:在vue中,可以使用代理去实现跨域,但是每次新地址都需要配置,还是比较麻烦,这里我们采用直接配置跨域,一次配置就可以一劳永逸。
import axios from 'axios';//引入axios组件
axios.defaults.withCredentials=true; //跨域保存session有用
axios.defaults.baseURL = "http://localhost:3000"; //打包的时候直接删掉,默认基础路径在这里配置
//将 axios 赋值给 Vue,方便在子组件里面使用
Vue.prototype.$reqs = axios;
此时登录并没有任何反应,因为还没实现login()函数
4.5 登录请求的实现
在Login.vue中实现login()函数
login(){
var _this = this;
this.disablebtn = true;
this.loginText = "登录中...";
//this.$reqs就访问到了main.js中绑定的axios
this.$reqs.post("/users/login",{
username:this.username,
password:this.password
}).then(function(result){
//成功
console.log(result)
_this.disablebtn = false;
_this.loginText = "登录";
}).catch(function (error) {
//失败
_this.disablebtn = false;
_this.loginText = "登录"
});
}
此时再次点击登录(已经自动刷新)F12即可看到登录成功的返回值:
本文全文参考了:https://www.cnblogs.com/chengduxiaoc/p/7718768.html
之所以重写一遍是因为自己私下里走了两三遍,为的就是让自己熟悉开发环境。同时对参考的博客有些不必要的截图给予省略,命令行和代码用不同的背景严格区分,使得更易阅读。
更多推荐
所有评论(0)