原创vite-vue3-wechat仿微信网页版界面聊天实例。
基于最新前端技术
vite5.x+vue3+vue-router+pinia+elementPlus
搭建网页端聊天室。实现了聊天、通讯录、朋友圈、短视频、我的等功能模块。支持侧边栏展开/收缩、动态主题壁纸、锁屏、最大化等功能。
vite-wechat实现了文字/emoj混排、图片/视频预览、红包、地图、语音播放等功能。
使用技术
- 编辑器: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
- 预编译样式:sass^1.77.4
- 构建工具:vite^5.2.0
项目结构目录
vite-wechat使用
vite5.x
构建项目模板,采用
vue3 setup
语法糖编码开发模式。
main.js配置
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实现滑动解锁
<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:'*'},])//...// 触摸事件(开始/更新)consthandleTouchStart=(e)=>{
touchY.value = e.clientY
touchable.value =true}consthandleTouchUpdate=(e)=>{let swipeY = touchY.value - e.clientY
if(touchable.value && swipeY >100){
splashScreen.value =false
touchable.value =false}}consthandleTouchEnd=(e)=>{
touchY.value =0
touchable.value =false}// 点击数字键盘consthandleClickNum=(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)}}}// 删除consthandleDel=()=>{let num =Array.from(pwdValue.value)
num.splice(-1,1)
pwdValue.value = num.join('')}// 清空consthandleClear=()=>{
pwdValue.value =''}// 返回consthandleBack=()=>{
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-elseclass="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>
vue3-wechat布局模板
<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>
vue3路由管理
/**
* 路由管理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)}})
vue3小视频模块
vite5-wechat项目加入了小视频模块。使用
swiper
组件实现上下滑动小视频。
视频底部mini播放进度条,采用
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聊天模块
聊天输入框支持多行文本输入、光标处插入gif图片、粘贴截图发送图片等功能。
<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使用高德地图。
// 拾取地图位置let map =nullconsthandlePickMapLocation=()=>{
popoverChooseRef?.value?.hide()
mapLocationVisible.value =true// 初始化地图
AMapLoader.load({
key:"af10789c28b6ef1929677bc5a2a3d443",// 申请好的Web端开发者Key,首次调用 load 时必填
version:"2.0",// 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15}).then((AMap)=>{// JS API 加载完成后获取AMap对象
map =newAMap.Map("vu__mapcontainer",{
viewMode:"3D",// 默认使用 2D 模式
zoom:10,// 初始化地图级别
resizeEnable:true,})// 获取当前位置
AMap.plugin('AMap.Geolocation',function(){var geolocation =newAMap.Geolocation({// 是否使用高精度定位,默认:true
enableHighAccuracy:true,// 设置定位超时时间,默认:无穷大
timeout:10000,// 定位按钮的停靠位置的偏移量,默认:Pixel(10, 20)
buttonOffset:newAMap.Pixel(10,20),// 定位成功后调整地图视野范围使定位位置及精度范围视野内可见,默认:false
zoomToAccuracy:true,// 定位按钮的排放位置, RB表示右下
buttonPosition:'RB'})
map.addControl(geolocation)
geolocation.getCurrentPosition(function(status, result){if(status =='complete'){onComplete(result)}else{onError(result)}})})// 定位成功的回调函数functiononComplete(data){var str =['定位成功']
str.push('经度:'+ data.position.getLng())
str.push('纬度:'+ data.position.getLat())if(data.accuracy){
str.push('精度:'+ data.accuracy +' 米')}// 可以将获取到的经纬度信息进行使用console.log(str.join('<br>'))}// 定位失败的回调函数functiononError(data){console.log('定位失败:'+ data.message)}}).catch((e)=>{// 加载错误提示console.log('amapinfo', e)})}// 打开预览地图位置consthandleOpenMapLocation=(data)=>{
mapLocationVisible.value =true// 初始化地图
AMapLoader.load({
key:"af10789c28b6ef1929677bc5a2a3d443",// 申请好的Web端开发者Key,首次调用 load 时必填
version:"2.0",// 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15}).then((AMap)=>{// JS API 加载完成后获取AMap对象
map =newAMap.Map("vu__mapcontainer",{
viewMode:"3D",// 默认使用 2D 模式
zoom:13,// 初始化地图级别
center:[data.longitude, data.latitude],// 初始化地图中心点位置})// 添加插件
AMap.plugin(["AMap.ToolBar","AMap.Scale","AMap.HawkEye"],function(){//异步同时加载多个插件
map.addControl(newAMap.ToolBar())// 缩放工具条
map.addControl(newAMap.HawkEye())// 显示缩略图
map.addControl(newAMap.Scale())// 显示当前地图中心的比例尺})
mapPosition.value =[data.longitude, data.latitude]addMarker()// 实例化点标记functionaddMarker(){const marker =newAMap.Marker({
icon:"//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png",
position: mapPosition.value,
offset:newAMap.Pixel(-26,-54),})
marker.setMap(map)/* marker.setLabel({
direction:'top',
offset: new AMap.Pixel(0, -10), //设置文本标注偏移量
content: "<div class='info'>我是 marker 的 label 标签</div>", //设置文本标注内容
}) *///鼠标点击marker弹出自定义的信息窗体
marker.on('click',function(){
infoWindow.open(map, marker.getPosition())})const infoWindow =newAMap.InfoWindow({
offset:newAMap.Pixel(0,-60),
content:`
<div style="padding: 10px;">
<p style="font-size: 14px;">${data.name}</p>
<p style="color: #999; font-size: 12px;">${data.address}</p>
</div>
`})}}).catch((e)=>{// 加载错误提示console.log('amapinfo', e)})}// 关闭预览地图位置consthandleCloseMapLocation=()=>{
map?.destroy()
mapLocationVisible.value =false}
OK,以上就是vue3+vite5+element-plus开发网页聊天项目的一些分享。
https://blog.csdn.net/yanxinyun1990/article/details/139510447
https://blog.csdn.net/yanxinyun1990/article/details/138317354
https://blog.csdn.net/yanxinyun1990/article/details/136996521
版权归原作者 xiaoyan_2018 所有, 如有侵权,请联系我们删除。