微信小程序使用recycle-view进行聊天页面的开发

前言:

微信小程序本身自带列表的渲染,但是存在着一些问题:

  1. 不能局部刷新,每次更新就会刷新全部数据,在性能上会有一些影响
  2. 数据量很大时候,渲染会出现卡顿现象,比如一百条以上,分页几十页

针对这种问题,微信用插件的方式推出了recycle-view,下面主要对recycle-view的使用方式及其使用过程中遇到的一些问题进行描述。但是recycle-view不是很完善,相对于AndroiodRecycleView来说依然有着很多限制。

效果展示

在这里插入图片描述

集成方式

在这里使用npm进行集成,npm的配置方式参考该链接: https://blog.csdn.net/Mr_Tony/article/details/107735467

recycle-view的集成方式参考该链接: https://developers.weixin.qq.com/miniprogram/dev/extended/component-plus/recycle-view.html

代码

数据格式

chatList: [
      {
        msgId: 0,
        msgType: 0,
        avater: "https://ossweb-img.qq.com/images/lol/web201310/skin/big143004.jpg",
        content: "这是文本内容",
        fromId: 2,
        toId: 1,
        sendTime: 1597073074000,
        sendStatus:1
      },
      {
        msgId: 1,
        msgType: 0,
        avater: "https://ossweb-img.qq.com/images/lol/web201310/skin/big143004.jpg",
        content: "这是文本内容",
        fromId: 1,
        toId: 2,
        sendTime: 1597505074000,
        sendStatus:1
      },
      {
        msgId: 2,
        msgType: 1,
        avater: "https://ossweb-img.qq.com/images/lol/web201310/skin/big143004.jpg",
        content: "https://ossweb-img.qq.com/images/lol/web201310/skin/big143004.jpg",
        fromId: 1,
        toId: 2,
        sendTime: 1597505074000,
        sendStatus:1
      },
      {
        msgId: 2,
        msgType: 2,
        avater: "https://ossweb-img.qq.com/images/lol/web201310/skin/big143004.jpg",
        content: "这是一条系统消息这是一条系统消息这是一条系统消息这是一条系统消息",
        fromId: 1,
        toId: 2,
        sendTime: 1597505074000,
        sendStatus:1
      }
    ],

消息状态

msgSendStatus.js

//消息发送状态类型
const SEND_LOADING = 0;//发送中
const SEND_SUCCESS = 1;//发送成功
const SEND_FAIL = 2;//发送失败

export{
  SEND_LOADING,
  SEND_SUCCESS,
  SEND_FAIL
}

消息类型

msgType.js

//聊天类型

const TEXT = 0;
const PHOTO = 1;

export{
  TEXT,
  PHOTO
}

工具类

util.js

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(':')
}

/**
 * 将Json转为form表单格式进行提交
 */
function JSON_to_URLEncoded(element,key,list){
  var list = list || [];
  if(typeof(element)=="object"){
    for (var idx in element)
      this.JSON_to_URLEncoded(element[idx],key?key+"["+idx+"]":idx,list);
  } else {
    list.push(key+"="+encodeURIComponent(element));
  }
  return list.join("&");
}

const formatNumber = n => {
  n = n.toString()
  return n[1] ? n : '0' + n
}

const getFileSuffix = fileName =>{
  return fileName.slice(fileName.lastIndexOf("."))
}

module.exports = {
  formatTime: formatTime,
  formatNumber: formatNumber,
  JSON_to_URLEncoded,
  getFileSuffix
}

文件上传工具类:

fileUtils.js

/**
 * 生成详情Banner文件名字
 * @param fileSuffix 文件后缀
 */
const getDetailsFileName = (fileSuffix) => {
  return "goods_details_"+Date.now()+fileSuffix
}

/**
 * 生成详情Banner文件名字
 * @param fileSuffix 文件后缀
 */
const getLogoFileName = (fileSuffix) => {
  return "goods_logo_"+Date.now()+fileSuffix
}

module.exports = {
  getDetailsFileName,
  getLogoFileName
}

消息发送工具类

// 处理 聊天功能的逻辑

