欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

用React实现小Q聊天机器人

程序员文章站 2022-03-16 17:08:40
...

前几篇讲过用Vue实现小Q聊天机器人,既然用了Vue,那React自然也是少不了的,本项目实现效果与vue实现的效果完全一样:

GitHub源码:https://github.com/baiyuliang/Qrobot_React
用React实现小Q聊天机器人
进入正题之前,我们来聊聊前端三剑客 angular,react,vue!

这三种框架的面世时间:angular>react>vue,angular出世这么早,但是为什么我们在国内常见的前端开发基本都是用的react或者vue呢?主要是angular的版本升级出现了断层,也就是新版本不兼容老版本,导致流失大量用户,另外angular框架量级比较重,直白点就是难用!就国内的互联网环境来看,这注定是流行不起来的!所以react成为了最流行的前端开发框架,而新出世的vue凭借着它的易用性也迅速成为了最火的前端开发框架!

据本人了解,就国内目前最火的几种前端或者跨端开发平台,基本都是基于react和vue这两种框架,例如:
1.weex基于vue(现在通过rax也间接支持react)
2.rn不必说了,基于react
3.taro 支持react和vue
4.uni-app 基于vue

可以说学习前端,除了最基础的js+html+css外,react和vue是必学框架,没商量!

回到本项目,接下来,我会基于本项目粗略的对react和vue的实现过程进行一个对比,但不会深入!

1.创建项目
本人较懒,不喜欢用命令行去创建项目再外加一堆配置,而是直接用WebStrom创建,跟前几篇vue创建项目一样:
用React实现小Q聊天机器人
创建完成即可运行!

2.项目结构
我这里进行一个完整项目对比:左vue,右react
用React实现小Q聊天机器人用React实现小Q聊天机器人
3.页面结构、组件

vue的页面都是以.vue结尾的文件格式,其中包含了 templete,script,style,模板(html布局),js操作,css样式全在一个文件中实现,并且style提供scope属性,来确保css样式不会冲突,而vue创建组件同样也是创建.vue后缀文件,并声明组件名称name:XXX;

react的页面,没有特殊格式,全部为js,在这里大家有必要先了解一下JSX
react组件形式有两种:class组件和函数(function)组件,
class组件功能大而全,类似于Java的类,可以继承,有构造方法,静态方法,普通方法等,通过render()函数渲染DOM树,通过export default导出组件:

import React from 'react'

class Page2 extends React.Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
            <div>
                page2
            </div>
        )
    }
}
export default Page2

函数组件功能比较单一,return jsx格式DOM树即可!

function Item() {
    return <div>Item</div>
}

react相当于将js,html糅合到了一块,而css则单独分离了出去,所以使用样式时必须创建对应的css文件,并通过import导入!但是需要注意的是,react并没有像vue一样提供scope,所以直接通过

import ‘xxx.css’

使用会导致样式冲突,解决办法有两个:一个是给class名加上前缀来保证类名唯一性,另一个是css模块化:

import Style from ‘xxx.css’

<div className={Style.xxx}></div>

4.数据绑定
vue:通过v-model进行双向数据绑定;
react:单项数据绑定,只能通过state进行数据同步!
关于双向数据绑定好,还是单项数据绑定好,vue和react都有自己的解释,开发者也都有自己的理解,不用纠结于此!

5.网络请求
网络请求部分,两者倒没有什么不同,vue版小Q使用axios进行网络请求封装,而react可以直接拿来使用就可以了,没有任何区别!

6.跨域问题
vue在使用代理解决跨域时的方法,配置vue.config.js:

module.exports = {
    devServer: {
        proxy: {
            "/api": {
                target: 'https://api.ai.qq.com',
                changeOrigin: true,
                pathRewrite: {
                    '^/api': '/'
                }
            }
        }
    }
};

react则配置setupProxy.js(注意文件放入位置):

const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
    app.use(
        createProxyMiddleware('/api', {  //`api`是需要转发的请求
            target: 'https://api.ai.qq.com',  // 这里是接口服务器地址
            changeOrigin: true,
        })
    )
}

当然,两者还有其它很多不同的地方,就不再一一列举了,这里贴出聊天主界面代码,完整代码可以去GitHub(Qrobot_React)下载:

import React from "react";
import {getChatResponse} from "../api/ApiChat";
import './Chat.scss'
import RightItem from "../components/RightItem";
import LeftItem from "../components/LeftItem";

class Chat extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            text: '',
            msglist: [{
                id: 1,
                type: 1,
                content: '欢迎你!',
                me: false
            }]
        }
    }

    //调用接口
    getResponse = (text) => {
        getChatResponse(text).then(res => {
            this.state.msglist.push({
                id: this.state.msglist[this.state.msglist.length - 1].id + 1,
                type: 1,
                content: res.data.answer,
                me: false
            })
            this.setState({
                msglist: this.state.msglist,
            })
        })
    }

    //输入框数据改变时同步state
    changeText = (e) => {
        this.setState({
            text: e.target.value
        })
    }

    //监听enter键
    onKeyup = (e) => {
        if (e.keyCode === 13) {
            this.send()
        }
    }

    //发送文本
    send = () => {
        if (this.state.text) {
            this.state.msglist.push({
                id: this.state.msglist[this.state.msglist.length - 1].id + 1,
                type: 1,
                content: this.state.text,
                me: true
            })
            this.setState({
                msglist: this.state.msglist,
                text: ''
            })
            this.getResponse(this.state.text)
        }
    }

    //自动滚动到底部
    scrollToBottom = () => {
        this.messagesEnd.scrollIntoView({behavior: "smooth"});
    }

    //数据更新时执行scrollToBottom
    componentDidUpdate() {
        this.scrollToBottom();
    }

    render() {
        return (
            <div className="chat-container">
                <div className="chat-list">
                    <ul>
                        <ListItem list={this.state.msglist}/>
                    </ul>
                    <div style={{float: "left", clear: "both"}}
                         ref={(el) => {
                             this.messagesEnd = el;
                         }}>
                    </div>
                </div>
                <div className="chat-bottom">
                    <div className="chat-line"/>
                    <div className="chat-input-send">
                        <input placeholder="请输入内容..." value={this.state.text} onChange={this.changeText}
                               className="chat-input" onKeyUp={this.onKeyup}/>
                        <button className="chat-send" onClick={this.send}>发送</button>
                    </div>
                </div>

            </div>
        )
    }

}

function ListItem(props) {
    return props.list.map(item => {
        if (item.me) {
            return <li key={item.id}><RightItem msg={item}/></li>
        } else {
            return <li key={item.id}><LeftItem msg={item}/></li>
        }
    })
}


export default Chat

如果看过本人vue实现小Q文章的同学,会知道如何在vue中解决聊天列表自动滚动到底部的问题,而react依然面临着这个问题,解决办法其实大同小异,都是在列表下方放置一个空的div,并在每次聊天结束后,定位到这个div的位置:

第一步:

   <div className="chat-list">
         <ul>
             <ListItem list={this.state.msglist}/>
         </ul>
         <div style={{float: "left", clear: "both"}}
              ref={(el) => {
                  this.messagesEnd = el;
              }}>
         </div>
     </div>

第二步:

    //自动滚动到底部
    scrollToBottom = () => {
        this.messagesEnd.scrollIntoView({behavior: "smooth"});
    }

    //数据更新时执行scrollToBottom
    componentDidUpdate() {
        this.scrollToBottom();
    }

GitHub源码:https://github.com/baiyuliang/Qrobot_React

相关标签: 前端 react