This commit is contained in:
liuguili 2018-04-17 20:23:59 +08:00
commit b34d1ca5f0
15 changed files with 1675 additions and 0 deletions

39
app.js Normal file
View File

@ -0,0 +1,39 @@
//app.js
App({
onLaunch: function () {
// 展示本地存储能力
var logs = wx.getStorageSync('logs') || []
logs.unshift(Date.now())
wx.setStorageSync('logs', logs)
// 登录
wx.login({
success: res => {
// 发送 res.code 到后台换取 openId, sessionKey, unionId
}
})
// 获取用户信息
wx.getSetting({
success: res => {
if (res.authSetting['scope.userInfo']) {
// 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
wx.getUserInfo({
success: res => {
// 可以将 res 发送给后台解码出 unionId
this.globalData.userInfo = res.userInfo
// 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
// 所以此处加入 callback 以防止这种情况
if (this.userInfoReadyCallback) {
this.userInfoReadyCallback(res)
}
}
})
}
}
})
},
globalData: {
userInfo: null
}
})

9
app.json Normal file
View File

@ -0,0 +1,9 @@
{
"pages": ["pages/index/index", "pages/chat/index"],
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "weapp.socket.io chat demo",
"navigationBarTextStyle": "black"
}
}

35
app.wxss Normal file
View File

@ -0,0 +1,35 @@
@import './styles/weui.wxss';
page {
background-color: #f8f8f8;
font-size: 16px;
font-family: -apple-system-font, Helvetica Neue, Helvetica, sans-serif;
}
.page__hd {
padding: 40px;
}
.page__bd {
padding-bottom: 40px;
}
.page__bd_spacing {
padding-left: 15px;
padding-right: 15px;
}
.page__ft {
padding-bottom: 10px;
text-align: center;
}
.page__title {
text-align: left;
font-size: 20px;
font-weight: 400;
}
.page__desc {
margin-top: 5px;
color: #888888;
text-align: left;
font-size: 14px;
}

238
pages/chat/index.js Normal file
View File

