抽了兩天工做中閒暇時間,文章詳情頁終於寫完了,先上圖哈,截圖少了下面一部分哈,見諒!react
本篇文章爲使用React構建精簡版本掘金系列第三篇,想看前兩篇的話,請查看 第一篇, 第二篇。主要包含點贊數量顯示、評論數量、收藏按鈕,分享連接等。因爲要常駐在左側,且頁面滾動過程當中位置不變,故使用fixed定位方式,而且使用ant-design中的Avatar,Badge,Icon,Popover組件。git
import { Avatar,Badge,Icon,Popover } from 'antd';
...
<div style={articleSuspendedPanel}>
<Badge count={this.props.starCount} overflowCount={this.state.overflowCount} style={badgeSy}>
<div style={panelCircleSy}>
<Icon type="like" theme="filled" style={IconSy}/>
</div>
</Badge>
<Badge count={this.props.commentsCount} overflowCount={this.state.overflowCount} style={badgeSy}>
<div style={panelCircleSy}>
<Icon type="message" theme="filled" style={IconSy}/>
</div>
</Badge>
<div style={panelCircleSy}>
<Icon type="star" theme="filled" style={IconSy}/>
</div>
<label>分享</label>
<Avatar style={avatarSy1}>
<img alt="" src="//b-gold-cdn.xitu.io/v3/static/img/weibo.2076a57.svg" />
</Avatar>
<Avatar style={avatarSy1}>
<img alt="" src="//b-gold-cdn.xitu.io/v3/static/img/qq.0834411.svg" />
</Avatar>
<Popover content={<QRCode value={window.location.href+'/post/'+this.props.wxShareAddr} />} placement="bottom">
<Avatar style={avatarSy1}>
<img alt="" src="//b-gold-cdn.xitu.io/v3/static/img/wechat.63e1ce0.svg" />
</Avatar>
</Popover>
</div>
複製代碼
render中的代碼結構如上,starCount和commentsCount數據是從父級組件傳入的,微信分享掃一掃利用了QRCode組件,關於該組件的介紹可查看上一篇文章,有詳細的說明。github
仔細看的話,其實中間部分也能夠分爲頂部的做者介紹,包括文章編輯時間,閱讀量,登陸用戶是否關注了做者。第二部分纔是真正的文章詳情。第三部分有關於該文章的評論區域,最下面是一系列的相關推薦文章。接下來分別介紹下:redux
<List
itemLayout="horizontal"
dataSource={this.state.articleInfo.articleList}
renderItem={item => (
<List.Item actions={[item.isFocus?<button className='focusedBtn'>已關注</button>:<button className='focusBtn'>關注</button>]}>
<List.Item.Meta
avatar={<Avatar src={item.authorImage} />}
title={item.author}
description={<div><span>{item.editDate}</span><span style={{marginLeft:'10px'}}>閱讀{item.readNum}</span></div>}
/>
</List.Item>
)}
/>
複製代碼
很簡單的一部分,應該能看明白。bash
中間部分我這裏就簡單的用section包裹內容了,實際開發中我的以爲應該須要讀取對應各層標題的樣式、正文的樣式,分段落顯示,須要去分類型解析各類內容,包括圖片、超連接等內容。微信
<div style={{marginLeft:'10px',flex:'1'}}>
<div>
<Input value={this.state.value} placeholder="輸入評論..." onFocus={this.handleFocus.bind(this)} onChange={this.handleChange.bind(this)} onPressEnter={this.handlePressEnter.bind(this)}/>
</div>
{
this.state.showIconAndBtn?
<div style={{display:'flex',justifyContent:'space-between',marginTop:'10px'}}>
<span style={{color:'#027fff',cursor: 'pointer',display:'flex',alignItems:'center'}} onClick={info}>
<img alt='' src='//b-gold-cdn.xitu.io/v3/static/img/emoji.5594dbb.svg' />
表情
</span>
<p>
<label style={{color:'#c2c2c2',marginRight:'8px'}}>Enter</label>
<Button type="primary" onClick={this.handlePressEnter.bind(this)}>評論</Button>
</p>
</div>:''
}
</div>
複製代碼
showIconAndBtn是控制輸入框下面那一行是否顯示的,初始進入頁面的時候是隻能看到輸入框,下面的表情和評論按鈕只能等輸入框獲取焦點後才能顯示。 輸入框上綁定了三個事件,分別用來處理獲取焦點事件、輸入內容改變事件、按下回車事件。antd
handleFocus=()=>{
this.setState({
showIconAndBtn:true
})
}
複製代碼
handleChange=(e)=>{
this.setState({
value:e.target.value
});
}
複製代碼
handlePressEnter=()=>{
if(this.state.value!==''){
this.props.submitComment(this.state.value);//調用父級組件並傳值
this.setState({
value:'',
showIconAndBtn:false
})
}else{
message.warning('還未填寫評論哦!');
}
}
複製代碼
這裏有用到子組件向父組件傳值的方法,簡單介紹下:
父向子傳值app
父向子傳值起始比較簡單,重點要考慮向下傳值是否會使得父組件中的狀態過於繁雜,是否會影響頁面性能。svg
假設存在一個組件ComponentA,在父組件中調用ComponentA,而且傳遞參數data函數
...
this.state={
text:'hello world'
}
...
<ComponentA data={this.state.text} /
複製代碼
在組件ComponentA中就能夠經過this.props.data獲取到父組件傳入的data值了。
子向父傳值
由子組件的事件觸發,在觸發的函數體中調用父組件傳入的方法,將子組件裏的值傳入便可。
假設存在父組件ComponentParent,子組件ComponentChild,父組件中調用ComponentChild
父組件:
...
handleChange=(val)=>{
console.log(`信息:`+val);//子組件傳入的數據
}
...
<ComponentChild change={this.handleChange.bind(this)} />
複製代碼
子組件:
//假設有個方法叫handleClick
handleClick=()=>{
this.props.change('hello');
}
複製代碼
在子組件中執行handleClick方法的時候就會觸發父組件中的方法handleChange,並在控制檯輸出hello。
兄弟組件傳值
能夠將數據提高到共同的父組件中,進行傳值,以後在利用父子組件傳值便可。
多層級組件或者稱爲不相鄰組件傳值
能夠利用redux管理全局狀態,以後在任何地方均可以取到對應的數據。
這種方式的使用方式在第一篇文章作了說明,能夠瀏覽哦!
待實現功能:
我的實現的這塊區域和掘金有少量不一樣。
<List
itemLayout="vertical"
size="large"
dataSource={this.props.commentList}
renderItem={item => (
<List.Item
key={item.userId}
actions={[<span>{moment().subtract(item.editDate, 'days').fromNow()}</span>,<IconText type="like-o" text={item.starNum} />, <IconText type="message" text={item.commentNum} />]}
>
<List.Item.Meta
avatar={<a href={'/user/'+item.userId}><Avatar src={item.userImage} /></a>}
title={<div>{item.authorName}</div>}
description={item.userDesc}
/>
{item.commentText}
</List.Item>
)}
/>
複製代碼
採用了ant-design中的List組件進行顯示
待實現
該部分結構採用了首頁列表組件,只需按照文章類型,推薦不一樣內容便可,這裏再也不贅述。
右側總體結構和首頁右側內容相似,分6塊:
<Card
title="關於做者"
style={{ width: '100%' }}
hoverable={'true'}
headStyle={{fontSize:'14px',color:'#333'}}
bodyStyle={{padding:'0 16px'}}
>
<List
itemLayout="vertical"
dataSource={this.props.author}
renderItem={item => (
<List.Item onClick={()=>window.location.href='/user/'+item.id}>
<List.Item.Meta
avatar={<Avatar size={46} src={item.authorImage} />}
title={item.author}
/>
{item.isGroup?<div>
<Avatar style={{ backgroundColor: '#e1efff',color:'#7bb9ff' }} icon="user" />
<label style={{color:'#000',marginLeft:'10px',fontSize:'16px'}}>聯合編輯</label>
</div>:''}
<div style={{marginTop:'10px'}}>
<Avatar style={{ backgroundColor: '#e1efff' }}>
<Icon type="like" theme="filled" style={{color:'#7bb9ff'}} />
</Avatar>
<label style={{color:'#000',marginLeft:'10px',fontSize:'16px'}}>得到贊數{item.allStarNum}</label>
</div>
<div style={{marginTop:'10px'}}>
<Avatar style={{ backgroundColor: '#e1efff' }}>
<Icon type="eye" theme="filled" style={{color:'#7bb9ff'}} />
</Avatar>
<label style={{color:'#000',marginLeft:'10px',fontSize:'16px'}}>得到閱讀數{item.allReadNum<99999?item.allReadNum:'99999+'}</label>
</div>
</List.Item>
)}
/>
</Card>
複製代碼
<Card
title="你可能感興趣的小冊"
style={{ width: '100%',marginTop:'20px' }}
hoverable={'true'}
headStyle={{fontSize:'14px',color:'#333'}}
bodyStyle={{padding:'0 16px'}}
>
<List
itemLayout="horizontal"
dataSource={this.props.recommendBooks}
className="bookCard"
renderItem={item => (
<List.Item onClick={()=>window.location.href='/book/'+item.id}>
<List.Item.Meta
avatar={<img alt='' src={item.bookImage} />}
title={item.title}
description={<p className="book-desc"><span>{item.sellNum+'人已購買'}</span><span className="try-read">試讀</span></p>}
/>
</List.Item>
)}
/>
</Card>
複製代碼
這一塊單獨抽一個組件,別的地方也可能會用到,後期只需傳入小冊內容便可。目前首頁和文章詳情頁用的都是這個組件。
<Card style={{ width: '100%',marginTop:'20px' }} hoverable='true' className="download-card" bodyStyle={{padding:'15px'}}>
<NavLink to='/app'>
<img alt='qrcode' src='//b-gold-cdn.xitu.io/v3/static/img/timeline.e011f09.png' />
<div>
<div className="headline">下載掘金客戶端</div>
<div className="desc">一個幫助開發者成長的社區</div>
</div>
</NavLink>
</Card>
複製代碼
<Card
style={{ width: '100%',marginTop:'20px' }}
hoverable={'true'}
bodyStyle={{padding:'0'}}
>
<img alt='' src='//b-gold-cdn.xitu.io/v3/static/img/backend.ba44b94.png' style={{height:'200px',width:'100%'}} />
</Card>
複製代碼
<Card
title="相關文章"
headStyle={{fontSize:'14px',color:'#333'}}
style={{ width: '100%',marginTop:'20px'}}
hoverable={'true'}
bodyStyle={{padding:'0 16px'}}
>
<List
itemLayout="vertical"
dataSource={this.props.relationArticles}
split={false}
renderItem={item => (
<List.Item onClick={()=>window.location.href='/post/'+item.id}>
<div style={{color:'#333',fontSize:'16px'}}>{item.title}</div>
<div style={{marginTop:'10px',color:'#b2bac2',fontSize:'12px'}}>
<Icon type="like" theme="filled" style={{marginRight:'3px'}} />{item.starNum}
<Icon type="message" theme="filled" style={{marginLeft:'15px',marginRight:'3px'}} />{item.commentNum}
</div>
</List.Item>)}
/>
</Card>
複製代碼
<div className='text-catalogue'>
<Timeline>
{this.props.data.map((item,index)=>{
return <Timeline.Item color='#000' key={item.text} dot={<span className='catalogue-circle'></span>}>{(item.children && item.children.length !== 0)?<div><a href={`#heading-${index}`}>{item.text}</a><div className='secondCatalogue'><Catalogue data={item.children} /></div></div>:<a href={`#heading-${index}`}>{item.text}</a>}</Timeline.Item>
})}
</Timeline>
</div>
複製代碼
用到了ant-design中的Timeline組件,這個單獨抽離成一個組件,整個系統中均可以複用,這裏用到了遞歸組件實現目錄嵌套的功能。
從首頁文章列表進入文章詳情頁的時候須要傳遞一些參數,好比文章的id值
<Route path='/post/:articleId' component={Post}/>
複製代碼
showArticleInfo=(id)=>{
console.log(`文章id值:${id}`);
window.location.href='/post/'+id;
}
複製代碼
componentDidMount(){
const {match}=this.props;
console.log(`文章id:${match.params.articleId}`);
}
複製代碼
<Route path='/post' component={Post} />
複製代碼
let data = {id:3,name:sam};
let path = {
pathname:'/post',
state:data,
}
複製代碼
連接跳轉
<Link to={path}>詳情</Link>
複製代碼
let data = this.props.location.state;
let {id,name} = data;
複製代碼
截止到目前爲止,首頁和文章詳情頁的結構和基本功能就算完成了,細節後續在優化,剩餘部分陸續更新中。
上述詳細代碼請見github,不要忘了star和點贊哦,多謝!