IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> react + zarm + rc-form + crypto-js 实现个人中心页面,头像上传,密码重置,登录退出功能 -> 正文阅读

[JavaScript知识库]react + zarm + rc-form + crypto-js 实现个人中心页面,头像上传,密码重置,登录退出功能

需要实现的大致效果

这里大致需要实现4个页面,一个个人中心的主页面,另外还有3个子页面,用户信息修改页,重置密码页,关于我们页。这里关于我们页,就不写了。重点实现一下用户信息修改以及重置密码页面功能。下面样式部分的代码就不粘贴了,有需要的参考我这篇,里面有我学习的项目地址:https://kaimo313.blog.csdn.net/article/details/122586455

在这里插入图片描述

实现过程

1.联调问题以及路由添加

一个问题是上传的时候有问题,该问题由Lweilve提出https://blog.csdn.net/kaimo313/article/details/122689960#comments_20557507

在这里插入图片描述
所以首先需要改动一下后端服务的问题:

在这里插入图片描述

第二个问题就是获取头像的时候,获取参数有点问题:应该改成query去获取,这个是get请求。

在这里插入图片描述

路由添加:在 router.js 文件里添加路由

import Login from '@/container/Login'
import Home from '@/container/Home'
import Data from '@/container/Data'
import User from '@/container/User'
import Detail from '@/container/Detail'
import UserInfo from '@/container/UserInfo'
import Account from '@/container/Account'

const routes = [
  {
    path: "/login",
    component: Login
  },{
    path: "/",
    component: Home
  },{
    path: "/data",
    component: Data
  },{
    path: "/user",
    component: User
  },{
    path: "/userInfo",
    component: UserInfo
  },{
    path: "/detail",
    component: Detail
  },{
    path: "/account",
    component: Account
  }
];

export default routes

2.实现个人中心页面:退出登录

实现的效果如下:

在这里插入图片描述

我们在按照下面的结构新建文件,分别添加代码:

在这里插入图片描述

import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { Cell, Button, Toast } from 'zarm';
import { userInfo, getAvatar } from './api/index.js';
// 引入图片
import geqian from "@/assets/images/geqian.png";
import gxqm from "@/assets/images/gxqm.png";
import zhaq from "@/assets/images/zhaq.png";
import lianxi from "@/assets/images/lianxi.png";
import defaultAvatar from "@/assets/images/default.jpg";

import s from './style.module.less';

const User = () => {
  const navigate = useNavigate();
  const [avatarUrl, setAvatarUrl] = useState(defaultAvatar); // 头像显示路径
  const [user, setUser] = useState({});
  
  useEffect(() => {
    getUserInfo();
  }, []);

  // 获取用户信息
  const getUserInfo = async () => {
    const { status, desc, data } = await userInfo({});
    if(status === 200) {
      setUser(data);
      // 获取头像
      if(data.avatar) {
        const res = await getAvatar({picname: data.avatar});
        console.log(res);
        if(res.status === 200) {
          setAvatarUrl(res.data);
        }else{
          Toast.show(res.desc);
        }
      }
    }else{
      Toast.show(desc);
    }
  };

  // 退出登录
  const logout = async () => {
    localStorage.removeItem('token');
    navigate('/login');
  };

  return <div className={s.user}>
    <div className={s.head}>
      <div className={s.info}>
        <span>昵称:{user.username || '--'}</span>
        <span>
          <img style={{ width: 30, height: 30, verticalAlign: '-10px' }} src={geqian} alt="" />
          <b>{user.signature || '这个人很懒,暂无个签'}</b>
        </span>
      </div>
      <img className={s.avatar} style={{ width: 60, height: 60, borderRadius: 8 }} src={avatarUrl} alt="" />
   </div>
   <div className={s.content}>
    <Cell
      hasArrow
      title="用户信息修改"
      onClick={() => navigate('/userinfo')}
      icon={<img style={{ width: 20, verticalAlign: '-7px' }} src={gxqm} alt="" />}
    />
    <Cell
      hasArrow
      title="重制密码"
      onClick={() => navigate('/account')}
      icon={<img style={{ width: 20, verticalAlign: '-7px' }} src={zhaq} alt="" />}
    />
    <Cell
      hasArrow
      title="关于我们"
      onClick={() => navigate('/about')}
      icon={<img style={{ width: 20, verticalAlign: '-7px' }} src={lianxi} alt="" />}
    />
   </div>
   <Button className={s.logout} block theme="danger" onClick={logout}>退出登录</Button>
  </div>
}

export default User
import { fetchData } from "@/utils/axios.js";

// 获取用户信息
export function userInfo(data) {
  return fetchData('/api/user/getUserInfo', 'get', data);
}

