首页 > 编程语言 >小程序的聊天功能中如何让消息列表定位到未读消息

小程序的聊天功能中如何让消息列表定位到未读消息

时间:2023-02-17 16:26:32浏览次数:52  
标签:未读 列表 消息 NodesRef 组件 wx SelectorQuery view

需求中有这样的一条:要将聊天消息定位到首个未读消息。看到这样的需求笔者灵机一动:首先想到就是把聊天消息放到滚动容器中,然后根据已读的消息设置滚动条的滚动高度,如此一来就可以定位到未读消息啦。

wx.createSelectorQuery、SelectorQuery 与 NodesRef

可是这个解决方案中的关键点时啥啊?想一想,无非就是要知道那些已读消息的高度。那么微信中有没有相关的 API 可以获取到 wxml 中元素(组件)的高度呢?还真有,那就是wx.createSelectorQuery

wx.createSelectorQuery 方法调用后会返回一个 SelectorQuery 对象实例,SelectorQuery 对象实例用于查询节点信息的对象,提供了如下的方法(以下 5 个方法本文中都会使用,都需要关注! ):

  1. SelectorQuery SelectorQuery.in(Component component):将选择器的选取范围更改为自定义组件 component 内。
  2. NodesRef SelectorQuery.select(string selector):在当前页面下选择第一个匹配选择器 selector 的节点。返回一个 NodesRef 对象实例,可以用于获取节点信息。
  3. NodesRef SelectorQuery.selectAll(string selector):在当前页面下选择匹配选择器 selector 的所有节点。
  4. NodesRef SelectorQuery.selectViewport():选择显示区域。可用于获取显示区域的尺寸、滚动位置等信息。
  5. NodesRef SelectorQuery.exec(function callback):执行所有的请求。请求结果按请求次序构成数组,在 callback 的第一个参数中返回。

看到对于 select、selectAll、selectViewport 还有 exec 方法都返回NodesRef类型的对象,它是用于获取 WXML 节点信息的对象,看一下这个类的实例可以调用的一个重要的方法:
SelectorQuery NodesRef.boundingClientRect(NodesRef.boundingClientRectCallback callback):添加节点的布局位置的查询请求。相对于显示区域,以像素为单位。其功能类似于 DOM 的 getBoundingClientRect。返回 NodesRef 对应的 SelectorQuery 。

需要注意:SelectorQuery 实例的 select、selectAll、selectViewport 方法调用后会返回 NodesRef 的实例,NodesRef 实例的 boundingClientRect 方法调用后又会返回 SelectorQuery 实例。这也就是本文中接下来介绍的演示代码中可以链式调用的原因。

代码示例

如下所示:在 data 中定义了 scrollTop 用于控制 scroll-view 组件的滚动高度;定义了 blockList 数组用于循环渲染出 view 组件从而来模拟聊天消息,注意这里定义了 9 个已读消息,10 个未读消息。

data: {
    scrollTop: 0,
    blockList: [
        {
            content: '1',
            hasRead: true
        },
        //....
        {
            content: '9',
            hasRead: true
        },
        {
            content: '10',
            hasRead: false
        },
        //....
        {
            content: '20',
            hasRead: false
        },
    ]
},

如下所示的 wxml 代码中,在 scroll-view 组件中嵌套了一个固定的 view 组件和用 wx:for 指令循环生成的一组 view 组件。注意对于循环生成的 view 组件为其绑定了动态的 class,如果是已读消息则 class 类名为 read-class,如果是未读消息则 class 类名为 unread-class:

<!--pages/test/test.wxml-->
<view class="test-container">这是页面主体
  <scroll-view class="test-scroll" 	scroll-top="{{scrollTop}}"	scroll-y="true" bindscrolltolower="loadMore">
    <view class="block-read" >我是测试内容块</view>
    <view wx:for="{{blockList}}" class="{{item.hasRead ? 'read-class': 'unread-class'}}" >
      {{item.content}}
    </view>
  </scroll-view>
</view>

