到目前为止,首页、文章详情页、动态页、话题页及小册页面内容完成了,看一下效果图哈,数据不全,见谅哈!
实现过程
动态页
该页面从布局来说分左右两部分,左边有分为输入框和已发表内容部分。
- 输入框部分
我这里采用了ant-design中的input作为输入框,而掘金是采用了可编辑的div来实现输入内容,通过设置contenteditable=”true”实现,感兴趣的小伙伴可查阅相关资料。
发布按钮的disabled状态将根据输入框是否有值来决定。功能类似todolist添加功能,可参考文章详情页面的发布评论功能。
1 | <div style={{background:'#fff',padding:'15px',position:'relative'}}> |
输入框内容发生变化事件
1 | handelInputChange=(e)=>{ |
发布按钮事件
1 | handlePressEnter=()=>{ |
- 添加话题
如图所示,一个搜索框加一个话题列表。
dom结构如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21<div style={{background:'#fff'}}>
<Search
placeholder="搜索话题"
onSearch={value => this.handleSearch(value)}
style={{ width: '100%' }}
/>
<List
itemLayout="horizontal"
dataSource={this.state.topicListData}
style={{height:'300px',overflow:'auto'}}
renderItem={item => (
<List.Item style={{cursor:'pointer'}} onClick={this.handleClick.bind(this,item.title)}>
<List.Item.Meta
avatar={<Avatar size={42} shape="square" src={item.img} />}
title={item.title}
description={<div>{item.followers}关注 {item.num}沸点</div>}
/>
</List.Item>
)}
/>
</div>
搜索框回车搜索事件:
1 | handleSearch=(value)=>{ |
话题列表点击事件:
1 | handleClick=(val)=>{ |
这里向父组件传递了一个val代表当前点击话题,关于父子组件传值的相关说明前面文章做了介绍,这里不再赘述。
- 已发表的话题列表
使用ant-design的list组件实现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
52render() {
const IconText = ({ type, text,tag }) => (
<span onClick={this.handleClick.bind(this,tag)}>
<Icon type={type} style={{ marginRight: 8 }} />
{text}
</span>
);
const PopoverContent=(id)=>{
return <p style={{cursor:'pointer'}} onClick={this.handleReport.bind(this,id)}>举报</p>
}
return (
<div>
<List
itemLayout="vertical"
size="large"
dataSource={this.state.listData}
renderItem={item => (
<List.Item
key={item.author}
actions={
[
<IconText type="like" text={item.likeNum===0?'赞':item.likeNum} tag='like' />,
<IconText type="message" text={item.commentNum===0?'评论':item.commentNum} tag='comment' />,
<IconText type="share-alt" text="分享" tag='share' />
]
}
extra={
<div>
{!item.isFollowed && <Button style={{borderColor:'#6cbd45',color:'#6cbd45'}} onClick={()=>this.handleFollow(item.id)}>{item.isFollowed?'已关注':'关注'}</Button>}
<Popover placement="bottom" content={<PopoverContent author={item.author} />} trigger="click">
<span style={{cursor:'pointer',margin:'10px'}}>...</span>
</Popover>
</div>
}
>
<List.Item.Meta
// avatar={<Avatar size={45} src={item.avatar} />}
avatar={<Popover placement="top" content={<PersonalPop info={item} handleFollow={(id)=>this.handleFollow(id)} />}>
<Avatar size={45} src={item.avatar} />
</Popover>}
title={<Popover placement="top" content={<PersonalPop info={item} handleFollow={(id)=>this.handleFollow(id)} />}>
<span style={{cursor:'pointer'}}>{item.author}</span>
</Popover>}
description={<div><span>{item.description}</span><span style={{margin:'0 5px'}}>·</span><span>{timeUtil.getTimeAgo(item.editTime)}</span></div>}
/>
{item.content}
</List.Item>
)}
/>
</div>
);
}
用户头像鼠标滑过会出现详情,使用了popover组件,具体内容是单独抽离的一个PersonalPop组件。每一项根据isFollowed值判断是否显示关注按钮,如果没有关注,点击可关注。
- 右侧内容
右侧内容统一使用card组件实现,利用Redux获取登录用户信息。
1 | render() { |
鉴于关注的话题和更多话题内容结构类似,故抽离为一个公用组件,且为函数式组件。
1 | function TopicCard({ title,list,link }){ |
React组件可分为函数组件(Functional Component )和类组件(Class Component),划分依据是根据组件的定义方式。函数组件使用函数定义组件,类组件使用ES6 class定义组件。
函数组件的写法要比类组件简洁,不过类组件比函数组件功能更强大。类组件可以维护自身的状态变量,即组件的state,类组件还有不同的生命周期方法,可以让我们能够在组件的不同阶段(挂载、更新、卸载)对组件做更多的控制,进行不同的操作。但函数组件的使用可以从思想上让你在设计组件时进行更多思考,更加关注逻辑控制和显示的分离,设计出更加合理的组件结构。实际操作中,当一个组件不需要管理自身状态时,可以把它设计成函数组件,当你有足够的理由发现它需要“升级”为类组件时,再把它改造为类组件。因为函数组件“升级”为类组件是有一定成本的,这样就会要求你做这个改造前更认真地思考其合理性,而不是仅仅为了一时的方便就使用类组件。
话题页
同样适用函数式组件
1 | function TopicItem({item,showCount}){ |
关注的话题数据其实是全部话题的子集,在父页面调用的时候根据数据中的isFollowed属性进行一次筛选。
1 | componentDidMount(){ |
小册页
- 头部的导航
1 | function TopNav({tags,changeLink}){ |
- 小册列表
使用ant-design中的list组件进行基本布局
1 | render() { |
会根据属性是否预售isPresell和是否已经购买isBuy来判断显示不同内容。
相关文章
相关详细代码可查看github,不要忘了star哦!工作中主要是以vue作为主要技术栈,这是第一次使用React+React-router+Redux来构建项目,不足之处还请大家多多包涵。
金三已过,银四会是什么样子呢?