这是一个我开发了一周的php大作业,其中接触到了很多新的知识,编码过程中也力求规范,在界面美化上也下足了功夫,作为前端语言以及php的入门开发很合适,所以把具体的实现思想分享给需要的人。

对此项目使用NodeJs做了改版,详情看:https://blog.csdn.net/qq_42748385/article/details/108986268

需求分析及涉及功能:

1) 创建聊天室(模态窗口实现)
输入聊天室名称及有效期,有效期过后,聊天室自动删除。
设置每个聊天室的人数上限。
设置每个用户限加入的聊天室数量。

2) 聊天
随机分配昵称,但不允许同名,有昵称随机动画。
随时显示聊天室的剩余时间,js实现。
ajax实现消息从数据库的获取。
消息输入框使用富文本编辑器ueditor。
退出按钮,点击后退出聊天室。

表结构:

在数据库中一共用到了四个表,用户表、房间表、角色表、以及消息表。其中角色表和消息表的房间id参照房间表,使得删除房间时级联删除角色和消息。但要注意数据库引擎使用支持外键的innodb,对于其他引擎,可以使用触发器。

用户表users

房间表room

用户角色表role

消息表msg

系统简介:

匿名聊天系统支持多个用户登录, 用户登录后进入大厅界面,首页index.html如下

用户随意输入账号,按回车登录,下为聊天室大厅room.php

房间界面分为两个模块,第一个模块是已经加入的聊天室,根据用户账号检索角色表,获得加入的房间id,并在页面中以块(图片廓)的形式显示出来,用户进入时使用之前的身份。第二个模块是对房间表所有房间的查询,并使用count统计每个房间已经加入的人数,如果房间已加入的人数超过6人,房间将不可进入,样式变成灰色点击无反应。

当一个账号加入的房间超过6个时会弹出

右上方有创建房间功能和退出功能,退出即退出当前账号回到主界面。当点击创建房间时,将弹出一个模态窗口,如下

并使用蒙版使背景变灰,在这里输入的房间名不能超过5个字,房间存在时间不能小于1分钟,输入完成且正确将在数据库中插入一条包含销毁时间的数据,这个销毁时间由函数date_add()实现,即把分钟累加在当前时间上,这样做的好处是,在房间过期时,只需要一条delete between 过去某个时间 and当前时间的数据库语句即可完成。

用户可以点击任何一个房间并进入聊天室界面chats.php,如果 此用户是第一次到此房间将动态随机分配一个昵称(保证不重复),然后在上方提示你在本房间的昵称,如下

聊天界面的布局类似于qq中的聊天框,不同的地方在于右上角动态显示房间的剩余时间,当时间到期时,将自动退出并提示房间已销毁。

聊天窗口的消息的获取使用ajax异步无刷新的技术,每秒调用一次函数获取数据库中的消息,无需刷新页面。对于聊天框中溢出的消息,将出现滚动条,这里有一个细节是,每次获取消息会判断滚动条的位置,如果位置不在最下方,说明在看之前的消息,那么新消息来时,滚动条位置不变;否则,说明在等新消息,滚动条滚至最下方,即弹出最新消息。当发送的文字超过最大宽度的60%时,会自动换行。

消息的样式使用气泡包围,并区分是否为本人发送动态改变浮动方向,输入框使用富文本编辑器,精简后只保留发送表情功能。按钮是3D的按钮,使用hover伪类,当用户点击时,将获取输入框中的信息,并置空,利用另一个php文件插入消息到数据库。

用户可以随时退出房间(此处退出是失去角色退出,如果不想失去角色身份可以使用浏览器自带的回退),当用户重新进入此房间时将获得新的身份。退出房间按钮我采用了独特的方式,是点击左下角的门,当触碰门的轮廓时光标改变,对于这个梯形的绘制也完全符合门的形状。

重要功能实现:

1.当房间加入的人数达到6人时,房间将变得不可点击。

这里使用css的选择器实现,我在打印每个房间时会给title属性赋值为房间已经加入的人数,这个人数由查询房间表和角色表时获得

<a title="<?php echo $rows['num']?>" href="chats.php?room_id=<?php echo $rows['room_id']?>&users_id=<?php echo $users_id;?>">

