15 聊天界面開發
(this.$nextTick,長單詞超出,flex-direction: row-reverse,scroll-view絕對定位)
縱覽效果圖:
一 跳轉和配置
1 components/msg/msg-list.vue 進行跳轉到pages/user-chart/user-chart.vue
2 配置pages .json
效果圖:
代碼:
,{
"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>