Javascript

一款基于React、C++,使用TCP/HTTP协议的多人聊天室小应用

本文主要是介绍一款基于React、C++,使用TCP/HTTP协议的多人聊天室小应用,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

1. 前言

最近和后端同学I’M渣渣一起完成了一个Demo级的多人聊天室应用,实现了聊天室的基本功能。

采用前后端分离方案,我负责前端代码的编写,I’M渣渣实现了后端的接口。

预览地址:多人聊天室

源码仓库:[GitHub]


2. 应用简介

主要功能

  1. 用户注册
  2. 用户登录
  3. 发送、接收消息
  4. 退出功能

主要用到的技术

前端:

  1. React脚手架Create-React-App
  2. 状态管理redux + react-redux
  3. 前端路由 React-Router、路由鉴权
  4. 少量使用 AntD 组件库 (Icon 图标、Notification 通知提醒框、Message 全局提示)

这里仅记录了前端的相关技术,后端基于TCP/HTTP协议,采用C/C++实现,详细请查看I’M渣渣。

3. 主要功能实现

1. 路由鉴权

将用户的登录状态放入redux,默认为false未登录。

App组件挂载时,判断用户登录状态,若已经登录,则直接跳转到聊天室页面;若未登录,则跳转到注册/登录页面,让用户登录。

<Switch>
{this.props.loginState ? (
    <Fragment>
        <Route path="/room" component={Room} />
        <Redirect to="/room" />
    </Fragment>
) : (
    <Fragment>
        <Route path="/welcome" component={Welcome} />
        <Redirect to="/welcome" />
    </Fragment>
)}
</Switch>

2. 用户注册

需要验证用户填写的用户名、密码是否符合规范,若不符合规范给出提示并直接return,若符合规范才发送注册请求给服务器。

// 点击按钮,登录
register = () => {
    // 数字字母组合,字母开头
    const unameReg = /^[a-zA-Z][a-zA-Z0-9]{2,9}$/;
    const uname = this.uname.value;
    const pwd = this.pwd.value;
    const pwdAgian = this.pwdAgian.value;
    // 判断用户名是否符合规则
    if (!unameReg.test(uname)) {
        this.openUnameError();
        return;
    }
    // 判断密码长度
    if (!(pwd.length >= 6 && pwd.length <= 16)) {
        this.openPwdError();
        return;
    }
    // 判断两次输入的密码是否一致
    if (pwd !== pwdAgian) {
        this.openPwdUnEqual();
        return;
    }
    // 调用接口,发送注册请求
    const url = `${constUrl}/register`;
    axios({
        method: 'get',
        url,
        params: {
            name: uname,
            pwd,
        },
    })
        .then(res => {
            // 注册成功
            if (res.data.register === 0) {
                this.openRegisterSuccess();
                this.uname.value = '';
                this.pwd.value = '';
                this.pwdAgian.value = '';
                // 跳转到登录页
                this.props.history.replace(`/welcome/login`);
            } else {
                // 注册失败,打开相应的提示框
                switch (res.data.error) {
                    case 0: {
                        this.openUnameReuse();
                        return;
                    }
                    default: {
                        this.openOtherError();
                        return;
                    }
                }
            }
        })
        .catch(err => console.error(err));
};

3. 用户登录

登录功能没什么好说的,收集参数并发送请求就可以了,若登录成功,则给出提示,并更改redux中的登录状态为true,页面自动会跳转到聊天室页面。若登陆失败,则根据服务器返回的数据,给出相应提示。