<img src="data:images/room.jpg" alt="图片">

<?php echo $rows['room_name'];?></a>

最后只需在style样式中设置

[title='6'] {

/*变得不可以点击*/

cursor: pointer;

pointer-events: none;

color: gray;

}

即可实现,后面的气泡浮动方向也是同样的方法。

2.模态窗口的实现

在设置页面时,已经绘制好了模态窗口的样式,只是将其display设置为不可见,点击创建房间时,调用js函数更改样式为block可见,遮罩层同理,设置的z-index低一些,代码如下

/*点击弹出按钮*/

function popBox() {

var pBox = document.getElementById("popBox");

var pLayer = document.getElementById("popLayer");

 pBox.style.display = "block";

        pLayer.style.display = "block";

}

/*点击关闭按钮*/

function closeBox() {

var pBox = document.getElementById("popBox");

var pLayer = document.getElementById("popLayer");

pBox.style.display = "none";

        pLayer.style.display = "none";

}

3.判断用户加入的房间是否超过6

在每次进入chats.php时,获取当前用户创建的角色数量,在这里使用mysql_num_rows函数获得返回的结果条数,如果大于6,则跳转界面,不再执行后续代码。

$role_num=mysql_num_rows(mysql_query($con,"SELECT * FROM role WHERE users_id='$users_id'"));

if($role_num>=6){

echo "<script language='javascript'>alert('加入的聊天室已达上限!');window.location.href='room.php?users_id=$users_id';</script>";

die();//不再执行后续代码

}

在这里我遇到一个问题,就是如果不加这个die函数,虽然弹出提示返回上一页面,但仍然在数据库中创建了一条插入房间的数据,这就说明window.location.hert和header函数跳转界面后,后续代码仍然执行,解决办法要么加个条件,要么使用die()或exit()函数。

4.如果是第一次加入房间,随机获得昵称并去重同名

在chats.php页面有一个昵称池,里面有预先定义好的325个昵称,在用户点击房间加入聊天室时,首先会判断是否第一次加入房间,如果是则使用$names[rand(0,325)],随机函数随机获取数组中的值。但在此之前需要获得该房间已经使用的昵称,即保证昵称不重复,代码如下

$exist_names=mysql_query($con,"SELECT role_name FROM role where room_id='$room_id'");

if(!mysql_num_rows($exist_names))//房间第一个加入

$role_name=$names[rand(0,325)];

else{//不重名验证

while($exist_name=mysql_fetch_assoc($exist_names))

$data[]=$exist_name['role_name'];

do{

$role_name=$names[rand(0,325)];

}

while(in_array($role_name,$data));//判断数组中是否存在,存在为真

}

mysql_query($con,"INSERT INTO role(role_name,users_id,room_id) VALUES('$role_name','$users_id',$room_id)");

$newUser='true';//新用户标志,后面随机效果的条件

这里面我把数据库查询的昵称转换为一个数组,这样只需要封装好的in_array函数就能判断是否重名。后面的newUser变量作用在后面是否执行获取昵称的随机动画。

5.获取昵称,随机动画的实现

这里的随机动画,其实真就是一个动画,就是展示给用户看的,昵称在页面加载的时候就已经确定好了。主要逻辑就是使用setInterval每隔0.1秒使用innerHTML更改标签的内容,循环20次后停止,使用clearInterval通过句柄暂停,然后延时0.2秒弹出提示窗口。

本来我是想直接在js中使用php的随机函数,但发现无论循环多少次随机值都是一个,这让我感到很诧异,后来突然想起来php代码是预加载的,就是页面还没渲染出来时随机数就已经执行了,对于后来的js来说php随机数函数就是一个确定了的字符串。所以后来改用js中的随机数,但在js与php代码的混合使用中又出现了问题,最后百度知道了要把php数组转化为json数组,js才能调用。这也让我知道了json在网页中扮演什么角色。

随机昵称函数代码如下:

var names = eval(<?php echo json_encode($names);?>); //转换php数组为json格式

