一、项目简介

基于Vue3.0+Vant3.x+Vuex4.x+Vue-router4+V3Popup等技术开发实现的仿微信手机App聊天实例项目Vue3-Chatroom。实现了发送图文表情消息/gif图、图片/视频预览、网址查看、下拉刷新功能、红包/朋友圈等功能。

二、技术选型

  • 编辑器:VScode/Sublime
  • 使用技术:Vue3.x+Vuex4.x+Vue-Router4
  • UI组件库:Vant-UI3.x (有赞移动端Vue3组件库)
  • 弹层组件:V3Popup(基于vue3.0封装自定义弹出层组件)
  • iconfont图标:阿里字体图标库
  • 自定义顶部导航栏+底部tabBar

◆ 项目结构

◆ Vue3自定义顶部Navbar+底部Tabbar

项目中顶部导航条和底部tabbar组件均是在之前vue2版的基础上开发的vue3版。

大家如果感兴趣,可以去看看之前的一篇分享文章。

https://www.cnblogs.com/xiaoyan2017/p/13791980.html

◆ Vue3自定义弹层组件

项目中使用到的弹框场景,均是最新开发的vue3.0自定义弹框组件v3popup来实现的。

v3popup 一款汇集多种弹框类型及动画效果的vue3.x自定义弹框组件。开发设计灵感来源于之前的vue2版,并在功能及效果上保持一致性。

如果大家对具体的实现感兴趣的话,可以去看看之前的这篇文章。

https://www.cnblogs.com/xiaoyan2017/p/14210820.html

◆ vue.config.js配置

/**
* Vue3基础配置文件
*/ const path = require('path') module.exports = {
// 基本路径
// publicPath: '/', // 输出文件目录
// outputDir: 'dist', // assetsDir: '', // 环境配置
devServer: {
// host: 'localhost',
// port: 8080,
// 是否开启https
https: false,
// 编译完是否打开网页
open: false, // 代理配置
// proxy: {
// '^/api': {
// target: '<url>',
// ws: true,
// changeOrigin: true
// },
// '^/foo': {
// target: '<other_url>'
// }
// }
}, // webpack配置
chainWebpack: config => {
// 配置路径别名
config.resolve.alias
.set('@', path.join(__dirname, 'src'))
.set('@assets', path.join(__dirname, 'src/assets'))
.set('@components', path.join(__dirname, 'src/components'))
.set('@views', path.join(__dirname, 'src/views'))
}
}

◆ Vue3.0主入口页面

在main.js中配置一些状态管理、地址路由,引入一些js和公共组件。

import { createApp } from 'vue'
import App from './App.vue' // 引入vuex和地址路由
import store from './store'
import router from './router' // 引入js
import '@assets/js/fontSize' // 引入公共组件
import Plugins from './plugins' const app = createApp(App) app.use(store)
app.use(router)
app.use(Plugins) app.mount('#app')

◆ Vuex + 表单登录验证

vue3中状态管理及表单验证操作。

import { createStore } from 'vuex'

export default createStore({
state: {
user: localStorage.getItem('user') || null,
token: localStorage.getItem('token') || null
},
mutations: {
SET_USER(state, data) {
localStorage.setItem('user', data)
state.user = data
},
SET_TOKEN(state, data) {
localStorage.setItem('token', data)
state.token = data
},
LOGOUT(state) {
localStorage.removeItem('user')
localStorage.removeItem('token')
state.user = null
state.token = null
}
},
getters: {},
actions: {}
})
<script>
import { reactive, inject, getCurrentInstance } from 'vue'
export default {
components: {},
setup() {
const { ctx } = getCurrentInstance() const v3popup = inject('v3popup')
const utils = inject('utils')
const formObj = reactive({}) // ... const handleSubmit = () => {
if(!formObj.tel){
Snackbar('手机号不能为空!')
}else if(!utils.checkTel(formObj.tel)){
Snackbar('手机号格式不正确!')
}else if(!formObj.pwd){
Snackbar('密码不能为空!')
}else{
ctx.$store.commit('SET_TOKEN', utils.setToken());
ctx.$store.commit('SET_USER', formObj.tel); // ...
}
} return {
formObj,
handleSubmit
}
}
}
</script>

