react_app 项目开发 (7)_难点集合
/src/App/Admin/Header
布局 import {Row, Col} from "antd"
<div className="header_box">
<Row className="header_top">
<span>欢迎</span>
<a>退出</a>
</Row>
<Row className="header_bottom">
<Col span={4}></Col>
<Col span={20}>
<span className="weather_time">时间</span>
<span className="weather_img">图片</span>
<span className="weather_detail">晴天</span>
</Col>
</Row>
</div>
sysTime = Date.now() / DidMount 中计时器 时间动态显示
5
- 天气接口 - jsonp 解决跨域
import jsonp from jsonp;
MyTools.weather(city){
return new Promise((resolve, reject)=>{
0
})
}
- 根据 path 获取到 breadcrumb_title 和 父菜单
- 分类列表 - 增加分类 - 修改分类 ---- 熟练对 API 的运用能力
antd 界面 ---- Button、Icon、Card、Table(包含分页)
- 每个分类
parentId 一级分类的 parentId 为 0
_id 自动生成
name 新分类的名字
__v 自动生成
- 添加分类返回的响应

- 更新状态 state 是异步的,this.setState({...}, ()=>{...})
注意其第二参数是一个回调函数,在状态更新完成以后立即执行
- 对话框不保存上一次的交互记录,可以给 Modal 设置一下属性

