小蝌蚪聊天室增加在线列表以及历史聊天记录

原创  郑建华   2020-05-26   321人阅读  0 条评论

    小蝌蚪聊天室增加在线列表、历史聊天记录、加速、跟随、瞬移等功能。

image.png

    访问蝌蚪聊天室

    介绍一下如何修改源码,升级这些功能

    一、修改index.html源码

image.png

在图中位置插入如下代码

<div id="online-users">
        <div class="header">
            <h3>在线列表</h3>
            <div @click.stop="toggleOnlineUsers">{{ showOnlineUsersText }}</div>
        </div>
        <span>在线:{{ onlineCount }}只</span>
        <div class="users" v-if="showOnlineUsers">
            <template v-for="(user,index) in onlineUsers">
                <div class="user" :key="index">
                    <div @click.stop="toUserPos(user.user)" class="name"><span title="点击瞬移到玩家身边" class="name">{{ user.name }}</span><span class="pos">[{{ user.user.x | parseInt }},{{ user.user.y | parseInt }}]</span>
                    </div>
                    <div class="follow" @click.stop="onClickFollowUser(user)"
                         v-if="followUser==null || user.id !== followUser.id">跟随
                    </div>
                    <div class="cancel-follow" @click.stop="onClickCancelFollow" v-else>取消跟随</div>
                </div>
            </template>
        </div>

    </div>
    <div id="world">
        <div class="header">
            <h3>世界动态</h3>
            <div @click.stop="toggleMessages">{{ showText }}</div>
        </div>
        <div class="logs" ref="messages" v-if="showMessages">
            <template v-for="(message,index) in messages">
                <div class="message" v-if="message.type === 'message'" :key="index">
                    <div><span @click.stop="toUserPos(message.user)" title="点击瞬移到玩家身边" class="name">{{ message.user.name }}</span><span
                            title="点击前往" @click.stop="deliveryTo(message.message.x,message.message.y)" class="pos">[{{ message.message.x }},{{ message.message.y }}]</span>:
                        <span class="content">{{ message.message.content }}</span></div>
                </div>
            </template>
        </div>
    </div>

在如下图位置,增加代码

<script src="js/lib/vue-2.6.11.min.js"></script>
<script src="js/New.js"></script>

image.png

二、修改main.css文件,在结尾处添加如下内容

#world {
    border-radius: 10px;
    padding: 10px;
    width: 300px;
    position: absolute;
    bottom: 30px;
    right: 60px;
    color: white;
    z-index: 100;
    background: rgba(0, 0, 0, .3);
}

#world > .header {
    display: flex;
    font-size: 1.5em;
    margin-bottom: 5px;
}

#world > .header > h3 {
    flex: 1;
}

#world > .logs {
    width: 300px;
    max-height: 200px;
    overflow: scroll;
}

#world > .logs::-webkit-scrollbar {
    width: 4px;
    height: 4px;
    scrollbar-arrow-color: #fff;
}

#world > .logs::-webkit-scrollbar-thumb {
    border-radius: 5px;
    -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
    background: rgba(255, 255, 255, 0.2);
    scrollbar-arrow-color: red;
}

#world > .logs::-webkit-scrollbar-track {
    -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
    border-radius: 0;
    background: rgba(255, 255, 255, 0.1);
}

#world > .logs > .message {
    display: flex;
}

#world > .logs > .message .content {
    color: #999;
    font-size: 1.3em;
}

#world > .logs > .message .name {
    color: white;
    font-weight: bold;
    font-size: 1.3em;
}


#world > .logs > .message .name:hover {
    cursor: pointer;
    text-decoration: underline;
}

#world > .logs > .message .pos {
    color: #999;
    font-size: 1.3em;
}

#world > .logs > .message .pos:hover {
    text-decoration: underline;
    cursor: pointer;
}

#online-users {
    border-radius: 10px;
    padding: 10px;
    width: 20vw;
    position: absolute;
    left: 60px;
    bottom: 30px;
    color: white;
    z-index: 99;
    background: rgba(0, 0, 0, .3);
}

#online-users > .header {
    display: flex;
    font-size: 1.5em;
    margin-bottom: 5px;
}

#online-users > .header > h3 {
    flex: 1;
}

#online-users > span {
    font-size: 1.3em;
    color: #999999;
    display: inline-block;
}

#online-users > .users {
    max-height: 200px;
    font-size: 1.4em;
    overflow: scroll;
}

