react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

React18 Hooks+Arco-Design+Zustand仿微信客户端聊天ReactWebchat

react18-webchat基于react18+vite4.x+arco-design+zustand等技术开发的一款仿制微信网页版聊天实战项目。实现发送带有emoj消息文本、图片/视频预览、红包/朋友圈、局部模块化刷新/美化滚动条等功能。

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

使用技术

  • 编辑器:vscode
  • 技术栈:react18+vite4+react-router-dom+zustand+sass
  • 组件库:@arco-design/web-react (字节跳动react组件库)
  • 状态管理:zustand^4.4.1
  • 路由管理:react-router-dom^6.15.0
  • classname拼合:clsx^2.0.0
  • 对话框组件:rdialog (基于react18 hooks自定义桌面端弹窗组件)
  • 预处理样式:sass^1.66.1

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

项目目录结构

使用vite4.x创建react18项目,目录线性结构如下。

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

react-webchat 项目全部采用react18 hooks规范编码开发,使用到的对话框及虚拟滚动条均是自研组件实现功能效果。

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

react18 hooks自定义对话框+美化滚动条

大家看到的弹窗及滚动条组件都是自定义组件实现功能场景。

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

// 引入对话框组件
import RDialog,{ rdialog } from '@/components/rdialog'

 组件式调用
<RDialog
    visible={confirmVisible}
    title="标题信息"
    content="对话框内容信息"
    closeable
    shadeclose={false}
    zIndex="2050"
    dragOut
    maxmin
    btns={[
        {text: '取消',click: () => setConfirmVisible()},{text: '确定',click: handleInfo}
    ]}
    onClose={()=>setConfirmVisible()}
/>

 函数式调用
rdialog({
    title: '标题信息'trueeclose: '取消'react-scrollbar美化系统滚动条调用非常简单,需要包裹需要滚动的内容块即可快速生成一个虚拟滚动条。

// 引入滚动条组件
import RScroll from '@/components/rscroll'

<RScroll autohide maxHeight={100}>
    包裹需要滚动的内容块。。。
</RScroll>

main.jsx入口配置

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import '@arco-design/web-react/dist/css/arco.css'
import './style.scss'

ReactDOM.createRoot(document.getElementById('root')).render(<App />)

App.jsx配置

import { HashRouter } from 'react-router-dom'

 引入useRoutes集中式路由配置文件
import Router from './router'

function App() {
    return (
        <>
            <HashRouter>
              <Router />
            </HashRouter>
        </>
    )
}

export default App

react18-router-dom配置

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

自定义路由占位模板,有点类似vue里面的router-view占位。

 路由占位模板(类似vue中router-view)
const RouterLayout = () => {
    const authState = authStore()
     (
        <div classname="rc__container flexbox flex-alignc flex-justifyc" style={{'--themeSkin': authState.skin}}>
            <div classname="rc__layout flexbox flex-col">
                {/* <div classname="rc__layout-header">顶部栏</div> */}
                <div classname="rc__layout-body flex1 flexbox">
                    { 菜单栏 }
                    <Menu />
 中间栏 }
                    <Aside />
 主内容区 }
                    <div classname="rc__layout-main flex1 flexbox flex-col">
                        { lazyload(<Outlet />) }
                    </div>
                </div>
            </div>
        </div>
    )
}

路由配置文件

*
 * react-router路由配置 by HS Q:282310962


import { lazy,Suspense } from 'react'
import { useRoutes,Outlet,Navigate } from 'react-router-dom'
import { Spin } from '@arco-design/web-react'

import { authStore } from '@/store/auth'

 引入路由页面
import Login from '@views/auth/login'
import Register from '@views/auth/register'
const Index = lazy(() => import('@views/index'))
const Contact = lazy(() => import('@views/contact'))
const Uinfo = lazy(() => import('@views/contact/uinfo'))
const NewFriend = lazy(() => import('@views/contact/newfriend'))
const Chat = lazy(() => import('@views/chat/chat'))
const ChatInfo = lazy(() => import('@views/chat/info'))
const RedPacket = lazy(() => import('@views/chat/redpacket'))
const Fzone = lazy(() => import('@views/my/fzone'))
const Favorite = lazy(() => import('@views/my/favorite'))
const Setting = lazy(() => import('@views/my/setting'))
const Error = lazy(() => import('@views/404'))

