[个人主页搭建] 一、项目架构和登录验证实现

579 阅读4分钟

起因背景:

先做一个全栈的项目,实现一个自己喜欢的个人主页

技术选型:

前端:

  • react 技术栈
    • react-dom
    • hooks
    • react-router-dom
    • babel(也可归到后端,主要使用babel进行es6到es5的转换)
    • axios

后端:

  • node.js 技术栈
    • express 用于服务器搭建
    • babel(转译es6的语法)
    • cros 跨域问题
    • mongodb (数据库)
      • mongoose 操作 mongodb数据库

服务器与操作系统

  • tx云centos7操作系统(具有公网ip)
  • nginx (静态资源管理,接入外网请求反向代理)

本期需求:

实现用户登录验证测试并进行页面跳转。

前端:

  • 用户登录基本模态框
    • 用户名输入
    • 密码输入
    • 点击提交按钮
  • 用户跳转路由配置
    • 验证成功后跳转页面

后端:

  • express 服务器搭建
    • 服务器及端口配置
    • 基本接口配置
  • 数据库
    • 后端测试数据库搭建插入测试数据
    • 数据库模型建立

服务器:

  • 搭建后台服务器
    • nginx 配置暴露外网IP和端口
    • 配置nodejs的反向代理

版本管理

  • 码云(git)

前端页面

1.编写思路:

类似于creat react-app 这样的操作就不说了,主要思路就是遵循react的思想,组件化。 目录构建如下:

image.png

  • Login组件就是一个登录模态框,它的子组件有:
    • FormInput 输入框
    • Button 按钮组件

实现效果如下:

image.png

这样分解组件的主要考虑的是,可以多编写一个可复用的公共样式,另外也提供了一些可选择的属性:

// FormInput.js
export default function FormInput(props) {
    // input type 属性:
    
    const [inputMust,setInputMust] = useState('');

    // 控制必填属性
    function handleInputMust() {
        // console.log(props.inputMust);
        if (props.inputMust) {
            setInputMust('(必填)');
        }
    };

    // 进行渲染
    useEffect(()=>{
        handleInputMust();
    })

    return (
        <div className="com-input">
           <span>{props.inputName}</span> 
           <input type={props.inputType} onChange={props.getInputValue}></input> 
           <span>{inputMust}</span>
        </div>
    )
}

对于 Button组件:

export default function Button(props) {

    const [buttonName,setButtonName] = useState('');
    // const [buttonEvent,setButtonEvent] = useState(()=>{});

    function handleButtonProps() {
        setButtonName(props.buttonName);
        // setButtonEvent(props.buttonEvent);
    }

    return (
        <button onClick={props.buttonClick}>{props.buttonName}</button>
    )
}

在Login.js中可以定制一些自己需要的属性:

export default function Login(props) {

  
  // const [buttonEvent,setButtonEvent] = useState(buttonEventHandle);
  const [inputNameVal,setInputNameVal] = useState('');
  const [inputPassVal,setInputPassVal] = useState('');

  function buttonEventHandle() {
    let that = this;
    const url = 'http://82.156.***.***/db'; // ip打码
    axios.post(url,{
      'id':inputNameVal !== ''?inputNameVal:'NONE',
      'pass':inputPassVal !== ''?inputPassVal:'NONE'
    }).then(res=>{
      // 登录成功后进行跳转:
      if (res.data['res']) {
        props.history.push('/home');
      }
    });
  }

  function getInputName(val) {
    console.log(val.target.value);
    setInputNameVal(val.target.value);
  }

  
  function getInputPass(val) {
    console.log(val.target.value);
    setInputPassVal(val.target.value);
  }

  return (
    <div>
    {/* login模态框 */}
      <div className="login">
        <FormInput getInputValue={getInputName} inputType="text" inputName="工号/用户名:" inputMust="true"></FormInput>
        <FormInput getInputValue={getInputPass} inputType="password" inputName="密码:" inputMust="true"></FormInput>
        <Button buttonName="登录" buttonClick={buttonEventHandle}></Button>
      </div>
    </div>
  )
}

即可实现上面图片的效果。

2.父子组件通信

2.1 父传子:

这个模态框的实现中,存在很多父传子的通信,比如:

image.png

Login父组件为了设定一些自己想要的属性,向子组件FormInput 和 Button 传递了一些数据,而在两个子组件中,分别进行接受使用:
Button

image.png FormInput:

image.png

2.2 子传父:

在react中,子传父数据通信的思路一般是:
在子组件中调用父组件的方法,并用此方法影响父组件中的数据。
个人理解,还是建立在父传子技术的基础之上,毕竟还是需要向子组件传递一个函数的。

目前这个项目中涉及到的子传父主要是 FormInputLogin之间的来往:
Login

image.png

FormInput

image.png

3.使用REACT HOOK

3.1 初识HOOK:

真正接触HOOK之后,才发现HOOK的便捷之处。
在目前的项目中,我主要是为了替代类组件中的statesetState (在接触react之前接触了微信小程序,发现这个写法和小程序的datasetData一样)。

3.2 管理函数组件中数据的状态:

Button中控制是否为必填选项

image.png

FormInput中控制input输入值

image.png

4. 使用react-router-dom:

4.1 仅用react对路由进行管理:

不再利用后端的express路由跳转html静态页面的方式进行跳转,而是通过加载不同的组件达到加载不同页面的目的。

4.2 在index.js中开启路由:

image.png

4.3 在APP.js中进行全局配置:

image.png

目前配置了两个路由:
/:入口页面,跳转到登录页面
/home:登录验证成功后跳转页面,目前只是给一个跳转显示验证是否成功。

5.使用axios对后端接口发起请求:

点击了登录模态框中的登录按钮后,会向对应接口发起post请求,验证登录的信息。

5.1 添加按钮点击事件:

Login.js

image.png image.png

Button.js

image.png

5.2 点击事件函数:

  • 利用axios的post接口对后端接口发起请求;
  • 异步接受返回数据;
  • 根据返回结果判断是否进行跳转;
  • 存在跨域问题,在后端中利用cors方法进行解决;

后端服务:

1. 语言及技术栈:

  • 使用nodejs作为后端开发语言;
  • express搭建服务;
  • mongodb作为后端;
  • cors 解决跨域问题;

2. 使用express搭建服务:

记录几个坑:

2.1 托管静态库:

第一次用express从0搭建后端服务,没有注意这个细节,导致一直报404:

image.png

2.2 express中路径需要写绝对路径:

image.png

2.3 express中配置静态页面入口页应该与nginx的配置保持一致:

image.png

image.png

即:在根路径下进行访问即可.
这个问题对于新手真的很折磨很难发现。

2.4 nginx 配置express反向代理:

如上图所示。

3.mongoose踩坑记录:

一个model不能重复定义,应该封装成一个模块引入:

image.png

image.png

nginx配置:

image.png

思考:

1.为什么react提倡使用函数组件?

2.配置nginx的方法?

zhuanlan.zhihu.com/p/101961241