#online-users > .users::-webkit-scrollbar {
    width: 4px;
    height: 4px;
    scrollbar-arrow-color: #fff;
}

#online-users > .users::-webkit-scrollbar-thumb {
    border-radius: 5px;
    -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
    background: rgba(255, 255, 255, 0.2);
    scrollbar-arrow-color: red;
}

#online-users > .users::-webkit-scrollbar-track {
    -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
    border-radius: 0;
    background: rgba(255, 255, 255, 0.1);
}

#online-users .users .name:hover {
    cursor: pointer;
    text-decoration: underline;
}

#online-users .users .user .pos {
    color: #999;
}

.users > .user {
    display: flex;
    padding: 5px 0;
}

.users > .user .name {
    flex: 1;
}

.users > .user .follow {
    display: none;
    cursor: pointer;
    background: rgba(255, 255, 255, .5);
    padding: 2px;
    border-radius: 2px;
}

.users > .user .cancel-follow {
    cursor: pointer;
}

.users > .user:hover .follow {
    display: block;
}


三、修改js目录下的Tadpole.js文件内容,将其替换为如下内容

var Tadpole = function () {
	var tadpole = this;

	this.x = Math.random() * 300 - 150;
	this.y = Math.random() * 300 - 150;
	this.size = 4;

	this.name = '';
	this.age = 0;
	this.sex = -1;

	this.hover = false;

	this.momentum = 0;
	this.maxMomentum = 5;
	this.angle = Math.PI * 2;

	this.targetX = 0;
	this.targetY = 0;
	this.targetMomentum = 0;

	this.messages = [];
	this.timeSinceLastActivity = 0;

	this.changed = 0;
	this.timeSinceLastServerUpdate = 0;

	this.update = function (mouse) {
		tadpole.timeSinceLastServerUpdate++;

		tadpole.x += Math.cos(tadpole.angle) * tadpole.momentum;
		tadpole.y += Math.sin(tadpole.angle) * tadpole.momentum;

		if (tadpole.targetX != 0 || tadpole.targetY != 0) {
			tadpole.x += (tadpole.targetX - tadpole.x) / 20;
			tadpole.y += (tadpole.targetY - tadpole.y) / 20;
		}

		// Update messages
		for (var i = tadpole.messages.length - 1; i >= 0; i--) {
			var msg = tadpole.messages[i];
			msg.update();

			if (msg.age == msg.maxAge) {
				tadpole.messages.splice(i, 1);
			}
		}

		// Update tadpole hover/mouse state
		if (Math.sqrt(Math.pow(tadpole.x - mouse.worldx, 2) + Math.pow(tadpole.y - mouse.worldy, 2)) < tadpole.size + 2) {
			tadpole.hover = true;
			mouse.tadpole = tadpole;
		} else {
			if (mouse.tadpole && mouse.tadpole.id == tadpole.id) {
				//mouse.tadpole = null;
			}
			tadpole.hover = false;
		}

		tadpole.tail.update();
	};

	this.onclick = function (e) {
		if (e.ctrlKey && e.which == 1) {
			if (isAuthorized() && tadpole.hover) {
				window.open("http://twitter.com/" + tadpole.name.substring(1));
				return true;
			}
		} else if (e.which == 2) {
			//todo:open menu
			e.preventDefault();
			return true;
		}
		return false;
	};

	this.userUpdate = function (tadpoles, angleTargetX, angleTargetY) {
		this.age++;

		var prevState = {
			angle: tadpole.angle,
			momentum: tadpole.momentum,
		}

		// Angle to targetx and targety (mouse position)
		var anglediff = ((Math.atan2(angleTargetY - tadpole.y, angleTargetX - tadpole.x)) - tadpole.angle);
		while (anglediff < -Math.PI) {
			anglediff += Math.PI * 2;
		}
		while (anglediff > Math.PI) {
			anglediff -= Math.PI * 2;
		}

		tadpole.angle += anglediff / 5;

		// Momentum to targetmomentum
		if (tadpole.targetMomentum != tadpole.momentum) {
			tadpole.momentum += (tadpole.targetMomentum - tadpole.momentum) / 20;
		}

		if (tadpole.momentum < 0) {
			tadpole.momentum = 0;
		}

		tadpole.changed += Math.abs((prevState.angle - tadpole.angle) * 3) + tadpole.momentum;

		if (tadpole.changed > 1) {
			this.timeSinceLastServerUpdate = 0;
		}
	};

	this.draw = function (context) {
		var opacity = Math.max(Math.min(20 / Math.max(tadpole.timeSinceLastServerUpdate - 300, 1), 1), .2).toFixed(3);

		// console.log(tadpole);

		if (tadpole.hover && isAuthorized()) {
			context.fillStyle = 'rgba(192, 253, 247,' + opacity + ')';
			// context.shadowColor   = 'rgba(249, 136, 119, '+opacity*0.7+')';
		} else {
			context.fillStyle = 'rgba(226,219,226,' + opacity + ')';
		}

		if (tadpole.sex == 0) {
			context.fillStyle = 'rgba(255, 181, 197,' + opacity + ')';
		} else if (tadpole.sex == 1) {
			context.fillStyle = 'rgba(192, 253, 247,' + opacity + ')';
		}

		context.shadowOffsetX = 0;
		context.shadowOffsetY = 0;
		context.shadowBlur = 6;
		context.shadowColor = 'rgba(255, 255, 255, ' + opacity * 0.7 + ')';

		// Draw circle
		context.beginPath();
		context.arc(tadpole.x, tadpole.y, tadpole.size, tadpole.angle + Math.PI * 2.7, tadpole.angle + Math.PI * 1.3, true);

		tadpole.tail.draw(context);

		context.closePath();
		context.fill();

		context.shadowBlur = 0;
		context.shadowColor = '';

		drawName(context);
		drawMessages(context);
	};

	var isAuthorized = function () {
		return tadpole.name.charAt('0') == "@";
	};

	var drawName = function (context) {
		var opacity = Math.max(Math.min(20 / Math.max(tadpole.timeSinceLastServerUpdate - 300, 1), 1), .2).toFixed(3);
		context.fillStyle = 'rgba(226,219,226,' + opacity + ')';
		context.font = 7 + "px 'proxima-nova-1','proxima-nova-2', arial, sans-serif";
		context.textBaseline = 'hanging';
		var width = context.measureText(tadpole.name).width;
		context.fillText(tadpole.name, tadpole.x - width / 2, tadpole.y + 8);
	}

	var drawMessages = function (context) {
		tadpole.messages.reverse();
		for (var i = 0, len = tadpole.messages.length; i < len; i++) {
			tadpole.messages[i].draw(context, tadpole.x + 10, tadpole.y + 5, i);
		}
		tadpole.messages.reverse();
	};


	// Constructor
	(function () {
		tadpole.tail = new TadpoleTail(tadpole);
	})();
}