login = async () => {
    const url = `${constUrl}/login`;
    const name = this.inputUname.value;
    const pwd = this.inputPwd.value;
    axios({
        method: 'get',
        url,
        params: {
            name,
            pwd,
        },
    })
        .then(res => {
            if (res.data.login === 0) {
                this.props.login(name);
                this.openLoginSuccess();
                return;
            }
            switch (res.data.error) {
                case 0: {
                    this.openUnameNotFound();
                    this.props.logout();
                    return;
                }
                case 1: {
                    this.openPwdError();
                    this.props.logout();
                    return;
                }
                case 2: {
                    this.openOtherError();
                    this.props.logout();
                    return;
                }
                default:
                    return;
            }
        })
        .catch(err => console.error(err));

4. 接收消息

接受消息功能,同样也是向服务器发送请求,获得所需消息,并展示在页面上。

这里需要将展示聊天记录容器的滚动条自动调整到底部,详情见JavaScript 实现容器滚动条默认出现在底部位置。

由于发送一次接收消息的请求,只能得到一次消息,所以我在componentDidMount()生命周期函数中,开启了一个定时器,每隔1秒就发送一次请求,获得所有消息,展示到页面上。由于React的diff算法,即使没有新的消息,频繁地发送请求,也不会有浪费太多性能。记得在componentWillUnmount()中,清除定时器。

componentDidMount() {
    this.getMsg();
    this.msgUpdate = setInterval(() => {
        this.getMsg();
    }, 1000);
}
componentWillUnmount() {
    // 清除定时器
    clearInterval(this.msgUpdate);
}
// 获取所需消息
getMsg = () => {
    const url = `${constUrl}/information`;
    const name = this.props.name;
    axios({
        method: 'get',
        url,
        params: { name },
        // responseType: 'blob',
    })
        .then(res => {
            console.log(res);
            // 获取人数
            const userCount = res.data.userCount;
            this.setState({ userCount });
            // 获取新数据
            const newMsg = res.data.msg;
            // 获取原数据
            const oldMsg = this.state.msg;
            if (res.data.information === 0) {
                this.setState({ msg: [...oldMsg, ...newMsg] }, () => {
                    // 滚动条自动到底部
                    this.messageBox.scrollTop = this.messageBox.scrollHeight;
                });
            }
        })
        .catch(err => console.error(err));
};

5. 发送消息

发送请求之前,先判断输入框是否为空。不为空,再进行下一步,发送请求。

成功发送消息后,调用一次接收消息函数,获得所有消息,即可将刚刚发送的消息立即展示到页面。

   // 发送消息
   sendMsg = () => {
    const msg = this.editMsg.value;
    const name = this.props.name;
    if (msg === '') {
        message.warning('请输入消息!');
        return;
    }
    const url = `${constUrl}/information`;
    axios({
        method: 'post',
        url,
        params: {
            msg,
            name,
            time: new Date().getTime(),
            id: nanoid(),
        },
    })
        .then(res => {
            // console.log(res);
            if (res.data.msg === 0) {
                this.editMsg.value = '';
                message.success('发送成功!');
                // 调用获取所有消息函数
                this.getMsg();
            }
        })
        .catch(err => console.error(err));

6. 退出功能

退出时,发送请求给服务器,告诉服务器有用户退出了、哪个用户退出了,主要用于展示当前在线人数。

redux中的登录状态改为false,页面自动跳转到注册/登录页面。

logout = () => {
    const url = `${constUrl}/logout`;
    const name = this.props.name;
    axios({
        method: 'get',
        url,
        params: {
            name,
        },
    });
    this.openLogout();
    this.props.logout();
};

4. Todo

由于本人能力有限,本Demo还有一些BUG没有解决:

  1. 当前在数人数显示模块没有正常工作,若用户不点击退出按钮,直接关闭浏览器页面,没有监听到用户的退出动作。
  2. 接收到的消息中,空格?=#等字符会显示其编码,无法正常显示。

将来可能添加的功能:

  1. 采用token验证用户身份

  2. 自定义背景图片切换

  3. 支持黑暗模式

  4. 适配移动端

  5. 支持上传头像

  6. 支持发送图片

这篇关于一款基于React、C++,使用TCP/HTTP协议的多人聊天室小应用的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!