import * as messageType from './msgType'
import * as sendStatus from './msgSendStatus'
/**
 * 生成通用的消息对象
 * @param {发送者Id} fromId 
 * @param {接收者Id} toId 
 */
function createCommonMessage(fromId,toId,avater){
  return {
    fromId,
    toId,
    avater,
    sendStatus:sendStatus.SEND_LOADING//发送状态,0:
  }
}

/**
 * @param {文本内容} textContent
 * @param {通用消息结构} commentMessage
 */
const createChatTextMessage = (commentMessage,textContent) => {
  commentMessage.content = textContent
  commentMessage.sendTime = new Date().getTime()
  commentMessage.msgType = messageType.TEXT
  return commentMessage
}

/**
 * @param {图片内容} photoContent
 * @param {通用消息结构} commentMessage
 */
const createChatPhotoMessage = (commentMessage,photoContent,localMessageId) => {
  commentMessage.content = photoContent
  commentMessage.sendTime = new Date().getTime()
  commentMessage.msgType = messageType.PHOTO
  commentMessage.localMessageId = localMessageId
  return commentMessage
}

module.exports = {
  createCommonMessage,
  createChatTextMessage,
  createChatPhotoMessage
}

xml中使用的聊天工具类

js和xml中工具类无法通用

chat_util.wxs

/**
 * 主要是用来处理聊天页面逻辑
 */
var durtionTime = 180000 //三分钟

var foo = "'hello world' from tools.wxs";
var bar = function (d) {
  return d;
}

/**
 * 判断消息朝向
 */
var isSelf = function (sendUser, selfUser) {
  return sendUser == selfUser
}

var showTime = function (sendTime) {
  let result = ""
  let currentTime = getDate().getTime()
  if (currentTime - sendTime < durtionTime) {
    result = ""
  } else {
    result = "三分钟前"
  }
  return result
}

/**
 * 
 * @param timestamp 时间戳类型
 */
var dateDiff = function (timestamp) {
  // 补全为13位
  var arrTimestamp = (timestamp + '').split('');
  for (var start = 0; start < 13; start++) {
    if (!arrTimestamp[start]) {
      arrTimestamp[start] = '0';
    }
  }
  timestamp = arrTimestamp.join('') * 1;

  var minute = 1000 * 60;
  var hour = minute * 60;
  var day = hour * 24;
  var halfamonth = day * 15;
  var month = day * 30;
  var now = getDate().getTime();
  var diffValue = now - timestamp;

  // 如果本地时间反而小于变量时间
  if (diffValue < 0) {
    return '不久前';
  }

  // 计算差异时间的量级
  var monthC = diffValue / month;
  var weekC = diffValue / (7 * day);
  var dayC = diffValue / day;
  var hourC = diffValue / hour;
  var minC = diffValue / minute;

  // 数值补0方法
  var zero = function (value) {
    if (value < 10) {
      return '0' + value;
    }
    return value;
  };

  // 使用
  if (monthC > 12) {
    // 超过1年,直接显示年月日
    return (function () {
      var date = getDate(timestamp);
      return date.getFullYear() + '年' + zero(date.getMonth() + 1) + '月' + zero(date.getDate()) + '日';
    })();
  } else if (monthC >= 1) {
    return parseInt(monthC) + "月前";
  } else if (weekC >= 1) {
    return parseInt(weekC) + "周前";
  } else if (dayC >= 1) {
    return parseInt(dayC) + "天前";
  } else if (hourC >= 1) {
    return parseInt(hourC) + "小时前";
  } else if (minC >= 1) {
    return parseInt(minC) + "分钟前";
  }
  return '刚刚';
};

/**
 * 
 * @param dateStr 时间格式为 2016-12-12 12:20:00
 */