四、修改js目录下的WebSocketService.js文件,替换如下内容

var WebSocketService = function (model, webSocket) {
    var webSocketService = this;

    var webSocket = webSocket;
    var model = model;
    var gouserList = [];

    this.hasConnection = false;

    this.welcomeHandler = function (data) {
        webSocketService.hasConnection = true;

        model.userTadpole.id = data.id;
        model.tadpoles[data.id] = model.tadpoles[-1];
        delete model.tadpoles[-1];

        $('#chat').initChat();
        if ($.cookie('todpole_name')) {
            webSocketService.sendMessage('name:' + $.cookie('todpole_name'));
        }
        if ($.cookie('todpole_sex')) {
            webSocketService.sendMessage('我是' + $.cookie('todpole_sex'));
        }
    };

    this.updateHandler = function (data) {
        var newtp = false;

        if (!model.tadpoles[data.id]) {
            newtp = true;
            model.tadpoles[data.id] = new Tadpole();
            model.arrows[data.id] = new Arrow(model.tadpoles[data.id], model.camera);
        }

        var tadpole = model.tadpoles[data.id];

        if (tadpole.id == model.userTadpole.id) {
            tadpole.name = data.name;
            return;
        } else {
            tadpole.name = data.name;
        }

        if (newtp) {
            tadpole.x = data.x;
            tadpole.y = data.y;
            vmLog.updateUsers(model.tadpoles);
        } else {
            tadpole.targetX = data.x;
            tadpole.targetY = data.y;
        }

        tadpole.angle = data.angle;
        tadpole.sex = data.sex;
        tadpole.momentum = data.momentum;

        tadpole.timeSinceLastServerUpdate = 0;
    }

    this.messageHandler = function (data) {
        var tadpole = model.tadpoles[data.id];
        if (!tadpole) {
            return;
        }
        tadpole.timeSinceLastServerUpdate = 0;
        tadpole.messages.push(new Message(data.message));
        vmLog.addLog(tadpole, {
            content: data.message,
            time: new Date(),
            x: parseInt(tadpole.x),
            y: parseInt(tadpole.y)
        });
    }

    this.closedHandler = function (data) {
        if (model.tadpoles[data.id]) {
            delete model.tadpoles[data.id];
            delete model.arrows[data.id];
            vmLog.updateUsers(model.tadpoles);
        }
    }

    this.redirectHandler = function (data) {
        if (data.url) {
            if (authWindow) {
                authWindow.document.location = data.url;
            } else {
                document.location = data.url;
            }
        }
    }

    this.processMessage = function (data) {
        var fn = webSocketService[data.type + 'Handler'];
        if (fn) {
            fn(data);
        }
    }

    this.connectionClosed = function () {
        webSocketService.hasConnection = false;
        $('#cant-connect').fadeIn(300);
    };

    this.sendUpdate = function (tadpole) {
        var sendObj = {
            type: 'update',
            x: tadpole.x.toFixed(1),
            y: tadpole.y.toFixed(1),
            angle: tadpole.angle.toFixed(3),
            momentum: tadpole.momentum.toFixed(3),
            sex: tadpole.sex
        };

        if (tadpole.name) {
            sendObj['name'] = tadpole.name;
        }

        webSocket.send(JSON.stringify(sendObj));
    }

    this.sendMessage = function (msg) {
        let regexp = /^(name[::;;]|我叫)(.+)/i;
        if (regexp.test(msg)) {
            model.userTadpole.name = msg.match(regexp)[2];
            $.cookie('todpole_name', model.userTadpole.name, {
                expires: 14
            });
            return;
        }

        regexp = /^(我是|sex)(男生|女生|0|1|男|女)/;
        if (regexp.test(msg)) {
            let sex = msg.match(regexp)[2];
            if (sex === "女生" || sex === '0') {
                model.userTadpole.sex = 0;
            } else if (sex === "男生" || sex === '1') {
                model.userTadpole.sex = 1;
            } else {
                model.userTadpole.sex = -1;
            }
            $.cookie('todpole_sex', model.userTadpole.sex, {
                expires: 14
            });
            return;
        }

        regexp = /^跟随(.+)/i;
        if (regexp.test(msg)) {

            let _this = this;
            let gouserByname = msg.match(regexp)[1];
            console.log(gouserByname);

            var gousergo = setInterval(function () {

                var gouser = queryByName(gouserByname);
                let xx = /x: ?(.+)y/i;
                let yy = /y: ?(.+)/i;
                // console.log(gouser+"-"+xx+"-"+yy);
                if (gouser != null) {
                    model.userTadpole.x = parseFloat(gouser.match(xx)[1] - 12);
                    model.userTadpole.y = parseFloat(gouser.match(yy)[1] - 12);
                    _this.sendUpdate(model.userTadpole);
                } else {
                    clearInterval(gousergo);
                    app.sendMessage("他跑了!!");
                }

                gouserList.push(gousergo);
                // console.log(gouserList);

            }, 10);

            return;
        }

        regexp = /^(停止|stop)(挂机|跟随)/;
        if (regexp.test(msg)) {

            let gouserByname = msg.match(regexp)[2];
            // console.log(gouserByname);
            if (gouserByname == "挂机" || gouserByname == "跟随") {
                // console.log(gouserList);
                gouserList.forEach((item, index) => {
                    clearInterval(item);
                })
                gouserList = [];
                gousergo = 0;
                return;

            }
        }

        regexp = /^-?(\d+)[,,]-?(\d+)$/i;
        if (regexp.test(msg)) {
            let pos = msg.match(regexp);
            // console.log(pos)
            app.deliveryTo(pos[1], pos[2]);
            return;
        }

        regexp = /^速度(\d+)$/i;
        if (regexp.test(msg)) {
            let num = msg.match(regexp);
            let speed = parseInt(num[1]) > 0 ? parseInt(num[1]) : 1;
            app.speed(speed);
        }

        regexp = /^flicker$/;
        if (regexp.test(msg)) {
            let _this = this;
            let interval = setInterval(function () {
                model.userTadpole.sex = model.userTadpole.sex ^ 1;
                $.cookie('todpole_sex', model.userTadpole.sex, {
                    expires: 14
                });
                _this.sendUpdate(model.userTadpole);
            }, 500);
            setTimeout(function () {
                clearInterval(interval);
            }, 60000);
            return;
        }

        var sendObj = {
            type: 'message',
            message: msg
        };

        webSocket.send(JSON.stringify(sendObj));
    }

    this.authorize = function (token, verifier) {
        var sendObj = {
            type: 'authorize',
            token: token,
            verifier: verifier
        };

        webSocket.send(JSON.stringify(sendObj));
    }

    var queryByName = function (name) {
        var x;
        var y;
        var userid = JSON.stringify(model.tadpoles);
        userid = JSON.parse(userid);

        for (var j in userid) {

            if (userid[j].name == name || j == name) {
                x = userid[j].x;
                y = userid[j].y;

                return "x:" + x + "y:" + y;
            }
        }

        return null;
    }
}

