百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Vue3.0桌面端聊天|vue3仿微信/QQ网页版聊天实例

zhezhongyun 2024-12-26 17:42 39 浏览

随着vue3.x越来越稳定及vite2.0的快速迭代推出,加上很多大厂相继推出了vue3的UI组件库,在2021年必然受到开发者的再一次热捧。

Vue3迭代更新频繁,目前star高达20.2K+

// 官网地址
https://v3.vuejs.org/

Vitejs目前的star达到15.7K+

// 官网地址
https://vitejs.dev/

项目介绍

vue3-webchat 基于vue3.x+vuex4+vue-router4+element-plus+v3layer+v3scroll等技术架构的仿微信PC端界面聊天实例。

以上是仿制微信界面聊天效果,同样也支持QQ皮肤。

技术栈

  • 使用技术:vue3.0+vuex4+vue-router4
  • UI组件库:element-plus(饿了么Vue3 pc端组件库)
  • 弹窗组件:V3Layer(基于Vue3自定义桌面端弹窗)
  • 滚动条组件:V3Scroll(基于Vue3自定义虚拟美化滚动条)
  • iconfont图标:阿里字体图标库

Vue3.x自定义弹窗组件

大家看到的所有弹窗功能,均是自己开发的vue3.0自定义弹窗V3Layer组件。

前段时间有过一篇详细的分享,这里就不作介绍了。感兴趣的话可以去看看。

vue3.0系列:Vue3自定义PC端弹窗组件V3Layer

Vue3.x自定义美化滚动条组件

为了使得项目效果一致,所有页面的滚动条均是采用vue3.0自定义组件实现。

v3scroll 一款轻量级的pc桌面端模拟滚动条组件。支持是否原生滚动条、自动隐藏、滚动条大小/层叠/颜色等功能。

大家感兴趣的话,可以去看看这篇分享。

Vue3.0系列:vue3定制美化滚动条组件v3scroll

vue.config.js项目配置

/**
 * Vue3.0项目配置
 */

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('@layouts', path.join(__dirname, 'src/layouts'))
            .set('@views', path.join(__dirname, 'src/views'))
    }
}

Vue3引入/注册公共组件

// 引入饿了么ElementPlus组件库
import ElementPlus from 'element-plus'
import 'element-plus/lib/theme-chalk/index.css'

// 引入vue3弹窗组件v3layer
import V3Layer from '../components/v3layer'

// 引入vue3滚动条组件v3scroll
import V3Scroll from '@components/v3scroll'

// 引入公共组件
import WinBar from '../layouts/winbar.vue'
import SideBar from '../layouts/sidebar'
import Middle from '../layouts/middle'

import Utils from './utils'

const Plugins = app => {
    app.use(ElementPlus)
    app.use(V3Layer)
    app.use(V3Scroll)

    // 注册公共组件
    app.component('WinBar', WinBar)
    app.component('SideBar', SideBar)
    app.component('Middle', Middle)

    app.provide('utils', Utils)
}

export default Plugins

项目中主面板毛玻璃效果(虚化背景)

<!-- //虚化背景(毛玻璃) -->
<div class="vui__bgblur">
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" class="blur-svg" viewBox="0 0 1920 875" preserveAspectRatio="none">
    <filter id="blur_mkvvpnf"><feGaussianBlur in="SourceGraphic" stdDeviation="50"></feGaussianBlur></filter>
    <image :xlink:href="store.state.skin" x="0" y="0" width="100%" height="100%" externalResourcesRequired="true" xmlns:xlink="http://www.w3.org/1999/xlink" style="filter:url(#blur_mkvvpnf)" preserveAspectRatio="none"></image>
    </svg>
    <div class="blur-cover"></div>
</div>

Vue3拦截登录状态

vue3.0中使用全局路由钩子拦截登录状态。