// 获取头像
export function getAvatar(data) {
  return fetchData('/api/upload/getAvatar', 'get', data);
}

3.实现用户信息修改页:上传头像

这里需要注意的是需要用表单方式上传, 通过 axios 传 forms 设置 'Content-Type': 'multipart/form-data', 进行文件上传

if (ajaxType === 'get') {
  config.url = url + '?r=' + Math.random() * 1000;
  config.params = data;
} else if (ajaxType === 'post') {
  if(data.forms) {
    config.data = data.forms;
    config.headers['Content-Type'] = 'multipart/form-data;charset=UTF-8';
  }else{
    config.data = data;
    config.headers['Content-Type'] = 'application/json;charset=UTF-8';
  }
}

我们在按照下面的结构新建文件,分别添加代码:

在这里插入图片描述

import React, { useEffect, useState } from 'react';
import { Button, FilePicker, Input, Toast } from 'zarm';
import { useNavigate } from 'react-router-dom';
import Header from '@/components/Header';
import { getAvatar, userInfo, uploadAvatar, updateUserInfo } from './api/index.js';
import defaultAvatar from "@/assets/images/default.jpg";

import s from './style.module.less';

const UserInfo = () => {
  const navigate = useNavigate();; // 路由实例
  const [avatarUrl, setAvatarUrl] = useState(defaultAvatar); // 头像显示路径
  const [avatar, setAvatar] = useState(''); // 头像
  const [signature, setSignature] = useState(''); // 个签

  useEffect(() => {
    getUserInfo(); // 初始化请求
  }, []);

  useEffect(async () => {
    if(avatar) {
      // 获取头像
      const { status, data, desc } = await getAvatar({picname: avatar});
      if(status === 200) {
        setAvatarUrl(data);
      }else{
        Toast.show(desc);
      }
    }
  }, [avatar]);

  // 获取用户信息
  const getUserInfo = async () => {
    const { status, desc, data } = await userInfo({});
    if(status === 200) {
      setAvatar(data.avatar)
      setSignature(data.signature)
    }else{
      Toast.show(desc);
    }
  };

  // 获取图片回调 
  const handleSelect = async (file) => {
    console.log('file.file', file.file)
    if (file && file.file.size > 200 * 1024) {
      Toast.show('上传头像不得超过 200 KB!')
      return
    }
    // 生成 form-data 数据类型
    let formData = new FormData()
    formData.append('file', file.file)
    // 通过 axios 传 forms 设置  'Content-Type': 'multipart/form-data', 进行文件上传
    const { status, desc, data } = await uploadAvatar({
      forms: formData
    });
    // 返回图片地址
    if(status === 200) {
      setAvatar(data)
    }else{
      Toast.show(desc);
    }
  }

  // 编辑用户信息方法
  const save = async () => {
    if (signature && signature.length > 36) {
      Toast.show('个性签名不能超过36个字!')
      return
    }
    const { status, desc } = await updateUserInfo({
      signature,
      avatar
    });
    if(status === 200) {
      Toast.show('修改成功')
      // 成功后回到个人中心页面
      navigate(-1)
    }else{
      Toast.show(desc);
    }
  }

  return <>
    <Header title='用户信息修改' />
    <div className={s.userinfo}>
      <div className={s.item}>
        <div className={s.title}>头像</div>
        <div className={s.avatar}>
          <img className={s.avatarUrl} src={avatarUrl} alt=""/>
          <div className={s.desc}>
            <span>支持 jpg、png、jpeg 格式大小 200KB 以内的图片</span>
            <FilePicker className={s.filePicker} onChange={handleSelect} accept="image/*">
              <Button className={s.upload} theme='primary' size='xs'>点击上传</Button>
            </FilePicker>
          </div>
        </div>
      </div>
      <div className={s.item}>
        <div className={s.title}>个性签名</div>
        <div className={s.signature}>
          <Input
            clearable
            type="text"
            value={signature}
            placeholder="个性签名不能超过36个字"
            onChange={(value) => setSignature(value)}
          />
        </div>
      </div>
      <Button onClick={save} style={{ marginTop: 50 }} block theme='primary'>保存</Button>
    </div>
  </>
};

export default UserInfo;
import { fetchData } from "@/utils/axios.js";

// 获取头像
export function getAvatar(data) {
  return fetchData('/api/upload/getAvatar', 'get', data);
}

// 获取用户信息
export function userInfo(data) {
  return fetchData('/api/user/getUserInfo', 'get', data);
}

// 更新用户信息
export function updateUserInfo(data) {
  return fetchData('/api/user/updateUserInfo', 'post', data);
}

// 上传头像
export function uploadAvatar(data) {
  return fetchData('/api/upload/avatar', 'post', data);
}

写完测试一下:点击用户信息修改进入