function randRole() {

if (<?php echo $newUser;?> == true) {

var turn = 20; //循环次数

var intervar = setInterval(function() {

document.getElementById("rolename").innerHTML = names[Math.ceil(Math.random() * 325)];

if (!turn--) {

document.getElementById("rolename").innerHTML = '<?php echo $role_name?>';

setTimeout('alert("你在本聊天室的昵称为<?php echo $role_name?>,尽情畅聊吧!!");', 200);

clearInterval(intervar);

}

}, 100);

}

document.getElementById("rolename").innerHTML = '<?php echo $role_name?>';

}

6.动态显示剩余时间

这里注意时间显示函数的调用必须在页面加载完后,也就是id=“timeleft”定义之后。对于时间计算我在网上找到的现成的函数经过修改使用的,主要逻辑是获取当前房间的销毁时间然后减去当前时间得到的毫秒数换算而来,再通过setTimeout()函数,每秒运行一次时间换算函数,如果剩余秒数小于1则刷新界面,此时便会弹出“房间已销毁”的提示。个人感觉此函数的功能比较浪费系统资源,应该有更好的办法。

function TimeDown(endDateStr) {

var endDate = new Date(endDateStr);

var nowDate = new Date();

var totalSeconds = parseInt((endDate - nowDate) / 1000);

if (totalSeconds < 1) {

            location.reload();//刷新界面

        }

var days = Math.floor(totalSeconds / (60 * 60 * 24));

var modulo = totalSeconds % (60 * 60 * 24);

var hours = Math.floor(modulo / (60 * 60));

modulo = modulo % (60 * 60);

var minutes = Math.floor(modulo / 60);

var seconds = modulo % 60;

document.getElementById("timeleft").innerHTML = days + "天" + hours + "小时" + minutes + "分钟" + seconds + "秒";

setTimeout(function() {

TimeDown(endDateStr);

}, 1000)

}

7.富文本编辑器的引入

根据官方文档的指示,我需要在想要使用的页面先引入两个js文件,设置好路径。

<!-- 富文本编辑器 -->

<script type="text/javascript" src="edit/ueditor.config.js"></script>

<script type="text/javascript" src="edit/ueditor.all.js"></script>

然后在想插入的位置,实例化一个富文本编辑器

<script id="txtmsg" type="text/plain"></script>

<!-- 实例化富文本编辑器 -->

<script type="text/javascript">

var ue = UE.getEditor('txtmsg');

</script>

然后根据id修改富文本编辑器的样式。对于精简功能,根据官方文档的指示修改 ueditor.config.js 里面的 toolbars根据需要我只保留了表情包功能。这里面用到了几个api,有

if (UE.getEditor('txtmsg').hasContents()) { //判断是否有内容

strmsg = UE.getEditor('txtmsg').getContent(); //获取内容

UE.getEditor('txtmsg').setContent(''); //清空输入内容

}

因为要发送表情包,所以我使用getContent获取输入框全部内容,包括html标签,但出现的问题是这个编译器会自动给每一行前后套上一个<p>标签,导致我输出消息的时候上下都有换行,最后没办法我只好禁用了p标签的功能

P{display: inline;}最后还是有一些bug

8.ajax的使用

在这里ajax的主要作用体现在输出消息上面,他的无刷新是只刷新消息窗口,而不刷新整个界面。关键代码也就几行,

oxmlHttp = new XMLHttpRequest();

oxmlHttp.onreadystatechange = get_chat_msg_result;

oxmlHttp.open("GET", "chat_recv_ajax.php?room_id=<?php echo $room_id;?>", true);

oxmlHttp.send(null);

首先定义一个ajax请求,然后通过open建立ajax连接,send发送,因为是get请求所以发送null就行,如果是post请求send函数中就要规定发送的内容了。后台调用chat_recv_ajax.php,这个过程一共有四个状态,每次状态改变都调用get_chat_msg_result()函数,当状态为4或完成时渲染新的内容

if (oxmlHttp.readyState == 4 || oxmlHttp.readyState == "complete") {

var scrollDiv = document.getElementById("chatmsg");

…}

chat_recv_ajax.php文件中返回的查询结果