router.beforeEach((to, from, next) => {
    const token = store.state.token

    // 判断当前路由地址是否需要登录权限
    if(to.meta.requireAuth) {
        if(token) {
            next()
        }else {
            // 未登录授权
            V3Layer({
                content: '还未登录授权!', position: 'top', layerStyle: 'background:#fa5151', time: 2,
                onEnd: () => {
                    next({ path: '/login' })
                }
            })
        }
    }else {
        next()
    }
})

Vue3.x聊天模块

如上图:聊天编辑框部分支持文字+emoj表情、在光标处插入表情、多行文本内容。

编辑器抽离了一个公共的Editor.vue组件。

<template>
    <div
        ref="editorRef"
        class="editor"
        contentEditable="true"
        v-html="editorText"
        @click="handleClick"
        @input="handleInput"
        @focus="handleFocus"
        @blur="handleBlur"
        style="user-select:text;-webkit-user-select:text;">
    </div>
</template>

另外还支持粘贴截图发送,通过监听paste事件,判断是否是图片类型,从而发送截图。

editorRef.value.addEventListener('paste', function(e) {
    let cbd = e.clipboardData
    let ua = window.navigator.userAgent
    if(!(e.clipboardData && e.clipboardData.items)) return

    if(cbd.items && cbd.items.length === 2 && cbd.items[0].kind === "string" && cbd.items[1].kind === "file" &&
        cbd.types && cbd.types.length === 2 && cbd.types[0] === "text/plain" && cbd.types[1] === "Files" &&
        ua.match(/Macintosh/i) && Number(ua.match(/Chrome\/(\d{2})/i)[1]) < 49){
        return;
    }
    for(var i = 0; i < cbd.items.length; i++) {
        var item = cbd.items[i]
        // console.log(item)
        // console.log(item.kind)
        if(item.kind == 'file') {
            var blob = item.getAsFile()
            if(blob.size === 0) return
            // 读取图片记录
            var reader = new FileReader()
            reader.readAsDataURL(blob)
            reader.onload = function() {
                var _img = this.result

                // 返回图片给父组件
                emit('pasteFn', _img)
            }
        }
    }
})

还支持拖拽图片至聊天区域进行发送。

<div class="ntMain__cont" @dragenter="handleDragEnter" @dragover="handleDragOver" @drop="handleDrop">
    // ...
</div>
const handleDragEnter = (e) => {
    e.stopPropagation()
    e.preventDefault()
}
const handleDragOver = (e) => {
    e.stopPropagation()
    e.preventDefault()
}
const handleDrop = (e) => {
    e.stopPropagation()
    e.preventDefault()
    // console.log(e.dataTransfer)

    handleFileList(e.dataTransfer)
}
// 获取拖拽文件列表
const handleFileList = (filelist) => {
    let files = filelist.files
    if(files.length >= 2) {
        v3layer.message({icon: 'error', content: '暂时支持拖拽一张图片', shade: true, layerStyle: {background:'#ffefe6',color:'#ff3838'}})
        return false
    }
    for(let i = 0; i < files.length; i++) {
        if(files[i].type != '') {
            handleFileAdd(files[i])
        }else {
            v3layer.message({icon: 'error', content: '目前不支持文件夹拖拽功能', shade: true, layerStyle: {background:'#ffefe6',color:'#ff3838'}})
        }
    }
}

大家如果感兴趣可以自己去试试哈。

ok,基于vue3+element-plus开发仿微信/QQ聊天实战项目就分享到这里。

基于vue3.0+vant3移动端聊天实战|vue3聊天模板实例

相关推荐

JPA实体类注解,看这篇就全会了

基本注解@Entity标注于实体类声明语句之前,指出该Java类为实体类,将映射到指定的数据库表。name(可选):实体名称。缺省为实体类的非限定名称。该名称用于引用查询中的实体。不与@Tab...

Dify教程02 - Dify+Deepseek零代码赋能,普通人也能开发AI应用

