一、效果图展示
二、初始化项目
① 安装react脚手架工具
// 全局安装 create-react-app
sudo npm -g install create-react-app
// 通过create-react-app命令创建react项目
create-react-app evernote
除了通过全局安装create-react-app来创建react项目外,我们还可以通过npm init命令去创建,即
npm init react-app evernote
因为执行npm init
命令的时候,会自动在init之后的包名加上create前缀,所以相当于安装并执行create-react-app包,所以我们再传入项目名称即可创建对应的react项目了。注意,react的项目名不能以大写字母开头。
② 修改public下的index.html文件
react项目和vue项目一样也是单页面应用,所以public目录下也会有一个index.html页面,用于挂载react渲染的结果。由于我们的项目中会用到一些字体图标,所以我们需要把我们的字体链接对应的css引入进来,如:
// public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="//at.alicdn.com/t/font_1609262_ijm97o315o.css"/>
</head>
</html>
这个在线css链接可以到阿里巴巴iconfont字体库中找到,如图所示:
③ 修改src/App.js文件
src/App.js是项目的根组件,我们将App.js中的代码删除,默认App是函数组件,我们这里改成类组件,因为我们需要让App组件拥有自己的状态,然后修改为如下代码:
import React from 'react';
import './App.css';
class App extends React.Component {
render() {
return (
<div className="app-container">
hello evernote.
</div>
);
}
}
export default App;
④ 修改src/App.css
将原来的App.css内容清空,这里样式就不做过多解释,然后修改如下:
.app-container {
display: flex;
height: 100%;
}
.app-left {
width: 10%;
min-width: 190px;
background: #343434;
}
.app-left-header, .app-left-body-title {
display: flex;
align-items: center;
color: white;
font-weight: bold;
padding: 10px 0;
}
.add {
width: 25px;
height: 25px;
display: inline-block;
border-radius: 50%;
margin: 0 10px;
background:#6fcb66;
text-align: center;
line-height: 25px;
font-size: 15px;
font-weight: bold;
}
.notebook-icon {
height: 25px;
text-align: center;
line-height: 25px;
margin: 0 5px 0 10px;
}
.notebook-list, .app-center-list{
margin: 0;
list-style: none;
padding: 0;
color: white;
}
.notebook-list li {
margin-top: 10px;
font-size: 14px;
display: flex;
padding: 5px 0 5px 25px;
}
.notebook-list .active {
background: #1a1a1a;
}
.notebook-list li i {
margin-right: 3px;
}
.app-center{
width: 12%;
min-width: 180px;
background: #ececec;
display: flex;
flex-direction: column;
}
.app-center-header {
padding: 10px 0px 10px 10px;
font-weight: bold;
border-bottom: 1px solid #ccc;
}
.app-center-list {
padding: 0;
height: 100%;
overflow: scroll;
}
.app-center-list .active {
background: yellow;
}
.app-center-list li {
margin: 5px 10px;
height: 180px;
background: white;
color: black;
}
.app-center-list-item .note-header {
font-weight: bold;
text-align: center;
height: 30px;
line-height: 30px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
padding-left: 5px;
font-size: 12px;
}
.app-center-list-item .note-content {
padding: 0px 10px;
font-size: 13px;
line-height: 22px;
overflow: hidden;
height: 130px;
line-clamp: 3;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 6;
}
.app-right {
width: 78%;
display: flex;
flex-direction: column;
}
.app-right-header {
height: 30px;
line-height: 30px;
padding-left: 10px;
border-bottom: 1px solid #ccc;
}
.app-right-header .notebookName {
margin-left: 5px;
font-weight: bolder;
font-size: 13px;
}
.app-right-title {
height: 20px;
line-height: 20px;
padding: 8px 0 8px 30px;
font-weight: bold;
outline: none;
}
.app-right-content {
display: flex;
flex: 1;
overflow: scroll;
}
.app-right-edit {
background: #22272a;
width: 50%;
color: white;
font-size: 15px;
line-height: 25px;
padding: 10px 0 0 10px;
outline: none;
resize: none;
}
.app-right-show {
border-top: 1px solid #ccc;
width: 50%;
padding-left: 20px;
overflow: scroll;
}
这里为了方便,将所有样式都写到了,App.css中,这样其他子组件都可以共享App.css中定义的样式了。
④ 修改index.css
为了让App组件能够占满全屏,需要对html、body、#root进行高度100%的设置,如:
html,body{
height: 100%;
}
#root {
height: 100%;
}
至此,evernote项目已经初始化完成。
三、项目分析
从效果图上可以看到,整个印象笔记分为左、中、右三块,所以我们可以把它们分成左、中、右三个组件。左边用于显示笔记本列表,中间用于显示每个笔记本下的笔记列表,右侧用于显示当前正在查看和编辑的笔记。所以在src目录下新建一个components目录,用于存放这三个组件。
// src/components/Left.js
import React from "react";
class Left extends React.Component {
render() {
return (
<div className="app-left">
我是左边
</div>
);
}
}
export default Left;
// src/components/Center.js
import React from "react";
class Center extends React.Component {
render() {
return (
<div className="app-center">
我是中间
</div>
);
}
}
export default Center;
// src/components/Right.js
import React from "react";
class Right extends React.Component {
render() {
return (
<div className="app-right">
我是右边
</div>
);
}
}
export default Right;
同时在App.js中引入这三个组件,如:
// src/App.js
class App extends React.Component {
render() {
return (
<div className="app-container">
<Left/>
<Center/>
<Right/>
</div>
);
}
}
四、模拟数据
为了简单实现印象笔记在线操作功能,我们这里就不连接数据库了,而是采用json-server来模拟数据库,首先全局安装json-server模块,如:
sudo npm install -g json-server
然后在src目录下新建一个data目录,里面放一个db.json文件,内容如下:
{
"notebooks": [
{
"id": 1,
"name": "默认笔记本"
},
{
"id": 2,
"name": "我的2019"
},
{
"id": 3,
"name": "我的2020"
}
],
"notes": [
{
"id": 1,
"title": "这是一段代码",
"content": "## 一段react的示例代码\n## 安装react\n```\nnpm install react --save-dev\nnpm install react-dowm --save-dev\n```\n### JS部分\n```\n// 引入react\nimport React from \"react\";\nimport ReactDOM from \"react-dom\";\n// 定义函数组件\nfunction App() {\n return (<h1>hello react !</h1>)\n}\n// 渲染组件到根节点\nReactDOM.render(<App/>, document.getElementById(\"root\"));\n```\n\n### html部分\n```\n<!DOCTYPE html>\n<html lang=\"en\">\n <head></head>\n <div id=\"root\">\n </div>\n</html>\n```",
"bookId": 1
},
{
"id": 2,
"title": "2019好笑的笑话 最好能笑死别人",
"content": "## 第一个\n> 朋友去唱歌找了小姐,买单时发现没有现金只有银行卡,服务员说:“可以刷卡。”他说:“这卡是我老婆名字,刷了收到你们KTV短信,会打死我的。”服务员说:“没事,我们可以帮你刷成饭店消费。”此男一听很开心然后就刷了…结果刚一进家门老婆劈里啪啦两个大耳光,把手机短信给他看:“沙县小吃,消费8333元,你没有撑死?”\n\n## 第二个\n> 有一次,一个男人准备去办公室工作,他听说来了很多美女,就把自己打扮得漂漂亮亮,到了办公室,美女们都对男人微笑,他认为美女觉得自己很帅,其实,他的牙上沾了一颗红的和一颗绿的辣椒皮!\n\n## 第三个\n> 女婿跟老丈人抱怨,我老婆开着80多W的车,穿着几千的衣服, 用着苹果X,我天天电动车,一年四季2件外衣,用着淘汰的老年机,你知道我多惨吗? 只见老丈人神色淡定的说道:你天天睡着个开80多万的车,穿着几千块衣服,手拿苹果X的女人,还有什么不满意的!\n\n## 第四个\n> 前几天哥几个晚上去网吧玩,凌晨三点多回家,都离家比较近走着回去的,走到一半一哥们在路边冲着一棵树小解,我们走前面,他解完就追上我们,然后我说 你尿尿的姿势不对呀!哥们一脸懵逼,问我:怎么不对了?我:你应该抬起一条腿!然后就被追杀7条街!\n\n## 第五个\n> 某君儿子没考上大学,便找到在国企做董事长的老同学。董事长很爽快:让他来做副总经理吧,月薪五万,每天例行开会就行了。某君:给个一般职位就行了。董事长:做总经理助理吧,月薪2万,给总经理倒倒茶就行了。某君:还是从普通业务员做起吧。董事长:我们的业务员起码要硕士学历,薪水很低,还欠薪!\n\n## 第六个\n> 一女同事和我住同一个小区,有时我蹭她的车,有时她蹭我的车,经常一起回到公司。昨天公司门卫跟我说:“我看到你媳妇在外面搂着个男的。”我知道他误会女同事是我媳妇了,故意逗他说:“她这人就是贪玩,我也管不了。”今天女同事回来,说门卫给了她一朵玫瑰。\n\n## 第七个\n> 一新兵跑步老落后腿。班长问:为何老最后?新兵答:报告班长,吃饭时间只有二分钟,没吃饱跑不动。第二天,班长让新兵吃了个饱。结果那新兵还是跑了个倒数第一。班长问:咋还落后腿。新兵答:报告班长。吃太撑了。\n\n## 第八个\n> 我读小学的时候迟到、逃学、打架什么坏事都干,反正就是一个〝万人嫌〞,所以罚站罚跪就成了家常便饭。每次罚完跪,我都是哭着趴在姐姐背上回家的。有一次姐姐心疼的对我说:小冰呀,你以后还是带着爸爸的护膝上学吧!\n\n## 第九个\n> 我手机背景换了几百次了,老公的依旧是我的大脸照。我说:不会换张美女啊什么的,我不会不开心的?这二货道:这样很好,可以控制玩手机的欲望!\n\n## 第十个\n> 一日,和哥们去一个没去过的地方吃饭,找不到那个地方,看见路边有个协警(背对着),看身材貌似是中年妇女。于是哥们冲过去说道:“阿姨,XXX饭店怎么走。”那个协警黑着脸转过身来,原来是个大叔,但他还是指了路。哥们听完很感激,继续说:“谢谢阿姨……”\n本人一直单身,不知道为什么怎么也找不到对象。最近的几天遇上十年一遇的高温,很让人难受。我们公司的一位漂亮妹纸有天终于热得受不了了。她就问我:你住的那里有空调吗?我:有啊。妹纸:那我以后中午去你那休息,蹭一下空调好不好。我:当然不行,电费这么贵。然后就没有然后了...\n",
"time": "2019-12-16",
"bookId": 1
},
{
"id": 3,
"title": "2019年度最沙雕新闻你觉得是哪一个?",
"content": "## 2019年度最沙雕新闻你觉得是哪一个?\n> 2019年度最沙雕新闻你觉得是哪一个? 1 男子带了一顶绿帽去盗窃,帽子上面写的“忘了他吧,我偷电瓶车养你”,最后因为这个帽子太鲜明被警方抓获。男子说买这个帽子是在地摊上看到,觉得很符合自己又穷又没有爱情的心境,没想到电瓶车没偷,女孩也没有跟我走就被抓了。 2 警察抓毒贩时,毒贩正在看以扫毒为主题的电视剧《破冰行动》,网友称电视剧来到现实。后因网络反响强烈,记者追问已被拘捕的毒贩对电视剧的评价,毒贩说主演演得很好。 3 女子收电信诈骗电话,将卡号密码告诉了犯罪分子,银行察觉异常叫了警察,后来警察发现女子因为记性不好给了错误密码而避免了损失。 4 男子报警称自己的山地自行车被偷,民警处理发现这车本来是报警的男子偷来的,被真车主碰上后在警察协助下骑走。警察问报警男子为何自投罗网,偷车男子说骑了一段时间也有感情了。 5 男子和邻居吵架,怕对方人多势众自己吃亏所以报警,民警做笔录发现报警男子是逃犯。 6 男子接到电话称自己被网上追逃,到派出所查询想证明清白,民警一查确为追逃对象将其拘捕。 7 四川南充民警准备抓特大电信诈骗案件嫌疑人,但强行破门有风险,后发现嫌疑人的钥匙插在门锁上忘拔,最后民警顺利破门抓获嫌疑人。 8 两男子凌晨潜入串串店自行搭配锅底偷吃串串,连吃三天后老板才发现店里进贼,第四天两男子来偷吃终于被潜伏民警抓获。 9 小偷入室盗窃,房主年纪大不会用手机报警,小偷:我帮你打110吧。最后被刑拘。 10 成都一女子要跳楼,一男子在对面看热闹不慎失足坠楼死亡,女子看到后觉得太吓人了放弃跳楼。 11 男子报警称被车压到脚,周围多个路人帮忙作证要求车主赔钱。男子善解人意说没啥大事赔5000就行,后来调监控发现是他自己把脚伸车轮下,而且路人都是同伙。",
"time": "2019-12-16",
"bookId": 1
},
{
"id": 4,
"title": "2019年我的美好回忆",
"content": "## 2019年我的美好回忆\n> 时光匆匆,岁月悠悠,春去冬来,不知不觉,2019年即将过去了,2020年就要到来了。\n回忆即将过去的一年,我有甜、有酸、有苦、也有乐,但所有的甜与酸苦与乐,都在岁月的流逝中化作了醇厚的浓香,令人回味无穷。\n2019,是丰盈而充实的一年,收获了一缕阳光,一股温暖,一片友情。使我的晚年生活更加充实,更加幸福,更加美好。\n\n> 这一年,我怀着一颗热爱美篇的心,虚心学习,努力写作。编写了四十多篇文章和六十多条话题投稿美篇后,有八篇文章被美篇录取加精,有四篇文章被加荐。其中有一篇《我是怎样制作美篇文章的?》文章,被《美篇手册》录取,收录在“美友经验分享区”栏目里,引起了很大的反响,美友阅读量突破46000人,点赞留评人数达到1400多人。\n这一小小的收获,除了自己努力之外,离不开众人的帮助。在这里要感谢美篇平台的支持和关心,感谢《原创笔记》等圈子的帮助和鼓励,特别要感谢美友们的到访与点评。",
"time": "2019-12-26",
"bookId": 2
},
{
"id": 5,
"title": "怎样才能娶到一个好老婆啊",
"content": "## 怎样才能娶到一个好老婆啊\n> 只要你们感情好。在一起时间长了不会觉得很烦。你爱他。他也爱你。那样生活起来才不会觉得累。那样才会永远相爱一辈子。这才叫娶个好老婆。\n\n> 如果你娶个很贤惠而且什么都好的老婆。你不喜欢她。那日子也不会长久。不会长久的生活还在乎娶什么老婆吗?衷心的祝福你能找到个诚心如意的老婆。男人年轻时,选老婆或选女友,\n第一都是看身材和脸蛋,人品性格和脾气通通不管;到了中年时,才会发现:原来,女人的美,不在外表,而在具有包容心和好脾气的个性,尤其是会撒娇的女人,一旦撒娇撒到男人的死穴,也就是打中了男人心坎里的弱点,这时,就算她要男人去死,男人也会带着微笑和满足的表情从容就义。\n男人要的只是一种类似母爱的包容和关怀,一种无怨无悔、夫唱妇随的契合感觉,我并非把女人当跟班或第二性,也不是歧视女性,真的,男人要的就只是那种即使自己再落魄再倒霉,她也不弃不离的那种生死相随的感动",
"time": "2019-12-31",
"bookId": 3
}
]
}
此时再通过json-server去启动并监听db.json文件,就可以以REST API的形式访问db.json中的数据了,如:
json-server --watch ./src/data/db.json --port 8080
比如,我们在浏览器中通过http://localhost:8080/notebooks
即可访问到db.json文件中notebooks对应的数组数据了。
这里解释一下db.json中的数据结构,notebooks表示的是有哪些笔记本,notes表示的是有哪些比较,其中有一个bookId字段表示其是属于哪个笔记本下。
五、开发Left组件
我们这里把所有的状态数据都放在App根组件上,然后通过props传递到子组件上,Left组件要显示所有的笔记本列表,所有需要notebooks这个数组以及当前选择的是哪个笔记本,所有需要知道当前笔记本索引currentIndex,在App组件上新增notebooks和currentIndex两个状态数据,我们可以在App组件挂载完成的时候去获取所有的笔记本列表,请求数据使用axios,如:
npm install axios --save-dev
// src/App.js 新增notebooks和currentIndex两个状态属性
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
notebooks: [], // 存放笔记本列表
currentIndex: 0, // 默认显示第一个笔记本
}
}
componentDidMount() {
axios.get("http://localhost:8080/notebooks").then((res) => {
this.setState({
notebooks: res.data // 更新笔记本列表
});
});
}
render() {
return (
<div className="app-container">
<Left notebooks={this.state.notebooks} currentIndex={this.state.currentIndex}/>
<Center/>
<Right/>
</div>
);
}
}
此时App组件向Left组件中传递了notebooks笔记本列表数组和currentIndex当前笔记本索引两个数据,然后开始开发Left组件,
// src/components/Left.js
import React from "react";
class Left extends React.Component {
render() {
return (
<div className="app-left">
<div className="app-left-header">
<i className="add iconfont icon-jiahao"></i>
<span className="add-notebook">新建笔记</span>
</div>
<div className="app-left-body">
<div className="app-left-body-title">
<i className="notebook-icon iconfont icon-bijiben"></i>
<span>笔记本</span>
</div>
<ul className="notebook-list">
{
this.props.notebooks.map((notebook, index) => {
return (
<li key={notebook.id}
className={this.props.currentIndex === index ? "active" : ""}
>
<i className="iconfont icon-bijiben1"></i>{notebook.name}
</li>
)
})
}
</ul>
</div>
</div>
);
}
}
export default Left;
六、开发Center组件
Center组件用于显示笔记列表,所以需要把当前选择的比较本下的所有笔记列表传递给Center组件,在App组件中新建一个notes状态属性,同样是在componentDidMount的时候根据currentIndex获取到当前笔记本下的所有笔记,如:
// src/App.js
// 在state中新增一个notes属性
this.state = {
notes: [], // 笔记列表
}
// 新增一个getNotes方法用于根据笔记本的id获取其下的所有笔记列表
getNotes(bookId) { // 根据bookId获取笔记列表
axios.get(`http://localhost:8080/notes?bookId=${bookId}`).then((res) => {
this.setState({
notes: res.data // 将获取到的比较列表存放到notes状态中
});
});
}
// 修改componentDidMount,在获取到笔记本列表后,根据currentIndex获取到对应的笔记本信息,然后根据其id获取笔记列表
componentDidMount() {
axios.get("http://localhost:8080/notebooks").then((res) => {
this.setState({
notebooks: res.data
}); // 更新笔记本列表
const notebook = this.state.notebooks[this.state.currentIndex];// 取出当前索引对应的笔记本
this.getNotes(notebook.id); // 根据当前笔记本的id去获取笔记列表
});
}
// 将notes笔记列表传递给Center组件
<Center notes={this.state.notes} />
// src/component/Center.js
import React from "react";
class Center extends React.Component {
render() {
return (
<div className="app-center">
<div className="app-center-header">笔记列表</div>
<ul className="app-center-list">
{
this.props.notes.map((note, index) => {
return (
<li key={note.id}>
<div className="app-center-list-item">
<div className="note-header">{note.title}</div>
<div className="note-content"><pre>{note.content}</pre></div>
</div>
</li>
)
})
}
</ul>
</div>
);
}
}
export default Center;
七、开发Right组件
Right组件主要用于显示选择的笔记内容,所以需要将当前选择的笔记传递给Right组件,App中新增一个currentNote状态属性,用于保存当前选择的笔记,由于Right组件中还需要显示所在的笔记本名称,而这些信息都在notebooks中,所以也需要传递notebooks和currentIndex,如:
// src/App.js
// 新增currentNote状态属性
this.state = {
currentNote: null // 当前显示的笔记
}
// 如果选择了某个笔记,才会在右边区域显示具体的笔记内容
{
this.state.currentNote ?
<Right notebooks={this.state.notebooks}
currentIndex={this.state.currentIndex}
currentNote={this.state.currentNote}
/> : null
}
// src/component/Right.js
import React from "react";
class Right extends React.Component {
render() {
return(
<div className="app-right">
<div className="app-right-header">
<i className="iconfont icon-bijiben1"></i>
<span className="notebookName">{this.props.notebooks[this.props.currentIndex].name}</span>
</div>
<input className="app-right-title" name="title" value={this.props.currentNote.title}/>
<div className="app-right-content">
<textarea className="app-right-edit" name="content" value={this.props.currentNote.content}/>
<div className="app-right-show">
{this.props.currentNote.content}
</div>
</div>
</div>
);
}
}
export default Right;
八、添加事件
此时右边还不会显示具体的笔记内容,因为currentNote为null,所以需要进行currentNote的初始化,当笔记列表项被点击的时候,根据其点击的索引,然后找到对应的笔记信息赋值给currentNote即可,
// src/App.js
// 新增一个处理笔记列表项被点击事件
doNoteClick(index) {
const notebook = this.state.notes[index]; // 根据索引拿到被点击的那个笔记
const noteId = notebook.id; // 拿到笔记的id
axios.get(`http://localhost:8080/notes/${noteId}`).then((res) => { // 根据id获取对应的笔记并保存到currentNote中
this.setState({
currentNote: res.data
});
});
}
// 根Center组件传递一个事件处理函数
<Center notes={this.state.notes}
doNoteClick={(index) => {this.doNoteClick(index)}}
/>
// src/component/Center.js
// 新增笔记被点击事件,执行父组件传递过来的事件
doNoteClick(index) {
this.props.doNoteClick(index);
}
// 当某个笔记项被点击后,将index传递给App组件
<li key={note.id}
onClick={() => {this.doNoteClick(index)}}
>
此时可以显示笔记内容了。但是Left组件中点击笔记本列表项无法切换,所以需要给Left组件的每个选项添加click事件,如:
// src/App.js
// 给Left组件传递一个doNotebookClick事件,接收点击的index
<Left notebooks={this.state.notebooks}
currentIndex={this.state.currentIndex}
doNotebookClick={(index) => {this.doNotebookClick(index)}}
/>
// 新增一个doNotebookClick事件
doNotebookClick(index) {
this.setState({
currentIndex: index // 更新currentIndex
});
const notebook = this.state.notebooks[index];// 根据index拿到对应的笔记本
this.getNotes(notebook.id);// 然后根据笔记本的id找到旗下的所有笔记列表
this.setState({
currentNote: null // 清空currentNote
});
}
// src/components/Left.js
// 主要将index传递给App组件
doNotebookClick(index) {
this.props.doNotebookClick(index);
}
<li key={notebook.id}
onClick={() => this.doNotebookClick(index)}
>
还有一个就是新建笔记功能,添加doAdd事件,如:
// src/App.js
// 给子组件传递doAdd事件
<Left notebooks={this.state.notebooks}
doAdd={() => {this.doAdd()}}
/>
// 添加doAdd事件
doAdd() {
const id = parseInt(Math.random() * 100); // 随机生成一个id
const bookId = this.state.notebooks[this.state.currentIndex].id; // 获取当前笔记本的id
const note = { // 创建一个笔记
id,
title: `新建笔记${id}`,
content: "笔记内容",
bookId
}
axios.post("http://localhost:8080/notes", note).then(() => { // 通过post添加一个笔记
this.getNotes(bookId);// 笔记新建成功后重新获取笔记列表
this.setState({ // 并且显示新建的笔记本内容
currentNote: note
});
});
}
// src/components/Left.js
doAdd() {
this.props.doAdd();
}
<i className="add iconfont icon-jiahao" onClick={() => {this.doAdd()}}></i>
九、实现markdown编辑器的显示功能
现在Right组件虽然可以正常了,但是Right组件的右侧显示区显示的是markdown的源文本,我们需要对markdown源文本进行转换后再显示出来,我们可以通过marked这个模块进行markdown文本的转换,如:
// 安装marked模块
npm install marked --save-dev
// 安装github-markdown-css,给转换后的marked html添加样式
npm install github-markdown-css --save-dev
// src/components/Right.js
import marked from "marked";
import "github-markdown-css";
// 将转换后的html插入到显示区
<div className="app-right-show markdown-body"
dangerouslySetInnerHTML={{__html: marked(this.props.currentNote.content)}} />
十、实现markdown的在线编辑功能
要想实现在线编辑功能,那么我们需要给编辑器添加上onChange事件,然后重置notes的内容,并且将其提交给服务器,如:
// src/App.js
// 给子组件传递onChange事件
<Right doContentChange={(e) => {this.doContentChange(e)}}
/>
doContentChange(e) {
const currentNote = this.state.currentNote; // 取出当前编辑的笔记
currentNote[e.target.name] = e.target.value; // 更新笔记内容
this.setState({ // 重置笔记内容以便显示区能够更新
currentNote
});
const notes = this.state.notes; // 获取的整个笔记列表
notes.forEach((note, index) => {
if (note.id === currentNote.id) { // 找到当前更新的笔记
notes[index] = currentNote;// 更新notes以便列表处也能实时更新
this.setState({
notes
});
}
}); axios.put(`http://localhost:8080/notes/${currentNote.id}`, currentNote); // 将更新提交到服务器
}
// src/components/Right.js
doContentChange(e) {
this.props.doContentChange(e);
}
<input className="app-right-title" name="title" value={this.props.currentNote.title} onChange={(e) => {this.doContentChange(e)}}/>
<textarea className="app-right-edit" name="content" value={this.props.currentNote.content} onChange={(e) => {this.doContentChange(e)}} />
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。