function getDateDiff(dateStr) {
  var publishTime = getDateTimeStamp(dateStr) / 1000,
    d_seconds,
    d_minutes,
    d_hours,
    d_days,
    timeNow = parseInt(getDate().getTime() / 1000),
    d,

    date = getDate(publishTime * 1000),
    Y = date.getFullYear(),
    M = date.getMonth() + 1,
    D = date.getDate(),
    H = date.getHours(),
    m = date.getMinutes(),
    s = date.getSeconds();
  //小于10的在前面补0
  if (M < 10) {
    M = '0' + M;
  }
  if (D < 10) {
    D = '0' + D;
  }
  if (H < 10) {
    H = '0' + H;
  }
  if (m < 10) {
    m = '0' + m;
  }
  if (s < 10) {
    s = '0' + s;
  }

  d = timeNow - publishTime;
  d_days = parseInt(d / 86400);
  d_hours = parseInt(d / 3600);
  d_minutes = parseInt(d / 60);
  d_seconds = parseInt(d);

  if (d_days > 0 && d_days < 3) {
    return d_days + '天前';
  } else if (d_days <= 0 && d_hours > 0) {
    return d_hours + '小时前';
  } else if (d_hours <= 0 && d_minutes > 0) {
    return d_minutes + '分钟前';
  } else if (d_seconds < 60) {
    if (d_seconds <= 0) {
      return '刚刚';
    } else {
      return d_seconds + '秒前';
    }
  } else if (d_days >= 3 && d_days < 30) {
    return M + '-' + D + ' ' + H + ':' + m;
  } else if (d_days >= 30) {
    return Y + '-' + M + '-' + D + ' ' + H + ':' + m;
  }
}



module.exports = {
  FOO: foo,
  bar: bar,
  isSelf: isSelf,
  showTime: showTime,
  dateDiff: dateDiff,
};
module.exports.msg = "some msg";

templete模版代码

templete_chatitem.wxml

<!--pages/template/chat/templete_chatitem.wxml-->

<!--文本布局-->
<template name="chatText">
	<view>
		<view class="chat-item {{self ? 'self' : ''}}">
			<image class="avatar chat-border" src="{{avater}}" lazy-load="true">
			</image>
			<view class="content-text {{self ? 'right-text' : 'left-text'}}">{{content}}</view>
			<template is="chatStatus" data="{{sendStatus}}"></template>
		</view>
		<view class="chatTime" hidden="{{!showTime}}">
			{{showTime}}
		</view>
	</view>
</template>

<!-- 图片布局 -->
<template name="chatPhoto">
	<view>
		<view class="chat-item {{self ? 'self' : ''}}">
			<image class="avatar chat-border" src="{{avater}}" lazy-load="true">
			</image>
			<image class="content-photo" src="{{content}}" lazy-load="true"></image>
			<template is="chatStatus" data="{{sendStatus}}"></template>
		</view>
	</view>
	<view class="chatTime" hidden="{{!showTime}}">
		{{showTime}}
	</view>
</template>

<!-- 系统文本布局 -->
<template name="chatSystemText">
	<view class="chat-item-system">
		<view class="system-text">{{content}}</view>
	</view>
</template>

<template name="chatStatus">
	<!--消息发送中-->
	<image wx:if="{{sendStatus == 0}}" class="send-status" src="http://148.70.194.24:8086/file/fileDown?saveName=2e5077937c0844a09f25e9c4c087c048.gif"></image>
	<!--消息发送失败-->
	<image wx:elif="{{sendStatus == 2}}" class="send-status" src="http://148.70.194.24:8086/file/fileDown?saveName=957e88f4c71845aab2dd787ba49d0619.png"></image>
</template>

templete_chatitem.wxss

/* pages/template/chat/templete_chatitem.wxss */
.chat-border{
  border-radius: 10rpx;
}

.self{
  flex-direction: row-reverse;
}

.chat-item{
  display: flex;
  padding: 30rpx;

}

.chatTime{
  display: flex;
  justify-content: center;
  color: gray;
  font-size: 30rpx;
}

.avatar{
  width: 100rpx;
  height: 100rpx;
  margin-right: 10rpx;
  flex-shrink: 0;
}
.send-status{
  width: 50rpx;
  height: 50rpx;
}
.chat-item view{
  background-color: #fff;
  padding: 5px 8px;
  display: inline-block;
  border-radius: 4px;
  margin:10rpx 30rpx 30rpx 30rpx;
  position: relative;
  
}
.left-text::after{
  content: '';
  border: 8px solid #ffffff00;
  border-right: 8px solid #fff;
  position: absolute;
  top: 6px;
  left: -16px;
}

