Vue3.0聊天室|vue3+vant3仿微信聊天實例|vue3.x仿微信app界面

1、項目簡介

基於Vue3.0+Vant3.x+Vuex4.x+Vue-router4+V3Popup等技術開發實現的仿微信手機App聊天實例項目Vue3-Chatroom。實現了發送圖文表情消息/gif圖、圖片/視頻預覽、網址查看、下拉刷新功能、紅包/朋友圈等功能。html

2、技術選型

  • 編輯器:VScode/Sublime
  • 使用技術:Vue3.x+Vuex4.x+Vue-Router4
  • UI組件庫:Vant-UI3.x (有贊移動端Vue3組件庫)
  • 彈層組件:V3Popup(基於vue3.0封裝自定義彈出層組件)
  • iconfont圖標:阿里字體圖標庫
  • 自定義頂部導航欄+底部tabBar

◆ 項目結構

◆ Vue3自定義頂部Navbar+底部Tabbar

項目中頂部導航條和底部tabbar組件均是在以前vue2版的基礎上開發的vue3版。vue

 

 

你們若是感興趣,能夠去看看以前的一篇分享文章。react

http://www.javashuo.com/article/p-rxwieczb-nu.htmlwebpack

◆ Vue3自定義彈層組件

項目中使用到的彈框場景,均是最新開發的vue3.0自定義彈框組件v3popup來實現的。web

v3popup 一款聚集多種彈框類型及動畫效果的vue3.x彈框組件。開發靈感來源於以前的vue2版,並在功能及效果上保持一致性。vue-router

若是你們對具體的實現感興趣的話,能夠去看看以前的這篇文章。vuex

http://www.javashuo.com/article/p-wafhykwt-ny.htmlapi

◆ vue.config.js配置

/**
 * Vue3基礎配置文件
 */

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.0主入口頁面

在main.js中配置一些狀態管理、地址路由,引入一些js和公共組件。微信

import { createApp } from 'vue'
import App from './App.vue'

// 引入vuex和地址路由
import store from './store'
import router from './router'

// 引入js
import '@assets/js/fontSize'

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

const app = createApp(App)

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

app.mount('#app')

◆ Vuex + 表單登陸驗證

vue3中狀態管理及表單驗證操做。app

import { createStore } from 'vuex'

export default createStore({
    state: {
        user: localStorage.getItem('user') || null,
        token: localStorage.getItem('token') || null
    },
    mutations: {
        SET_USER(state, data) {
            localStorage.setItem('user', data)
            state.user = data
        },
        SET_TOKEN(state, data) {
            localStorage.setItem('token', data)
            state.token = data
        },
        LOGOUT(state) {
            localStorage.removeItem('user')
            localStorage.removeItem('token')
            state.user = null
            state.token = null
        }
    },
    getters: {},
    actions: {}
})
<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經過在onMounted中監聽scroll事件來控制頂部導航透明顯示。

  

<!-- //朋友圈模板 -->
<template>
    <div>
        <header-bar :bgcolor="headerBg" transparent zIndex="1010">
            <template #backIco><i class="iconfont icon-arrL"></i></template>
            <template v-slot:right><div @click="isShowPublish=true"><i class="iconfont icon-tianjia"></i></div></template>
        </header-bar>

        <div class="vui__scrollview flex1" ref="scrollview">
            ...
        </div>
    </div>
</template>

<script>
import { onMounted, onBeforeUnmount, ref, reactive, toRefs, inject } from 'vue'
import { ImagePreview } from 'vant'

export default {
    components: {},
    setup() {
        const scrollview = ref(null)

        const data = reactive({
            headerBg: 'transparent',
            // ...
        })

        onMounted(() => {
            scrollview.value.addEventListener('scroll', handleScroll)
        })

        onBeforeUnmount(() => {
            scrollview.value.removeEventListener('scroll', handleScroll)
        })

        // 頁面滾動處理
        const handleScroll = (e) => {
            if(e.target.scrollTop > 160) {
                data.headerBg = 'linear-gradient(to right, #00d2ee, #00e077)'
            }else {
                data.headerBg = 'transparent';
            }
        }

        // ...

        return {
            ...toRefs(data),
            scrollview,
            
            // ...
        }
    }
}
</script>

◆ Vue3聊天代碼片斷

vue3中實現聊天功能實現,其中編輯器支持圖文插入,而且單獨抽離了一個Editor.vue組件。

/**
 * @Desc     Vue3.0仿微信聊天實例
 * @Time     andy by 2021-01
 * @About    Q:282310962  wx:xy190310
 */
<script>
import { onMounted, onUnmounted, ref, reactive, toRefs, nextTick, inject } from 'vue'
import { useRouter } from 'vue-router'
import Editor from './editor.vue'
import { ImagePreview } from 'vant'

// ...

