15 uniapp-聊天界面开发(this.$nextTick,长单词超出,flex-direction: row-reverse,scroll-view绝对定位)
15 聊天界面开发
(this.$nextTick,长单词超出,flex-direction: row-reverse,scroll-view绝对定位)
纵览效果图:
一 跳转和配置
1 components/msg/msg-list.vue 进行跳转到pages/user-chart/user-chart.vue
2 配置pages .json
效果图:![image-20200408144110553](15 聊天界面开发.assets/image-20200408144110553.png)
代码:
,{
"path" : "pages/user-chart/user-chart",
"style" : {
"app-plus":{
"titleNView":{
"buttons":[{
"color":"#333333",
"colorPressed":"#FD597C",
"float":"right",
"fontSize":"20px",
"fontSrc":"/static/iconfont.ttf",
"text":"\ue628"
}]
}
}
}
}
二 编写底部聊天框
效果图:
代码:
<template>
<view>
<!-- 底部操作条 -->
<view style="height: 100rpx;"
class="fixed-bottom flex align-center border-top bg-light">
<input type="text" value="" class="flex-1 rounded ml-2 bg-white" style="padding:10rpx;" placeholder="文明发言"/>
<view class="iconfont icon-fabu flex align-center justify-center font-lger animated" hover-class="jello text-main" style="width: 100rpx;">
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
}
},
methods: {
}
}
</script>
<style>
</style>
三 封装聊天页面组件
效果图:
代码(涉及最大宽度问题,涉及聊天时间显示问题,涉及镜像反转flex):
components/user-chart-list/User-chart-list.vue
<template>
<view>
<!-- 聊天时间 -->
<view v-if="shortTime"
class="py2 flex align-center justify-center font-sm text-light-muted">
{{shortTime}}
</view>
<!-- 消息气泡 -->
<view class="p-2 flex align-start "
<!-- 镜像反转flex -->
:style="isSelf? 'flex-direction: row-reverse;':''">
<image :src="item.avatar"
class="rounded-circle"
mode=""
style="height: 80rpx; width: 80rpx; "></image>
<!-- max-width属性设置元素内容的最大宽度。
注意: max-width属性不包括填充,边框,或页边距! -->
<view class="px-1 mx-1 mt-2 bg-light " style="max-width: 400rpx;">
{{item.data}}
</view>
</view>
</view>
</template>
<script>
// 模拟当前登录用户的userid
const uid = 1;
import $T from '@/common/time.js';
export default {
props:{
item:Object,
index:Number,
pretime:[Number,String]
},
data() {
return {
}
},
computed:{
// 是否是登陆的本人
isSelf(){
return uid === this.item.user_id
},
// 转化时间,直接拿到计算好的是否超过了3分钟的人性化时间
shortTime(){
return $T.getChatTime(this.item.create_time,this.pretime)
}
},
methods: {
}
}
</script>
<style>
</style>
pages/user-chart/User-chart.vue(关注聊天scroll 部分
<template>
<view>
<!-- 底部操作条 -->
<view style="height: 100rpx;"
class="fixed-bottom flex align-center border-top bg-light">
<input type="text" value="" class="flex-1 rounded ml-2 bg-white" style="padding:10rpx;" placeholder="文明发言"/>
<view class="iconfont icon-fabu flex align-center justify-center font-lger animated" hover-class="jello text-main" style="width: 100rpx;">
</view>
</view>
<!-- 聊天scroll -->
<scroll-view scroll-y="true" :style="'height:'+scrollH+'px;'">
<!-- 聊天气泡+时间 -->
<block v-for="(item,index) in list" :key="index">
<user-chart-list :item="item" :index="index" :pretime="index > 0 ?list[index-1].create_time:0"></user-chart-list>
</block>
</scroll-view>
</view>
</template>
<script>
import userChartList from '@/components/user-chart/user-chart-list.vue'
export default {
components:{
userChartList
},
data() {
return {
list:[{
user_id:2,
avatar:"/static/default.jpg",
username:"昵称",
data:"你好啊",
type:"text",
create_time:1570783530
},{
user_id:1,
avatar:"/static/default.jpg",
username:"昵称",
data:"你好啊",
type:"text",
create_time:1570783530
},
{
user_id:1,
avatar:"/static/default.jpg",
username:"昵称",
data:"小火挺精神的",
type:"text",
create_time:1586247107
},
{
user_id:1,
avatar:"/static/default.jpg",
username:"昵称",
data:"小火挺精神的",
type:"text",
create_time:1586247120
}]
}
},
onLoad() {
uni.getSystemInfo({
success: (res) => {
this.scrollH = res.windowHeight - uni.upx2px(101)
}
})
},
methods: {
}
}
</script>
<style>
</style>
四 完善发送聊天功能
完善的内容
1 输入内容实现发送
2 页面载入的时候跳转到scroll-view的最后一个元素
3 发送完了信息的时候跳转到scroll-view的最后一个元素
效果图:
1 修改之前长单词抄出问题
<!-- max-width属性设置元素内容的最大宽度。
注意: max-width属性不包括填充,边框,或页边距! -->
<view class="px-1 mx-1 mt-2 bg-light " style="max-width: 400rpx;word-break:break-all; ">
{{item.data}}
</view>
2 scroll-view 关于聊天输入框往上推移的问题可以用绝对定位的思路
涉及知识点:
点1
// 等待dom渲染完成后再执行滚动到页面底部,不然dom没渲染这个是无效的。
this.$nextTick(function(){
// 滚动至页面底部
this.pageToBottom()
})
点2
input 的confirm时间监听键盘enter操作
点3
如果碰到键盘和scroll-view可以考虑使用绝对定位scroll-view组件
完整代码:
<template>
<view>
<!-- style="position: absolute;left:0;right:0;bottom: 100rpx;" -->
<!-- 聊天scroll --> <!--远离就是我给底下的字元素们起了一堆id名字,我视角定位到某一个id就ok -->
<scroll-view scroll-y="true"
style="position: absolute;left:0;top:0;right:0;bottom: 100rpx;"
:scroll-into-view="scrollInto" scroll-with-animation>
<!-- 聊天气泡+时间 -->
<block v-for="(item,index) in list" :key="index">
<view :id="'chart'+index">
<user-chat-list :item="item" :index="index" :pretime="index > 0 ?list[index-1].create_time:0"></user-chat-list>
</view>
</block>
</scroll-view>
<!-- 底部操作条 -->
<view style="height: 100rpx;"
class="fixed-bottom flex align-center border-top bg-light">
<input type="text" v-model="content" class="flex-1 rounded ml-2 bg-white" style="padding:10rpx;" placeholder="文明发言"
@confirm="submit"/>
<view class="iconfont icon-fabu flex align-center justify-center font-lger animated"
hover-class="jello text-main" style="width: 100rpx;"
@click="submit">
</view>
</view>
</view>
</template>
<script>
import userChatList from '@/components/user-chat/user-chat-list.vue'
export default {
components:{
userChatList
},
data() {
return {
scrollInto:"",
content:'',
list:[{
user_id:2,
avatar:"/static/default.jpg",
username:"昵称",
data:"你好啊",
type:"text",
create_time:1570783530
},{
user_id:1,
avatar:"/static/default.jpg",
username:"昵称",
data:"你好啊",
type:"text",
create_time:1570783530
},
{
user_id:1,
avatar:"/static/default.jpg",
username:"昵称",
data:"小火挺精神的",
type:"text",
create_time:1586247107
},
{
user_id:1,
avatar:"/static/default.jpg",
username:"昵称",
data:"小火挺精神的",
type:"text",
create_time:1586247120
},
{
user_id:1,
avatar:"/static/default.jpg",
username:"昵称",
data:"小火挺精神的",
type:"text",
create_time:1586247107
},
{
user_id:1,
avatar:"/static/default.jpg",
username:"昵称",
data:"小火挺精神的",
type:"text",
create_time:1586247107
},
{
user_id:1,
avatar:"/static/default.jpg",
username:"昵称",
data:"小火挺精神的",
type:"text",
create_time:1586247107
},
{
user_id:2,
avatar:"/static/default.jpg",
username:"昵称",
data:"小火挺精神的小火挺精神的小火挺精神的小火挺精神的小火挺精神的小火挺精神的小火挺精神的小火挺精神的小火挺精神的小火挺精神的小火挺精神的小火挺精神的小火挺精神的",
type:"text",
create_time:1586247107
},
{
user_id:2,
avatar:"/static/default.jpg",
username:"昵称",
data:"小火挺精神的",
type:"text",
create_time:1586247107
},]
}
},
onLoad() {
uni.getSystemInfo({
success: (res) => {
this.scrollH = res.windowHeight - uni.upx2px(101)
}
})
},
onReady(){
this.pageToBottom()
},
methods: {
submit(){
if (this.content===''){
return uni.showToast({
title:"消息不能为空",
icon:'none'
})
}
let obj={
user_id:1,
avatar:"/static/default.jpg",
username:"昵称",
data:this.content,
type:"text",
create_time:1586247120
}
this.list.push(obj)
// 清空输入框
this.content = ''
// 等待dom渲染完成后再执行滚动到页面底部,不然dom没渲染这个是无效的。
this.$nextTick(function(){
// 滚动至页面底部
this.pageToBottom()
})
},
// 滚动至底部
pageToBottom(){
// setTimeout(()=>{
let lastIndex = this.list.length -1
if (lastIndex<0) return;
this.scrollInto = 'chart'+ lastIndex
// },10)
}
}
}
</script>
<style>
</style>