◆ 仿微信朋友圈透明导航实现

vue3通过在onMounted中监听scroll事件来控制顶部导航透明显示。

  

<!-- //朋友圈模板 -->
<template>
<div>
<header-bar :bgcolor="headerBg" transparent zIndex="1010">
<template #backIco><i class="iconfont icon-arrL"></i></template>
<template v-slot:right><div @click="isShowPublish=true"><i class="iconfont icon-tianjia"></i></div></template>
</header-bar> <div class="vui__scrollview flex1" ref="scrollview">
...
</div>
</div>
</template> <script>
import { onMounted, onBeforeUnmount, ref, reactive, toRefs, inject } from 'vue'
import { ImagePreview } from 'vant' export default {
components: {},
setup() {
const scrollview = ref(null) const data = reactive({
headerBg: 'transparent',
// ...
}) onMounted(() => {
scrollview.value.addEventListener('scroll', handleScroll)
}) onBeforeUnmount(() => {
scrollview.value.removeEventListener('scroll', handleScroll)
}) // 页面滚动处理
const handleScroll = (e) => {
if(e.target.scrollTop > 160) {
data.headerBg = 'linear-gradient(to right, #00d2ee, #00e077)'
}else {
data.headerBg = 'transparent';
}
} // ... return {
...toRefs(data),
scrollview, // ...
}
}
}
</script>

◆ Vue3聊天代码片段

vue3中实现聊天功能实现,其中编辑器支持图文插入,并且单独抽离了一个Editor.vue组件。

/**
* @Desc Vue3.0仿微信聊天实例
* @Time andy by 2021-01
* @About Q:282310962 wx:xy190310
*/
<script>
import { onMounted, onUnmounted, ref, reactive, toRefs, nextTick, inject } from 'vue'
import { useRouter } from 'vue-router'
import Editor from './editor.vue'
import { ImagePreview } from 'vant' // ... export default {
components: {
Editor
},
setup() {
const scrollview = ref(null)
const editorRef = ref(null)
const pickImageRef = ref(null)
const pickVideoRef = ref(null)
const playerRef = ref(null) const router = useRouter() const v3popup = inject('v3popup') const data = reactive({
editorText: '', isShowFootBar: false,
showFootBarIndex: 0, // 表情列表
emojList: emoJSON, // 消息记录
msgList: msgJSON, // 链接预览
isShowLinkView: false,
linkView: '', // ...
}) onMounted(() => {
nextTick(() => {
imgLoaded(scrollview)
})
}) onUnmounted(() => {
window.removeEventListener('popstate', handlePopStateClosed, false)
})
// 监听地址打开
const handlePopStateOpen = () => {
if(window.history && window.history.pushState) {
history.pushState(null, null, document.URL)
window.addEventListener('popstate', handlePopStateClosed, false)
}
}
// 监听地址关闭(手机回退按钮事件)
const handlePopStateClosed = () => {
// console.log('监听关闭视频事件!')
data.isShowLinkView = false
data.isShowVideoPlayer = false
} /**
* 滚动条到底部
* @param ref 容器ref
*/
const scrollBottom = (ref) => {
let viewport = ref.value
if(viewport) {
viewport.scrollTop = viewport.scrollHeight
}
} // 点击聊天消息区域
const handleMsgPanelClicked = () => {
if(!data.isShowFootBar) return
data.isShowFootBar = false
} /**
* 表情|选择区切换
* @param index 切换索引
*/
const handleEmojChooseView = (index) => {
data.isShowFootBar = true
data.showFootBarIndex = index nextTick(() => { imgLoaded(scrollview) })
} /**
* 表情Tab切换
* @param index 索引index
*/
const handleEmojTab = (index) => {
let emojLs = data.emojList
for(var i = 0, len = emojLs.length; i < len; i++) {
emojLs[i].selected = false
}
emojLs[index].selected = true
data.emojList = emojLs
} /* ---------- { 编辑器|表情模块 } ---------- */
// 点击编辑器
const handleEditorClick = () => {
// console.log('点击编辑器')
data.isShowFootBar = false
} // 编辑器获取焦点
const handleEditorFocus = () => {
// console.log('编辑器获取焦点')
} // 编辑器失去焦点
const handleEditorBlur = () => {
// console.log('编辑器失去焦点')
} // 判断编辑器是否为空
const isEmpty = (html) => {
html = html.replace(/<br[\s/]{0,2}>/ig, "\r\n")
html = html.replace(/<[^img].*?>/ig, "")
html = html.replace(/&nbsp;/ig, "")
return html.replace(/\r\n|\n|\r/, "").replace(/(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g, "") == ""
}
// 匹配转换聊天消息中链接
const transferHTML = (html) => {
let reg = /(http:\/\/|https:\/\/)((\w|=|\?|\.|\/|&|-)+)/g
return html.replace(reg, "<a href='$1$2'>$1$2</a>")
} // ... /* ---------- { 选择功能模块 } ---------- */
// 选择图片
const handleChooseImage = () => {
let msgLs = data.msgList
let len = msgLs.length
// 消息队列
let arrLS = {
// ...
} let file = pickImageRef.value.files[0]
if(!file) return
let size = Math.floor(file.size / 1024)
if(size > 2*1024) {
v3popup({content: '请选择2MB以内的图片!'})
return false
}
var reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = function() {
let img = this.result // ...
}
} // 预览图片
const handleImgPreview = (src) => {
ImagePreview({
images: [
src
],
showIndex: false,
showIndicators: true,
closeable: true,
});
} /* ---------- { 视频功能模块 } ---------- */
// 播放视频
const handleVideoPlayed = (item) => {
data.isShowVideoPlayer = true
data.videoList = item nextTick(() => {
playerRef.value.play()
}) // 监听手机回退按钮事件
handlePopStateOpen()
} // 抖一抖
const handleShakeWin = () => {
let ntbox = document.querySelector('.vui__container')
ntbox.classList.add('shake')
setTimeout(() => {
ntbox.classList.remove('shake')
}, 1000);
} // ... return {
...toRefs(data), scrollview,
editorRef,
pickImageRef,
pickVideoRef,
playerRef, handleMsgPanelClicked,
handleMsgClicked, // ...
}
}
}
</script>