import Menu from '@/layouts/menu'
import Aside from '@/layouts/aside'

 加载提示
const SpinLoading = () => {
     (
        <div classname="rcLoading">
            <Spin size="20" tip='loading...' />
        </div>
    )
}

 延迟加载
const lazyload = children => React 16.6 新增了<Suspense>组件,让你可以“等待”目标代码加载,并且可以直接指定一个加载的界面,让它在用户等待的时候显示
     路由懒加载报错:react-dom.development.js:19055 Uncaught Error: A component suspended while responding to synchronous input.
     懒加载的模式需要我们给他加上一层 Loading的提示加载组件
    return <Suspense fallback={<SpinLoading />}>{children}</Suspense>
}

 路由鉴权验证
const Routerauth = ({ children }) => authStore()

    return authState.isLogged ? (
        children
    ) : (
        <Navigate to="/login" replace={true} />
    )
}

export const routerConfig = [
    {
        path: '/'rauth><RouterLayout /></Routerauth> 首页
            { index: true,element: <Index /> }, 通讯录模块
            { path: '/contact',element: <Contact /> },{ path: '/uinfo',element: <Uinfo /> },{ path: '/newfriend',element: <NewFriend /> },1)"> 聊天模块
            { path: '/chat',element: <Chat /> },{ path: '/chatinfo',element: <ChatInfo /> },{ path: '/redpacket',element: <RedPacket /> },1)"> 我的模块
            { path: '/fzone',element: <Fzone /> },{ path: '/favorite',element: <Favorite /> },{ path: '/setting',element: <Setting /> },1)"> 404模块 path="*"不能省略
            { path: '*',element: <Error /> }
        ]
    }, 登录/注册
    { path: '/login',element: <Login /> },{ path: '/register',element: <Register /> }
]

const Router = () => useRoutes(routerConfig)

export default Router

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

react新状态管理器Zustand

这次开发react项目没有使用redux作为状态管理,而是使用支持react18 hooks新一代状态管理库Zustand。

 NPM
npm install zustand

 Yarn
yarn add zustand

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

zustand提供了内置的persist本地持久化存储管理。

*
 * react18状态管理库Zustand

import { create } from 'zustand'
import { persist,createJSONStorage } from 'zustand/middleware'

export const authStore = create(
    persist(
        (set,get) => ({
            isLogged: null 折叠侧边栏
            collapse:  个性换肤
            skin:  登录数据
            loggedData: (data) => set({isLogged: data.isLogged,token: data.token}),setCollapse: (v) => set({collapse: v}),setSkin: (v) => set({skin: v})
        }),{
            name: 'authState' name: 'auth-store',// name of the item in the storage (must be unique)
             storage: createJSONStorage(() => sessionStorage),// by default,'localStorage'
        }
    )
)

react18-chat聊天模块

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

聊天区域支持拖拽发送图片、编辑框支持多行文本、光标处插入emoj表情符。

return (
    div
        {...rest}
        ref={editorRef}
        classname={clsx('editor',classname)}
        contentEditable
        onClick={handleclick}
        onInput={handleInput}
        onFocus={handleFocus}
        onBlur={handleBlur}
        style={{'userSelect': 'text','WebkitUserSelect': 'text'}}
    />
)

获取输入光标位置

 获取光标最后位置
const getLastCursor = () => {
    let sel = window.getSelection()
    if(sel && sel.rangeCount > 0) {
        return sel.getRangeAt(0)
    }
}

光标处插入内容

 光标处插入emoj表情符内容
