Vue實(shí)現(xiàn)聊天界面
本文實(shí)例為大家分享了Vue實(shí)現(xiàn)聊天界面展示的具體代碼,供大家參考,具體內(nèi)容如下
1.功能需求
根據(jù)索引選擇跟不同的人進(jìn)行聊天


2.代碼展示
mock.js:
import Mock from 'mockjs'
Mock.mock("/chatchild",{
'result':[
{
id:"001",
imgurl:"/static/image/10.jpg",
name:"XKDK",
date:"09:23",
words:"哈哈,好噠"
},
// ... ...
]
});
export default Mock
userinfo.js:
let usermsg={
id:"122",
imgurl:"/static/image/8.jpg",
words:"是的!",
data:{
id:"1529",
imgurl:"/static/image/7.jpg",
name:"易安居士",
words:[
{info:"在嗎?"},
{info:"不在"},
{info:"你把草稿交了沒(méi)有"},
{info:"我今天中午吃完飯 就一直看劇了"},
{info:"我發(fā)現(xiàn)我真的是宅女"},
{info:"哈哈哈"},
{info:"有空找你約頓飯"},
{info:"嗯嗯"},
{info:"反正影響不大"}
]
}
}
export default usermsg
index.js:
import Vue from 'vue'
import Router from 'vue-router'
import Chat from '../components/Chat.vue'
import ChatDetail from '../components/Pages/ChatDetail.vue'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/Chat ',
component: Chat
},
{
path:'/ChatDetail',
component:ChatDetail
}
]
})
// 解決路由報(bào)錯(cuò)的代碼
const originalPush = Router.prototype.push
Router.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
}
Chat.vue:
<template>
<div id="chat">
<Bottom />
<Header :name="msg" />
<div class="chat_alluser">
<div ref="chatuser" @click="checkChild(index)" class="chatuser" v-for="(item,index) in chat" :key="index">
<ChatChild :imgsrc="item.imgurl" :nickname="item.name" :time="item.date" :word="item.words" />
</div>
</div>
</div>
</template>
<script>
import Bottom from "../components/Menu/Bottom";
import Header from "../components/Menu/Header";
import ChatChild from "../components/Pages/ChatChild";
export default {
name: "Chat",
components: {
Bottom: Bottom,
Header: Header,
ChatChild: ChatChild
},
data() {
return {
msg: "微信",
chat: null,
name: null
};
},
mounted() {
this.$axios.get("/chatchild").then(res => {
this.chat = res.data.result;
});
},
methods: {
checkChild(index) {
this.$refs.chatuser[index].style.backgroundColor = "rgb(240,240,240)";
// 動(dòng)態(tài)dom元素渲染完成之后,跳轉(zhuǎn)到另一個(gè)界面(ChatDetail)
// 獲取動(dòng)態(tài)name
let username = this.chat[index].name;
this.$nextTick(() => {
this.$router.push({
path: "/ChatDetail",
query: { name: username }
});
});
}
}
};
</script>
<style lang="scss" scope>
#chat {
width: 100%;
.chat_alluser {
margin-bottom: 7.5rem;
.chatuser {
position: relative;
top: 3.5rem;
padding: 0.3rem 0;
}
}
}
</style>
父組件使用子組件里的屬性和方法:
在父組件中的子組件上定義ref屬性,通過(guò) this.$ refs.name.屬性或this.$refs.name.方法
ChatChild.vue:
<template>
<div id="chatchild">
<div class="photo">
<img :src="imgsrc" alt />
</div>
<div class="content">
<div>
<span class="content_nickname">{{nickname}}</span>
<span class="content_time">{{time}}</span>
</div>
<span class="content_word">{{word}}</span>
</div>
</div>
</template>
<script>
export default {
name: "ChatChild",
props:{
'imgsrc':String,
'nickname':String,
'time':String,
'word':String
}
};
</script>
<style lang="scss" scope>
#chatchild {
width: 100%;
height: 5rem;
display: flex;
flex-direction: row;
box-sizing: border-box;
.photo {
flex: 1;
height: 5rem;
img{
object-fit: cover;
width: 4rem;
height: 4rem;
border-radius: 5px;
display: block;
margin: 0 auto;
margin-top: 0.5rem;
margin-left: 1rem;
}
}
.content {
flex: 4;
height: 5rem;
border-bottom: 0.5px solid rgb(240, 240, 240);
padding-left: 0.5rem;
padding-top: 0.5rem;
box-sizing: border-box;
div{
.content_nickname{
display: inline-block;
font-size: 1.1rem;
margin-top: 0.3rem;
}
.content_time{
float: right;
margin-right: 1rem;
color: rgb(209, 206, 206);
font-size: 0.8rem;
}
}
.content_word{
color: rgb(209, 206, 206);
font-size: 0.8rem;
display: block;
margin-top: 0.5rem;
}
}
}
</style>
ChatDetail.vue:
<template>
<div id="chatdetail">
<div class="chattop">
<div @click="goback" class="chattop_back">
<icon-svg icon-class="houtui_shangyibu_zuojiantou_shangyiye" />
</div>
<div class="chattop_name">{{name}}</div>
<div class="chattop_more">
<icon-svg icon-class="gengduo" />
</div>
</div>
<div class="chatcontent">
<ChatMsg ref="chatmsg" />
</div>
<div class="chatfooter">
<div @click="changeSound">
<icon-svg :icon-class="issound" />
</div>
<div>
<input ref="sendcontent" @keypress="sendmsg" :type="istype" :value="isvalue" />
</div>
<div>
<icon-svg icon-class="biaoqing" />
</div>
<div>
<icon-svg icon-class="del" />
</div>
</div>
</div>
</template>
<script>
import ChatMsg from "./ChatMsg";
export default {
name: "ChatDetail",
data() {
return {
name: null,
issound: "xiaoxitongzhi",
istype: "text",
isvalue: "",
isshow: false,
tomsg: "",
msgchild: null
};
},
components: {
ChatMsg: ChatMsg
},
mounted() {
this.name = this.$route.query.name;
this.msgchild = this.$refs.chatmsg;
},
methods: {
// 進(jìn)行返回操作
goback() {
this.$router.go(-1);
},
// 切換input的類型
changeSound() {
// 在data中定義一個(gè)變量isshow:false,利用this.isshow與!this.isshow進(jìn)行切換
if (!this.isshow) {
this.isshow = true;
this.issound = "yuyin";
this.istype = "button";
this.isvalue = "按住 說(shuō)話";
} else {
this.isshow = false;
this.issound = "xiaoxitongzhi";
this.istype = "text";
this.isvalue = "";
}
},
// 發(fā)送消息
sendmsg(e) {
// 1、用ref定義輸入回復(fù)內(nèi)容的input文本框,定義sendcontent變量接收其value值(輸入的內(nèi)容)
let sendcontent = this.$refs.sendcontent.value;
if (e.keyCode === 13 && sendcontent.split(" ").join("").length !== 0) {
// 2、將ChatDetail(父)組件中的sendcontent(文本框輸入的值)先用tomsg接收
this.tomsg = sendcontent;
// 3、用ref定義ChatMsg(子)組件,并在mounted中使用$refs獲取,即this.msgchild
// 4、調(diào)子組件里的方法,并將tomsg傳到ChatMsg(子)組件(具體的聊天內(nèi)容)中
this.msgchild.saveMsg(this.tomsg);
// 5、發(fā)送完一條信息之后,需清空文本框
this.$refs.sendcontent.value = "";
// 回車時(shí),調(diào)用子組件的隨機(jī)消息的方法
this.msgchild.randomMsg();
}
}
}
};
</script>
<style lang="scss" scope>
#chatdetail {
position: relative;
background-color: rgb(238, 212, 238);
.chattop {
position: fixed;
top: 0;
left: 0;
z-index: 10;
width: 100%;
height: 3.5rem;
line-height: 3.5rem;
background-color: rgb(240, 240, 240) !important;
display: flex;
flex-direction: row;
.chattop_back {
flex: 1;
margin-left: 1rem;
}
.chattop_name {
flex: 20;
text-align: center;
}
.chattop_more {
flex: 1;
margin-right: 1rem;
}
}
.chatcontent {
width: 100%;
height: 100%;
}
.chatfooter {
position: fixed;
left: 0;
bottom: 0;
z-index: 10;
width: 100%;
height: 3.5rem;
line-height: 3.5rem;
text-align: center;
background-color: rgb(240, 240, 240) !important;
display: flex;
flex-direction: row;
div:nth-child(1),
div:nth-child(3),
div:nth-child(4) {
flex: 1;
svg {
font-size: 1.5rem;
margin-top: 0.9rem;
}
}
div:nth-child(2) {
flex: 5;
input {
width: 100%;
height: 2.5rem;
outline: none;
padding-left: 0.5rem;
box-sizing: border-box;
height: 2.5rem;
margin-top: 0.5rem;
border-style: none;
font-size: 0.9rem;
border-radius: 4px;
background-color: #fff;
color: #000;
}
}
}
}
</style>
ChatMsg.vue:
<template>
<div id="chatmsg" ref="msg">
<!-- 動(dòng)態(tài)創(chuàng)建 -->
<div v-for="(item,index) in lists" :key="index">
<div v-if="item.id==122" class="user">
<div v-scroll>
<img :src="item.face" alt />
<div class="bubble">
<span>{{item.word}}</span>
</div>
</div>
</div>
<div v-if="item.id==1529" class="touser">
<div v-scroll>
<img :src="item.face" alt />
<div class="tobubble">
<span>{{item.word}}</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import userinfo from "./userinfo";
export default {
name: "ChatMsg",
data() {
return {
userimg: "",
lists: []
};
},
mounted() {
this.userid = userinfo.id;
this.userimg = userinfo.imgurl;
},
// vue自動(dòng)滾動(dòng)到底部
directives: {
scroll: {
inserted(el) {
el.scrollIntoView();
}
}
},
methods: {
saveMsg(tomsg) {
this.lists.push({
id: this.userid,
face: this.userimg,
word: tomsg
});
},
randomMsg() {
let touserdata = userinfo.data;
this.lists.push({
id: touserdata.id,
face: touserdata.imgurl,
word:
touserdata.words[Math.floor(Math.random() * touserdata.words.length)]
.info
});
}
}
};
</script>
<style lang="scss" scope>
#chatmsg {
position: relative;
top: 3.5rem;
width: 100%;
min-height: 44rem;
background-color: rgb(238, 212, 238);
margin-bottom: 3.5rem;
overflow-x: hidden;
overflow-y: auto;
.user {
position: relative;
width: 100%;
overflow: hidden;
margin: 0.8rem 0;
img {
object-fit: cover;
width: 3rem;
height: 3rem;
border-radius: 3px;
float: right;
margin-right: 1rem;
}
.bubble {
position: relative;
float: right;
margin-right: 1rem;
padding: 0.8rem;
box-sizing: border-box;
border-radius: 3px;
max-width: 65%;
background-color: rgb(116, 228, 116);
span {
height: 1.25rem;
line-height: 1.25rem;
}
}
.bubble::after {
position: absolute;
right: -1.3rem;
top: 0.8rem;
content: "";
width: 0;
height: 0;
border: 0.7rem solid;
border-color: transparent transparent transparent rgb(116, 228, 116);
}
}
.touser {
position: relative;
width: 100%;
overflow: hidden;
margin: 0.8rem 0;
img {
object-fit: cover;
width: 3rem;
height: 3rem;
border-radius: 3px;
float: left;
margin-left: 1rem;
}
.tobubble {
position: relative;
float: left;
margin-left: 1rem;
padding: 0 0.7rem;
box-sizing: border-box;
border-radius: 3px;
max-width: 65%;
background-color: rgb(116, 228, 116);
line-height: 3rem;
}
.tobubble::after {
position: absolute;
left: -1.3rem;
top: 0.8rem;
content: "";
width: 0;
height: 0;
border: 0.7rem solid;
border-color: transparent rgb(116, 228, 116) transparent transparent;
}
}
}
</style>
3.目錄結(jié)構(gòu)
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
詳解vuex持久化插件解決瀏覽器刷新數(shù)據(jù)消失問(wèn)題
這篇文章主要介紹了詳解vuex持久化插件解決瀏覽器刷新數(shù)據(jù)消失問(wèn)題,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-04-04
vue 中使用 watch 出現(xiàn)了如下的報(bào)錯(cuò)的原因分析
這篇文章主要介紹了vue 中使用 watch 出現(xiàn)了如下的報(bào)錯(cuò)信息的原因分析及解決方法,本文附有代碼解決方案,非常不錯(cuò),需要的朋友可以參考下2019-05-05
vue3中使用v-model實(shí)現(xiàn)父子組件數(shù)據(jù)同步的三種方案
這篇文章主要介紹了vue3中使用v-model實(shí)現(xiàn)父子組件數(shù)據(jù)同步的三種方案,如果只有一個(gè)匿名v-model的傳遞的話,可以使用vue3.3新添加的編譯宏,defineModel來(lái)使用,每種方案結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10
el-date-picker如何篩選時(shí)間日期選擇范圍
這篇文章主要介紹了el-date-picker篩選時(shí)間日期選擇范圍,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2024-12-12
vue.js+elementUI實(shí)現(xiàn)點(diǎn)擊左右箭頭切換頭像功能(類似輪播圖效果)
這篇文章主要介紹了vue.js+elementUI實(shí)現(xiàn)點(diǎn)擊左右箭頭切換頭像功能(類似輪播圖),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09
Vue3偵聽(tīng)器的實(shí)現(xiàn)原理詳情
這篇文章主要介紹了Vue3偵聽(tīng)器的實(shí)現(xiàn)原理詳情,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-08-08
關(guān)于vue v-for 循環(huán)問(wèn)題(一行顯示四個(gè),每一行的最右邊那個(gè)計(jì)算屬性)
這篇文章主要介紹了關(guān)于vue v-for 循環(huán)問(wèn)題(一行顯示四個(gè),每一行的最右邊那個(gè)計(jì)算屬性),需要的朋友可以參考下2018-09-09
解決vue項(xiàng)目router切換太慢問(wèn)題
這篇文章主要介紹了解決vue項(xiàng)目router切換太慢問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-07-07