@ -0,0 +1,238 @@
const io = require('../../utils/weapp.socket.io.js')
//index.js
//获取应用实例
const app = getApp()
/**
* 生成一条聊天室的消息的唯一 ID
*/
function msgUuid() {
if (!msgUuid.next) {
msgUuid.next = 0
}
return 'msg-' + ++msgUuid.next
}
/**
* 生成聊天室的系统消息
*/
function createSystemMessage(content) {
return { id: msgUuid(), type: 'system', content }
}
/**
* 生成聊天室的聊天消息
*/
function createUserMessage(content, user, isMe) {
const color = getUsernameColor(user)
return { id: msgUuid(), type: 'speak', content, user, isMe, color }
}
var COLORS = [
'#e21400',
'#91580f',
'#f8a700',
'#f78b00',
'#58dc00',
'#287b00',
'#a8f07a',
'#4ae8c4',
'#3b88eb',
'#3824aa',
'#a700ff',
'#d300e7',
]
// Gets the color of a username through our hash function
function getUsernameColor(username) {
// Compute hash code
var hash = 7
for (var i = 0; i < username.length; i++) {
hash = username.charCodeAt(i) + (hash << 5) - hash
}
// Calculate color
var index = Math.abs(hash % COLORS.length)
return COLORS[index]
}
Page({
data: {
inputContent: 'Hello everybody',
messages: [],
lastMessageId: 'none',
},
onLoad: function() {},
/**
* 页面渲染完成后启动聊天室
* */
onReady() {
wx.setNavigationBarTitle({ title: 'weapp.socket.io 聊天室演示' })
if (!this.pageReady) {
this.pageReady = true
this.enter()
}
},
/**
* 后续后台切换回前台的时候也要重新启动聊天室
*/
onShow() {
if (this.pageReady && !this.socket) {
this.enter()
}
},
onUnload() {
this.quit()
},
quit() {
if (this.socket) {
this.socket.close()
this.socket = null
}
},
/**
* 启动聊天室
*/
enter() {
this.pushMessage(createSystemMessage('正在登录...'))
// 如果登录过,会记录当前用户在 this.me 上
if (!this.me) {
wx.getUserInfo({
success: res => {
this.me = res.userInfo
this.createConnect()
},
})
} else {
this.createConnect()
}
},
/**
* 通用更新当前消息集合的方法
*/
updateMessages(updater) {
var messages = this.data.messages
updater(messages)
this.setData({ messages })
// 需要先更新 messagess 数据后再设置滚动位置,否则不能生效
var lastMessageId = messages.length
? messages[messages.length - 1].id
: 'none'
this.setData({ lastMessageId })
},
/**
* 追加一条消息
*/
pushMessage(message) {
this.updateMessages(messages => messages.push(message))
},
/**
* 替换上一条消息
*/
amendMessage(message) {
this.updateMessages(messages => messages.splice(-1, 1, message))
},
/**
* 删除上一条消息
*/
popMessage() {
this.updateMessages(messages => messages.pop())
},
changeInputContent: function(e) {
this.setData({
inputContent: e.detail.value,
})
},
sendMessage: function(e) {
const msg = e.detail.value
if (!msg) {
return
}
this.socket.emit('new message', msg)
this.pushMessage(createUserMessage(msg, this.me.nickName))
this.setData({ inputContent: null })
},
createConnect: function(e) {
this.amendMessage(createSystemMessage('正在加入群聊...'))
const socket = (this.socket = io(
'https://vast-plateau-30681.herokuapp.com/',
))
/**
* Aboud connection
*/
socket.on('connect', () => {
this.popMessage()
this.pushMessage(createSystemMessage('You joined'))
})
socket.on('connect_error', d => {
this.pushMessage(createSystemMessage(`connect_error: ${d}`))
})
socket.on('connect_timeout', d => {
this.pushMessage(createSystemMessage(`connect_timeout: ${d}`))
})
socket.on('disconnect', reason => {
this.pushMessage(createSystemMessage(`disconnect: ${reason}`))
})
socket.on('reconnect', attemptNumber => {
this.pushMessage(
createSystemMessage(`reconnect success: ${attemptNumber}`),
)
})
socket.on('reconnect_failed', () => {
this.pushMessage(createSystemMessage('reconnect_failed'))
})
socket.on('error', err => {
this.pushMessage(createSystemMessage(`error: ${err}`))
})
/**
* About chat
*/
socket.on('login', d => {})
socket.on('new message', d => {
const { username, message } = d
this.pushMessage(createUserMessage(message, username))
})
socket.on('user joined', d => {
this.pushMessage(createSystemMessage(`${d.username} joined`))
this.pushMessage(createSystemMessage(`当前共有 ${d.numUsers}`))
})
socket.on('user left', d => {
this.pushMessage(createSystemMessage(`${d.username} left`))
this.pushMessage(createSystemMessage(`当前共有 ${d.numUsers}`))
})
socket.on('typing', d => {})
socket.on('stop typing', d => {})
socket.emit('add user', this.me.nickName)
},
})

18
pages/chat/index.wxml Normal file
View File

@ -0,0 +1,18 @@
<view class="page-wrap">
<scroll-view class="chat-container" scroll-y scroll-into-view="{{lastMessageId}}" scroll-top="9999999999">
<view wx:for="{{messages}}" wx:for-item="message" wx:key="id" id="{{message.id}}" class="message {{message.type}}">
<view wx:if="{{message.type == 'speak'}}" class="user-message {{message.isMe ? 'me' : 'other'}}">
<view class="text">
<view class="nickname" style="color: {{message.color}};">{{message.user}}</view>
<view class="content">{{message.content}}</view>
</view>
</view>
<view wx:if="{{message.type == 'system'}}" class="system-message">
{{message.content}}
</view>
</view>
</scroll-view>
<view class="input-panel">
<input type="text" value="{{inputContent}}" bindchange="changeInputContent" class="send-input" confirm-type="send" confirm-hold="true" bindconfirm="sendMessage"></input>
</view>
</view>

144
pages/chat/index.wxss Normal file
View File