.right-text::after{
  content: '';
  border: 8px solid #ffffff00;
  border-left: 8px solid #fff;
  position: absolute;
  top: 6px;
  right: -16px;
}

.content-text{
  color: #E0441A;
  font-size: 32rpx;
  word-wrap: break-word;
  word-break: break-all;
  white-space: pre-line;
  margin: 100rpx;
}

.content-photo{
  max-width: 400rpx;
  max-height: 300rpx;
  margin: 0 30rpx;
}

.chat-item-system{
  display: flex;
  justify-content: center;
  width: 100%;
}

.system-text{
  display: flex;
  max-width: 500rpx;
  font-size: 28rpx;
  color: white;
  word-wrap: break-word;
  word-break: break-all;
  white-space: pre-line;
  background-color: gray;
  opacity: 0.8;
  display: flex;
  padding: 20rpx;
  border-radius: 20rpx;
}

聊天模块配置

chat.json

{
  "usingComponents": {
    "recycle-view": "miniprogram-recycle-view/recycle-view",
    "recycle-item": "miniprogram-recycle-view/recycle-item"
  },
  "navigationBarTitleText": "客服聊天",
  "enablePullDownRefresh": false
}

聊天逻辑展示:

chat.js

// pages/chat/chat.js
import * as sendStatus from './msgSendStatus'

