vite5-vue3-wchat最新原创研发vite5.x+vue3+pinia+swiper+element-plus等技术搭建仿微信web端聊天室模板Vue3-ViteChat。
采用vue3 setup
语法编码,包含了聊天、通讯录、朋友圈、短视频、我的等功能模块。支持收缩侧边栏、背景壁纸换肤、锁屏、最大化等功能。
使用技术
- 开发工具:Vscode
- 技术框架:Vite5.2+Vue3.4+vue-router4.3+Pinia2
- UI组件库:element-plus^2.7.5 (饿了么网页端vue3组件库)
- 状态管理:pinia^2.1.7
- 地图插件:@amap/amap-jsapi-loader(高德地图组件)
- 视频滑动:swiper^11.1.4
- 图文编辑器:wangeditor^4.7.15(笔记/朋友圈文本编辑器)
- 样式编译:sass^1.77.4
- 构建工具:vite^5.2.0
之前有分享过一篇flutter3.x桌面端仿微信EXE聊天,感兴趣的可以去看看。
https://segmentfault.com/a/1190000044675519
项目结构
整个项目使用vite5.x
构建工具搭建项目模板。
目前该项目已经同步到我的最新原创作品集。
https://gf.bilibili.com/item/detail/1106226011
import { createApp } from 'vue'
import './style.scss'
import App from './App.vue'
// 引入组件库
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import VEPlus from 've-plus'
import 've-plus/dist/ve-plus.css'
// 引入路由/状态管理
import Router from './router'
import Pinia from './pinia'
const app = createApp(App)
app
.use(ElementPlus)
.use(VEPlus)
.use(Router)
.use(Pinia)
.mount('#app')
vue3上滑数字解锁验证
vue3-wechat聊天项目采用全新上滑数字密码解锁模式。
<script setup>
import { ref, computed, inject, nextTick } from 'vue'
import { useRouter } from 'vue-router'
import { authState } from '@/pinia/modules/auth'
import { uuid, guid } from '@/utils'
const authstate = authState()
const router = useRouter()
// 启动页
const splashScreen = ref(true)
const authPassed = ref(false)
// 滑动距离
const touchY = ref(0)
const touchable = ref(false)
// 数字键盘输入值
const pwdValue = ref('')
const keyNumbers = ref([
{letter: 'a'},
{letter: 'b'},
{letter: 'c'},
{letter: 'd'},
{letter: 'e'},
{letter: 'f'},
{letter: 'g'},
{letter: 'h'},
{letter: 'i'},
{letter: 'j'},
{letter: 'k'},
{letter: 'l'},
{letter: 'm'},
{letter: 'n'},
{letter: 'o'},
{letter: 'p'},
{letter: 'q'},
{letter: 'r'},
{letter: 's'},
{letter: 't'},
{letter: 'u'},
{letter: 'v'},
{letter: 'w'},
{letter: 'x'},
{letter: 'y'},
{letter: 'z'},
{letter: '1'},
{letter: '2'},
{letter: '3'},
{letter: '4'},
{letter: '5'},
{letter: '6'},
{letter: '7'},
{letter: '8'},
{letter: '9'},
{letter: '0'},
{letter: '@'},
{letter: '#'},
{letter: '%'},
{letter: '&'},
{letter: '!'},
{letter: '*'},
])
//...
// 触摸事件(开始/更新)
const handleTouchStart = (e) => {
touchY.value = e.clientY
touchable.value = true
}
const handleTouchUpdate = (e) => {
let swipeY = touchY.value - e.clientY
if(touchable.value && swipeY > 100) {
splashScreen.value = false
touchable.value = false
}
}
const handleTouchEnd = (e) => {
touchY.value = 0
touchable.value = false
}
// 点击数字键盘
const handleClickNum = (num) => {
let pwdLen = passwordArr.value.length
if(pwdValue.value.length >= pwdLen) return
pwdValue.value += num
if(pwdValue.value.length == pwdLen) {
// 验证通过
if(pwdValue.value == password.value) {
// ...
}else {
setTimeout(() => {
pwdValue.value = ''
}, 200)
}
}
}
// 删除
const handleDel = () => {
let num = Array.from(pwdValue.value)
num.splice(-1, 1)
pwdValue.value = num.join('')
}
// 清空
const handleClear = () => {
pwdValue.value = ''
}
// 返回
const handleBack = () => {
splashScreen.value = true
}
</script>
<template>
<div class="uv3__launch">
<div
v-if="splashScreen"
class="uv3__launch-splash"
@mousedown="handleTouchStart"
@mousemove="handleTouchUpdate"
@mouseup="handleTouchEnd"
>
<div class="uv3__launch-splashwrap">
...
</div>
</div>
<div v-else class="uv3__launch-keyboard">
<div class="uv3__launch-pwdwrap">
<div class="text">密码解锁</div>
<div class="circle flexbox">
<div v-for="(num, index) in passwordArr" :key="index" class="dot" :class="{'active': num <= pwdValue.length}"></div>
</div>
</div>
<div class="uv3__launch-numwrap">
<div v-for="(item, index) in keyNumbers" :key="index" class="numbox flex-c" @click="handleClickNum(item.letter)">
<div class="num">{{item.letter}}</div>
</div>
</div>
<div class="foot flexbox">
<Button round icon="ve-icon-clean" @click="handleClear">清空</Button>
<Button type="danger" v-if="pwdValue" round icon="ve-icon-backspace" @click="handleDel">删除</Button>
<Button v-else round icon="ve-icon-rollback" @click="handleBack">返回</Button>
</div>
</div>
</div>
</template>
项目布局模板
<template>
<div class="vu__container" :style="{'--themeSkin': appstate.config.skin}">
<div class="vu__layout">
<div class="vu__layout-body">
<!-- 菜单栏 -->
<slot v-if="!route?.meta?.hideMenuBar" name="menubar">
<MenuBar />
</slot>
<!-- 侧边栏 -->
<div v-if="route?.meta?.showSideBar" class="vu__layout-sidebar" :class="{'hidden': appstate.config.collapsed}">
<aside class="vu__layout-sidebar__body flexbox flex-col">
<slot name="sidebar">
<SideBar />
</slot>
<!-- 折叠按钮 -->
<Collapse />
</aside>
</div>
<!-- 主内容区 -->
<div class="vu__layout-main flex1 flexbox flex-col">
<Winbtn v-if="!route?.meta?.hideWinBar" />
<router-view v-slot="{ Component, route }">
<keep-alive>
<component :is="Component" :key="route.path" />
</keep-alive>
</router-view>
</div>
</div>
</div>
</div>
</template>
vite5路由管理
/**
* 路由管理Router
* @author andy
*/
import { createRouter, createWebHashHistory } from 'vue-router'
import { authState } from '@/pinia/modules/auth'
import Layout from '@/layouts/index.vue'
// 批量导入路由
const modules = import.meta.glob('./modules/*.js', { eager: true })
const patchRouters = Object.keys(modules).map(key => modules[key].default).flat()
/**
* meta配置
* @param meta.requireAuth 需登录验证页面
* @param meta.hideWinBar 隐藏右上角按钮组
* @param meta.hideMenuBar 隐藏菜单栏
* @param meta.showSideBar 显示侧边栏
* @param meta.canGoBack 是否可回退上一页
*/
const routes = [
...patchRouters,
// 错误模块
{
path: '/:pathMatch(.*)*',
redirect: '/404',
component: Layout,
meta: {
title: '404error',
hideMenuBar: true,
hideWinBar: true,
},
children: [
{
path: '404',
component: () => import('@/views/error/404.vue'),
}
]
},
]
const router = createRouter({
history: createWebHashHistory(),
routes,
})
// 全局路由钩子拦截
router.beforeEach((to, from) => {
const authstate = authState()
// 登录验证
if(to?.meta?.requireAuth && !authstate.authorization) {
console.log('你还未登录!')
return {
path: '/login'
}
}
})
router.afterEach((to, from) => {
// 阻止浏览器回退
if(to?.meta?.canGoBack == false && from.path != null) {
history.pushState(history.state, '', document.URL)
}
})
vite5聊天小视频模块
vite5-webchat短视频模块。使用swiper
组件实现上下滑动切换短视频。
采用el-slider
组件实现底部播放进度条功能。支持拖拽到指定时间点。
<!-- 短视频模块 -->
<div class="vu__video-container">
<!-- tabs操作栏 -->
<div class="vu__video-tabswrap flexbox">
<el-tabs v-model="activeName" class="vu__video-tabs">
<el-tab-pane label="关注" name="attention" />
<el-tab-pane label="推荐" name="recommend" />
</el-tabs>
</div>
<swiper-container
class="vu__swiper"
direction="vertical"
:speed="150"
:grabCursor="true"
:mousewheel="{invert: true}"
@swiperslidechange="onSlideChange"
>
<swiper-slide v-for="(item, index) in videoList" :key="index">
<!-- 视频层 -->
<video
class="vu__player"
:id="'vuplayer-' + index"
:src="item.src"
:poster="item.poster"
loop
preload="auto"
:autoplay="index == currentVideo"
webkit-playsinline="true"
x5-video-player-type="h5-page"
x5-video-player-fullscreen="true"
playsinline
@click="handleVideoClicked"
>
</video>
<div v-if="!isPlaying" class="vu__player-btn" @click="handleVideoClicked"></div>
<!-- 右侧操作栏 -->
<div class="vu__video-toolbar">
...
</div>
<!-- 底部信息区域 -->
<div class="vu__video-footinfo flexbox flex-col">
<div class="name">@{{item.author}}</div>
<div class="content">{{item.desc}}</div>
</div>
</swiper-slide>
</swiper-container>
<!-- ///底部进度条 -->
<el-slider class="vu__video-progressbar" v-model="progressBar" @input="handleSlider" @change="handlePlay" />
<div v-if="isDraging" class="vu__video-duration">{{videoTime}} / {{videoDuration}}</div>
</div>
vue3-wechat聊天功能
<template>
<!-- 顶部导航 -->
...
<!-- 内容区 -->
<div class="vu__layout-main__body">
<Scrollbar ref="scrollRef" autohide gap="2">
<!-- 渲染聊天内容 -->
<div class="vu__chatview" @dragenter="handleDragEnter" @dragover="handleDragOver" @drop="handleDrop">
...
</div>
</Scrollbar>
</div>
<!-- 底部操作栏 -->
<div class="vu__footview">
<div class="vu__toolbar flexbox">
...
</div>
<div class="vu__editor">
<Editor ref="editorRef" v-model="editorValue" @paste="handleEditorPaste" />
</div>
<div class="vu__submit">
<button @click="handleSubmit">发送(S)</button>
</div>
</div>
...
</template>
vue3-vitechat聊天项目涉及到的知识点还是蛮多的,今天就暂分享到这里。
https://segmentfault.com/a/1190000044899693
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。