开始今天的教程之前,先解决昨天遇到的一个问题,docker安装Dify的时候有个报错,进入Dify面板的时候会出现“InternalServerError”的提示,log日志报错:S3_USE_A...

用离散标记重塑人体姿态:VQ-VAE实现关键点组合关系编码

在人体姿态估计领域,传统方法通常将关键点作为基本处理单元,这些关键点在人体骨架结构上代表关节位置(如肘部、膝盖和头部)的空间坐标。现有模型对这些关键点的预测主要采用两种范式:直接通过坐标回归或间接通过...

B 客户端流RPC (clientstream Client Stream)

客户端编写一系列消息并将其发送到服务器,同样使用提供的流。一旦客户端写完消息,它就等待服务器读取消息并返回响应gRPC再次保证了单个RPC调用中的消息排序在客户端流RPC模式中,客户端会发送多个请...

我的模型我做主02——训练自己的大模型:简易入门指南

模型训练往往需要较高的配置,为了满足友友们的好奇心,这里我们不要内存,不要gpu,用最简单的方式,让大家感受一下什么是模型训练。基于你的硬件配置,我们可以设计一个完全在CPU上运行的简易模型训练方案。...

开源项目MessageNest打造个性化消息推送平台多种通知方式

今天介绍一个开源项目,MessageNest-可以打造个性化消息推送平台,整合邮件、钉钉、企业微信等多种通知方式。定制你的消息,让通知方式更灵活多样。开源地址:https://github.c...

使用投机规则API加快页面加载速度

当今的网络用户要求快速导航,从一个页面移动到另一个页面时应尽量减少延迟。投机规则应用程序接口(SpeculationRulesAPI)的出现改变了网络应用程序接口(WebAPI)领域的游戏规则。...

JSONP安全攻防技术

关于JSONPJSONP全称是JSONwithPadding,是基于JSON格式的为解决跨域请求资源而产生的解决方案。它的基本原理是利用HTML的元素标签,远程调用JSON文件来实现数据传递。如果...

大数据Doris(六):编译 Doris遇到的问题

编译Doris遇到的问题一、js_generator.cc:(.text+0xfc3c):undefinedreferenceto`well_known_types_js’查找Doris...

网页内嵌PDF获取的办法

最近女王大人为了通过某认证考试,交了2000RMB,官方居然没有给线下教材资料,直接给的是在线教材,教材是PDF的但是是内嵌在网页内,可惜却没有给具体的PDF地址,无法下载,看到女王大人一点点的截图保...

印度女孩被邻居家客人性骚扰,父亲上门警告,反被围殴致死

微信的规则进行了调整希望大家看完故事多点“在看”,喜欢的话也点个分享和赞这样事儿君的推送才能继续出现在你的订阅列表里才能继续跟大家分享每个开怀大笑或拍案惊奇的好故事啦~话说只要稍微关注新闻的人,应该...

下周重要财经数据日程一览 (1229-0103)

下周焦点全球制造业PMI美国消费者信心指数美国首申失业救济人数值得注意的是,下周一希腊还将举行第三轮总统选举需要谷歌日历同步及部分智能手机(安卓,iPhone)同步日历功能的朋友请点击此链接,数据公布...

PyTorch 深度学习实战(38):注意力机制全面解析

在上一篇文章中,我们探讨了分布式训练实战。本文将深入解析注意力机制的完整发展历程,从最初的Seq2Seq模型到革命性的Transformer架构。我们将使用PyTorch实现2个关键阶段的注意力机制变...

聊聊Spring AI的EmbeddingModel

序本文主要研究一下SpringAI的EmbeddingModelEmbeddingModelspring-ai-core/src/main/java/org/springframework/ai/e...

前端分享-少年了解过iframe么

iframe就像是HTML的「内嵌画布」,允许在页面中加载独立网页,如同在画布上叠加另一幅动态画卷。核心特性包括:独立上下文:每个iframe都拥有独立的DOM/CSS/JS环境(类似浏...