/src/App/Admin/Headercss
佈局 import {Row, Col} from "antd"html
<div className="header_box">react
<Row className="header_top">git
<span>歡迎</span>github
<a>退出</a>web
</Row>ajax
<Row className="header_bottom">json
<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
})
}
antd 界面 ---- Button、Icon、Card、Table(包含分頁)
parentId 一級分類的 parentId 爲 0
_id 自動生成
name 新分類的名字
__v 自動生成
注意其第二參數是一個回調函數,在狀態更新完成之後當即執行
若是不指定 dataIndex,則第一個參數爲整個對象
若是指定了 dataIndex,則第二個參數爲整個對象,第一個參數爲指定的數據
5
優化: 保存每次請求的頁碼即數據
關鍵: 數據結構;通常分頁/搜索分頁
能夠在 "新頁面" 獲取到傳遞的數據
傳遞的數據 = this.props.location.state || {} // 優化: 保證 數據 始終是一個存在的對象
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> ); } }
.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 去關聯獲取組件中的屬性和方法。)
getRichTextEditor = ()=>{ const {editorState} = this.state;
return draftToHtml(convertToRaw(editorState.getCurrentContent()); };
<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() // 默認建立一個空的文本內容 } }
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 // 更新界面相關內容 }) } }
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 就能夠獲得組件對象
意味着,父組件調用子組件的方法,能夠 this.refs.ref關聯的名字.方法
5
返回一個 data 包含了 name 和 服務器資源路徑url
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 }) } } // 此時,能夠看到已有的圖片了
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