okey,以上就是基于vue3开发仿微信界面聊天室的介绍。希望大家能喜欢~~

最后附上一个Electron+Vue聊天实例

https://www.cnblogs.com/xiaoyan2017/p/12169391.html

Vue3.0聊天室|vue3+vant3仿微信聊天实例|vue3.x仿微信app界面的更多相关文章

  1. Websocket直播间聊天室教程 - GoEasy快速实现聊天室

    最近两年直播那个火啊,真的是无法形容!经常有朋友问起,我想实现一个直播间聊天或者我想开发一个聊天室, 要如何开始呢? 今天小编就手把手的教你用GoEasy做一个聊天室,当然也可以用于直播间内的互动.全 ...

  2. Vue3.0工程创建 && setup、ref、reactive函数 && Vue3.0响应式实现原理

    1 # 一.创建Vue3.0工程 2 # 1.使用vue-cli创建 3 # 官方文档: https://cli.vuejs.org/zh/guide/creating-a-project.html# ...

  3. 基于nodejs+webSocket的聊天室(实现:加入聊天室、退出聊天室、在线人数、在线列表、发送信息、接收信息)

    1  安装 socket.io模块 npm install "socket.io": "latest" 2 app.js相关 ws = require('soc ...

  4. ASP.NET SignalR 与LayIM配合,轻松实现网站客服聊天室(二) 实现聊天室连接

    上一篇已经简单介绍了layim WebUI即时通讯组件和获取数据的后台方法.现在要讨论的是SingalR的内容,之前都是直接贴代码.那么在贴代码之前先分析一下业务模型,顺便简单讲一下SingalR里的 ...

  5. Netty学习笔记(六) 简单的聊天室功能之WebSocket客户端开发实例

    在之前的Netty相关学习笔记中,学习了如何去实现聊天室的服务段,这里我们来实现聊天室的客户端,聊天室的客户端使用的是Html5和WebSocket实现,下面我们继续学习. 创建客户端 接着第五个笔记 ...

  6. Vue3实战系列:Vue3.0 + Vant3.0 搭建种子项目

    最近在用 Vue3 写一个开源的商城项目,开源后让大家也可以用现成的 Vue3 大型商城项目源码来练练手,目前处于开发阶段,过程中用到了 Vant3.0,于是就整理了这篇文章来讲一下如何使用 Vue3 ...

  7. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(二) 之 ChatServer搭建,连接服务器,以及注意事项。

    上篇:ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(一) 之 基层数据搭建,让数据活起来(数据获取) 上一篇我们已经完成了初步界面的搭建工作,本篇将介绍IM的核心内容 ...

  8. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(七) 之 历史记录查询(时间,关键字,图片,文件),关键字高亮显示。

    前言 上一篇讲解了如何自定义右键菜单,都是前端的内容,本篇内容就一个:查询.聊天历史纪录查询,在之前介绍查找好友的那篇博客里已经提到过 Elasticsearch,今天它又要上场了.对于Elastic ...

  9. 利用Node.js的Net模块实现一个命令行多人聊天室

    1.net模块基本API 要使用Node.js的net模块实现一个命令行聊天室,就必须先了解NET模块的API使用.NET模块API分为两大类:Server和Socket类.工厂方法. Server类 ...

  10. 使用WebRTC搭建前端视频聊天室——信令篇

    博客原文地址 建议看这篇之前先看一下使用WebRTC搭建前端视频聊天室——入门篇 如果需要搭建实例的话可以参照SkyRTC-demo:github地址 其中使用了两个库:SkyRTC(github地址 ...

随机推荐

  1. Pentaho Report Designer 入门教程(一)

    PentahoReport Designer 入门教程 采用Pentaho Report Designer5.1版本,也是最新的版本. 一.       安装和介绍 介绍部分内容略,首先安装jdk,并 ...

  2. 安装虚拟机(centos7)

    安装VMware 15 这里就不介绍VMware如何安装了,可以自行百度安装. 准备centos7镜像 我选择的是网易的镜像源,地址是:http://mirrors.163.com/centos/7/ ...

  3. (数据科学学习手札99)掌握pandas中的时序数据分组运算

    本文示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 我们在使用pandas分析处理时间序列数据 ...

  4. web前端页面常见优化方法

    (1)减少http请求,尽量减少向服务器的请求数量 (2)避免重定向 (3)利用缓存:使用外联式引用CSS.JS,在实际应用中使用外部文件可以提高页面速度,因为JavaScript和CSS文件都能在浏 ...

  5. Python术语对照表

    >>> 交互式终端中默认的 Python 提示符.往往会显示于能以交互方式在解释器里执行的样例代码之前. ... 可以是指:交互式终端中输入特殊代码行时默认的 Python 提示符, ...

  6. 【笔记】「pj复习」深搜——拿部分分

    说在最前面 众所周知, NOIP pj 的第三题大部分都是 dp ,但是有可能在考场上想不到动态转移方程,所以我们就可以拿深搜骗分. 方法 深搜拿部分分 剪枝 记忆化 看数据范围 有时候发现,写完深搜 ...

  7. eclipse 搭建连接 activemq

    今天我特地写下笔记,希望可以完全掌握这个东西,也希望可以帮助到任何想对学习这个东西的同学. 1.下载activemq压缩包,并解压(如果需要下载请看文章尾部附录) 2.进入bin文件夹,(64位电脑就 ...

  8. Python3中zipfile模块文件名乱码问题

    inux下zip文件乱码已经是一个常见问题了,再加上python想不遇到乱码问题都难. 在zipfile.ZipFile中获得的filename有中日文则很大可能是乱码,这是因为 在zip标准中,对文 ...

  9. Validated 注解完成 Spring Boot 参数校验

    1.  @Valid 和 @Validated @Valid 注解,是 Bean Validation 所定义,可以添加在普通方法.构造方法.方法参数.方法返回.成员变量上,表示它们需要进行约束校验. ...

  10. vue+axois 封装请求+拦截器(请求锁+统一错误)

     需求 封装常用请求 拦截器-请求锁 统一处理错误码 一.封装常用的请求 解决痛点:不要每一个模块的api都还要写get,post,patch请求方法.直接将这些常用的方法封装好. 解决方案:写一个类 ...