经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » HTML/CSS » HTML5 » 查看文章
react网页版聊天|仿微信、微博web版|react+pc端仿微信实例
来源:cnblogs  作者:xiaoyan2017  时间:2019/6/29 14:27:35  对本文有异议

一、项目介绍

基于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
  1. {
  2. "name": "react-webchat",
  3. "version": "0.1.0",
  4. "private": true,
  5. "dependencies": {
  6. "react": "^16.8.6",
  7. "react-dom": "^16.8.6",
  8. "react-redux": "^7.1.0",
  9. "react-router-dom": "^5.0.1",
  10. "react-scripts": "0.9.x",
  11. "redux": "^4.0.1",
  12. "redux-thunk": "^2.3.0"
  13. },
  14. "devDependencies": {
  15. "jquery": "^2.2.3",
  16. "react-custom-scrollbars": "^4.2.1",
  17. "react-photoswipe": "^1.3.0",
  18. "swiper": "^4.5.0"
  19. },
  20. "scripts": {
  21. "start": "set HOST=localhost&& set PORT=3003 && react-scripts start",
  22. "build": "react-scripts build",
  23. "test": "react-scripts test --env=jsdom",
  24. "eject": "react-scripts eject"
  25. }
  26. }

◆ App主页面布局及路由配置:

  1. render() {
  2. let token = this.props.token
  3. return (
  4. <Router>
  5. <div className="vChat-wrapper flexbox flex-alignc">
  6. <div className="vChat-panel" /*style={{ backgroundImage: `url(${require("./assets/img/placeholder/vchat__panel-bg02.jpg")})` }}*/ >
  7. <div className="vChat-inner flexbox">
  8. {/* //顶部(最大、最小、关闭) */}
  9. <Switch>
  10. <WinBar />
  11. </Switch>
  12. {/* //侧边栏 */}
  13. <Switch>
  14. <SideBar />
  15. </Switch>
  16. {/* //主页面 */}
  17. <div className="flex1 flexbox">
  18. {/* 路由容器 */}
  19. <Switch>
  20. {
  21. routers.map((item, index) => {
  22. return <Route key={index} path={item.path} exact render={props => (
  23. !item.meta || !item.meta.requireAuth ? (<item.component {...props} />) : (
  24. token ? <item.component {...props} /> : <Redirect to={{pathname: '/login', state: {from: props.location}}} />
  25. )
  26. )} />
  27. })
  28. }
  29. {/* 初始化页面跳转 */}
  30. <Redirect push to="/index" />
  31. </Switch>
  32. </div>
  33. </div>
  34. </div>
  35. </div>
  36. </Router>
  37. );
  38. }

◆ react+react-redux配合状态管理:

  1. import {combineReducers} from 'redux'
  2. import defaultState from './state.js'
  3.  
  4. function auth(state = defaultState, action) {
  5. // 不同的action处理不同的逻辑
  6. switch (action.type) {
  7. case 'SET_TOKEN':
  8. return {
  9. ...state, token: action.data
  10. }
  11. case 'SET_USER':
  12. return {
  13. ...state, user: action.data
  14. }
  15. case 'SET_LOGOUT':
  16. return {
  17. user: null, token: null
  18. }
  19. default:
  20. return { ...state }
  21. }
  22. }

