微信小程序云开发 — 实现多人实时弹幕(非websocket)

362 阅读4分钟

最近想在自己的小程序当中实现以下多人实时弹幕的功能。查了各种资料后终于搞定,这里记录以下全过程

那么就先上小程序的菊花码为敬,可以先简单体验一下,废话不多说直接上主要部分的实现过程

在这里插入图片描述

1:基础内容准备

wxml

这一部分的内容非常简单,就是弹幕部分的wxml,不做过多的赘述了

<!-- 弹幕部分wxml-->
<view class="danmu">
  <view wx:for="{{danmu}}" wx:key="*this" class="danmu-item" style="top:{{item.top}}rpx" animation="{{item.ani}}">
    <image src="{{item.avatarUrl}}" mode="widthFix"></image>
    <text>{{item.nickName}}</text>
    <text> 选中了 {{item.text}}</text>
  </view>
</view>

<!-- 由于想在弹幕中展示发送弹幕的用户的头像和微信名称,所以需要获取这两样东西-->
<button class="start" open-type="getUserInfo" bindgetuserinfo="btnClick">{{started ? '结束' : '换一个'}}</button>

wxss

这里就是最基础的css,没什么特别需要强调的东西。如果您只是想看实现的核心代码,请直接跳过。

.danmu{
  position: absolute;
  width: 750rpx;
  top: 0;
  z-index: 10;
}
.danmu-item{
  display: flex;
  position: absolute;
  height: 34rpx;
  padding: 3rpx 30rpx 3rpx 0;
  line-height: 34rpx;
  background-color: rgba(0,0,0,.7);
  align-items: center;
  border-radius: 15rpx;
  transform: translate(790rpx,0);
}
.danmu-item image{
  display: block;
  position: relative;
  width: 40rpx;
  height: 40rpx;
  margin-left: -20rpx;
  margin-right: 10rpx;
  border-radius: 20rpx;
  overflow: hidden;
  border: solid 1rpx #333;
}
.danmu-item text{
  font-size: 25rpx;
  color: #fff;
}

动画

其实弹幕的动画通过css也是一定可以实现,由于本人对于css动画确实已经用的比较多了,所以想尝试一下微信小程序的动画API。

wx.createAnimation({ duration: 7000 }).translateX(-500).step().export()

2:创建数据库 数据库权限设置

这里直接从云开发后台直接创建即可。 在这里插入图片描述 当然也有通过代码的创建方式,但此处并没有什么必要。

之后这里有很重要的一点,需要把数据库的权限设置为所有用户可读,仅创建者可写在这里插入图片描述 我在这个地方确实卡了一段时间,之前一直只能是看到自己发的弹幕。因为创建的时候是默认为仅创建者可读写,所以一直无法监听到

3:向数据库推送数据

这里的业务是当用户点击按钮,当用户选中某一个结果后向直接向数据库添加一条数据,也就是发送一条弹幕

// 用户的点击事件
btnClick() {
    const _this = this
    const menu = this.data.menu.split(' ')
    const started = !this.data.started
    this.setData({
      started
    })
    if (started) {
      const max = menu.length
      timer = setInterval(() => {
        const randomIndex = parseInt(max * Math.random())
        const result = menu[randomIndex]
        this.setData({
          result
        })
      }, 100)
    } else {
      clearInterval(timer)
      wx.getUserInfo({
        lang: 'zh_CN',
        success(res) {
          const {
            userInfo
          } = res
          _this.sendDanMu(userInfo)
        },
        fail(err) {
          console.log(err)
          _this.sendDanMu()
        }
      })
    }
  },
  // 推送弹幕到数据库
  sendDanMu({ avatarUrl = '', nickName = '不愿意透露姓名的神秘人' }) {
    const text = this.data.result
    db.collection('danmu').add({
      data: {
        avatarUrl,
        nickName,
        text
      }
    })
  },

4:实时监听数据库

这里是实现实时弹幕的核心代码,通过集合进行监听,来完成弹幕的本地化

相关文档:developers.weixin.qq.com/miniprogram…

// 监听danmu集合,同时在页面的onLoad当中进行调用
listenDanMu() {
    const _this = this
    db.collection('danmu')
      .watch({
        onChange: function (snapshot) {
          // 在第一次调用watch的时候 snapshot.type 的值会为 init
          // 这里强调在不为初始化、并且对集合执行的操作为add的时候,才会进行弹幕的生成
          if (snapshot.type !== 'init' && snapshot.docChanges[0].dataType === 'add') {
            const { avatarUrl, nickName, text } = snapshot.docChanges[0].doc
            const item = {
              avatarUrl,
              nickName,
              text,
              top: Math.floor(Math.random()*(1 - 100) + 100) + 50
            }
            const danmu = _this.data.danmu
            danmu.push(item)
            _this.setData({
              danmu
            })
            setTimeout(() => {
              item.ani = wx.createAnimation({ duration: 7000 }).translateX(-500).step().export()
              _this.setData({
                danmu
              })
            }, 100)

          }
        },
        onError: function (err) {
          console.error('the watch closed because of error', err)
        }
      })
  },

这里我有一点想说的,在尝试添加动画相关的那段代码的时候,发现必须要动画对隔一点时间在放到item中。

琢磨了一下,其实应该就是跟transition动画的原理差不多,需要有真正意义上的时间差。

当然如果这里有用的不对的地方请大佬指正。

5:定时清空数据库

新建云函数 (清空数据库)

// 云函数入口文件
const cloud = require('wx-server-sdk')

cloud.init()

const db = cloud.database()

// 云函数入口函数
exports.main = async (event, context) => {
  console.log('清空danmu集合')
  let res = await db.collection('danmu').where({
  	//每一条数据第一都会有_id,所以判断条件是_id不为空
    _id: db.command.neq('')
  }).remove()
  console.log(res)
}

配置定时触发器

我制定的是凌晨3点半清空数据库danmu集合,相关的配置文档链接

developers.weixin.qq.com/miniprogram…

"triggers": [
  {
    "name": "clearDanMu",
    "type": "timer",
    "config": "0 30 3 * * * *"
  }
 ]

最后记得一定要将云函数和定时器发布上去 ! 这是定时器调用成功的日志 调用成功

最后在文末再放上菊花码,这篇文章如果对你有用的话,扫一下进去溜达一圈,让我也稍微挣点广告费啥的。。。

在这里插入图片描述

转载可以,要注明出处哦~