五、在js目录下添加文件New.js,内容如下

let vmLog = new Vue({
    el: '#ui',
    data: {
        messages: [],
        showMessages: true,
        users: null,
        onlineCount: 0,
        onlineUsers: [],
        model: null,
        showOnlineUsers: true,
        followUser: null,
        followInterval: null,
    },
    filters: {
        parseInt: function (value) {
            return parseInt(value);
        }
    },
    watch: {
        messages() {
            this.$nextTick(() => {
                let container = this.$refs.messages;
                let scrollTop = container.scrollTop;
                let scrollHeight = container.scrollHeight;
                let clientHeight = container.clientHeight;
                if (clientHeight - scrollTop <= 220) {
                    container.scrollTop = scrollHeight
                }
                container.scrollTop = scrollHeight
            })
        },
        followUser(newUser, oldUser) {
            if (this.followInterval !== null) clearInterval(this.followInterval);
            if (newUser !== null) {
                this.followUser = newUser;
                this.followInterval = setInterval(() => {
                    // console.log(this.followUser)
                    this.deliveryTo(this.followUser.user.x, this.followUser.user.y);
                }, 100);
                // console.log(this.followInterval)
            }
        },
        onlineUsers(newOnlineUsers, oldOnlineUsers) {
            if (this.followUser !== null) {
                let index = newOnlineUsers.findIndex((user) => {
                    return this.followUser.id === user.id;
                });
                // console.log('update onlineUsers')
                if (index === -1) {
                    console.log("用户离开,跟随结束")
                    clearInterval(this.followInterval);
                    this.followUser = null;
                    this.followInterval = null;
                }
            }
        }
    },
    computed: {
        showText() {
            return this.showMessages ? '隐藏' : '显示';
        },
        showOnlineUsersText() {
            return this.showOnlineUsers ? '隐藏' : '显示';
        }
    },
    methods: {
        addLog(user, message) {
            this.messages.push({
                user: user,
                message: message,
                type: 'message'
            });
        },
        toggleMessages() {
            this.showMessages = !this.showMessages;
        },
        toggleOnlineUsers() {
            this.showOnlineUsers = !this.showOnlineUsers;
        },
        deliveryTo(x, y) {
            // console.log(x, y, app)
            app.deliveryTo(x, y);
        },
        toUserPos(user) {
            this.deliveryTo(user.x, user.y);
        },
        updateUsers(users) {
            this.users = users;
            this.onlineCount = this.users ? Object.keys(this.users).length : 0;

            //在线用户列表
            let userList = []
            for (let id in this.users) {
                userList.push({
                    id: id,
                    name: this.users[id].name,
                    user: this.users[id]
                })
            }
            this.onlineUsers = userList
        },
        updateModel(model) {
            this.model = model;
        },
        onClickFollowUser(user) {
            this.followUser = user;
            // console.log(user)
        },
        onClickCancelFollow() {
            this.followUser = null;
            clearInterval(this.followInterval);
        }
    }
});

六、在js/lib目录下添加文件

vue-2.6.11.min.js


修改版代码获取:

此处内容已经被作者隐藏,请输入验证码查看内容
验证码:
请关注本站微信公众号,回复“资源下载”,获取验证码。在微信里搜索“华仔部落”或者“hzbl_zjh”或者微信扫描右侧二维码都可以关注本站微信公众号。

本文地址:https://www.zjh336.cn/?id=1832
版权声明:本文为原创文章,版权归 郑建华 所有,欢迎分享本文,转载请保留出处!

发表评论


表情

还没有留言,还不快点抢沙发?