highlight: an-old-hope
全局导入
import SocketIO from './plugins/io' // 导入插件
app.use(SocketIO, { // 应用
connection: 'http://43.138.15.137:3000', // socket服务地址
})
parsion.json:
拼音依赖插件
{ "pinyin": "^4.0.0-alpha.0",
"segmentit": "^2.0.3",}
"postcss-pxtorem": "^6.1.0",
聊天依赖
"socket.io": "^4.7.5",
"socket.io-client": "^4.7.5",
需要安装
<template>
<div>
<div class="contact-wrap">
<div class="my-header">
<div class="back-wrap"><span class="iconfont"></span>
</div>
<div><span>
选择联系人
</span></div><!---->
</div>
<div class="listview">
<ul
style="transition-timing-function: cubic-bezier(0.165, 0.84, 0.44, 1); transition-duration: 0ms; transform: translate(0px, 0px) scale(1) translateZ(0px);">
<li class="list-group">
<div class="search-bar-wrap">
<div class="input-wrap"><span class="iconfont icon-sousuo"
style="color: white;"></span><input placeholder="搜索用户昵称" class="input"><span
class="iconfont icon-close" style="display: none;"></span></div>
</div>
<ul></ul>
</li>
<li class="list-group" v-for="(item, index) in list" :key="index">
<h2 class="list-group-title">{{ index }} </h2>
<ul>
<li class="list-group-item" v-for="item1, index1 in item" :key="index1">
<img :src="'http://43.138.15.137:3000' + item1.userAvatar" width="50" height="50"
class="avatar">
<div class="main"><span class="name">{{ item1.userNickname }}</span><span
class="desc">{{
item1.userDesc }}</span></div><span class="iconfont icon-xiazai16"
@click="liao(item)"></span>
</li>
</ul>
</li>
</ul>
<div class="list-shortcut">
<ul>
<li data-index="0" class="item current">
<p class="iconfont icon-sousuo" style="color: white;"></p>
</li>
<li data-index="1" class="item">
<p>F</p>
</li>
<li data-index="2" class="item">
<p>O</p>
</li>
<li data-index="3" class="item">
<p>Y</p>
</li>
<li data-index="4" class="item">
<p>#</p>
</li>
</ul>
</div>
<div class="list-fixed" style="display: none;">
<div class="fixed-title"> </div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { userconatlAPI } from '../api/suoyinlan'
import { getFirstPinyinInitial } from '../uilts/index.js'
import { useRouter } from 'vue-router';
let router = useRouter()
let list = ref([])
let duixsj = ref({})
let getUserList = async () => {
let dxq = await userconatlAPI(localStorage.getItem('userId'))
dxq.data.data.forEach((item) => {
item.initial = getFirstPinyinInitial(item.userNickname);
});
dxq.data.data.sort((a, b) => {
const initialA = a.initial.toUpperCase();
const initialB = b.initial.toUpperCase();
if (initialA < initialB) return -1;
if (initialA > initialB) return 1;
return 0;
});
const groupedData = {};
dxq.data.data.forEach((item) => {
const { initial } = item;
if (!groupedData[initial]) {
groupedData[initial] = [];
}
groupedData[initial].push(item);
});
list.value = groupedData;
console.log(list.value);
}
getUserList()
function liao(item) {
duixsj.value = item
let zhong =JSON.stringify( duixsj.value)
router.push({ path: '/ChatWith', query:{ shuju:zhong } })
}
</script>
<style scoped>
.contact-wrap {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
.my-header {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
position: relative;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
color: #e8e8e9;
height: 44px;
line-height: 44px;
font-size: 16px;
z-index: 33;
border-bottom: 0.5px solid rgba(41, 40, 37, 0.8);
background: #161622;
}
.my-header .back-wrap {
position: absolute;
left: 10px;
}
.my-header .back-wrap {
padding: 10px;
}
.listview {
position: absolute;
width: 100%;
margin-top: 44px;
top: 0;
bottom: 0;
overflow: hidden;
background: #161622;
}
.listview .list-shortcut {
position: absolute;
right: 5px;
top: 50%;
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
width: 20px;
padding: 20px 0;
border-radius: 10px;
text-align: center;
background: rgba(22, 24, 35, 0.98);
font-family: Helvetica;
}
.listview .list-shortcut .item {
padding: 3px;
line-height: 1;
color: #e8e8e9;
font-size: 12px;
}
.listview .list-group {
padding-bottom: 10px;
}
.listview .search-bar-wrap {
padding: 10px 20px;
}
.input-wrap {
width: 100%;
background: #242630;
border-radius: 5px;
height: 44px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.input-wrap .iconfont {
margin-left: 10px;
font-size: 21px;
}
.input-wrap .input {
height: 21px;
background: #1a1b20;
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
font-size: 14px;
color: #e8e8e9;
padding-left: 10px;
background: none;
caret-color: #face15;
/* border: none;
outline: none; */
}
.input-wrap .icon-close {
font-size: 12px;
margin-right: 10px;
padding: 5px;
}
.input-wrap .iconfont {
margin-left: 10px;
font-size: 21px;
}
.listview .list-group .list-group-title {
height: 30px;
line-height: 30px;
padding-left: 20px;
font-size: 14px;
color: #e8e8e9;
background: #161622;
}
.listview .list-group .list-group-item {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
padding: 20px 0 0 20px;
}
.listview .list-group .list-group-item .avatar {
border-radius: 50%;
}
.listview .list-group .list-group-item .main {
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
margin-left: 10px;
}
.listview .list-group .list-group-item .main .name {
color: #e8e8e9;
font-size: 14px;
}
.listview .list-group .list-group-item .main .desc {
margin-top: 10px;
color: #8b8c96;
font-size: 12px;
}
.listview .list-group .list-group-item .icon-xiazai16 {
margin-right: 30px;
padding: 10px;
font-size: 18px;
color: white;
}
</style>
<template>
<div>
<div class="topBar"><span class="backbtn iconfont icon-left"></span>
<p class="title">10086</p>
</div>
<div class="scroll-wrap scroll-wrap-bottom" style="color: white;overflow-y: scroll;" ref="hua">
<ul>
<div class="chat-item"><span class="time">13:10</span></div>
<div class="chat-item" v-for="item, index in lefts" :key="index">
<div class="right" v-if="item.fromId == userId">
<div class="content">
{{ item.privateLetterContent }}
</div><img
src="http://43.138.15.137:3000/assets/avatar/2edc518d-06fd-47b1-bc8a-0b965833ff67.png"
alt="" width="40" height="40" class="avatar">
</div>
<div class="left" v-else><img
src="http://43.138.15.137:3000/assets/avatar/4f5305b1-c16c-4adc-985d-440e4dbf82e5.png"
alt="" width="40" height="40" class="avatar">
<div class="content">
{{ item.privateLetterContent }}
</div>
</div>
</div>
</ul>
</div>
<div class="input-bar"><input placeholder=" 发送消息..." type="text" class="input" v-model="onbj.msg"
@keyup.enter="fasong"><span class="iconfont icon-at"></span><span class="iconfont icon-check"></span>
</div>
</div>
</template>
<script setup>
import { useRoute } from 'vue-router';
let route = useRoute()
import { ref, reactive, computed, toRef, onMounted, onUpdated } from 'vue'
import { postprivateletterAPI, getliaotianAPI } from '../api/liaot'
import { inject } from "vue";
const socket = inject("socket"); // 注入到全局
let jies = ref([])
jies.value = JSON.parse(route.query.shuju)
console.log(jies.value[0].userId);
let onbj = reactive({
msg: ''
})
let userId = ref(localStorage.getItem('userId'))
let lefts = ref([])
let rights = ref([])
let hua = ref(null)
async function fasong() {
let message = await postprivateletterAPI(localStorage.getItem('userId'), jies.value[0].userId, {
content: onbj.msg,
fromUserId: localStorage.getItem('userId'),
toUserId: jies.value[0].userId
})
let obj = {
fromId: localStorage.getItem('userId'),
toId: jies.value[0].userId,
privateLetterContent: onbj.msg,
createdAt: +new Date(),
userAvatar: localStorage.getItem('userAvatar'),
userNickname: localStorage.getItem('userNickname'),
}
socket.emit('sendPrivateLetter', obj) // sendPrivateLetter客户端和服务端协商好的事件
console.log(message);
lefts.value.push(message.data.data)
liaotxinxi()
}
socket.on('receivePrivateLetter', data => { // receivePrivateLetter客户端和服务端协商好的事件
lefts.value.push(data)
})
async function liaotxinxi() {
let gwet = await getliaotianAPI(localStorage.getItem('userId'), jies.value[0].userId)
lefts.value = gwet.data.data
console.log(gwet);
}
liaotxinxi()
// function getbaos() {
// if (hua.value) {
// hua.value.scrollTop = hua.value.scrollTop - hua.value.clientHeight
// console.log( hua.value.scrollTop = hua.value.scrollTop - document.clientHeight);
// }
// }
// onUpdated(() => {
// getbaos()
// })
</script>
<style scoped>
.topBar {
position: fixed;
z-index: 33;
width: 100%;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
height: 44px;
border-bottom: 1px solid rgba(41, 40, 37, 0.8);
background: #161622;
}
.topBar .backbtn {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
height: 44px;
width: 44px;
}
.topBar .title {
margin-right: 44px;
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
line-height: 44px;
text-align: center;
font-size: 16px;
}
.scroll-wrap-bottom {
margin-bottom: 44px;
}
.scroll-wrap {
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
margin-top: 44px;
}
.chat-item {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
width: 100%;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
}
.chat-item .time {
margin-top: 10px;
font-size: 10px;
}
.chat-item .right {
-webkit-box-pack: end;
-ms-flex-pack: end;
justify-content: flex-end;
margin-left: 100px;
}
.chat-item>div {
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
margin: 20px 0;
}
.chat-item .content {
position: relative;
border-radius: 5px;
background: #fff;
color: #000;
padding: 10px;
word-break: break-all;
}
.chat-item .right .content:after {
display: block;
position: absolute;
top: 8px;
right: -16px;
border: 8px solid transparent;
border-left: 8px solid #fff;
content: '';
}
.chat-item .avatar {
-ms-flex-negative: 0;
flex-shrink: 0;
border-radius: 50%;
margin: 0 15px;
}
.chat-item .left {
margin-right: 100px;
}
.chat-item>div {
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
margin: 20px 0;
}
.chat-item .avatar {
-ms-flex-negative: 0;
flex-shrink: 0;
border-radius: 50%;
margin: 0 15px;
}
.chat-item .content {
position: relative;
border-radius: 5px;
background: #fff;
color: #000;
padding: 10px;
word-break: break-all;
}
.chat-item .left .content:after {
display: block;
position: absolute;
top: 8px;
left: -16px;
border: 8px solid transparent;
border-right: 8px solid #fff;
content: '';
}
.input-bar {
position: fixed;
width: 100%;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
height: 44px;
position: absolute;
bottom: 0;
background: #161622;
border-top: 1px solid rgba(41, 40, 37, 0.8);
}
.input-bar .input {
background: #161622;
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
font-size: 14px;
color: #e8e8e9;
padding-left: 10px;
caret-color: #face15;
}
.input-bar .iconfont {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
width: 44px;
}
</style>