while($line=mysql_fetch_assoc($result)){

$msg=$msg."<li title=".$line['role_name'].">".

$line['role_name']." ".$line['msg_time'].

"<br><div class='msgbox'>".$line['msg_context'].

"</div></li>";

}

这整个过程是每秒执行一次,当然这个时间可以自己规定,时间太长新消息获取的不及时,太短的话多次建立连接查询数据库浪费资源。

9.滚动条位置的获取以及改变

为了达到好的用户体验,模拟qq的聊天环境,我想到qq中消息来时会自动弹出新消息,当我在看以前的消息时,来新消息则不会跳转。所以通过百度,我学会了获取滚动条的位置,这里用到了三个属性分别是scrollTop 获取滚动条隐藏的高度,clientHeight显示的滚动条高度也就是窗口高度,scrollHeight滚动条的总高度。它们三者之间有一个关系是scrollTop +clientHeight == scrollHeight时说明滚动到最下方,如果前者之和小于后者说明滚动条位置在中间某个位置,所以在ajax渲染新消息的函数下面,添加一个条件

if (scrollDiv.scrollTop + scrollDiv.clientHeight == scrollDiv.scrollHeight)

                var waitNewMsg = true;

if (document.getElementById("chatmsg") != null) {

document.getElementById("chatmsg").innerHTML = oxmlHttp.responseText;

oxmlHttp = null;

}

if (waitNewMsg == true)

   scrollDiv.scrollTop = scrollDiv.scrollHeight -scrollDiv.clientHeight;

为什么要分开在innerHTML的两边呢?因为我要保存新消息来之前滚动条的位置,新消息来之后scrollHeight高度就变了。如果条件满足,就把滚动条定位至最底下。

10.补充一点,考虑到不同时区人的使用,所以在每个文件的前面手动规定时间为上海的时间,这样插入数据库时的时间都是一致的。

date_default_timezone_set('Asia/shanghai');

遇到的一些问题:

1.修改外部引用的css文件后,刷新页面不生效。

这里在排除所有可能的问题后仍然不生效,最后查得资料发现谷歌浏览器中单纯的刷新并不会重新载入修改的.css文件,要使用ctrl+f5刷新。欺负新人系列。

2.房间名的位置会随左右文字的长度改变而改变。

这个问题在随机动画时尤其明显,定义样式时,我把三个字段放置在一个块中,这样左面的设置左浮动,右面的设置有浮动,中间的在父标签中定义text-align:center;一切看起来都很完美,但是左面文字长度改变时,房间名位置也会发生变化。最后没办法我让房间名脱离文档流,单独放在一个块中,一直在想有没有固定位置还不用脱离文档流的办法。

3.发送消息时,气泡中的文字如果是英文和数字超过最大宽度不换行。

不换行的原因浏览器把很长且连续的英文或数字解读为一个单词,导致溢出气泡。最后在样式中添加word-wrap: break-word;问题解决了。

4.边框的阴影也是边框的一部分,必须留出一部分空间显示阴影,当然,可以指定层叠。

5. window.location.hertheader函数跳转界面后,后续代码仍然执行,解决办法要么加个条件,要么使用die()函数和exit()函数。

6. php代码是预加载的,然后是浏览器执行html等代码。

后话:

虽然我是个完美主义者,编码时力求规范,但作为新手肯定还有待改善的地方,希望朋友们不吝指点。