export default {
    components: {
        Editor
    },
    setup() {
        const scrollview = ref(null)
        const editorRef = ref(null)
        const pickImageRef = ref(null)
        const pickVideoRef = ref(null)
        const playerRef = ref(null)

        const router = useRouter()

        const v3popup = inject('v3popup')

        const data = reactive({
            editorText: '',

            isShowFootBar: false,
            showFootBarIndex: 0,

            // 表情列表
            emojList: emoJSON,

            // 消息記錄
            msgList: msgJSON,

            // 連接預覽
            isShowLinkView: false,
            linkView: '',

            // ...
        })

        onMounted(() => {
            nextTick(() => {
                imgLoaded(scrollview)
            })
        })

        onUnmounted(() => {
            window.removeEventListener('popstate', handlePopStateClosed, false)
        })
        // 監聽地址打開
        const handlePopStateOpen = () => {
            if(window.history && window.history.pushState) {
                history.pushState(null, null, document.URL)
                window.addEventListener('popstate', handlePopStateClosed, false)
            }
        }
        // 監聽地址關閉(手機回退按鈕事件)
        const handlePopStateClosed = () => {
            // console.log('監聽關閉視頻事件!')
            data.isShowLinkView = false
            data.isShowVideoPlayer = false
        }

        /**
         * 滾動條到底部
         * @param ref 容器ref
         */
        const scrollBottom = (ref) => {
            let viewport = ref.value
            if(viewport) {
                viewport.scrollTop = viewport.scrollHeight
            }
        }

        // 點擊聊天消息區域
        const handleMsgPanelClicked = () => {
            if(!data.isShowFootBar) return
            data.isShowFootBar = false
        }

        /**
         * 表情|選擇區切換
         * @param index 切換索引
         */
        const handleEmojChooseView = (index) => {
            data.isShowFootBar = true
            data.showFootBarIndex = index

            nextTick(() => { imgLoaded(scrollview) })
        }
        
        /**
         * 表情Tab切換
         * @param index 索引index
         */
        const handleEmojTab = (index) => {
            let emojLs = data.emojList
            for(var i = 0, len = emojLs.length; i < len; i++) {
                emojLs[i].selected = false
            }
            emojLs[index].selected = true
            data.emojList = emojLs
        }


        /* ---------- { 編輯器|表情模塊 } ---------- */
        // 點擊編輯器
        const handleEditorClick = () => {
            // console.log('點擊編輯器')
            data.isShowFootBar = false
        }

        // 編輯器獲取焦點
        const handleEditorFocus = () => {
            // console.log('編輯器獲取焦點')
        }

        // 編輯器失去焦點
        const handleEditorBlur = () => {
            // console.log('編輯器失去焦點')
        }

        // 判斷編輯器是否爲空
        const isEmpty = (html) => {
            html = html.replace(/<br[\s/]{0,2}>/ig, "\r\n")
            html = html.replace(/<[^img].*?>/ig, "")
            html = html.replace(/&nbsp;/ig, "")
            return html.replace(/\r\n|\n|\r/, "").replace(/(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g, "") == ""
        }
        // 匹配轉換聊天消息中連接
        const transferHTML = (html) => {
            let reg = /(http:\/\/|https:\/\/)((\w|=|\?|\.|\/|&|-)+)/g
            return html.replace(reg, "<a href='$1$2'>$1$2</a>")
        }

        // ...


        /* ---------- { 選擇功能模塊 } ---------- */
        // 選擇圖片
        const handleChooseImage = () => {
            let msgLs = data.msgList
            let len = msgLs.length
            // 消息隊列
            let arrLS = {
                // ...
            }

            let file = pickImageRef.value.files[0]
            if(!file) return
            let size = Math.floor(file.size / 1024)
            if(size > 2*1024) {
                v3popup({content: '請選擇2MB之內的圖片!'})
                return false
            }
            var reader = new FileReader()
            reader.readAsDataURL(file)
            reader.onload = function() {
                let img = this.result

                // ...
            }
        }

        // 預覽圖片
        const handleImgPreview = (src) => {
            ImagePreview({
                images: [
                    src
                ],
                showIndex: false,
                showIndicators: true,
                closeable: true,
            });
        }


        /* ---------- { 視頻功能模塊 } ---------- */
        // 播放視頻
        const handleVideoPlayed = (item) => {
            data.isShowVideoPlayer = true
            data.videoList = item

            nextTick(() => {
                playerRef.value.play()
            })

            // 監聽手機回退按鈕事件
            handlePopStateOpen()
        }

        // 抖一抖
        const handleShakeWin = () => {
            let ntbox = document.querySelector('.vui__container')
            ntbox.classList.add('shake')
            setTimeout(() => {
                ntbox.classList.remove('shake')
            }, 1000);
        }

        // ...

        return {
            ...toRefs(data),

            scrollview,
            editorRef,
            pickImageRef,
            pickVideoRef,
            playerRef,

            handleMsgPanelClicked,
            handleMsgClicked,

            // ...
        }
    } 
}
</script>

okey,以上就是基於vue3開發仿微信界面聊天室的介紹。但願你們能喜歡~~💪💪

最後附上一個Electron+Vue聊天實例

http://www.javashuo.com/article/p-ybuechct-mx.html

相關文章
相關標籤/搜索