◆ react页面路由配置:

  1. /*
  2. * @desc 页面地址路由js
  3. */
  4.  
  5. // 引入页面组件
  6. import Login from '../views/auth/login'
  7. import Register from '../views/auth/register'
  8. import Index from '../views/index'
  9. import Contact from '../views/contact'
  10. import Uinfo from '../views/contact/uinfo'
  11. import NewFriend from '../views/contact/new-friends'
  12. import Ucenter from '../views/ucenter'
  13. import News from '../views/news'
  14. import NewsDetail from '../views/news/detail';
  15. export default [
  16. {
  17. path: '/login', name: 'Login', component: Login,
  18. meta: { hideSideBar: true },
  19. },
  20. {
  21. path: '/register', name: 'Register', component: Register,
  22. meta: { hideSideBar: true },
  23. },
  24. {
  25. path: '/index', name: 'App', component: Index,
  26. meta: { requireAuth: true },
  27. },
  28. {
  29. path: '/contact', name: 'Contact', component: Contact,
  30. meta: { requireAuth: true },
  31. },
  32. {
  33. path: '/contact/uinfo', name: 'Uinfo', component: Uinfo,
  34. },
  35. {
  36. path: '/contact/new-friends', name: 'NewFriend', component: NewFriend,
  37. meta: { requireAuth: true },
  38. },
  39. {
  40. path: '/news', name: 'News', component: News,
  41. },
  42. {
  43. path: '/news/detail', name: 'NewsDetail', component: NewsDetail,
  44. },
  45. {
  46. path: '/ucenter', name: 'Ucenter', component: Ucenter,
  47. meta: { requireAuth: true },
  48. },
  49. // ...
  50. ]
  1. import React, { Component } from 'react';
  2. import { Link } from 'react-router-dom';
  3. import {connect} from 'react-redux'
  4. import $ from 'jquery'
  5. // 引入wcPop弹窗插件
  6. import { wcPop } from '../../assets/js/wcPop/wcPop'
  7.  
  8. // 引入自定义滚动条
  9. import { Scrollbars } from 'react-custom-scrollbars'
  10.  
  11. // 引入swiper
  12. import Swiper from 'swiper'
  13. import 'swiper/dist/css/swiper.css'
  14.  
  15. // 引入图片预览组件react-photoswipe
  16. import {PhotoSwipe} from 'react-photoswipe'
  17. import 'react-photoswipe/lib/photoswipe.css'
  18.  
  19. // 导入消息记录列表
  20. import RecordList from '../../components/recordList'
  1. // >>> 【编辑器+表情处理模块】------------------------------------------
  2. // ...处理编辑器信息
  3. function surrounds() {
  4. setTimeout(function () { //chrome
  5. var sel = window.getSelection();
  6. var anchorNode = sel.anchorNode;
  7. if (!anchorNode) return;
  8. if (sel.anchorNode === $(".J__wcEditor")[0] ||
  9. (sel.anchorNode.nodeType === 3 && sel.anchorNode.parentNode === $(".J__wcEditor")[0])) {
  10. var range = sel.getRangeAt(0);
  11. var p = document.createElement("p");
  12. range.surroundContents(p);
  13. range.selectNodeContents(p);
  14. range.insertNode(document.createElement("br")); //chrome
  15. sel.collapse(p, 0);
  16. (function clearBr() {
  17. var elems = [].slice.call($(".J__wcEditor")[0].children);
  18. for (var i = 0, len = elems.length; i < len; i++) {
  19. var el = elems[i];
  20. if (el.tagName.toLowerCase() == "br") {
  21. $(".J__wcEditor")[0].removeChild(el);
  22. }
  23. }
  24. elems.length = 0;
  25. })();
  26. }
  27. }, 10);
  28. }
  29. // 定义最后光标位置
  30. var _lastRange = null, _sel = window.getSelection && window.getSelection();
  31. var _rng = {
  32. getRange: function () {
  33. if (_sel && _sel.rangeCount > 0) {
  34. return _sel.getRangeAt(0);
  35. }
  36. },
  37. addRange: function () {
  38. if (_lastRange) {
  39. _sel.removeAllRanges();
  40. _sel.addRange(_lastRange);
  41. }
  42. }
  43. }
  44. // 格式化编辑器包含标签
  45. $("body").on("click", ".J__wcEditor", function(){
  46. $(".wc__choose-panel").hide();
  47. _lastRange = _rng.getRange();
  48. });
  49. $("body").on("focus", ".J__wcEditor", function(){
  50. surrounds();
  51. _lastRange = _rng.getRange();
  52. });
  53. $("body").on("input", ".J__wcEditor", function(){
  54. surrounds();
  55. _lastRange = _rng.getRange();
  56. });

 

原文链接:http://www.cnblogs.com/xiaoyan2017/p/11106246.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号