前言
我是一个大一的学生,参加学校工作室的考核,学习了一点flask的相关知识,这个聊天室只有两个页面,前段用的也是简单的js原生代码进行的一些dom操作
一、直接使用
想直接跑的可以自取
https://github.com/cgynb/a-flask-project/tree/chat
首先你需要配置一个虚拟环境,并且激活,不会的话,可以百度谷歌必应[doge]
然后安装第三方库
pip install -r package.txt
在命令行输入
python app.py
二、步骤
1.需要的东西
2.后端代码
引入
引入flask的一些东西,然后引入flask-socketio的SocketIO
from flask import Flask, render_template, request, session, redirect, url_for
from flask_socketio import SocketIO
app = Flask(__name__)
app.config['SECRET_KEY'] = 'jjj'
socketio = SocketIO()
socketio.init_app(app)
一些初始化
设置秘钥,然后给SocketIO绑定app
app = Flask(__name__)
app.config['SECRET_KEY'] = 'jjj'
socketio = SocketIO()
socketio.init_app(app)
视图函数
三个视图函数,首页,聊天,退出
首页
如果是get访问的话,判断会话中是否有’username’,如果有重定向到聊天界面,如果没有,则渲染首页
用post访问的话,获取表单,设置会话,然后重定向到聊天界面
@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'GET':
if 'username' in session:
return redirect(url_for('chat'))
return render_template('index.html')
else:
username = request.form.get('username')
session['username'] = username
return redirect(url_for('chat'))
聊天
判断会话中是否有’username’,如果与渲染聊天界面,并传入username,如果没有,重定向到首页
@app.route('/chat/')
def chat():
if 'username' in session:
username = session['username']
return render_template('chat.html', username=username)
else:
return redirect(url_for('index'))
退出登录
退出登录,就是删除会话
@app.route('/logout/')
def logout():
if 'username' in session:
session.clear()
return redirect(url_for('index'))
前段代码
页面效果不是重点,可以看看materialize的文档,简单看看就可以做到初步上手了,也可以到置顶的github仓库下载
主要是js的代码,即对于socketio的使用
index
这边的用的计时器方法的目的是,让用户输入昵称,如果不输入,按钮是不可点击的,所以每0.3秒判断一次
让按钮不可点击,是通过materialize的一个类disabled来控制的,所以添加或者删除类即可
let inp = document.querySelector('#icon_prefix');
let btn = document.querySelector('#submit');
setInterval(function () {
if(inp.value){
btn.classList.remove('disabled');
}else{
if(!btn.classList.contains('disabled')){
btn.classList.add('disabled');
}
}
}, 300);
chat
这边从用户连接,发送信息来讲
用户连接、断开连接
let socket= io();
socket.connect(location.protocol + '//' + document.domain + ':' + location.port);
取消连接,即关闭浏览器等,不用再来定义,如果想进行操作触发,可以用socket.disconnect()绑定事件
那么服务器怎么知道客户端连接上了呢?
所以在python代码中 我们要写监听函数
# 连接
@socketio.on('connect')
def handle_connect():
username = session.get('username')
print('*' * 20, f'{username} connect', '*' * 20)
socketio.emit('connect info', f'{username} connect')
这三行代码,1.从会话中得到昵称,2.打印连接信息,3.发送一个字符串到’connect info’,这个在前段会被接收,然后在页面上显示,之后会有提及
# 断开连接
@socketio.on('disconnect')
def handle_disconnect():
username = session.get('username')
print('*' * 20, f'{username} disconnect', '*' * 20)
socketio.emit('connect info', f'{username} disconnect')
断开连接跟连接是基本一致的
在前端的接收连接信息的监听函数如下,参数data就是传入的那个字符串,然后传建一个div元素,命名为connectInfo,在这个div中插入msg这段html,最后在聊天的区域(命名为messageBox)加入connectInfo
// 连接的信息
socket.on('connect info', function (data) {
console.log(data)
let connectInfo = document.createElement('div')
connectInfo.className = 'row'
let msg = `
<div class="col s4 offset-s4">
<div class="connect-info grey lighten-4 center" >
<span class="black-text">${data}
</span>
</div>
</div>`
connectInfo.innerHTML = msg
messageBox.appendChild(connectInfo)
})
这样在前端的效果就是
发送信息
给发送按钮绑定点击事件,获取到输入框中的信息,获取用户名,然后删除输入框的信息,最后用socket.emit()发送json数据(数据中有用户昵称,信息内容)到服务器,如果获取到输入框的信息是空,则弹出框
// 发送消息
sendMsgBtn.onclick = function () {
let msg = inp.value
let user = document.querySelector('#username').innerHTML
inp.value = ''
if(msg){
socket.emit('send msg', {
user: user,
message: msg
})
}else {
alert('消息不能为空')
}
}
这边有一个优化使用的操作,就是给回车按键绑定点击事件
// 回车发送消息
inp.addEventListener("keyup", function(event) {
event.preventDefault();
if (event.keyCode === 13) {
sendMsgBtn.click();
}
});
服务器接收发送的消息,data就是前端发送过来的json数据,然后使用socket.emit()发送到前段
@socketio.on('send msg')
def handle_message(data):
print('sendMsg' + str(data))
socketio.emit('send msg', data)
前段接收服务器发送来的信息
插入聊天信息操作跟上面接收连接信息是基本一致的,这里面有加一个判断,即信息是否是自己发送的
// 接受消息
socket.on('send msg', function (data) {
console.log(data)
let msg = null
let msgbox = document.createElement('div')
msgbox.className = 'row'
if (data.user === document.querySelector('#username').innerHTML) {
msg = `
<div class="col right">
<div class="tag teal z-depth-3" >
<span class="white-text">${data.message}
</span>
</div>
</div>`
} else {
msg = `
<div class="col">
<div class="tag z-depth-3">
<span class="teal-text"><b>${data.user}</b>: ${data.message}
</span>
</div>
</div>`
}
msgbox.innerHTML = msg
messageBox.appendChild(msgbox)
})