前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Vue3.x+Vant3仿微信聊天|朋友圈

Vue3.x+Vant3仿微信聊天|朋友圈

原创
作者头像
andy2018
修改2021-01-11 10:19:44
3.9K2
修改2021-01-11 10:19:44
举报
文章被收录于专栏:h5h5

项目简介

2021已来临,Vue3开发也要步入正轨了。今天为大家带来的是全新开发的Vue3.x实战聊天室项目Vue3_Chatroom,基于vue3+vant3+vuex+vue-router+v3popup等技术搭建的聊天实例。

vue3chat支持发送图文消息、图片/视频预览、网址链接查看、红包/朋友圈等功能。

技术架构

  • 编码+技术:Vscode + Vue3.0/Vuex4/Vue-Router4
  • UI 组件库:vant-ui3(有赞移动端 vue3.0 组件库)
  • 弹框组件:v3-popup(基于 vue3 弹层组件)
  • 字体图标:阿里 iconfont 字体图标库
  • 自定义顶部 Navbar+底部 Tabbar

项目中所有的页面及逻辑部分源码均是使用最新的Vue3.0语法编写。

Vue3自定义顶部导航+底部Tab组件

顶部headerBar和底部tabBar组件,均是自定义组件实现,在原先vue2基础上演变而来。

由于之前有过一篇分享文章,这里就不详细介绍了。

vue.js自定义顶部topbar和底部tabbar组件

Vue3自定义弹框组件

vue3chat中用到的弹框场景,都是最新开发的vue3.0自定义弹框V3Popup组件实现。

v3popup一款基于vue3.x构建的移动端弹框组件,拥有多种弹框类型及流畅动画效果。

如果感兴趣,可以去看看这篇文章。

vue3.0系列之自定义手机端弹框组件|vue3全局弹层组件v3popup

vue.config.js自定义配置

项目中的一些路径别名alias配置,避免过多的../../路径。

代码语言:javascript
复制
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引入公共组件

在main.js页面引入公共组件/样式,路由及vuex状态管理。

代码语言:javascript
复制
import { createApp } from 'vue'
import App from './App.vue'

// 引入vuex和router配置
import store from './store'
import router from './router'

import '@assets/js/fontSize'

// 引入公共组件
import Plugins from './plugins'

const app = createApp(App)

app.use(store)
app.use(router)
app.use(Plugins)

app.mount('#app')

Vue3实现表单验证

vue3中实现登录/注册表单操作验证。用到了reactive响应式函数和getCurrentInstance获取上下文this。

代码语言:javascript
复制
<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聊天模块

聊天编辑器部分采用抽离公共组件方式,支持图文混排、光标处插入emoj等功能。

代码语言:javascript
复制
<!-- //Vue3.0可编辑contenteditable功能 -->
<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>

是基于div的可编辑属性contenteditable实现。

代码语言:javascript
复制
const handleInput = () => {
    emit('update:modelValue', editorRef.value.innerHTML)
 
    data.lastCursor = getLastCursor()
}
// 删除内容
const handleDel = () => {
    let range
    let sel = window.getSelection()
    if(data.lastCursor) {
        sel.removeAllRanges()
        sel.addRange(data.lastCursor)
    }
    range = getLastCursor()
    range.collapse(false)
    document.execCommand('delete')
 
    // 删除表情时禁止输入法
    nextTick(() => {
        setTimeout(() => { editorRef.value.blur() }, 0);
    })
}
// 清空编辑器
const handleClear = () => {
    editorRef.value.innerHTML = ''
}
代码语言:javascript
复制
/**
 * @Desc     vue3图文混排编辑器
 * @Time     andy by 2021-01
 * @About    Q:282310962  wx:xy190310
 */
<script>
    import { ref, reactive, toRefs, watch, nextTick } from 'vue'
    export default {
        props: {
            modelValue: { type: String, default: '' }
        },
        setup(props, { emit }) {
            const editorRef = ref(null)
 
            const data = reactive({
                editorText: props.modelValue,
                isChange: true,
                lastCursor: null,
            })
 
            // ...
 
            // 获取光标最后位置
            const getLastCursor = () => {
                let sel = window.getSelection()
                if(sel && sel.rangeCount > 0) {
                    return sel.getRangeAt(0)
                }
            }
 
 
            // 光标处插入内容 @param html 需要插入的内容
            const insertHtmlAtCursor = (html) => {
                let sel, range
                if(window.getSelection) {
                    // IE9及其它浏览器
                    sel = window.getSelection()
 
                    // ##注意:判断最后光标位置
                    if(data.lastCursor) {
                        sel.removeAllRanges()
                        sel.addRange(data.lastCursor)
                    }
 
                    if(sel.getRangeAt && sel.rangeCount) {
                        range = sel.getRangeAt(0)
                        let el = document.createElement('div')
                        el.appendChild(html)
                        var frag = document.createDocumentFragment(), node, lastNode
                        while ((node = el.firstChild)) {
                            lastNode = frag.appendChild(node)
                        }
                        range.insertNode(frag)
                        if(lastNode) {
                            range = range.cloneRange()
                            range.setStartAfter(lastNode)
                            range.collapse(true)
                            sel.removeAllRanges()
                            sel.addRange(range)
                        }
                    }
                } else if(document.selection && document.selection.type != 'Control') {
                    // IE < 9
                    document.selection.createRange().pasteHTML(html)
                }
 
                // ...
            }
 
            return {
                ...toRefs(data),
                editorRef,
 
                handleInput,
                handleDel,
 
                // ...
            }
        }
    }
</script>

好了,基于vue3开发聊天项目,暂时就介绍到这里。后续还会分享一些Vue3.x实战案例。感谢大家的支持! 💪🏻

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 项目简介
  • 技术架构
  • Vue3自定义顶部导航+底部Tab组件
  • Vue3自定义弹框组件
  • vue.config.js自定义配置
  • Vue3引入公共组件
  • Vue3实现表单验证
  • Vue3聊天模块
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档