本篇接《[React-章节6 实践篇] 做一个留言板项目 之 规划》。
我从最简单的留言详情页开始编写,页面包含一个工具栏,一个标题,一个正文。
其中工具栏作为一个子组件实现,它包含了回退按钮,此前已经实践过。正文希望可以内容垂直居中并且可以填充满屏幕。
整个MsgDetailPage组件实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
import React from "react"; import {Link} from "react-router"; import $ from "jquery"; import style from "./MsgDetailPage.css"; import ToolBar from "./ToolBar/ToolBar"; export default class MsgDetailPage extends React.Component { constructor(props, context) { super(props, context); this.state = { msgId: this.props.params.msgId, contentHeight: 0, }; } componentDidMount() { let msgId = this.state.msgId; $.ajax({ type: 'GET', url: '/msg-detail', data: {'msgId': msgId}, dataType: 'json', success: (response) => { this.setState({ msgTitle: response.data.title, msgContent: response.data.content }); console.log(`msg-detail?msgId=${msgId} 请求成功, msgContent=${this.state.msgContent}`); }, error: () => { console.log(`msg-detail?msgId=${msgId} 请求异常`); } }); } componentDidUpdate() { let title = $(this.refs.MsgTitle); let container = $(this.refs.MsgContainer) let ToolBar = $(this.refs.ToolBar.refs.ToolBarContainter); // 上半部分总高度 let height = title.height() + parseInt(title.css('padding-top')) + parseInt(title.css('padding-bottom')) + parseInt(container.css("padding-top")) + parseInt(container.css("padding-bottom")) + parseInt(ToolBar.height()); // 窗口高度-上半部分总高度作为文章的最小高度 if (this.state.contentHeight != window.innerHeight - height) { // 如果一样则不要setState避免递归渲染 this.setState({ contentHeight: window.innerHeight - height, }); } } render() { // refs属性会捕获对应的原生的Dom节点,会在componentDidUpdate中访问Dom来动态计算高度 return ( <div> <ToolBar ref="ToolBar"/> <h1 id={style.MsgTitle} ref="MsgTitle">{this.state.msgTitle}</h1> <div id={style.MsgContainer} ref="MsgContainer" style={{minHeight: this.state.contentHeight}}> <p id={style.MsgContent}>{this.state.msgContent}</p> </div> </div> ); } } MsgDetailPage.contextTypes = { router: () => { React.PropTypes.object.isRequired } }; |
在DidMount时候,DOM已经生成,此时可以发起ajax获取数据,最终填充到state中触发Update渲染。
DidUpdate的时候,数据被填充,触发页面重新渲染。为了让正文部分填充满屏幕,我需要获取渲染后的页面真实样式,包括工具栏和标题栏的真实高度,从而动态计算正文部分的最小高度,修改其css。
这里render方法里用到了ref属性(点我学习),它用于方便的获取对应的原生DOM节点,用于一些个性化操作。首先在对应的html标签或者子组件标签内定义ref=”自定义名称”,之后在虚拟DOM真实渲染完成后(例如在DidUpdate,DidMount内)通过this.refs.xxxx取出DOM节点。这里,我为了操作方便将原生DOM转成了jquery的节点。
另外对于ToolBar来说,它是一个react组件,通过this.refs获取到就是对应的ToolBar类对象。我可以继续访问ToolBar的refs去获取其内部的DOM节点,也就是this.refs.ToolBar.refs.ToolBarContainer。
在DidUpdate内,我最后if判断了高度是否发生新的变化,如果没有变化则不进行setState。这是因为每次setState都会触发DidUpdate函数,而我们的DidUpdate又会调用setState,如果没有终止条件则会无限递归。
这里再看一下ToolBar的定义即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import React from "react"; import {Link} from "react-router"; import $ from "jquery"; import backImg from "./back.png"; import style from "./ToolBar.css"; export default class ToolBar extends React.Component { constructor(props, context) { super(props, context); this.state = { }; } render() { return ( <div id={style.ToolBarContainter} ref="ToolBarContainter"> <img id={style.BackImg} src={backImg} onClick={this.context.router.goBack}/> </div> ); } } ToolBar.contextTypes = { router: () => { React.PropTypes.object.isRequired } }; |
并没有太过于复杂的东西,onClick直接通过router的goBack实现浏览器回退。
这是页面的模样:
在本篇中,通过js动态调整正文部分的高度并不是很优雅,据说有flex这个类似于bootstrap的库可以用来轻松实现布局,有兴趣后面可以学习一下。
下一篇中,我将编写最复杂的MsgListPage,将会使用react iscroll插件实现滚动,并基于它的事件回调,自己实现下拉刷新,上拉加载能力。
如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~

还有黄段子吗
你们学校校风如何?很大。倍感珍惜by http://www.sodaan.net/class/class-13.html
读后深有感触谢谢你们.by https://ceshidaan.com/class/suzhou.html
感谢您.很喜欢您的文章穷并不可怕,可怕的是你真的觉得穷不可怕。by http://www.sodaan.net/class/class-12.html
1
1
1