如下所示的 css 代码中为固定的 view 组件定义了灰色(#ccc)的边框,为循环生成的代表已读消息的 view 组件定义了绿色边框,为循环生成的代表未读消息的 view 组件定义了红色边框:

.block-read {
  height: 400rpx;
  border: 1px solid #ccc;
}
.read-class {
  height: 200rpx;
  border: 1px solid green;
}

.unread-class {
  height: 180rpx;
  border: 1px solid red;
}

.test-scroll {
  height: 700px;
}

以上代码的执行效果如下图所示:

下面尝试使用 wx.createSelectorQuery,SelectorQuery 类的 select、selectAll,exec 方法,NodesRef 的 boundingClientRect 方法来获取 view 组件的高度。
首先使用 select 选中未读消息,代码如下图所示:

getViewHeight() {
  const query = wx.createSelectorQuery().in(this)
  query.select('.read-class').boundingClientRect((res:any) => {
    console.log(res)
  }).exec()
},

由于 select 只会在当前页面下选择第一个匹配选择器的节点,所以可以打印出一个节点的信息,如下图所示:

下面代码中将 select 换成 selectAll:

getViewHeight() {
  const query = wx.createSelectorQuery().in(this)
  query.selectAll('.read-class').boundingClientRect((res:any) => {
    console.log(res)
  }).exec()
},

selectAll 可以在当前页面下选择匹配选择器的所有节点,所以可以打印出一个数组,如下图所示

有了所有节点的数组后就可以循环遍历数组元素对元素 height 值累加,这样就得到了所有已读消息的高度,滚动条的 scrollTop 赋值为这个值之后就可以定位到首个未读消息了:

getViewHeight() {
  const query = wx.createSelectorQuery().in(this)
  query.selectAll('.read-class').boundingClientRect((res:any) => {
    let scrollTop = 0
    res.forEach((item: any) => {
      scrollTop += item.height
    })
    console.log(scrollTop)
    this.setData({
      scrollTop:scrollTop
    })
  }).exec()
},
onLoad() {
  this.getViewHeight()
},

代码执行效果如下图所示:

最后再来看一下 selectViewport 的使用:

const query = wx.createSelectorQuery().in(this);
query
  .selectViewport()
  .boundingClientRect((res) => {
    console.log(res);
  })
  .exec();

selectViewport 会选择显示区域,可用于获取显示区域的尺寸、滚动位置等信息,代码执行结果如下图所示:

可以看到显示区域的高度是 721px ,显示区域的宽度是 375px。使用调试器中的 wxml 进行元素选择得到的结果和代码是一致的,如下图所示:

总结

要将聊天消息定位到首个未读消息的需求可以把聊天消息放到滚动容器中,然后根据已读的消息设置滚动条的滚动高度。
scroll-view 组件的 scroll-top 属性用于设置竖向滚动条位置。
wx.createSelectorQuery 方法调用后会返回一个 SelectorQuery 对象实例,SelectorQuery 对象实例用于查询节点信息,提供了 select、selectAll、selectViewport 等方法。
NodesRef 类型的对象是用于获取 WXML 节点信息的对象,可以调用 boundingClientRect 来查询节点的布局位置。

标签:未读,列表,消息,NodesRef,组件,wx,SelectorQuery,view
From: https://www.cnblogs.com/wp-leonard/p/17130537.html

相关文章

  • python将列表切割成小列表
    想实现类似于php中array_chunk()函数把一个数组分割为新的数组块。python没有相关的函数,那么分享一下处理方法:如:有一个列表l,元素是a到z的字符串,我想将他切成3个字母为......
  • win64环境下监听键盘操作并发送MQTT消息
    1.MQTT服务安装下载EMQX做MQTT代理服务器https://www.emqx.cn/downloads/broker/v4.2.7/emqx-centos7-4.2.7-x86_64.zip解压安装即可启动MQTT服务器在emqx/bin目录下......
  • 【网络】Wireshark分析RST消息
    文章目录    前言    1、定义:    2、有三个条件可以产生RST:    3、说明    4、RST数据报文产生情况        1......
  • 消息队列非阻塞
    消息队列(也叫做报文队列)能够克服早期unix通信机制的一些缺点。作为早期unix通信机制之一的信号能够传送的信息量有限,后来虽然POSIX1003.1b在信号的实时性方面作了拓广,使......
  • python列表推导式的结构探究
    1、列表推导式结构包含在一对方括号中,一个表达式,后面是for子句,然后是零个或多个for或if子句。2、其结果将是一个新列表,根据for和if子句的内容计算表达式。实例fromcollecti......
  • Java: RocketMQ事务消息的优雅使用
    背景在项目中,技术方案需要使用事务消息来保证最终一致性达到实现业务的目的。但在一个服务中有多个业务需要使用事务消息发送不同的消息类型到不同的Topic时,RocketMQ的本......
  • 切换窗体或消息控制窗体的延时问题
    应用场景如:ShowWindow+SetForegroundWindow,用来切换窗体,有时切换失败对其他窗体SendMessageWM_KEYDOWN或其他消息控制动作,有时逻辑异常问题原因:其他窗......
  • HTML 速查列表
    HTML 速查列表HTML速查列表.你可以打印它,以备日常使用。HTML基本文档<!DOCTYPEhtml><html><head><title>文档标题</title></head><body>可见文本...</b......
  • vue2 - 条件渲染,列表熏染
    1.条件熏染v-if(1).v-if="表达式"(2).v-else-if="表达式"(3).v-else="表达式"适用于:切换频率较低的场景特点:不展示的DOM元素直接被移除注意:v-if可以和:v-else-if,v-e......
  • python入门之列表推导式嵌套
    #传统写法:list01=["a","b","c"]list02=["A","B","C"]list03=[]forrinlist01:forcinlist02:list03.append(r+c)print(list03) ......