zoukankan      html  css  js  c++  java
  • 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

    import jsonp from jsonp;

    MyTools.weather(city){

    return new Promise((resolve, reject)=>{

    0

    })

    }

     

    • 根据 path 获取到 breadcrumb_title 和 父菜单

     

    • 分类列表 - 增加分类 - 修改分类 ---- 熟练对 API 的运用能力

    antd 界面 ---- Button、Icon、CardTable(包含分页)

    • 每个分类

    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 || {}    // 优化: 保证 数据 始终是一个存在的对象

    git 上一个基于 react 的富文本编辑器

    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: 700;
          letter-spacing: 0;
      }
      
      .rdw-editor-toolbar {
          margin-bottom: 0;
      }
      
      .demo-editor {
          height: 120px;
          padding: 4px;
          
          font-size: 14px;
          line-height: 1.2em;
          letter-spacing: 0;
          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 - 图片文件名

    antd 组件

    管理图片的组件(上传/删除)

    • 父组件给子组件传 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

    --------小尾巴 ________一个人欣赏-最后一朵颜色的消逝-忠诚于我的是·一颗叫做野的心.决不受人奴役.怒火中生的那一刻·终将结束...
  • 相关阅读:
    51单片机学习笔记(清翔版)(23)——红外通讯
    51单片机学习笔记(清翔版)(22)——数字温度传感器DS18B20
    信号与系统1.1.4信号的分类-信号的MATLAB的表示与绘图
    信号与系统1.1.3信号的分类-能量与功率信号,因果与反因果
    信号与系统1.1.2信号的分类-周期与非周期
    信号与系统1.1.1信号的分类-确定与随机-离散与连续
    51单片机学习笔记(清翔版)(21)——ADDA数模转换
    51单片机学习笔记(清翔版)(19)——串口通信
    ecplise问题总结
    Android广播机制(转)
  • 原文地址:https://www.cnblogs.com/tianxiaxuange/p/10278785.html
Copyright © 2011-2022 走看看