const insertHtmlAtCursor = (html) => {
    let sel,range
    if(!editorRef.current.childNodes.length) {
        editorRef.current.focus()
    }

    if(window.getSelection) {
         IE9及其它浏览器
        sel = window.getSelection()

         ##注意:判断最后光标位置
        (lastCursor.current) {
            sel.removeAllRanges()
            sel.addRange(lastCursor.current)
        }

        if(sel.getRangeAt && sel.rangeCount) {
            range = sel.getRangeAt(0)
            range.deleteContents()
            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)
            (lastNode) {
                range = range.cloneRange()
                range.setStartAfter(lastNode)
                range.collapse()
                sel.removeAllRanges()
                sel.addRange(range)
            }
        }
    } else if(document.selection && document.selection.type != 'Control' IE < 9
        document.selection.createRange().pasteHTML(html)
    }

     执行输入操作
    handleInput()
}

okay,基于react18 hooks+arco开发网页聊天项目就分享到这里,希望对大家有些帮助哈~

最后附上两个最新uniapp/tauri跨端实例项目

https://www.cnblogs.com/xiaoyan2017/p/17507581.html

https://www.cnblogs.com/xiaoyan2017/p/17552562.html

react18-webchat网页聊天实例|React Hooks+Arco Design仿微信桌面端

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件举报,一经查实,本站将立刻删除。

本文链接:https://www.f2er.com/3188626.html

大家都在看

  • 飞码LowCode前端技术系列:如何便捷快速验证实现投产及飞码探索

    本篇文章从数据中心,事件中心如何协议工作、不依赖环境对vue2.x、vue3.x都可以支持、投产页面问题定位三个方面进行分析。
    2023-11-16 博文
  • 如何优雅使用 vuex

    大纲 本文内容更多的是讲讲使用 vuex 的一些心得想法,所以大概会讲述下面这些点: Q1:我为什么会想使用 vuex 来管理数据状态交互? Q2:使用 vuex 框架有哪些缺点或者说副作用? Q3:我是如何在项目里使用 vuex 的? 初识 vuex 对于 vuex,有人喜欢,有人反感 喜欢的人觉
    2023-11-16 博文
  • 第三方组件及计算属性传参的问题解决方式

    1. 前言 唉,好想玩滋嘣。 2. 计算属性直接传参接收不到 表格数据某一列需要用的计算属性时,模板中使用计算属性 fullName 就会直接调用 fullName 函数,而在模板中 fullName(item) 相当于fullName()(item),此处为函数柯里化。 &lt;el-table-
    2023-11-16 博文
  • 记录--Vue3基于Grid布局简单实现一个瀑布流组件

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前言 在学习Grid布局之时,我发现其是CSS中的一种强大的布局方案,它将网页划分成一个个网格,可以任意组合不同的网格,做出各种各样的布局,在刷某书和某宝首页时,我们发现其展示方式就是一种瀑布流,是一种流行的网站页面布局,视觉表……
    2023-11-16 博文
  • 用强数据类型保护你的表单数据-基于antd表单的类型约束

    接口数据类型与表单提交数据类型,在大多数情况下,大部分属性的类型是相同的,但很少能做到完全统一。我在之前的工作中经常为了方便,直接将接口数据类型复用为表单内数据类型,在遇到属性类型不一致的情况时会使用any强制忽略类型错误。后来经过自省与思考,这种工作模式会引起各种隐藏bug,一定有更……
    2023-11-16 博文
  • pinia的使用

    前言 最近新开了个项目,以前老项目都是vue2+vuex开发的,都说用vue3+pinia爽得多,那新项目就vue3+pinia吧。这里记录一下pinia的使用。 使用方法 安装pinia: npm i pinia main.js中引入pinia: //main.js import { create
    2023-11-16 博文
  • 记录--让我们来深入了解一下前端“三清”是什么

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前端“三清” 在前端开发中,我们经常听到关于“三清”的说法,即 window、document、Object。这三者分别代表了 BOM(浏览器对象模型)、DOM(文档对象模型)以及 JS 的顶层对象。在这个体系中,我们通过 JavaScr
    2023-11-16 博文
  • 记录--啊?Vue是有三种路由模式的?

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 众所周知,vue路由模式常见的有 history 和 hash 模式,但其实还有一种方式-abstract模式(了解一哈~) 别急,本文我们将重点逐步了解: 路由 + 几种路由模式 + 使用场景 + 思考 + freestyle 路由概念
    2023-11-16 博文