- 关于 Table 的 render 传值
如果不指定 dataIndex,则第一个参数为整个对象
如果指定了 dataIndex,则第二个参数为整个对象,第一个参数为指定的数据
5
- 后台分页,每次点击分页都发请求获取数据,即使已经获取过了
优化: 保存每次请求的页码即数据
关键: 数据结构;一般分页/搜索分页
- this.props.history.push("新页面", 要传递的数据) ---- this.props.history.goBack()
可以在 "新页面" 获取到传递的数据
传递的数据 = this.props.location.state || {} // 优化: 保证 数据 始终是一个存在的对象
- yarn add react-draf-wysiwyg html-to-draftjs
RichTextEditor.js
import React, { Component } from 'react';
import { EditorState, convertToRaw } from 'draft-js';
import { Editor } from 'react-draft-wysiwyg';
import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css';
import draftToHtml from 'draftjs-to-html';
import htmlToDraft from 'html-to-draftjs'; // import {Card, Button, Icon, Table, message, Modal, Form, Input, Select} from "antd"; import "./css/RichTextEditor.css"; /* 富文本编辑器组件 */
export default class RichTextEditor extends Component {
constructor(props){
super(props);
this.state = {
editorState: EditorState.createEmpty()
}
} onEditorStateChange = (editorState) => {
this.setState({
editorState,
});
}; render() {
const { editorState } = this.state;
return (
<div>
<Editor
editorState={editorState}
wrapperClassName="demo-wrapper" /* 包裹区类名 */
editorClassName="demo-editor" /* 编辑区类名 */
onEditorStateChange={this.onEditorStateChange}
/>
{/*<textarea // draft2html */}
{/*disabled*/}
{/*value={draftToHtml(convertToRaw(editorState.getCurrentContent()))}*/}
{/*/>*/}
</div>
);
}
}- css/RichTextEditor.css
.product_edit .rdw-dropdown-selectedtext{
min-width: 54px; font-size: 16px;
font-weight:;
letter-spacing:;
} .rdw-editor-toolbar {
margin-bottom:;
} .demo-editor {
height: 120px;
padding: 4px; font-size: 14px;
line-height: 1.2em;
letter-spacing:;
background-color: #74878f;
}
使用:(组件对象,就是标签对象,意味着可以使用 ref 去关联获取组件中的属性和方法。)
- 获取富文本编辑器最终生成的,html 标签内容
getRichTextEditor = ()=>{
const {editorState} = this.state;
return draftToHtml(convertToRaw(editorState.getCurrentContent());
};- 父组件给子组件设置 ref ,从而可以从子组件调用这个方法
- 编辑商品时,传递已有的 detail 给富文本编辑器显示
<div className="rich_text_editor">
<div className="product_detail_edit">商品详情:</div>
<div><RichTextEditor ref="RichTextEditor" detail={product.detail}/></div>
</div>- 默认创建的空文本内容
constructor(props){
super(props);
this.state = {
editorState: EditorState.createEmpty() // 默认创建一个空的文本内容
}
}- 使用第三方库,进行 html 到 draft 的转换
componentWillMount(){
const detail = this.props.detail;
if(detail){
const blocksFromHtml = htmlToDraft(detail); // 将传过来的 detail 转换
const { contentBlocks, entityMap } = blocksFromHtml;
const contentState = ContentState.createFromBlockArray(contentBlocks, entityMap);
const editorState = EditorState.createWithContent(contentState);
this.setState({
editorState // 更新界面相关内容
})
}
}- 最终的 RichTextEditor.js 组件代码为
import React, { Component } from 'react';
import { EditorState, convertToRaw, ContentState} from 'draft-js';
import { Editor } from 'react-draft-wysiwyg';
import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css';
import draftToHtml from 'draftjs-to-html'; import htmlToDraft from 'html-to-draftjs'; // 将已有的 html 标签内容,生成一个 draft 内容 import "./css/RichTextEditor.css"; /* 富文本编辑器组件 */
export default class RichTextEditor extends Component {
constructor(props){
super(props);
this.state = {
editorState: EditorState.createEmpty() // 默认创建一个空的文本内容
}
} onEditorStateChange = (editorState) => {
this.setState({
editorState,
});
}; getRichTextEditor = ()=>{ // 让父组件调
const {editorState} = this.state;
return draftToHtml(convertToRaw(editorState.getCurrentContent()))
}; componentWillMount(){
const detail = this.props.detail;
if(detail){
const blocksFromHtml = htmlToDraft(detail); // 将传过来的 detail 转换
const { contentBlocks, entityMap } = blocksFromHtml;
const contentState = ContentState.createFromBlockArray(contentBlocks, entityMap);
const editorState = EditorState.createWithContent(contentState);
this.setState({
editorState // 更新界面相关内容
})
}
} render() {
const { editorState } = this.state;
return (
<div>
<Editor
editorState={editorState} /* 初始显示文本的内容 */
wrapperClassName="demo-wrapper" /* 包裹区类名 */
editorClassName="demo-editor" /* 编辑区类名 */
onEditorStateChange={this.onEditorStateChange} /* 监听,实时获取最新的输入内容 */
/>
{/*<textarea // draft2html */}
{/*disabled*/}
{/*value={draftToHtml(convertToRaw(editorState.getCurrentContent()))}*/}
{/*/>*/}
</div>
);
}
}- 通过 ref 可以得到标签对象
因为标签对象就是组件对象,所以 ref 就可以得到组件对象
意味着,父组件调用子组件的方法,可以 this.refs.ref关联的名字.方法
- 在 componentWillMount 可以直接 this.state.xxx = xxxNew
5
- 图片上传 - 删除上传图片 name
- 图片上传 ---- form-data ---- image - 选择文件
返回一个 data 包含了 name 和 服务器资源路径url
- 删除上传的图片 ---- x-www-form-urlencoded ---- name - 图片文件名

- 父组件给子组件传 imgs 图片数组,生成对引用的 fileList,并更新其在 state 中的状态
componentWillMount(){
const imgs = this.props.imgs;
if(imgs && imgs.length>0){
const fileList = imgs.map((img, index)=>({
uid: -index,
name: img,
url: "http://localhost:5000/upload/"+img,
status: "done",
}));
this.setState({
fileList
})
}
} // 此时,可以看到已有的图片了



- 需要在 handleChange 上传图片完成 file.status: done 时,进行 response 取值,赋值
5
难点: 当用户 上传图片/删除图片 后,不进行保存,而是返回时,上传使得后台多了冗余数据,删除使得数据的丢失
解决:
1. 点击删除时,不是真的删除,而是保存删除的图片的名字 到数组 deleteNames 中
---- 当点击 提交保存 时,再将之前保存的 deleteNames 发送请求,发送 ajax 请求真正地删除
2. 点击上传时,真的上传了,同时保存下上传的图片的名字 到数组 fackNames 中
---- 当点击 返回 ← 时, 发送 ajax 请求 删除 之前保存的 fackNames
难点: 添加一条角色到后台,然后如何不发送获取列表的请求,来刷新页面
解决: 通过 name 添加到角色到, 后台返回一个角色的相关信息,可以将这个 role 角色对象,存入 roles 状态中
如此的问题在于,优化: 是 Component 始终在 setState 后 render
还是用 PureComponent + [...this.state.状态]去 浅拷贝 生成新状态来 激活 render
5
5
5
5
5
5
5
react_app 项目开发 (7)_难点集合的更多相关文章
- react_app 项目开发 (5)_前后端分离_后台管理系统_开始
项目描述 技术选型 react API 接口 接口文档,url,请求方式,参数类型, 根据文档描述的方法,进行 postman 测试,看是否能够得到理想的结果 collections - 创建文件取项 ...
- react_app 项目开发 (3)_单页面设计_react-router4
(web) 利用 react-router4 实现 单页面 开发 SPA 应用 ---- (Single Page Web Application) 整个应用只有 一个完整的页面 单击链接不会刷新页面 ...
- react_app 项目开发 (4)_ React UI 组件库 ant-design 的基本使用
最流行的开源 React UI 组件库 material-ui 国外流行(安卓手机的界面效果)文档 ant-design 国内流行 (蚂蚁金服 设计,一套 PC.一套移动端的____下拉菜单.分页.. ...
- react_app 项目开发 (6)_后台服务器端-node
后台服务器端 负责处理前台应用提交的请求,并向前台返回 json 数据 前台应用 负责 展现数据与用户交互 发 ajax 请求与后台应用交互 yarn add axios /src/api/ajax. ...
- react_app 项目开发 (8)_角色管理_用户管理----权限管理 ---- shouldComponentUpdate
角色管理 性能优化(前端面试) 需求:只要执行 setState(), 就会调用 render 重新渲染.由于有时调用了 setState,但是并没有发生状态的改变,以致于不必要的刷新 解决: 重写 ...
- react_app 项目开发 (9)_数据可视化 ECharts
数据可视化 ECharts yarn add echarts echarts-for-react
- react_app 项目开发
react_app 项目开发 npm install -g create-react-app npm root -g // 查看安装包位置 创建项目 create-react-app m ...
- react_app 项目开发_遇到的坑
1. favicon.ico <link rel="shortcut icon" type="image/x-icon" href="./fav ...
- com.panie 项目开发随笔_数据字典(2017.2.24)
(一) 做一个网站,第一步需要考虑的是从哪个地方开始下手.首先,每一个功能肯定有最基本的增删改查功能,而此功能一般都分为两个页面. 1) 列表显示页面.用列表来展示数据库中的数据,多用于分页显示.该页 ...
随机推荐
- .net异步委托
委托Delegate是一个类,定义了方法的类型, 使得可以将方法当做另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大佬使用If-Else(Switch)语句,同时使得程序 ...
- Memorise Me!——用数值做地址,实现快速查找
题目如下: Arijit is a brilliant boy. He likes memory games. He likes to participate alone but this time ...
- JSP起源
JSP起源: 在很多动态网页中,绝大部分内容都是固定不变的,只有局部内容需要动态产生和改变. 如果使用Servlet程序来输出只有局部内容需要动态改变的网页,其中所有的静态内容也需要程序员用Java程 ...
- Subsequence(序列自动机模板题)
题目链接:https://nanti.jisuanke.com/t/38232 题目大意:给你一个字符串,然后再给你m个字符串,然后问你在第一个字符串中不连续的子串能不能构成输入的子串. 具体思路:构 ...
- poj 2155 matrix 二维线段树 线段树套线段树
题意 一个$n*n$矩阵,初始全为0,每次翻转一个子矩阵,然后单点查找 题解 任意一种能维护二维平面的数据结构都可以 我这里写的是二维线段树,因为四分树的写法复杂度可能会退化,因此考虑用树套树实现二维 ...
- lua分割字符串
str = "abc;123;345" local tab = string.split(str, ";") 然后list里面就是 abc123345 了.第二 ...
- Atcoder Grand Contest 032
打的第一场Atcoder,已经知道会被虐得很惨,但没有想到竟然只做出一题-- 思维急需提升. A - Limited Insertion 这题还是很签到的. 感觉正着做不好做,我们反着来,把加数变为删 ...
- 2019 Android 高级面试题总结 从java语言到AIDL使用与原理
说下你所知道的设计模式与使用场景 a.建造者模式: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 使用场景比如最常见的AlertDialog,拿我们开发过程中举例,比如C ...
- Python 八皇后问题
八皇后问题描述:在一个8✖️8的棋盘上,任意摆放8个棋子,要求任意两个棋子不能在同一行,同一列,同一斜线上,问有多少种解法. 规则分析: 任意两个棋子不能在同一行比较好办,设置一个队列,队列里的每个元 ...
- UOJ#218. 【UNR #1】火车管理 线段树 主席树
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ218.html 题解 如果我们可以知道每次弹出栈之后新的栈顶是什么,那么我们就可以在一棵区间覆盖.区间求和 ...