Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

DotNet
• 阅读 161

vite5-vue3-wchat最新原创研发vite5.x+vue3+pinia+swiper+element-plus等技术搭建仿微信web端聊天室模板Vue3-ViteChat。

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

采用vue3 setup语法编码,包含了聊天、通讯录、朋友圈、短视频、我的等功能模块。支持收缩侧边栏、背景壁纸换肤、锁屏、最大化等功能。

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

使用技术

  • 开发工具: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

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

之前有分享过一篇flutter3.x桌面端仿微信EXE聊天,感兴趣的可以去看看。
https://segmentfault.com/a/1190000044675519

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

项目结构

整个项目使用vite5.x构建工具搭建项目模板。

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

目前该项目已经同步到我的最新原创作品集。
https://gf.bilibili.com/item/detail/1106226011

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

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上滑数字解锁验证

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

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>

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

项目布局模板

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

<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路由管理

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

/**
 * 路由管理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聊天小视频模块

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

vite5-webchat短视频模块。使用swiper组件实现上下滑动切换短视频。

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

采用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聊天功能

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

<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

https://segmentfault.com/a/1190000044741696

https://segmentfault.com/a/1190000044946983

Vue3Wechat基于vite5.x+vue3+pinia桌面pc版仿微信聊天实例

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
7个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
3年前
VBox 启动虚拟机失败
在Vbox(5.0.8版本)启动Ubuntu的虚拟机时,遇到错误信息:NtCreateFile(\\Device\\VBoxDrvStub)failed:0xc000000034STATUS\_OBJECT\_NAME\_NOT\_FOUND(0retries) (rc101)Makesurethekern
Wesley13 Wesley13
3年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Stella981 Stella981
3年前
SpringBoot整合Redis乱码原因及解决方案
问题描述:springboot使用springdataredis存储数据时乱码rediskey/value出现\\xAC\\xED\\x00\\x05t\\x00\\x05问题分析:查看RedisTemplate类!(https://oscimg.oschina.net/oscnet/0a85565fa
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Easter79 Easter79
3年前
SpringBoot整合Redis乱码原因及解决方案
问题描述:springboot使用springdataredis存储数据时乱码rediskey/value出现\\xAC\\xED\\x00\\x05t\\x00\\x05问题分析:查看RedisTemplate类!(https://oscimg.oschina.net/oscnet/0a85565fa
Wesley13 Wesley13
3年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这