const util = require("../../utils/util.js")
const fileUtil = require("../../utils/fileUtils.js")
const chatMessageUtil = require("./chat_message_util")
const createRecycleContext = require('miniprogram-recycle-view')//无限列表
const app = getApp()
var recycleView
const rpx2px = (rpx) => (rpx / 750) * wx.getSystemInfoSync().windowWidth
var localMessageId = 0;//每次本地消息id+1
Page({

  /**
   * 页面的初始数据
   */
  init: {
    tempFileList: [
      // {
      //   localPath: "",//图片在本地的地址
      //   netPath: "",//图片的网络地址
      //   saveName: "",//图片保存的名字
      //   localMessageId: localMessageId,//该消息的临时消息Id
      // }
    ],//本地图片列表
    commonMessage: {},//通用消息结构
    messageText: "",//输入的文本内容
    avater: "https://ossweb-img.qq.com/images/lol/web201310/skin/big143004.jpg",
    friendId:"1"//好友的用户Id
  },
  data: {
    userId: 1,
    chatContentHeight:440,//中间聊天内容的布局
    ispull:true,//是否开启下拉刷新
    isstoppull:true,//是否停止下拉刷新 false:停止,true:不停止

    chatList: [
      {
        msgId: 0,
        msgType: 0,
        avater: "https://ossweb-img.qq.com/images/lol/web201310/skin/big143004.jpg",
        content: "这是文本内容",
        fromId: 2,
        toId: 1,
        sendTime: 1597073074000,
        sendStatus:1
      },
      {
        msgId: 1,
        msgType: 0,
        avater: "https://ossweb-img.qq.com/images/lol/web201310/skin/big143004.jpg",
        content: "这是文本内容",
        fromId: 1,
        toId: 2,
        sendTime: 1597505074000,
        sendStatus:1
      },
      {
        msgId: 2,
        msgType: 1,
        avater: "https://ossweb-img.qq.com/images/lol/web201310/skin/big143004.jpg",
        content: "https://ossweb-img.qq.com/images/lol/web201310/skin/big143004.jpg",
        fromId: 1,
        toId: 2,
        sendTime: 1597505074000,
        sendStatus:1
      },
      {
        msgId: 2,
        msgType: 2,
        avater: "https://ossweb-img.qq.com/images/lol/web201310/skin/big143004.jpg",
        content: "这是一条系统消息这是一条系统消息这是一条系统消息这是一条系统消息",
        fromId: 1,
        toId: 2,
        sendTime: 1597505074000,
        sendStatus:1
      }
    ],
    selectIndex: 0
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    let friendId = options.userId
    this.init.friendId = friendId
    let userInfo = app.globalData.userInfo
    avater = userInfo.avatarUrl
    this.init.commonMessage = chatMessageUtil.createCommonMessage(userInfo.id, friendId, avater)
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {
    recycleView = createRecycleContext({
      id: 'recycleId',
      dataKey: 'chatList',
      page: this,
      // itemSize: { // 这个参数也可以直接传下面定义的this.itemSizeFunc函数
      //   height: rpx2px(220),
      //   width: rpx2px(750)
      // }
      itemSize:this.itemSizeFunc
    })
    // this.cacluteWidthAndHeight()
    recycleView.append(this.data.chatList)
    // this.cacluteChatContentHeight()
  },

  /**
   * 动态计算每一个item的宽高
   * @param {object} item 当前item显示的内容
   * @param {Integer} idx 
   */
  itemSizeFunc: function (item, idx) {
    return {
      width: rpx2px(220),
      height: rpx2px(400)
    }
  },

  cacluteWidthAndHeight: function(){

    let id = ".text"
    var obj=wx.createSelectorQuery();
    obj.selectAll(id).boundingClientRect();
    obj.exec(function (rect) {
        console.log("YM---->渲染区域信息:",rect)
    }) ;
  },

  /**
   * 计算聊天内容的整体页面高度
   */
  cacluteChatContentHeight: function(){
    let that = this
    let windowHeight = wx.getSystemInfoSync().windowHeight
    let id = ".chat_bottom"
    var obj=wx.createSelectorQuery();
    obj.selectAll(id).boundingClientRect();
    obj.exec(function (rect) {
        // console.log(rect[0].height)
        // console.log(rect[0].width)
        let bottomOperatorHeight = rect[0][0].height
        let chatContentHeight = windowHeight - bottomOperatorHeight
        that.setData({
          chatContentHeight:chatContentHeight
        })
        
    }) ;
  },
  /**
   * 
   * @param {*} e 下拉刷新
   */
  _refresherrefresh: function(e){
    // recycleView.splice(0,recycleView.getList().length)
    // recycleView.splice(this.data.chatList.length-1,recycleView.getList().length)
    recycleView.splice(0,recycleView.getList().length,this.data.chatList)
    this.setData({
      isstoppull:false
    })
  },
  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  },
  onTapSelecPhoto: function () {
    let that = this
    wx.chooseImage({
      count: 1,
      sizeType: ['original', 'compressed'],
      sourceType: ['album', 'camera'],
      success(res) {
        //tempFilePath可以作为img标签的src属性显示图片
        const tempFilePaths = res.tempFilePaths
        console.log("YM------>图片内容", tempFilePaths)
        localMessageId += 1
        that.sendPhoto(tempFilePaths[0],localMessageId)
        let tempFileObj = {
          localMessageId,
          localPath: tempFilePaths[0]
        }
        that.init.tempFileList.push(tempFileObj)
        that.uploadPicList()
      }
    })
  },
  upLoadPic: function (tempFile, resolve, reject) {
    // var content = util.JSON_to_URLEncoded(data)
    var updateApi = app.getApi(app.apiConstant.uploadOnly)
    let suffix = util.getFileSuffix(tempFile.localPath)
    let fileName = fileUtil.getDetailsFileName(suffix)
    // 当设置 mutiple 为 true 时, file 为数组格式,否则为对象格式
    console.log("YM------>开始上传任务", tempFile)
    wx.uploadFile({
      url: updateApi,
      filePath: tempFile.localPath,
      name: 'file',
      formData: {
        saveName: fileName
      },
      success(res) {
        let result = JSON.parse(res.data)
        if (!result.success) {
          reject(`错误码:${result.code}`)
          return
        }
        let data = result.data
        let fileUrl = app.getApi(app.apiConstant.imgUrl).concat(data.saveName)
        tempFile.netPath = fileUrl
        tempFile.saveName = data.saveName
        resolve(tempFile)
      },
      fail(error) {
        console.log("YM---->错误", error)
        reject(`${tempFile.localPath}出现错误`)
      },
    });
  },
  /**
   * 批量同步异步上传图片
   */
  uploadPicList: function () {
    let that = this
    let promiseList = []
    this.init.tempFileList.forEach(file => {
      let promise = new Promise(function (resolve, reject) {
        that.upLoadPic(file, resolve, reject)
      });
      promiseList.push(promise)
    })
    Promise.all(promiseList)
      .then((values) => {
        console.log("上传的结果",values);
        // let photoMessage = chatMessageUtil.createChatPhotoMessage(that.init.commonMessage, "图片路径")
        let result = values[0]
        that.updateMessageUI(result.localMessageId)
      }).catch((error) => {
        console.log(error)
        wx.showToast({
          title: `图片上传错误码,请检查网络`,
        })
      });
  },

  /**
   * 更新已经存在的消息
   * @param {*} messageId 根据已经存在的消息ID去查询历史消息记录
   */
  updateMessageUI: function(messageId){
    let allList = recycleView.getList()
    console.log("YM---->列表数据",allList)
    let findeResult = recycleView.getList().find(element => element.localMessageId == messageId)
    console.log("YM---->查找的结果",findeResult)
    if(!findeResult) {
      return
    }
    let index = recycleView.getList().indexOf(findeResult)//找到既定值的索引位置
    console.log("YM---->索引位置",index)
    findeResult.sendStatus = sendStatus.SEND_SUCCESS //更改发送状态为成功
    recycleView.update(index,findeResult,callBack => {
      console.log("YM---->列表的整体数据",recycleView.getList())
    })
  },

  /**
   * 发送文字
   */
  onTapSendText: function () {
    let textMessage = chatMessageUtil.createChatTextMessage(this.init.commonMessage, this.init.messageText)
    this.sendMessage(textMessage)
  },
  /**
   * 发送图片
   */
  sendPhoto: function(photoPath,localMessageId){
    let photoMessage = chatMessageUtil.createChatPhotoMessage(this.init.commonMessage, photoPath,localMessageId)
    this.sendMessage(photoMessage)
  },

  onBindInput: function (e) {
    this.init.messageText = e.detail.value
  },

  sendMessage: function (message) {
    let tempMessage = JSON.parse(JSON.stringify(message))//需要重新copy一份对象,否则会修改之前的内容
    recycleView.append(tempMessage, callback => {
      let allList = recycleView.getList()
      this.setData({
        selectIndex: allList.length - 1
      })
    })
  }
})

