1、回顧
2、點擊列表進入產品的詳情頁面
- 設計向頁面的布局結構,設計詳情頁面,入口導入布局文件
// index.js 入口文件
import Detail from '@/Detail';
<Route path="/d">
<Detail />
</Route>
// Detail.js 布局文件
import React from 'react';
// 一種布局有很多的頁面 --- Switch
import { Switch, Route } from 'react-router-dom';
import Detail from '@/views/detail';
// 布局找頁面
function App() {
return (
<Switch>
<Route path="/d/detail" component = { Detail } />
</Switch>
);
}
export default App;
// views/detail/index.jsx
import React, { Component } from 'react';
class Detail extends Component {
render () {
return (
<div className="container">
<div className="box">
<header className="header">詳情頭部</header>
<div className="content">
詳情內容
</div>
</div>
<footer className="footer">
詳情底部
</footer>
</div>
)
}
}
export default Detail
2.1 聲明式跳轉至詳情頁面
修改路由,添加參數 src/Detail.js 布局文件
<Switch>
<Route path="/d/detail/:proid" component = { Detail } />
</Switch>
列表組件點擊跳轉 --- Link ---- /components/Prolist/index.jsx
<Link to={ '/d/detail/' + item.proid } className="proitem" key = { item.proid }>
<div className="proimg">
<img src={ item.proimg } alt="" />
</div>
<div className="proinfo">
{ item.proname }
</div>
</Link>
- 設計請求詳情的接口 utils/api.js
/**
* 獲取詳情頁面的數據
* @param {*} type
*/
const getDetailData = (proid) => {
return new Promise(resolve => {
request.get('/pro/detail', { params: { proid }}).then(res => {
resolve(res.data)
})
})
}
// 3、暴露接口
export {
getProlist,
getBannerlist,
getCartlist,
login,
getDetailData // ++++++++++++++++++++++++
}
- 詳情頁面獲取數據
import React, { Component } from 'react';
import { getDetailData } from '@/utils/api'
class Detail extends Component {
constructor(props) {
super(props);
this.state = { // +++++++++++++++
proname: '',
proimg: ''
}
}
componentDidMount () { // +++++++++++++++++++++++
// console.log(this.props)
let proid = this.props.match.params.proid
getDetailData(proid).then(data => {
this.setState({
proname: data.data.proname,
proimg: data.data.proimg
})
})
}
render () {
return (
<div className="container">
<div className="box">
<header className="header">詳情頭部</header>
<div className="content">
<img src={ this.state.proimg } alt=""/>
<p>{ this.state.proname }</p>
</div>
</div>
<footer className="footer">
詳情底部
</footer>
</div>
)
}
}
export default Detail
2.2 編程式跳轉至詳情頁面
components/Prolist/index.jsx正常添加點擊事件,並未獲取到history這個屬性
如果內層組件跟路由無關(頁面找組件),頁面調用組件時傳遞參數 history,或者是直接將 this.props 傳遞給組件
// views/home/index.jsx
<Prolist prolist = { this.state.prolist } history = { this.props.history } { ...this.props }/>
App.js中更改布局調用頁面的方式
<Switch>
<Route path = "/home" component = { Home }/>
<Route path = "/kind" component = { Kind }/>
<Route path = "/cart" component = { Cart }/>
<Route path = "/user" component = { User }/>
{
//<Route path = "/user"><User /></Route>
}
</Switch>
- 列表跳轉 components/Prolist/index.jsx
<li onClick= { () => {
console.log(this.props)
// ++++++++++++++++++++++++++
this.props.history.push('/d/detail/' + item.proid)
}} className="proitem" key = { item.proid }>
<div className="proimg">
<img src={ item.proimg } alt="" />
</div>
<div className="proinfo">
{ item.proname }
</div>
</li>
3、加入購物車
- 設計加入購物車接口 utils/api.js
/**
* 加入購物車
* @param {*} type
*/
const addCart = (userid, proid, num) => {
return new Promise(resolve => {
request.get('/cart/add', { params: { userid, proid, num } }).then(res => {
resolve(res.data)
})
})
}
// 3、暴露接口
export {
getProlist,
getBannerlist,
getCartlist,
login,
getDetailData,
addCart //+++++++++++++++++
}
- 詳情點擊加入購物車,調用接口
<footer className="footer">
<Button type="primary" onClick = { () => {
let userid = localStorage.getItem('userid');
let proid = this.state.proid;
let num = 1;
addCart(userid, proid, num).then(data => {
if (data.code === '10119') {
Toast.fail('還未登陸', 1);
this.props.history.push('/o/login')
} else {
Toast.success('加入購物車成功', 1);
}
})
}}>加入購物車</Button>
</footer>
- 修改服務器的 token驗證的路由
day05/app.js
4、重定向與404
- 先寫一個404的頁面 views/notfound/index.jsx
import React from 'react';
class Com extends React.Component {
render () {
return (
<div className="box">
<header className="header">404頭部</header>
<div className="content">404內容</div>
</div>
)
}
}
export default Com;
- 修改App.js - exact 路由必須是當前的路由
<Switch>
<Route path = "/home" component = { Home }/>
<Route path = "/kind" component = { Kind }/>
<Route path = "/cart" component = { Cart }/>
<Route path = "/user" component = { User }/>
<Redirect from="/" exact to="/home"/>
<Route component = { NotFound } />
</Switch>
5、查看購物車
import React from 'react';
import { getCartlist } from '@/utils/api';
import { Link } from 'react-router-dom';
class Com extends React.Component {
constructor (props) {
super(props);
this.state = {
cartlist: [],
flag: false, // 是不是有數據
}
}
componentDidMount () {
console.log('222222222')
getCartlist(localStorage.getItem('userid')).then(data => {
console.log(data)
if (data.code === '10119') { // 有沒有登陸
this.props.history.push('/o/login')
} else if (data.code === '11000'){ // 有沒有數據
this.setState({
flag: false
})
} else {
this.setState({
flag: true,
cartlist: data.data
})
}
})
}
render () {
return (
<div className="box">
<header className="header">購物車頭部</header>
<div className="content">
{
this.state.flag ?
<ul>
{
this.state.cartlist.map((item, index) => {
return (
<li key={ item.cartid }>
<img src={ item.proimg } alt=""/>
{ item.proname } --- { item.price }
</li>
)
})
}
</ul>
: <div>購物車空空如也,<Link to="/home">請購物</Link></div>
}
</div>
</div>
)
}
}
export default Com;
- 計算總價與總數
import React from 'react';
import { getCartlist } from '@/utils/api';
import { Link } from 'react-router-dom';
class Com extends React.Component {
constructor (props) {
super(props);
this.state = {
cartlist: [],
flag: false, // 是不是有數據
totalNum: 0, // ++++++++++++++++++++++
totalPrice: 0 // +++++++++++++++++++++
}
}
componentDidMount () {
console.log('222222222')
getCartlist(localStorage.getItem('userid')).then(data => {
console.log(data)
if (data.code === '10119') { // 有沒有登陸
this.props.history.push('/o/login')
} else if (data.code === '11000'){ // 有沒有數據
this.setState({
flag: false
})
} else {
this.setState({
flag: true,
cartlist: data.data
})
this.getTotal() // ++++++++++++++++++++
}
})
}
// 計算總價以及總數量 ++++++++++++++++++++++++++
getTotal () {
console.log(3333)
let totalNum = 0
let totalPrice = 0
this.state.cartlist.map(item => {
totalNum += item.num
totalPrice += item.num * item.price
})
this.setState({
totalNum,
totalPrice
})
}
render () {
return (
<div className="box">
<header className="header">購物車頭部</header>
<div className="content">
{
this.state.flag ?
<ul>
{
this.state.cartlist.map((item, index) => {
return (
<li key={ item.cartid }>
<img src={ item.proimg } alt=""/>
{ item.proname } --- { item.price }
<button>-</button> { item.num } <button>+</button>
</li>
)
})
}
</ul>
: <div>購物車空空如也,<Link to="/home">請購物</Link></div>
}
<div>總數:{ this.state.totalNum }</div>
<div>總價:{ this.state.totalPrice }</div>
</div>
</div>
)
}
}
export default Com;
- 購物車數據的加減數量
import React from 'react';
import { getCartlist, updateCart } from '@/utils/api';
import { Link } from 'react-router-dom';
class Com extends React.Component {
constructor (props) {
super(props);
this.state = {
cartlist: [],
flag: false, // 是不是有數據
totalNum: 0,
totalPrice: 0
}
}
componentDidMount () {
console.log('222222222')
getCartlist(localStorage.getItem('userid')).then(data => {
console.log(data)
if (data.code === '10119') { // 有沒有登陸
this.props.history.push('/o/login')
} else if (data.code === '11000'){ // 有沒有數據
this.setState({
flag: false
})
} else {
this.setState({
flag: true,
cartlist: data.data
})
this.getTotal()
}
})
}
// 計算總價以及總數量
getTotal () {
console.log(3333)
let totalNum = 0
let totalPrice = 0
this.state.cartlist.map(item => {
totalNum += item.num
totalPrice += item.num * item.price
return 0
})
this.setState({
totalNum,
totalPrice
})
}
add (index, num) {
// 1、獲取列表
let cartlist = this.state.cartlist;
// 2、獲取加的這個產品 ---- 根據索引值
let obj = cartlist[index];
num++;
// 3、調用接口
updateCart(obj.cartid, num).then(data => {
if (data.code === '10119') {
this.props.history.push('/o/login')
} else if (data.code === '11111'){ // 數據庫數量更新成功
console.log('update success')
// 更新本地的數據
cartlist[index].num = num
this.setState({ // 重新渲染視圖
cartlist
})
this.getTotal()
}
})
}
reduce (index, num) {
// 1、獲取列表
let cartlist = this.state.cartlist;
// 2、獲取加的這個產品
let obj = cartlist[index];
if(num <= 1) {
num = 1
return // 代碼不繼續往下執行
} else {
num--
}
// 3、調用接口
updateCart(obj.cartid, num).then(data => {
if (data.code === '10119') {
this.props.history.push('/o/login')
} else if (data.code === '11111'){
console.log('update success')
cartlist[index].num = num
this.setState({
cartlist
})
this.getTotal()
}
})
}
render () {
return (
<div className="box">
<header className="header">購物車頭部</header>
<div className="content">
{
this.state.flag ?
<ul>
{
this.state.cartlist.map((item, index) => {
return (
<li key={ item.cartid }>
<img src={ item.proimg } alt=""/>
{ item.proname } --- { item.price }
<button onClick={ this.reduce.bind(this, index, item.num)}>-</button> { item.num } <button onClick={ this.add.bind(this, index, item.num) }>+</button>
</li>
)
})
}
</ul>
: <div>購物車空空如也,<Link to="/home">請購物</Link></div>
}
<div>總數:{ this.state.totalNum }</div>
<div>總價:{ this.state.totalPrice }</div>
</div>
</div>
)
}
}
export default Com;
- 刪除購物車
import React from 'react';
import { getCartlist, updateCart, deleteCart } from '@/utils/api';
import { Link } from 'react-router-dom';
class Com extends React.Component {
constructor (props) {
super(props);
this.state = {
cartlist: [],
flag: false, // 是不是有數據
totalNum: 0,
totalPrice: 0
}
}
componentDidMount () {
console.log('222222222')
getCartlist(localStorage.getItem('userid')).then(data => {
console.log(data)
if (data.code === '10119') { // 有沒有登陸
this.props.history.push('/o/login')
} else if (data.code === '11000'){ // 有沒有數據
this.setState({
flag: false
})
} else {
this.setState({
flag: true,
cartlist: data.data
})
this.getTotal()
}
})
}
// 計算總價以及總數量
getTotal () {
console.log(3333)
let totalNum = 0
let totalPrice = 0
this.state.cartlist.map(item => {
totalNum += item.num
totalPrice += item.num * item.price
return 0
})
this.setState({
totalNum,
totalPrice
})
}
add (index, num) {
// 1、獲取列表
let cartlist = this.state.cartlist;
// 2、獲取加的這個產品 ---- 根據索引值
let obj = cartlist[index];
num++;
// 3、調用接口
updateCart(obj.cartid, num).then(data => {
if (data.code === '10119') {
this.props.history.push('/o/login')
} else if (data.code === '11111'){ // 數據庫數量更新成功
console.log('update success')
// 更新本地的數據
cartlist[index].num = num
this.setState({ // 重新渲染視圖
cartlist
})
this.getTotal()
}
})
}
reduce (index, num) {
// 1、獲取列表
let cartlist = this.state.cartlist;
// 2、獲取加的這個產品
let obj = cartlist[index];
if(num <= 1) {
num = 1
return // 代碼不繼續往下執行
} else {
num--
}
// 3、調用接口
updateCart(obj.cartid, num).then(data => {
if (data.code === '10119') {
this.props.history.push('/o/login')
} else if (data.code === '11111'){
console.log('update success')
cartlist[index].num = num
this.setState({
cartlist
})
this.getTotal()
}
})
}
del (index) {
// 1、獲取列表
let cartlist = this.state.cartlist;
// 2、獲取加的這個產品
let obj = cartlist[index];
deleteCart(localStorage.getItem('userid'), obj.proid).then(data => {
if(data.code === '10119') {
this.props.history.push('/o/login')
} else if (data.code === '11110') {
cartlist.splice(index, 1)
console.log(cartlist)
this.setState({
cartlist
})
this.getTotal()
}
})
}
render () {
return (
<div className="box">
<header className="header">購物車頭部</header>
<div className="content">
{
this.state.flag ?
<ul>
{
this.state.cartlist.map((item, index) => {
return (
<li key={ item.cartid }>
<img src={ item.proimg } alt=""/>
{ item.proname } --- { item.price }
<button onClick={ this.reduce.bind(this, index, item.num)}>-</button> { item.num } <button onClick={ this.add.bind(this, index, item.num) }>+</button>
<button onClick= { this.del.bind(this, index) }>刪除</button>
</li>
)
})
}
</ul>
: <div>購物車空空如也,<Link to="/home">請購物</Link></div>
}
<div>總數:{ this.state.totalNum }</div>
<div>總價:{ this.state.totalPrice }</div>
</div>
</div>
)
}
}
export default Com;
- 選擇
import React from 'react';
import { getCartlist, updateCart, deleteCart } from '@/utils/api';
import { Link } from 'react-router-dom';
class Com extends React.Component {
constructor (props) {
super(props);
this.state = {
cartlist: [],
flag: false, // 是不是有數據
totalNum: 0,
totalPrice: 0,
all: true
}
}
componentDidMount () {
console.log('222222222')
getCartlist(localStorage.getItem('userid')).then(data => {
console.log(data)
if (data.code === '10119') { // 有沒有登陸
this.props.history.push('/o/login')
} else if (data.code === '11000'){ // 有沒有數據
this.setState({
flag: false
})
} else {
data.data.map(item => {
item.checked = true
return 0
})
this.setState({
flag: true,
cartlist: data.data
})
this.getTotal()
}
})
}
// 計算總價以及總數量
getTotal () {
console.log(3333)
let totalNum = 0
let totalPrice = 0
this.state.cartlist.map(item => {
if (item.checked) {
totalNum += item.num
totalPrice += item.num * item.price
} else {
totalNum += 0
totalPrice += 0
}
return 0
})
this.setState({
totalNum,
totalPrice
})
}
add (index, num) {
// 1、獲取列表
let cartlist = this.state.cartlist;
// 2、獲取加的這個產品 ---- 根據索引值
let obj = cartlist[index];
num++;
// 3、調用接口
updateCart(obj.cartid, num).then(data => {
if (data.code === '10119') {
this.props.history.push('/o/login')
} else if (data.code === '11111'){ // 數據庫數量更新成功
console.log('update success')
// 更新本地的數據
cartlist[index].num = num
this.setState({ // 重新渲染視圖
cartlist
})
this.getTotal()
}
})
}
reduce (index, num) {
// 1、獲取列表
let cartlist = this.state.cartlist;
// 2、獲取加的這個產品
let obj = cartlist[index];
if(num <= 1) {
num = 1
return // 代碼不繼續往下執行
} else {
num--
}
// 3、調用接口
updateCart(obj.cartid, num).then(data => {
if (data.code === '10119') {
this.props.history.push('/o/login')
} else if (data.code === '11111'){
console.log('update success')
cartlist[index].num = num
this.setState({
cartlist
})
this.getTotal()
}
})
}
del (index) {
// 1、獲取列表
let cartlist = this.state.cartlist;
// 2、獲取加的這個產品
let obj = cartlist[index];
deleteCart(localStorage.getItem('userid'), obj.proid).then(data => {
if(data.code === '10119') {
this.props.history.push('/o/login')
} else if (data.code === '11110') {
cartlist.splice(index, 1)
console.log(cartlist)
this.setState({
cartlist
})
this.getTotal()
}
})
}
// 全選
selectAll () {
let cartlist = this.state.cartlist;
let all = this.state.all
all = !all
cartlist.map(item => {
item.checked = all
return 0
})
this.setState({
cartlist,
all
})
this.getTotal()
}
// 單選
seletceItem (index) {
let cartlist = this.state.cartlist;
// 點擊切換當前的選擇框
cartlist[index].checked = !cartlist[index].checked;
if (cartlist[index].checked) {
let flag = cartlist.every(item => { // 所有的值都為true
return item.checked === true
})
if (flag) {
this.setState({
all: true,
cartlist
})
} else {
this.setState({
all: false,
cartlist
})
}
} else {
this.setState({
all: false,
cartlist
})
}
this.getTotal()
}
render () {
return (
<div className="box">
<header className="header">購物車頭部</header>
<div className="content">
{
this.state.flag ?
<ul>
{
this.state.cartlist.map((item, index) => {
return (
<li key={ item.cartid }>
<input type="checkbox" onChange={ this.seletceItem.bind(this, index)} checked={item.checked}/>
<img src={ item.proimg } alt=""/>
{ item.proname } --- { item.price }
<button onClick={ this.reduce.bind(this, index, item.num)}>-</button> { item.num } <button onClick={ this.add.bind(this, index, item.num) }>+</button>
<button onClick= { this.del.bind(this, index) }>刪除</button>
</li>
)
})
}
</ul>
: <div>購物車空空如也,<Link to="/home">請購物</Link></div>
}
<div><input type="checkbox" checked = { this.state.all } onChange = { this.selectAll.bind(this) }/> 全選</div>
<div>總數:{ this.state.totalNum }</div>
<div>總價:{ this.state.totalPrice }</div>
</div>
</div>
)
}
}
export default Com;
6、首頁面的下拉刷新和上拉加載
cnpm i react-pullload -S
- 在頁面處引入
import ReactPullLoad, { STATS } from "react-pullload";
import "react-pullload/dist/ReactPullLoad.css";
- 構造函數添加變量
constructor (props) {
super(props);
this.state = {
bannerlist: [{ bannerid: 1, img: 'images/1.jpg'}],
prolist: [],
hasMore: true, // 上拉加載時還有沒有更多的數據 ++++++++++++++++
action: STATS.init, // 下拉刷新和上拉加載的狀態 ++++++++++++
pageCode: 1 // 頁碼 +++++++++++++++++++
}
}
- 使用組件包裹內容
<ReactPullLoad
downEnough={150}
ref="reactpullload"
isBlockContainer={true}
action={this.state.action}
handleAction={this.handleAction.bind(this)}
hasMore={this.state.hasMore}
distanceBottom={100}
>
<ul></ul>
</ReactPullLoad>
render () {
return (
<div className="box">
<header className="header">首頁頭部</header>
<div className="content">
<ReactPullLoad
downEnough={150}
ref="reactpullload"
isBlockContainer={true}
action={this.state.action}
handleAction={this.handleAction.bind(this)}
hasMore={hasMore}
distanceBottom={100}
>
<Carousel
autoplay={ true }
infinite
beforeChange={(from, to) => console.log(`slide from ${from} to ${to}`)}
afterChange={index => console.log('slide to', index)}
>
{this.state.bannerlist.map(item => (
<a
key={ item.bannerid }
href="https://www.baidu.com"
style={{ display: 'inline-block', width: '100%', height: '176px' }}
>
<img
src={`http://47.92.152.70/${item.img}`}
alt=""
style={{ width: '100%', verticalAlign: 'top' }}
onLoad={() => {
// fire window resize event to change height
window.dispatchEvent(new Event('resize'));
this.setState({ imgHeight: 'auto' });
}}
/>
</a>
))}
</Carousel>
<Prolist prolist = { this.state.prolist } history = { this.props.history } { ...this.props }/>
</ReactPullLoad>
</div>
</div>
)
}
- 實現滑動事件 handleAction
handleAction (action) {
console.info(action, this.state.action, action === this.state.action);
//new action must do not equel to old action
if (action === this.state.action) { // 如果狀態並且發生改變
return false;
}
if (action === STATS.refreshing) { // 如果用戶在下拉並且觸發了更新的條件
//刷新
this.handRefreshing(); // 下拉刷新函數
} else if (action === STATS.loading) { // 上拉加載條件成立
//加載更多
this.handLoadMore(); // 上拉加載函數
} else {
//DO NOT modify below code
this.setState({ // 其他狀態
action: action
});
}
};
- 顯示下拉刷新以及上拉加載函數
handLoadMore () {
}
handRefreshing () {}
- 上拉加載
handLoadMore () {
if (STATS.loading === this.state.action) { // 如果正在加載數據
return false;
}
//無更多內容則不執行后面邏輯
if (!this.state.hasMore) {
return;
}
// 設置為加載狀態
this.setState({
action: STATS.loading
});
// 獲取頁碼
let pageCode = this.state.pageCode
// 請求數據
getProlist(pageCode).then(data => {
let more = data.data.length === 0 // 還有沒有數據
pageCode++
if (more) { // 沒有數據了
this.setState({
action: STATS.reset, // 重置action,重置狀態
hasMore: false // 沒有數據了
});
} else {
this.setState({
prolist: [...this.state.prolist, ...data.data], // 先合並在賦值
action: STATS.reset, // 重置狀態
pageCode: pageCode // 重置頁碼
})
console.log(this.state.prolist)
}
})
}
- 下拉刷新
handRefreshing () {
if (STATS.refreshing === this.state.action) { //如果正在刷新
return false;
}
this.setState({ // 設置為刷新狀態
action: STATS.refreshing
});
// 請求數據
getProlist().then(data => {
this.setState({
prolist: data.data, //默認數據
hasMore: true, // 代表可以請求下一頁數據
action: STATS.refreshed // 重置當前狀態
})
})
};
修改樣式 去修改 test.scss