@ -0,0 +1,144 @@
.page-wrap {
display: flex;
flex-direction: column;
background: #ebebeb;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow: hidden;
}
.chat-container {
flex: 1;
text-align: center;
overflow-y: auto;
}
.system-message {
font-size: 14px;
line-height: 14px;
color: #fff;
background: #cecece;
border-radius: 4px;
display: inline-block;
padding: 8rpx 15rpx;
margin: 30rpx 0 10rpx;
}
.user-message {
margin: 38rpx 20rpx 0;
text-align: left;
font-size: 0;
display: flex;
}
.avatar {
width: 84rpx;
height: 84rpx;
border: #a5a5a7 1rpx solid;
display: inline-block;
vertical-align: top;
}
.text {
display: inline-block;
vertical-align: top;
}
.user-message.other .text {
margin-left: 19rpx;
}
.user-message.other .text view {
display: inline-block;
}
.text .nickname {
color: #737373;
font-size: 14px;
margin-bottom: 6rpx;
}
.text .content {
font-size: 30rpx;
line-height: 36rpx;
padding: 20rpx;
position: relative;
}
.text .nickname {
font-size: 36rpx;
}
.user-message.other .text .content::after,
.user-message.other .text .content::before {
right: 100%;
border-right-style: solid;
}
.input-panel {
height: 100rpx;
box-sizing: border-box;
padding: 13rpx 20rpx 0;
background: #f5f5f7;
border-top: #d7d7d9 1rpx solid;
box-sizing: border-box;
display: flex;
}
.send-input {
flex: 1;
height: 72rpx;
background: #fff;
border: #ddd 1rpx solid;
border-radius: 3px;
/* margin-right: 20rpx; */
box-sizing: border-box;
/* padding: 0 10rpx; */
}
.me .nickname {
display: none;
}
@media (max-width: 360px) {
.avatar {
width: 100rpx;
height: 100rpx;
}
.text .content {
font-size: 36rpx;
line-height: 44rpx;
padding: 20rpx;
position: relative;
}
.text .nickname {
font-size: 42rpx;
}
.user-message.other .text .content::before {
top: 22rpx;
border-right-color: #ccc;
}
.user-message.other .text .content::after {
border: 14rpx solid transparent;
top: 23rpx;
border-right-color: #fff;
}
.input-panel {
height: 120rpx;
box-sizing: border-box;
padding: 13rpx 20rpx 0;
background: #f5f5f7;
border-top: #d7d7d9 1rpx solid;
box-sizing: border-box;
display: flex;
}
.send-input {
flex: 1;
height: 92rpx;
background: #fff;
border: #ddd 1rpx solid;
border-radius: 3px;
/* margin-right: 20rpx; */
box-sizing: border-box;
/* padding: 0 10rpx; */
}
}

66
pages/index/index.js Normal file
View File

@ -0,0 +1,66 @@
// pages/home/index.js
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})

1
pages/index/index.json Normal file
View File

@ -0,0 +1 @@
{}

9
pages/index/index.wxml Normal file
View File

@ -0,0 +1,9 @@
<view class="page">
<view class="page__hd">
<view class="page__title">聊天室 Demo</view>
<view class="page__desc">本 Demo 主要为开发者演示 weapp.socket.io 的基本用法</view>
</view>
<view class="page__bd page__bd_spacing">
<navigator url="/pages/chat/index" hover-class="weui-cell_active" class="chat-btn">进入聊天室</navigator>
</view>
</view>

9
pages/index/index.wxss Normal file
View File

@ -0,0 +1,9 @@
.chat-btn {
background-color: white;
width: 80%;
margin: auto;
height: 80rpx;
border-radius: 10rpx;
text-align: center;
line-height: 80rpx;
}

36
project.config.json Normal file
View File

@ -0,0 +1,36 @@
{
"description": "项目配置文件。",
"packOptions": {
"ignore": []
},
"setting": {
"urlCheck": false,
"es6": true,
"postcss": true,
"minified": true,
"newFeature": true
},
"compileType": "miniprogram",
"libVersion": "1.9.98",
"appid": "wxfbd99d2dee1708f9",
"projectname": "weapp.socket.io.demo",
"isGameTourist": false,
"condition": {
"search": {
"current": -1,
"list": []
},
"conversation": {
"current": -1,
"list": []
},
"game": {
"currentL": -1,
"list": []
},
"miniprogram": {
"current": -1,
"list": []
}
}
}

1042
styles/weui.wxss Normal file

File diff suppressed because it is too large Load Diff

19
utils/util.js Normal file
View File

@ -0,0 +1,19 @@
const formatTime = date => {
const year = date.getFullYear()
const month = date.getMonth() + 1
const day = date.getDate()
const hour = date.getHours()
const minute = date.getMinutes()
const second = date.getSeconds()
return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
}
const formatNumber = n => {
n = n.toString()
return n[1] ? n : '0' + n
}
module.exports = {
formatTime: formatTime
}

9
utils/weapp.socket.io.js Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long