聊天页面布局

<!--pages/chat/chat.wxml-->
<!-- 引入模块 -->
<import src="../template/chat/templete_chatitem.wxml" />
<wxs src="./chat_util.wxs" module="chatTools"></wxs>
<view>
	<recycle-view refresherenabled="{{ispull}}" refreshertriggered="{{isstoppull}}" bindrefresherrefresh="_refresherrefresh" class="chat_content" batch="{{batchSetRecycleData}}" id="recycleId" scroll-to-index="{{selectIndex}}">
		<recycle-item class="chat_item {{index == 0 ? 'first_mar_top' : ''}}" wx:for="{{chatList}}" wx:key="msgId">
			<view class="text" wx:if="{{item.msgType == 0}}">
				<!--文本布局-->
				<template is="chatText" data="{{...item,...{self:chatTools.isSelf(item.fromId,userId)},...{showTime:chatTools.dateDiff(item.sendTime)} }}"></template>
			</view>
			<block id="photo" wx:elif="{{item.msgType == 1}}">
				<!--图片布局-->
				<template is="chatPhoto" data="{{...item,...{self:chatTools.isSelf(item.fromId,userId)},...{showTime:chatTools.dateDiff(item.sendTime)}  }}"></template>
			</block>
			<block id="system" wx:elif="{{item.msgType == 2}}">
				<template is="chatSystemText" data="{{...item,...{self:chatTools.isSelf(item.fromId,userId)},...{showTime:chatTools.dateDiff(item.sendTime)} }}"></template>
			</block>
		</recycle-item>
	</recycle-view>
	<view class="chat_bottom">
		<input class="chat_bottom_input" placeholder="请留言~" bindinput="onBindInput"></input>
		<image class="chat_bottom_photo" bindtap="onTapSelecPhoto" src="../../img/add_more.png"></image>
		<view class="chat_bottom_send" bindtap="onTapSendText">发送</view>
	</view>
