本期主要内容
1.用户登录实践
2.webSocket
3.网页版聊天室的构建
1.学子问答--用户登录实践
• xzqa_author数据表结构

• 用户登录的实现
第一步:修改 src/views/Login.vue ,完成当用户单击按钮时实现登录的业务
示例代码如下:
methods: {
login() {
if (this.checkUsername() && this.checkPassword()) {
this.axios.post('/login').then(res=>{
//
});
}
}
}
以上代码存在两个问题:
第一:在发送 POST 请求时,没有将用户名和密码信息提交到 WEB 服务器 此时,上述代码修改如下:
methods: {
login() {
if (this.checkUsername() && this.checkPassword()) {
this.axios.post('/login','username=' + this.username + '&password=' + this.password).then(res=>{
//
});
}
}
}
此时运行的结果如下图所示:

第二:在 WEB 服务器上不存在对应的API路由
修改WEB服务器的app.js添加相关的路由,并且完成用户登录的业务逻辑,操作过程如下:
A.添加 POST 类型的 API ,名称为 /login ,示例代码如下:
// 用户登录的API
server.post('/login',(req,res)=>{
//获取提交的用户名和密码并且以此为条件进行查找操作
});
B.因为 AJAX 请求为 POST 类型,那么必须通过 body-parser 中间件来获取 POST 提交的数据,那么也就意味着:
- 安装 body-parser 中间件
npm install --save body-parser
- 加载并且使用 body-parser 模块
//加载body-parser模块
const bodyParser = require('body-parser');
//创建Express应用
const server = express();
//使用body-parser中间件
server.use(bodyParser.urlencoded({
extended:false
}));
C.以获取到的用户名和密码信息进行用户的查找操作,代码如下:
// 用户登录的API
server.post('/login',(req,res)=>{
//获取提交的用户名和密码
let username = req.body.username;
let password = req.body.password;
//并且以此为条件进行查找操作
let sql = 'SELECT id,username FROM xzqa_author WHERE username=? AND password=MD5(?)';
pool.query(sql,[username,password],(err,results)=>{
if(err) throw err;
if(results.length == 0){
res.send({message:'登录失败',code:0});
}
if(results.length == 1){
//后续要调整
res.send({message:'登录成功',code:1});
}
});
});
D.在 Vue 客户端接收服务器响应信息,并且根据响应信息显示不同的提示内容,示例代码如下:
login() {
if (this.checkUsername() && this.checkPassword()) {
this.axios.post('/login','username=' + this.username +'&password=' + this.password).then(res=>{
if(res.data.code == 0){
//Mint UI消息提示框
this.$messagebox('登录失败');
}
if(res.data.code == 1){
this.$router.push('/');
}
});
}
}
• 登录状态的保持
当用户成功登录后,将影响到首页的导航的变化,其实也应该去影响其它页面的变化。也就需要将用户登录的状态保存到 Vuex 中,所以在 src/store/index.js中修改如下:
state: {
//标识用户是否登录
isLogined:false
}
当存在以上代码之后,就可以在src/views/Home.vue中进行用户是否登录的判断了,如果已登录,则显示"注销",否则显示"登录"及"免费注册"的信息。示例代码如下:
<!-- 顶部导航开始 -->
<mt-header title="学前端,到学问">
<!-- 没有登录 -->
<div slot="right" class="shortcut" v-if="!$store.state.isLogined">
<router-link to="/register">免费注册</router-link>
<router-link to="/login">登录</router-link>
</div>
<!-- 已登录 -->
<div slot="right" v-else>
<router-link to="/">
<mt-button>
<img src="../assets/images/logout.png" slot="icon">
</mt-button>
</router-link>
</div>
</mt-header>
<!-- 顶部导航结束 -->
但是用户登录成功后,顶部导航没有发生任何改变,原因是:没有改变state的状态,所以第一步:在 Vuex 中定义修改 isLogined 状态的 mutations
mutations: {
logined_mutations:(state)=>{
//将用户登录状态改为真
state.isLogined = true;
}
}
第二步:在用户登录成功后,调用 mutations 以修改状态
在 src/views/Login.vue 调用 mutations 中的相关方法,示例代码如下:
login() {
if (this.checkUsername() && this.checkPassword()) {
this.axios.post('/login','username=' + this.username +'&password=' + this.password).then(res=>{
if(res.data.code == 0){
//Mint UI消息提示框
this.$messagebox('登录失败');
}
if(res.data.code == 1){
//调用Vuex中的Mutations
this.$store.commit('logined_mutations');
this.$router.push('/');
}
});
}
}
-- MySQL中更新记录
UPDATE 数据表名称 SET 字段名称 = 值[,字段名称 = 值,....] [WHERE 条件表达式]
-- 如,更新xzqa_author表中ID为15的记录,password字段值为 MD5(12345678)
UPDATE xzqa_author SET password=MD5('12345678') WHERE id=15;
现在可以通过正常的登录来实现首页顶部导航状态的变化了,但是既使已登录的情况,只要重新刷新页面,登录状态消失了--只要刷新,页面将重新加载!所以应该将用户登录的状态进行保持 --WebStorage ,故:
第一步:当用户成功登录时,不仅要修改state中的状态还要将相关的信息写入到webstorage 中,示例代码如下:
if(res.data.code == 1){
//将用户登录的状态保存到webStorage中
sessionStorage.setItem('isLogined',true);
//修改Vuex中的state
this.$store.commit('logined_mutations');
this.$router.push('/');
}
第二步:当登录成功后,再次刷新页面,仍然出现状态丢失的情况--Vuex中的state的初始值应该从 webStorage 中获取,如果获取不得到的话,则是 false
state: {
//标识用户是否登录
isLogined:sessionStorage.getItem('isLogined') ? sessionStorage.getItem('isLogined') : false
}
第三步:经过上述代码,既使再刷新也可以保存用户登录状态了,但是无法实现"注销"操作,所示:
A、在 Vuex 中创建 Mutations 用于实现修改 state 中的状态,同时清理掉webStorage
logout_mutations:(state)=>{
//将用户登录状态改为真
state.isLogined = false;
//清理掉webStroage
localStorage.clear();
}
B、单击"注销"按钮时,调用 Mutations
<div slot="right" v-else>
<mt-button @click="logout">
<img src="../assets/images/logout.png" slot="icon">
</mt-button>
</div>
<script>
export default{
methods: {
logout(){
this.$store.commit('logout_mutations');
}
}
}
</script>
2.webSocket
2.1 什么是WebSocket、socket.io ?
WebSocket 是一个网络通信协议,其最大特点是:服务器可以主动向客户端推送消息,客户端也可以向服务器主动发送消息,是一种真正的平等的双向对话。
WebSocket 协议于 2008 年诞生, 2011 年成为国际标准。
Socket.io 是一个为浏览器与WEB服务器之间提供实时、双向和基于事件的软件通信库。其内部对websocket 进行了封装,抹平了一些技术细节和平台的兼容性。
socket.io 包括:
1.Node.js 服务器
2.浏览器-- JavaScript 客户端
2.2 WebSocket的优点
A.没有同源限制,客户端可以与任何服务器通信
B.数据格式比较轻量,通信高效
C. websocket 协议的前缀是 ws ,如果加密的话,则为 wss
2.3 安装 socket.io
2.3.1 服务器端
npm install --save socket.io
2.3.2 浏览器端
A.下载 Socket.io 的 JavaScript的客户端库文件--cdn.jsdelivr.net/npm/socket.…
B.直接在网页文件中通过<script>标签引用外部的 JS 文件
2.4 API
2.4.1 服务器端
• on() 方法
on() 方法用于根据指定的事件来注册一个函数(侦听到指定的事件后,执行相的业务),语法结构是:
client.on('事件名称',callback)
• emit() 方法
emit() 方法用于实现服务器端向客户端广播事件,其语法结构是:
server.emit('事件名称'[,数据])
2.4.2 浏览器端
• emit() 方法
emit() 方法用于实现客户端向服务器端广播事件,其语法结构是:
client.emit('事件名称'[,数据])
事件名称为自定义的事件名称,与 JS 中的事件没有任何关系
• on() 方法
on() 方法用于根据指定的事件来注册一个函数(侦听到指定的事件后,执行相关的业务),语法结构是:
client.on('事件名称',callback)
3.网页版聊天室的构建
• 服务器的基本配置
//构建基础的HTTP服务器
const app = require('http').createServer();
//创建Socket.io服务器
const server = require('socket.io')(app);
//指定监听端口
app.listen(5000,()=>{
console.log('server running...');
});
##• 浏览器端的基本配置
chart.html 中示例代码如下:
<script src="scripts/socket.io.js"></script>
<script>
//创建socket.io的客户端
let client = io('ws://127.0.0.1:5000');
</script>
当在网页文件中引入 socket.io.js 后将自动暴露名称为 io 的函数
ws 为 websocket 协议的前缀