uni-app 之 聊天室页面滚动到底部
<p style="text-align: center"><strong><span style="font-size: 18pt">uni-app 之 聊天室滚到最底部</span></strong></p><p> <strong>请注意 !: 知识点为uni-app 与 vue 结合</strong></p>
<p> 这次写到聊天室,碰到一个emmmmm问题比较严重的事情,聊天嘛,咱们想实现的就无非是微信,QQ那种聊天的效果嘛,我们研究了,,,,emmmm (n久之长),终于是把这个功能写出来了,代码等什么时候整理出来给大家看,今天主要说一下碰到的一个问题,就是我发送消息的时候, 想要将消息弹出,发一条弹一条,代码附上</p>
<p> 注意:scroll-view要设置高度</p>
<p> 输入内容后,必然要在对话界面的底部显示内容,可以通过uni.pageScrollTo的方式,但是这个页面刷新的太厉害,输入框都刷新了,没法使用。所以只能使用scroll-view组件。但是通过scroll-view使用竖向滚动时,需要给 一个固定高度。为了适配屏幕的大小,则需要通过计算来确定scroll-view的高度。</p>
<div class="cnblogs_code">
<pre><view <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">content</span><span style="color: rgba(128, 0, 0, 1)">"</span> id=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">content</span><span style="color: rgba(128, 0, 0, 1)">"</span> :style=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{height: style.contentViewHeight + 'px'}</span><span style="color: rgba(128, 0, 0, 1)">"</span>>
<scroll-view id=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">scrollview</span><span style="color: rgba(128, 0, 0, 1)">"</span> <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">chat-window</span><span style="color: rgba(128, 0, 0, 1)">"</span> scroll-y=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">true</span><span style="color: rgba(128, 0, 0, 1)">"</span> :style=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{height: style.contentViewHeight + 'px'}</span><span style="color: rgba(128, 0, 0, 1)">"</span> :scroll-with-animation=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">true</span><span style="color: rgba(128, 0, 0, 1)">"</span> :scroll-top=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">scrollTop</span><span style="color: rgba(128, 0, 0, 1)">"</span>>
<!-- <view <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">chat-window</span><span style="color: rgba(128, 0, 0, 1)">"</span>> -->
<view <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">small-talk_time</span><span style="color: rgba(128, 0, 0, 1)">"</span>><span style="color: rgba(128, 0, 128, 1)">12</span>:<span style="color: rgba(128, 0, 128, 1)">18</span></view>
<!-- 聊天内容 -->
<view <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">content-all</span><span style="color: rgba(128, 0, 0, 1)">"</span>>
<!-- 聊天窗口 -->
<view :<span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">item.type</span><span style="color: rgba(128, 0, 0, 1)">"</span> v-<span style="color: rgba(0, 0, 255, 1)">for</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">(item, index) in chatRecord</span><span style="color: rgba(128, 0, 0, 1)">"</span> :key=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">index</span><span style="color: rgba(128, 0, 0, 1)">"</span> <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">m-item</span><span style="color: rgba(128, 0, 0, 1)">"</span>>
<!-- 收信人 -->
<view <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">talk-text talk-left</span><span style="color: rgba(128, 0, 0, 1)">"</span> v-<span style="color: rgba(0, 0, 255, 1)">if</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">item.type == 'talk-left'</span><span style="color: rgba(128, 0, 0, 1)">"</span>>
<!-- 收信人头像 -->
<view <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">talk-photo</span><span style="color: rgba(128, 0, 0, 1)">"</span>>
<image src=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">../../static/images/myself.jpg</span><span style="color: rgba(128, 0, 0, 1)">"</span> <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">talk-img</span><span style="color: rgba(128, 0, 0, 1)">"</span>></image>
</view>
<!-- 收信人消息 -->
<view <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">talk-content</span><span style="color: rgba(128, 0, 0, 1)">"</span>>
<view <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">talk-huge</span><span style="color: rgba(128, 0, 0, 1)">"</span>></view>
<view <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">talk-title</span><span style="color: rgba(128, 0, 0, 1)">"</span>>{{item.message}}</view>
</view>
</view>
<view <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">talk-text talk-right</span><span style="color: rgba(128, 0, 0, 1)">"</span> v-<span style="color: rgba(0, 0, 255, 1)">if</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">item.type == 'talk-right'</span><span style="color: rgba(128, 0, 0, 1)">"</span>>
<!-- 发信人消息 -->
<view <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">talk-content</span><span style="color: rgba(128, 0, 0, 1)">"</span>>
<view <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">talk-title</span><span style="color: rgba(128, 0, 0, 1)">"</span>>{{item.message}}</view>
<view <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">talk-huge</span><span style="color: rgba(128, 0, 0, 1)">"</span>></view>
</view>
<!-- 发信人头像 -->
<view <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">talk-photo</span><span style="color: rgba(128, 0, 0, 1)">"</span>>
<image src=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">../../static/images/myself.jpg</span><span style="color: rgba(128, 0, 0, 1)">"</span> <span style="color: rgba(0, 0, 255, 1)">class</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">talk-img</span><span style="color: rgba(128, 0, 0, 1)">"</span>></image>
</view>
</view>
</view>
</view>
<!-- </view> -->
</scroll-view>
</view></pre>
</div>
<p> 既然是聊天 先将聊天页面写出来 写好了你说我说的样式 大概就是这个样子</p>
<p><img src="https://img2018.cnblogs.com/blog/1664944/201907/1664944-20190729191544082-1880469160.png"></p>
<p>接下来是咱们的js了</p>
<div class="cnblogs_code">
<pre></pre>
<p> created () {<br> const res = uni.getSystemInfoSync(); <span style="color: rgba(51, 153, 102, 1)"> //获取手机可使用窗口高度 api为获取系统信息同步接口</span><br> this.style.pageHeight = res.windowHeight;<br> this.style.contentViewHeight = res.windowHeight - uni.getSystemInfoSync().screenWidth / 750 * (100) - 70; <span style="color: rgba(51, 153, 102, 1)">//像素 因为给出的是像素高度 然后我们用的是upx 所以换算一下 </span><br> this.scrollToBottom(); <span style="color: rgba(51, 153, 102, 1)">//创建后调用回到底部方法</span><br> },<span style="color: rgba(0, 128, 0, 1)"> </span></p>
<pre><span style="color: rgba(0, 128, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">export default {</span><br><span style="color: rgba(0, 0, 0, 1)"> data (){</span><br> //</span><span style="color: rgba(0, 128, 0, 1)"> 聊天页面时时滚动样式</span>
<span style="color: rgba(0, 0, 0, 1)"> style: {
pageHeight: </span><span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">,
contentViewHeight: </span><span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">,
footViewHeight: </span><span style="color: rgba(128, 0, 128, 1)">90</span><span style="color: rgba(0, 0, 0, 1)">,
mitemHeight: </span><span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">
},<br> }<br>}</span></pre>
</div>
<p>js代码:</p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* @author gongliying
* @date 2019-07-26
* @information 跳转页面底部
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
scrollToBottom: function () {
let that </span>= <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">;
let query </span>=<span style="color: rgba(0, 0, 0, 1)"> uni.createSelectorQuery();
query.selectAll(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">.m-item</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">).boundingClientRect();
query.</span><span style="color: rgba(0, 0, 255, 1)">select</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">#scrollview</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">).boundingClientRect();
query.exec((res) </span>=><span style="color: rgba(0, 0, 0, 1)"> {
that.style.mitemHeight </span>= <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
res[</span><span style="color: rgba(128, 0, 128, 1)">0</span>].forEach((rect) => that.style.mitemHeight = that.style.mitemHeight + rect.height + <span style="color: rgba(128, 0, 128, 1)">40</span><span style="color: rgba(0, 0, 0, 1)">) <span style="color: rgba(51, 153, 102, 1)">//获取所有内部子元素的高度
</span></span><span style="color: rgba(0, 0, 255, 1)">if</span> (that.style.mitemHeight > (that.style.contentViewHeight - <span style="color: rgba(128, 0, 128, 1)">100</span><span style="color: rgba(0, 0, 0, 1)">)) { <span style="color: rgba(51, 153, 102, 1)">//判断子元素高度是否大于显示高度</span>
that.scrollTop </span>= that.style.mitemHeight -<span style="color: rgba(0, 0, 0, 1)"> that.style.contentViewHeight <span style="color: rgba(51, 153, 102, 1)">//用子元素的高度减去显示的高度就获益获得序言滚动的高度</span>
}
})
}</span></pre>
</div>
<p> 这一步做的主要就是获取这个‘.m-item’这个里面的节点信息 uni-app虽然不支持window和document 但是咱们还是有一个api可以获取他元素的信息的 就算是uni.createSelectorQuery()这个api,他会返回一个 <code>SelectorQuery</code> 对象实例。可以在这个实例上使用 <code>select</code> 等方法选择节点,并使用 <code>boundingClientRect</code> 等方法选择需要查询的信息。这个exec()他会执行这里面所有的请求,我们最后会获取到他的id dataset 左边界坐标 右边界坐标 上边界坐标 下边界左边 节点的宽度 节点的高度 具体的这个方法的使用可以去官网查看一番,我就不具体解释了 毕竟今天重点不是他呀 回到 原题 咱们说了 在最开始created的时候获取你当前使用手机的品牌啊 型号啊 我们这里主要的是获取可使用窗口的高度 然后我们又获取了所有子元素的告诉 然后就可以看着我的注释走了~~~~</p>
<p> 但是呢。你们不要以为这样就好了 , 还有一个很重要的事情,如果你们认真看了这段代码还有就是实验了一下, 你们会发现到最后那个滚动条没有滚动到最底部,会发现最后一调消息被隐藏了,也不是没有 ,页面上有这条消息,但是呢就是没有弹出来,后来呢,</p>
<p>仔细分析了一下,因为<strong>由于vue采用虚拟dom,我每次生成新的消息时获取到的div的scrollHeight的值是生成新消息之前的值,所以造成每次都是最新的那条消息被隐藏掉了!</strong>这就是开头我跟大家说注意这是uni-app和vue结合的原因了</p>
<p> 解决方法:采用异步处理settimeout函数获取最新的scrollheight 让他先全部执行完了之后去走这个异步,这样就能确保滚动条每次滚到的都是最底部 上段代码更改如下:</p>
<p> </p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
* @author gongliying
* @date 2019-07-26
* @information 跳转页面底部
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
scrollToBottom: function () {
let that </span>= <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">;
let query </span>=<span style="color: rgba(0, 0, 0, 1)"> uni.createSelectorQuery();
query.selectAll(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">.m-item</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">).boundingClientRect();
query.</span><span style="color: rgba(0, 0, 255, 1)">select</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">#scrollview</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">).boundingClientRect();
query.exec((res) </span>=><span style="color: rgba(0, 0, 0, 1)"> {
that.style.mitemHeight </span>= <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
res[</span><span style="color: rgba(128, 0, 128, 1)">0</span>].forEach((rect) => that.style.mitemHeight = that.style.mitemHeight + rect.height + <span style="color: rgba(128, 0, 128, 1)">40</span>) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取所有内部子元素的高度</span></pre>
<p> <span style="color: rgba(255, 0, 0, 1)">// 因为vue的虚拟DOM 每次生成的新消息都是之前的,所以采用异步setTimeout 主要就是添加了这红字</span><br><span style="color: rgba(255, 0, 0, 1)"> setTimeout(() => {</span></p>
<pre><em id="__mceDel"> <span style="color: rgba(0, 0, 255, 1)">if</span> (that.style.mitemHeight > (that.style.contentViewHeight - <span style="color: rgba(128, 0, 128, 1)">100</span>)) { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">判断子元素高度是否大于显示高度</span>
that.scrollTop = that.style.mitemHeight - that.style.contentViewHeight <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">用子元素的高度减去显示的高度就获益获得序言滚动的高度</span>
<span style="color: rgba(0, 0, 0, 1)"> }<br> <span style="color: rgba(255, 0, 0, 1)">}, 100)</span>
})
}</span></em></pre>
</div>
<p>最后实现了每次聊天都是滚到最底部 要是想要进入页面就滚到最底部呢 我们是在socket链接读取文件的时候调用了这个方法</p>
<p>ending~~~~</p>
<p> </p><br><br>
来源:https://www.cnblogs.com/gongliying/p/11258189.html
頁:
[1]