一、项目介绍
基于react+react-dom+react-router-dom+redux+react-redux+webpack2.0+nodejs等技术混合开发的仿微信web端聊天室reactWebChat项目,实现了聊天记录右键菜单、发送消息、表情(动图),图片、视频预览,浏览器截图粘贴发送等功能。
二、技术选型
- MVVM框架:react / react-dom
- 状态管理:redux / react-redux
- 页面路由:react-router-dom
- 弹窗插件:wcPop
- 打包工具:webpack 2.0
- 环境配置:node.js + cnpm
- 图片预览:react-photoswipe
- 轮播滑动:swiper
{ "name": "react-webchat", "version": "0.1.0", "private": true, "dependencies": { "react": "^16.8.6", "react-dom": "^16.8.6", "react-redux": "^7.1.0", "react-router-dom": "^5.0.1", "react-scripts": "0.9.x", "redux": "^4.0.1", "redux-thunk": "^2.3.0" }, "devDependencies": { "jquery": "^2.2.3", "react-custom-scrollbars": "^4.2.1", "react-photoswipe": "^1.3.0", "swiper": "^4.5.0" }, "scripts": { "start": "set HOST=localhost&& set PORT=3003 && react-scripts start", "build": "react-scripts build", "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject" } }
◆ App主页面布局及路由配置:
render() { let token = this.props.token return ( <Router> <div className="vChat-wrapper flexbox flex-alignc"> <div className="vChat-panel" /*style={{ backgroundImage: `url(${require("./assets/img/placeholder/vchat__panel-bg02.jpg")})` }}*/ > <div className="vChat-inner flexbox"> {/* //顶部(最大、最小、关闭) */} <Switch> <WinBar /> </Switch> {/* //侧边栏 */} <Switch> <SideBar /> </Switch> {/* //主页面 */} <div className="flex1 flexbox"> {/* 路由容器 */} <Switch> { routers.map((item, index) => { return <Route key={index} path={item.path} exact render={props => ( !item.meta || !item.meta.requireAuth ? (<item.component {...props} />) : ( token ? <item.component {...props} /> : <Redirect to={{pathname: ‘/login‘, state: {from: props.location}}} /> ) )} /> }) } {/* 初始化页面跳转 */} <Redirect push to="/index" /> </Switch> </div> </div> </div> </div> </Router> ); }
◆ react+react-redux配合状态管理:
import {combineReducers} from ‘redux‘ import defaultState from ‘./state.js‘ function auth(state = defaultState, action) { // 不同的action处理不同的逻辑 switch (action.type) { case ‘SET_TOKEN‘: return { ...state, token: action.data } case ‘SET_USER‘: return { ...state, user: action.data } case ‘SET_LOGOUT‘: return { user: null, token: null } default: return { ...state } } }
◆ react页面路由配置:
/* * @desc 页面地址路由js */ // 引入页面组件 import Login from ‘../views/auth/login‘ import Register from ‘../views/auth/register‘ import Index from ‘../views/index‘ import Contact from ‘../views/contact‘ import Uinfo from ‘../views/contact/uinfo‘ import NewFriend from ‘../views/contact/new-friends‘ import Ucenter from ‘../views/ucenter‘ import News from ‘../views/news‘ import NewsDetail from ‘../views/news/detail‘; export default [ { path: ‘/login‘, name: ‘Login‘, component: Login, meta: { hideSideBar: true }, }, { path: ‘/register‘, name: ‘Register‘, component: Register, meta: { hideSideBar: true }, }, { path: ‘/index‘, name: ‘App‘, component: Index, meta: { requireAuth: true }, }, { path: ‘/contact‘, name: ‘Contact‘, component: Contact, meta: { requireAuth: true }, }, { path: ‘/contact/uinfo‘, name: ‘Uinfo‘, component: Uinfo, }, { path: ‘/contact/new-friends‘, name: ‘NewFriend‘, component: NewFriend, meta: { requireAuth: true }, }, { path: ‘/news‘, name: ‘News‘, component: News, }, { path: ‘/news/detail‘, name: ‘NewsDetail‘, component: NewsDetail, }, { path: ‘/ucenter‘, name: ‘Ucenter‘, component: Ucenter, meta: { requireAuth: true }, }, // ... ]
import React, { Component } from ‘react‘; import { Link } from ‘react-router-dom‘; import {connect} from ‘react-redux‘ import $ from ‘jquery‘ // 引入wcPop弹窗插件 import { wcPop } from ‘../../assets/js/wcPop/wcPop‘ // 引入自定义滚动条 import { Scrollbars } from ‘react-custom-scrollbars‘ // 引入swiper import Swiper from ‘swiper‘ import ‘swiper/dist/css/swiper.css‘ // 引入图片预览组件react-photoswipe import {PhotoSwipe} from ‘react-photoswipe‘ import ‘react-photoswipe/lib/photoswipe.css‘ // 导入消息记录列表 import RecordList from ‘../../components/recordList‘
// >>> 【编辑器+表情处理模块】------------------------------------------ // ...处理编辑器信息 function surrounds() { setTimeout(function () { //chrome var sel = window.getSelection(); var anchorNode = sel.anchorNode; if (!anchorNode) return; if (sel.anchorNode === $(".J__wcEditor")[0] || (sel.anchorNode.nodeType === 3 && sel.anchorNode.parentNode === $(".J__wcEditor")[0])) { var range = sel.getRangeAt(0); var p = document.createElement("p"); range.surroundContents(p); range.selectNodeContents(p); range.insertNode(document.createElement("br")); //chrome sel.collapse(p, 0); (function clearBr() { var elems = [].slice.call($(".J__wcEditor")[0].children); for (var i = 0, len = elems.length; i < len; i++) { var el = elems[i]; if (el.tagName.toLowerCase() == "br") { $(".J__wcEditor")[0].removeChild(el); } } elems.length = 0; })(); } }, 10); } // 定义最后光标位置 var _lastRange = null, _sel = window.getSelection && window.getSelection(); var _rng = { getRange: function () { if (_sel && _sel.rangeCount > 0) { return _sel.getRangeAt(0); } }, addRange: function () { if (_lastRange) { _sel.removeAllRanges(); _sel.addRange(_lastRange); } } } // 格式化编辑器包含标签 $("body").on("click", ".J__wcEditor", function(){ $(".wc__choose-panel").hide(); _lastRange = _rng.getRange(); }); $("body").on("focus", ".J__wcEditor", function(){ surrounds(); _lastRange = _rng.getRange(); }); $("body").on("input", ".J__wcEditor", function(){ surrounds(); _lastRange = _rng.getRange(); });
原文地址:https://www.cnblogs.com/xiaoyan2017/p/11106246.html
时间: 2024-10-21 14:50:11