在这里插入图片描述
我们可以通过下面的地方修改信息:
在这里插入图片描述

比如修改头像:

在这里插入图片描述
我们发现就上传成功了

在这里插入图片描述
我们可以查看本地的盘里是有该图片的:

在这里插入图片描述

修改个签:

在这里插入图片描述
成功之后就会跳转到个人中心。
在这里插入图片描述

4.安装依赖 rc-form、crypto-js

npm i rc-form -S

在这里插入图片描述

用法:参考https://github.com/react-component/form

import { createForm, formShape } from 'rc-form';

class Form extends React.Component {
  static propTypes = {
    form: formShape,
  };

  submit = () => {
    this.props.form.validateFields((error, value) => {
      console.log(error, value);
    });
  }

  render() {
    let errors;
    const { getFieldProps, getFieldError } = this.props.form;
    return (
      <div>
        <input {...getFieldProps('normal')}/>
        <input {...getFieldProps('required', {
          onChange(){}, // have to write original onChange here if you need
          rules: [{required: true}],
        })}/>
        {(errors = getFieldError('required')) ? errors.join(',') : null}
        <button onClick={this.submit}>submit</button>
      </div>
    );
  }
}

export createForm()(Form);

在这里插入图片描述

安装 crypto-js,用法请参考:crypto-js:加密标准的JavaScript库

npm install crypto-js -S

在这里插入图片描述

5.实现重置密码页

在下面文件里添加相应的代码:

在这里插入图片描述

import React from 'react';
import { Cell, Input, Button, Toast } from 'zarm';
import { useNavigate } from 'react-router-dom';
import { createForm  } from 'rc-form';
import Header from '@/components/Header'
import { resetPassword } from './api/index'
import CryptoJS from "crypto-js";

import s from './style.module.less'

const Account = (props) => {
  const navigate = useNavigate();
  // Account 通过 createForm 高阶组件包裹之后,可以在 props 中获取到 form 属性
  console.log('Account 通过 createForm 高阶组件包裹之后', props)
  const { getFieldProps, validateFields } = props.form;

  // DES 加密
  const DES_encrypt = (hashStr) => {
    return CryptoJS.DES.encrypt(
      hashStr,
      CryptoJS.enc.Utf8.parse("ABF"),// keyHex
      { 
        mode: CryptoJS.mode.ECB, 
        padding: CryptoJS.pad.Pkcs7 
      } // option
    ).ciphertext.toString();
  }

  // 提交修改方法
  const submit = () => {
    // validateFields 获取表单属性元素
    validateFields(async (error, value) => {
      // error 表单验证全部通过,为 false,否则为 true
      if (!error) {
        console.log(value)
        if (value.newPassword != value.newPassword2) {
          Toast.show('新密码输入不一致');
          return
        }
        const {status, desc} = await resetPassword({
          oldPassword: DES_encrypt(value.oldPassword),
          newPassword: DES_encrypt(value.newPassword)
        })
        if(status === 200) {
          Toast.show('修改成功');
          // 退出登录跳转登录页
          localStorage.removeItem("token");
          navigate('/login')
        }else{
          Toast.show(desc)
        }
      }else{
        Toast.show('参数校验不通过,请填写完整!')
      }
    });
  }

  return <>
    <Header title="重制密码" />
    <div className={s.account}>
      <div className={s.form}>
        <Cell title="原密码">
          <Input
            clearable
            type="text"
            placeholder="请输入原密码"
            {...getFieldProps('oldPassword', { rules: [{ required: true }] })}
          />
        </Cell>
        <Cell title="新密码">
          <Input
            clearable
            type="text"
            placeholder="请输入新密码"
            {...getFieldProps('newPassword', { rules: [{ required: true }] })}
          />
        </Cell>
        <Cell title="确认密码">
          <Input
            clearable
            type="text"
            placeholder="请确认新密码"
            {...getFieldProps('newPassword2', { rules: [{ required: true }] })}
          />
        </Cell>
      </div>
      <Button className={s.btn} block theme="primary" onClick={submit}>提交</Button>
    </div>
  </>
};

export default createForm()(Account);
import { fetchData } from "@/utils/axios.js";

// 重置密码
export function resetPassword(data) {
  return fetchData('/api/user/resetPassword', 'post', data);
}

测试一下效果:点击重置密码进去

在这里插入图片描述
填写好修改的信息
在这里插入图片描述
提交成功之后就会回到首页

在这里插入图片描述

输入之前的密码

在这里插入图片描述
就会提示密码错误

在这里插入图片描述
改成新的密码

在这里插入图片描述
发现可以登录成功了

在这里插入图片描述

参考资料

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-21 18:52:15  更:2022-05-21 18:52:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 20:09:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码