PHP实现匿名聊天室相关推荐

  1. 将“闲聊么”改造成匿名聊天室

    关于闲聊么 之前的文章早已有介绍,详见"闲聊么"给你的网站加上一个聊天框. 不过啊,它有一个致命的弱点,必须注册登录才能参与聊天.对于小网站来说,很是鸡肋.一般人看到这么麻烦就放弃 ...

  2. flask android app socketio加解密 匿名加密聊天室 不被任何官方非官方机构个人监视的匿名聊天室!!! 想聊什么就聊什么!

    www.miracleseller.xyz:860/ http://www.miracleseller.xyz:860/ app聊天室(匿名加密 不被任何人任何机构监视的app): http://ww ...

  3. TCP 聊天室v2 实现多人匿名聊天 C++,linux系统下

    使用select IO复用实现多人匿名聊天室(linux系统下) 功能:用户可发送消息,并同时能看到其他用户发的消息,用户输入over退出 实现思路: 服务端仅作为消息的中转方,使用select管理所 ...

  4. 基于python实现的聊天室(客户端:一)窗口设置

    前言 就是自己想用python做一个聊天室,然后看看socket库,websocket库,有点底层,然后也会用到协程的东西,不是很明白,一时间也不知道怎么写,因为前面使用过了flask-socketi ...

  5. 基于python实现的聊天室(服务端)

    前言 就是自己想用python做一个聊天室,然后看看socket库,websocket库,有点底层,然后也会用到协程的东西,不是很明白,一时间也不知道怎么写,然后就用了封装好的python-socke ...

  6. 一款开源的匿名聊天工具,太牛了

    今天推荐的这个项目是「anonymous-chat-room」,一个基于 livekit 和 Next.js 的匿名聊天室,可以进行文字.语音聊天,并支持语音录屏. 特点 部署简单:前端支持直接部署到 ...

  7. PHP匿名在线聊天室系统源码 自适应PC+WAP端

    介绍: PHP匿名在线聊天室系统源码 自适应PC+WAP端 可发语音.图片 修改数据库config\settings.php可拿去搭建专门跟客户聊天的网站 网盘下载地址: http://kekewl. ...

  8. PHP匿名在线聊天室系统源码

    PHP匿名在线聊天室系统源码,自适应PC+WAP端,可发 语音.图片.带有三套主题模板,完美可用. [完整源码链接] PHP匿名在线聊天室系统源码.zip-PHP文档类资源-CSDN文库

  9. 【聊天室系统源码】多语言海外版匿名中英文聊天室开发

    随着国际化发展的潮流和趋势,越来越多的各国友人通过社交软件在一起聊天,交流和学习,但是各国的专用社交软件都有一定的地域保护,不会让其他地区的网友随意注册和使用,当然我们国家也不让随意使用海外的社交软件 ...

  10. 从0搭建在线聊天室,只需4步!

    Vol. 5 聊天室不同于单聊和群聊,是一类集成了多种 IM 功能一体的大规模实时消息分发系统.在跨入新世纪的2000年,聊天室作为新型的即时通讯场景迅速在年轻人群体中火热起来,"网易聊天室 ...

最新文章

  1. ppt批量缩略图_拒绝加班系列:100个PPT常用快捷键,让PPT制作快到起飞
  2. 为什么微服务一定要有网关呢?
  3. apache和tomcat区别
  4. kubernetes1.8.4 安装指南 -- 11. 安装kubernetes dashboard
  5. webpack打包原理
  6. 天龙八部手游有网络显示网络或服务器异常,天龙八部手游微信登录不了_微信登录异常解决办法_玩游戏网...
  7. CentOS7下使用yum快速安装配置oracle数据库
  8. 容量耦合系数模型_使用Fluent电芯仿真模型进行结构设计优缺点分析
  9. 每日一句090516
  10. 对训练集和测试集的PCA方法
  11. HTML注册表单的页面制作
  12. img图片在父元素中居中的方法
  13. TYPORA主题更换
  14. JS的日期操作:String转date日期格式、求日期差
  15. 常见的电子元器件分类介绍
  16. 10.业余无线电术语
  17. Python笔记:利用pygame模块实现三原色颜色滚动条效果
  18. 【专题教程第4期】SEGGER的J-Scope波形上位机软件,HSS模式简单易用,无需额外资源,也不需要写目标板代码
  19. 如何找到迅雷自带播放器
  20. Unity尝试从零创建一个敌人

热门文章

  1. linux网络编程常用头文件总结
  2. raster包—stack函数
  3. python概率分布拟合_用Python实现概率分布
  4. Windows XP SP3安装教程(图)
  5. office中导入mathtype出现MathPage.wll未找到错误
  6. js 输出为underfined
  7. jQWidgets的TreeGrid 心得:
  8. Android Edittext设置软键盘输入法Enter回车键为完成按钮
  9. Java企业微信号开发之微信网页授权和获取用户信息
  10. 赵绍琴温病学讲座(一)