</view>

聊天页面渲染

/* pages/chat/chat.wxss */
@import "../template/chat/templete_chatitem.wxss";
page {
  background-color: #F8F8F8;
}

.chat_root{
  margin-bottom: 250rpx;
}

.item, .item > view {
  display: flex;
  align-items: center;
  height: 150px;
  width: 100%;
} 
.item-content {
  width: 100%;
  display: flex;
  flex-direction: row;
  justify-content: space-around;
  height: 150px;
  align-items: center;
}

.chat_content{
  padding-bottom: 50rpx;
}

.first_mar_top{
  padding-top: 50rpx;
}

.chat_item{
  width: 100%;

}
.chat_bottom{
  flex-grow: 0;
  background-color: white;
  padding: 30rpx;
  display: flex;
  flex-direction: row;
  align-items: center;
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
}

.chat_bottom_photo{
  width: 60rpx;
  height: 60rpx;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-shrink: 0;
}

.chat_bottom_input{
  color: #333;
  font-size: 32rpx;
  border-bottom:0.5rpx #e8e8e8 solid;
  margin: 0 20rpx;
  align-self: flex-end;
  flex-grow: 1;
}

.chat_bottom_send{
  display: flex;
  justify-content: center;
  align-items: center;
  flex-shrink: 0;
  width: 96rpx;
  height: 48rpx;
  background-color: #E8684C;
  padding: 10rpx;
  border-radius: 14rpx;
  margin-left: 16rpx;
  color: white;
  font-size: 36rpx;
}

遇到的问题

  1. 追加数据的问题:

     let tempMessage = JSON.parse(JSON.stringify(message))//需要重新copy一份对象,否则会修改之前的内容
    
      recycleView.append(tempMessage, callback => {//数据渲染后的回调监听
    
       let allList = recycleView.getList()//获取页面全部数据
    
       this.setData({
    
    ​    selectIndex: allList.length - 1
    
       })
    
      })
    
  2. 修改每一个item的宽高

     /**
       * 生命周期函数--监听页面初次渲染完成
       */
      onReady: function () {
        var recycleView = createRecycleContext({
          id: 'recycleId',
          dataKey: 'chatList',
          page: this,
          // itemSize: { // 这个参数也可以直接传下面定义的this.itemSizeFunc函数
          //   height: rpx2px(220),
          //   width: rpx2px(750)
          // }
          itemSize:this.itemSizeFunc
        })
        // this.cacluteWidthAndHeight()
        recycleView.append(this.data.chatList)
        // this.cacluteChatContentHeight()
      },
    
      /**
       * 动态计算每一个item的宽高
       * @param {object} item 当前item显示的内容
       * @param {Integer} idx  当前item索引值
       */
      itemSizeFunc: function (item, idx) {
        // console.log("YM--item",item)
        // console.log("YM--idx",idx)
        
        return {
          width: rpx2px(220),
          height: rpx2px(400)
        }
      },
    
    
  3. 清空并追加新的数据

    /**
       * 
       * @param {*} e 下拉刷新
       */
      _refresherrefresh: function(e){
        // 清空数据recycleView.splice(0,recycleView.getList().length)
        // 删除指定数据recycleView.splice(this.data.chatList.length-1,recycleView.getList().length)
        //删除制定数据并进行替换数据recycleView.splice(0,recycleView.getList().length,this.data.chatList)
        console.log("YM--->下拉刷新")
        this.setData({
          isstoppull:false
        })
      },
    
  4. 下拉刷新
    下拉刷新是根据网上改的recycle-view的源码做的,因为源码在npm中,所以如果使用npm进行重新构建的话,修改的部分会还原,所以要么换种方式,要么就把代码拿出来不使用npm构建

    
    

官方文档:https://developers.weixin.qq.com/miniprogram/dev/extended/component-plus/recycle-view.html

recycle-view添加下拉刷新:https://www.cnblogs.com/han-guang-xue/p/13048505.html

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值