光明与真知 發表於 2020-12-27 10:01:00

Next.js+React聊天室|Next仿微信桌面端|next.js聊天实例

<h3>一、项目介绍</h3>
<p><span style="font-size: 12px; font-family: &quot;comic sans ms&quot;, sans-serif; background-color: rgba(204, 255, 255, 1)">next-webchat 基于Next.js+React.js+Redux+Antd+RScroll+RLayer等技术构建的PC桌面端仿微信聊天项目。实现了消息/表情发送、图片/视频预览、拖拽/粘贴图片发送、红包/朋友圈等功能。</span></p>
<p><img src="https://img2020.cnblogs.com/blog/1289798/202012/1289798-20201227085529309-1710392267.gif"></p>
<p><img src="https://img2020.cnblogs.com/blog/1289798/202012/1289798-20201227085658345-925057248.gif"></p>
<h3>二、技术实现</h3>
<ul>
<li><span style="font-size: 12px; font-family: &quot;comic sans ms&quot;, sans-serif">技术框架:next.js+react.js+redux+react-redux</span></li>
<li><span style="font-size: 12px; font-family: &quot;comic sans ms&quot;, sans-serif">UI组件库:Antd (蚂蚁金服pc端react组件库)</span></li>
<li><span style="font-size: 12px; font-family: &quot;comic sans ms&quot;, sans-serif">字体图标:阿里iconfont图标库</span></li>
<li><span style="font-size: 12px; font-family: &quot;comic sans ms&quot;, sans-serif">弹窗组件:RLayer(基于react.js封装自定义弹窗)</span></li>
<li><span style="font-size: 12px; font-family: &quot;comic sans ms&quot;, sans-serif">虚拟滚动:RScroll(基于react.js自定义美化滚动条)</span></li>
</ul>
<p><img src="https://img2020.cnblogs.com/blog/1289798/202012/1289798-20201227090250892-1415148187.png"></p>
<p><img src="https://img2020.cnblogs.com/blog/1289798/202012/1289798-20201227090311092-982972179.png"></p>
<p><img src="https://img2020.cnblogs.com/blog/1289798/202012/1289798-20201227090343983-19402004.png"></p>
<p><img src="https://img2020.cnblogs.com/blog/1289798/202012/1289798-20201227090427640-1265041513.png"></p>
<p><img src="https://img2020.cnblogs.com/blog/1289798/202012/1289798-20201227090453416-759813785.png"></p>
<p><img src="https://img2020.cnblogs.com/blog/1289798/202012/1289798-20201227090733049-499123404.png"></p>
<p><img src="https://img2020.cnblogs.com/blog/1289798/202012/1289798-20201227090748139-813792933.png"></p>
<p><img src="https://img2020.cnblogs.com/blog/1289798/202012/1289798-20201227090757651-497107554.png"></p>
<p><img src="https://img2020.cnblogs.com/blog/1289798/202012/1289798-20201227090816188-613961863.png"></p>
<p><img src="https://img2020.cnblogs.com/blog/1289798/202012/1289798-20201227090825391-151810157.png"></p>
<p><img src="https://img2020.cnblogs.com/blog/1289798/202012/1289798-20201227090851914-2117141121.png"></p>
<p><img src="https://img2020.cnblogs.com/blog/1289798/202012/1289798-20201227090930882-1689435604.png"></p>
<p><img src="https://img2020.cnblogs.com/blog/1289798/202012/1289798-20201227090943093-1844550177.png"></p>
<h3 id="一项目简介"><strong>◆ Next.js简述</strong></h3>
<p><span style="font-size: 12px"><em>next.js</em>是一个基于react.js构建的服务器端SSR框架,<span style="color: rgba(255, 0, 0, 1)">star高达59K+</span>。让你的网页拥有<strong>SEO</strong>功能。</span></p>
<p><img src="https://img2020.cnblogs.com/blog/1289798/202012/1289798-20201227091419465-1931081262.png"></p>
<p><span style="font-size: 12px">https://www.nextjs.cn/</span></p>
<p><span style="font-size: 12px">https://github.com/vercel/next.js</span></p>
<h3 id="一项目简介"><strong>◆ 目录结构</strong></h3>
<p><img src="https://img2020.cnblogs.com/blog/1289798/202012/1289798-20201227091622457-1340299974.png"></p>
<h3 id="一项目简介"><strong>◆ next.js/react自定义弹窗组件</strong></h3>
<p><span style="font-size: 12px; font-family: &quot;comic sans ms&quot;, sans-serif">项目中没有使用Antd的Dialog弹框,而是自己造了一个react.js桌面端弹窗组件RLayer。</span></p>
<p><img src="https://img2020.cnblogs.com/blog/1289798/202012/1289798-20201227092147612-88349771.png"></p>
<p><span style="font-size: 12px">如果感兴趣的话,可以看看下面这篇分享文章。</span></p>
<p><span style="font-size: 12px">https://www.cnblogs.com/xiaoyan2017/p/14085142.html</span></p>
<h3 id="一项目简介"><strong>◆ next.js/react自定义虚拟滚动条组件</strong></h3>
<p><span style="font-size: 12px"><strong>如下图</strong>:项目中的滚动条均是自己开发的PC端美化滚动条组件<em>RScroll</em>。</span></p>
<p><img src="https://img2020.cnblogs.com/blog/1289798/202012/1289798-20201227090521314-732544413.gif"></p>
<p><span style="font-size: 12px"><strong>Rscroll</strong>支持<span style="background-color: rgba(204, 255, 255, 1)">原生滚动条、是否自动隐藏、滚动条尺寸/层级/颜色</span>等功能。</span></p>
<p><img src="https://img2020.cnblogs.com/blog/1289798/202012/1289798-20201227093018363-1278732698.gif"></p>
<p><img src="https://img2020.cnblogs.com/blog/1289798/202012/1289798-20201227093038809-1490642225.gif"></p>
<h3 id="一项目简介"><strong>◆ next公共布局</strong></h3>
<p><span style="font-size: 12px">next.js自定义公共模板,管理页面入口。新建layouts/index.js页面。</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> Layout(props) {
    const router </span>=<span style="color: rgba(0, 0, 0, 1)"> useRouter()

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 拦截验证</span>
    useEffect(() =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ...</span>
<span style="color: rgba(0, 0, 0, 1)">    }, [])

    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
    </span>&lt;&gt;<span style="color: rgba(0, 0, 0, 1)">
      {</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 配置公共head信息 </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">}
      </span>&lt;Head&gt;
            &lt;title&gt;Next.js聊天室&lt;/title&gt;
            &lt;link rel="icon" href="/favicon.ico" /&gt;
            &lt;meta name="keywords" content="Next.js|React.js|Next.js聊天室|Next.js仿微信|React聊天实例"&gt;&lt;/meta&gt;
            &lt;meta name="description" content="Next-WebChat 基于Next.js+React+Redux构建的服务端渲染聊天应用程序"&gt;&lt;/meta&gt;
      &lt;/Head&gt;

      &lt;div className="next__container flexbox flex-alignc flex-justifyc"&gt;
            &lt;div className={utils.classNames('next__wrapper')} style={{ backgroundImage: `url(${props.skin})` }}&gt;
                &lt;div className="next__board flexbox"&gt;<span style="color: rgba(0, 0, 0, 1)">
                  {</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 右上角按钮 </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">}
                  </span>&lt;WinBar {...props} /&gt;
<span style="color: rgba(0, 0, 0, 1)">
                  {</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 侧边栏 </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">}
                  </span>&lt;Sidebar {...props} /&gt;
<span style="color: rgba(0, 0, 0, 1)">
                  {</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 中间栏 </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">}
                  </span>&lt;Middle /&gt;
<span style="color: rgba(0, 0, 0, 1)">
                  {</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 主体布局 </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">}
                  </span>&lt;div className="nt__mainbox flex1 flexbox flex-col"&gt;<span style="color: rgba(0, 0, 0, 1)">
                        {props.children}
                  </span>&lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;
      &lt;/div&gt;
    &lt;/&gt;
<span style="color: rgba(0, 0, 0, 1)">    )
}</span></pre>
</div>
<p><span style="font-size: 12px"><strong>Head组件</strong>可以配置一些页面头部<strong>SEO</strong>信息,如:<span style="background-color: rgba(204, 255, 255, 1); color: rgba(255, 0, 0, 1)">标题title、关键词keyword、描述description及图标icon</span>等信息。</span></p>
<h3 id="一项目简介"><strong>◆ next聊天模块</strong></h3>
<p><img src="https://img2020.cnblogs.com/blog/1289798/202012/1289798-20201227094648449-1573837517.gif"></p>
<p><span style="font-size: 12px">聊天编辑框单独分离出了一个<em>editor.js</em>组件,在react中实现div可编辑器<strong>contenteditable</strong>属性处理<span style="background-color: rgba(204, 255, 255, 1); color: rgba(255, 0, 0, 1)">聊天输入、表情、光标处插入内容、粘贴截图</span>等功能。</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> react中实现div的contenteditable属性</span>
<span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
    </span>&lt;<span style="color: rgba(0, 0, 0, 1)">div
      ref</span>=<span style="color: rgba(0, 0, 0, 1)">{editorRef}
      className</span>="editor"<span style="color: rgba(0, 0, 0, 1)">
      contentEditable</span>="true"<span style="color: rgba(0, 0, 0, 1)">
      dangerouslySetInnerHTML</span>=<span style="color: rgba(0, 0, 0, 1)">{{__html: state.editorText}}
      onClick</span>=<span style="color: rgba(0, 0, 0, 1)">{handleClicked}
      onInput</span>=<span style="color: rgba(0, 0, 0, 1)">{handleInput}
      onFocus</span>=<span style="color: rgba(0, 0, 0, 1)">{handleFocus}
      onBlur</span>=<span style="color: rgba(0, 0, 0, 1)">{handleBlur}
      style</span>={{userSelect: 'text', WebkitUserSelect: 'text'}}&gt;
    &lt;/div&gt;
)</pre>
</div>
<p><img src="https://img2020.cnblogs.com/blog/1289798/202012/1289798-20201227094723736-1366795546.gif"></p>
<p><span style="font-size: 12px">基于RLayer弹窗实现的视频播放功能。</span></p>
<div class="cnblogs_code">
<pre>handlePlayVideo = (item, e) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
    rlayer({
      content: (
            </span>&lt;div className="flexbox flex-col" style={{height: '100%'}}&gt;
                &lt;div className="ntDrag__head"&gt;&lt;i className="iconfont icon-bofang"&gt;&lt;/i&gt; 视频预览&lt;/div&gt;
                &lt;div className="ntMain__cont flex1 flexbox flex-col"&gt;<span style="color: rgba(0, 0, 0, 1)">
                  {</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 视频video </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">}
                  </span>&lt;video className="vplayer" src={item.videosrc} poster={item.imgsrc} autoPlay preload="auto"<span style="color: rgba(0, 0, 0, 1)"> controls
                        x5</span>-video-player-fullscreen="true"<span style="color: rgba(0, 0, 0, 1)">
                        webkit</span>-playsinline="true"<span style="color: rgba(0, 0, 0, 1)">
                        x</span>-webkit-airplay="true"<span style="color: rgba(0, 0, 0, 1)">
                        playsInline
                        x5</span>-playsinline="true"<span style="color: rgba(0, 0, 0, 1)">
                        style</span>={{height: '100%', width: '100%', objectFit: 'contain', outline: 'none'<span style="color: rgba(0, 0, 0, 1)">}}
                  </span>/&gt;
                &lt;/div&gt;
            &lt;/div&gt;
<span style="color: rgba(0, 0, 0, 1)">      ),
      layerStyle: {background: </span>'#f6f5ef'<span style="color: rgba(0, 0, 0, 1)">},
      opacity: .</span>2<span style="color: rgba(0, 0, 0, 1)">,
      area: [</span>'550px', '450px'<span style="color: rgba(0, 0, 0, 1)">],
      drag: </span>'.ntDrag__head'<span style="color: rgba(0, 0, 0, 1)">,
      resize: </span><span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">,
      maximize: </span><span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">,
    })
}</span></pre>
</div>
<p><span style="font-size: 12px">编辑框支持拖拽发送图片功能。通过<em><strong>onDragEnter、onDragOver、onDrop</strong></em>事件处理拖拽。</span></p>
<div class="cnblogs_code">
<pre>handleDragEnter = (e) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
    e.stopPropagation()
    e.preventDefault()
}
handleDragOver </span>= (e) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
    e.stopPropagation()
    e.preventDefault()
}
handleDrop </span>= (e) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
    e.stopPropagation()
    e.preventDefault()
    console.log(e.dataTransfer)

    </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.handleFileList(e.dataTransfer)
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获取拖拽文件列表</span>
handleFileList = (filelist) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
    let files </span>=<span style="color: rgba(0, 0, 0, 1)"> filelist.files
    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(files.length &gt;= 2<span style="color: rgba(0, 0, 0, 1)">) {
      rlayer.message({icon: </span>'error', content: '暂时支持拖拽一张图片'<span style="color: rgba(0, 0, 0, 1)">})
      </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">
    }
    </span><span style="color: rgba(0, 0, 255, 1)">for</span>(let i = 0; i &lt; files.length; i++<span style="color: rgba(0, 0, 0, 1)">) {
      </span><span style="color: rgba(0, 0, 255, 1)">if</span>(files.type != ''<span style="color: rgba(0, 0, 0, 1)">) {
            </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.handleFileAdd(files)
      }</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
            rlayer.message({icon: </span>'error', content: '目前不支持文件夹拖拽功能'<span style="color: rgba(0, 0, 0, 1)">})
      }
    }
}
handleFileAdd </span>= (file) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(file.type.indexOf('image') == -1<span style="color: rgba(0, 0, 0, 1)">) {
      rlayer.message({icon: </span>'error', content: '目前不支持非图片拖拽功能'<span style="color: rgba(0, 0, 0, 1)">})
    }</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
      let reader </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileReader()
      reader.readAsDataURL(file)
      reader.onload </span>= <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">() {
            let img </span>= <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.result

            console.log(img)
      }
    }
}</span></pre>
</div>
<p><span style="font-size: 12px">好了,基于next.js+react实现pc网页聊天就分享到这里。希望大家能喜欢哈~~&nbsp;💪💪</span></p>
<p><strong><span style="font-size: 12px">最后附上一个Taro、Nuxt.js+Vue聊天项目</span></strong></p>
<p><span style="font-size: 12px">https://www.cnblogs.com/xiaoyan2017/p/13823195.html</span></p>
<p><span style="font-size: 12px">https://www.cnblogs.com/xiaoyan2017/p/12039544.html</span></p>
<p><img src="https://img2020.cnblogs.com/blog/1289798/202012/1289798-20201227095745654-1596926213.gif"></p>
<p>&nbsp;</p>

</div>
<div id="MySignature" role="contentinfo">
    本文为博主原创文章,未经博主允许不得转载,欢迎大家一起交流 QQ(282310962) wx(xy190310)<br><br>
来源:https://www.cnblogs.com/xiaoyan2017/p/14195483.html
頁: [1]
查看完整版本: Next.js+React聊天室|Next仿微信桌面端|next.js聊天实例