react基础06--react综合案例-电商网站导航
1 介绍
继上文 react基础05–react-router 路由, 本文将根据上述01-05小节的基础知识实现一个小型电商网站的基础导航和搜索模型.
分类导航是一个很重要且常见的功能, 常见美团App商品 菜品都是一级导航, 京东、淘宝等商城多为二级甚至三级导航。本文将实现一个基础的商品导航功能, 具体包括一级二级导航、商品展示、查看详情、筛选、搜索 等功能。
2 案例设计模块
2.1 分类导航数据模型设计
结构设计:
电商网站-{电器、服装、玩具、手机}
电器-{冰箱、洗衣机、空调}
服装-{外套、衬衣、裤子}
玩具-{挖掘机、赛车、游戏机}
手机-{华为、小米、苹果}
数据设计(data.json):
{
"navs": [
{
"id": 1,
"pid": 0,
"name": "电器"
},
{
"id": 2,
"pid": 1,
"name": "冰箱"
},
{
"id": 3,
"pid": 0,
"name": "空调"
},
{
"id": 4,
"pid": 0,
"name": "服装"
},
{
"id": 5,
"pid": 6,
"name": "外套"
},
{
"id": 6,
"pid": 0,
"name": "玩具"
},
{
"id": 7,
"pid": 0,
"name": "手机"
}
], "goods": [
{
"id": 1,
"classify": "3",
"title": "海尔空调",
"price": 2000
}, {
"id": 2,
"classify": "3",
"title": "格力空调",
"price": 1800
},
{
"id": 3,
"classify": "7",
"title": "小米新手机",
"price": 2990
},
{
"id": 4,
"classify": "7",
"title": "华为新手机",
"price": 3600
}
]
}
2.2 一级分类导航切换高亮效果
vim GoodList01.js
import React, { Component } from 'react';
import axios from 'axios'
export class GoodsList01 extends Component {
constructor(){
super();
this.state = {
navs: [], //所有分类数据
goods: [], //所有商品数据,
selId: 1 //被选中的id
}
}
componentDidMount(){
axios.get("http://localhost:3000/data.json")
.then((resp)=>{
console.log(resp.data)
this.setState({
navs: resp.data.navs
})
})
}
render() {
const { navs, goods, selId } = this.state;
return (
<div>
{navs.map((item, index) =>{
if (item.pid === 0){
return (
<div
key={index}
style={{color:selId === item.id ? 'red':"#999"}}
onClick={()=>{
this.setState({
selId: item.id
})
}
}
>
{item.name}
</div>
)
}else {
return (
<div key={index}>
</div>
)
}
})}
</div>
)
}
}
export default GoodsList01
结果:
2.3 显示二级分类导航
vim GoodList01.js
import React from 'react';
import axios from 'axios'
export class GoodsList01 extends React.Component {
constructor(){
super();
this.state = {
navs: [], //所有分类数据
goods: [], //所有商品数据,
selId: 1 //被选中的id
}
}
componentDidMount(){
axios.get("http://localhost:3000/data.json")
.then((resp)=>{
console.log(resp.data)
this.setState({
navs: resp.data.navs
})
})
}
render() {
const { navs, selId } = this.state;
return (
<div>
<div style={{display:"flex", flexDirection:"row"}}>
{navs.map((item, index) =>{
if (item.pid === 0){
return (
<div
key={index}
style={{color:selId === item.id ? 'red':"#999"}}
onClick={()=>{
this.setState({
selId: item.id
})
}
}
>
{item.name}
</div>
)
}else {
return (
<div key={index}>
</div>
)
}
})}
</div>
<hr />
{navs.map((item, index)=>{
if(item.pid === selId){
return (
<div key={index}>
{item.name}
</div>
)
}else {
return (
<div> </div>
)
}
})
}
</div>
)
}
}
export default GoodsList01
最下面新加一个 navs.map((item, index) 即可
2.4 路由跳转到二级导航的商品列表
vim Nav01.js
import React from 'react';
import axios from 'axios';
import { Link } from 'react-router-dom'
export class Nav01 extends React.Component {
constructor(){
super();
this.state = {
navs: [], //所有分类数据
goods: [], //所有商品数据,
selId: 1 //被选中的id
}
}
componentDidMount(){
axios.get("http://localhost:3000/data.json")
.then((resp)=>{
// console.log(resp.data)
this.setState({
navs: resp.data.navs
})
})
}
render() {
const { navs, selId } = this.state;
return (
<div>
<div style={{display:"flex", flexDirection:"row"}}>
{navs.map((item, index) =>{
if (item.pid === 0){
return (
<div
key={index}
style={{color:selId === item.id ? 'red':"#999"}}
onClick={()=>{
this.setState({
selId: item.id
})
}
}
>
{item.name}
</div>
)
}else {
return (
<div key={index}>
</div>
)
}
})}
</div>
<hr />
{navs.map((item, index)=>{
if(item.pid === selId){
return (
<Link key={index} to={`/list/${item.id}`}>
<div key={index}>
{item.name}
</div>
</Link>
)
}else {
return (
<div key={index}>
</div>
)
}
})
}
</div>
)
}
}
export default Nav01
vim GoodsList.js
import React, { Component } from 'react';
import axios from 'axios';
export class GoodsList extends Component {
constructor() {
super();
this.state = {
goods: []
}
}
UNSAFE_componentWillMount(){
// console.log(this.props)
let id = this.props.match.params.id;
console.log(id)
axios.get("http://localhost:3000/data.json")
.then((resp)=>{
let goodsList = resp.data.goods;
let goods = [];
goodsList.map((item)=>{
if(item.classify === id){
goods.push(item)
}
return goods
})
this.setState({
goods
})
})
}
render() {
return (
<div>
<div onClick={()=>{
window.history.back()
}}>返回</div>
This is GoodsList!
{this.state.goods.map((item, index)=>{
return (
<div key={index}>
{item.title},{item.price}
</div>
)
})}
</div>
)
}
}
export default GoodsList
vim App.js
import React from "react";
import { BrowserRouter, Switch, Route } from "react-router-dom";
import GoodsList from "./pages/GoodsList";
import Nav01 from "./pages/Nav01";
class App extends React.Component{
render(){
return (
<BrowserRouter>
<Switch>
<Route path="/list/:id" component={GoodsList} />
<Route exact path="/" component={Nav01} />
</Switch>
</BrowserRouter>
)
}
}
export default App
结果:
点击 手机-小米手机
2.5 商品搜索
vim Search.js
import React, { Component } from 'react';
import axios from 'axios';
export class Search extends Component {
constructor(){
super();
this.state = {
goods: [], //所有商品数据,
inputValue: '',
resultList: []
}
}
componentDidMount(){
axios.get("http://localhost:3000/data.json")
.then((resp)=>{
// console.log(resp.data)
this.setState({
goods: resp.data.goods
})
})
}
render(){
return (
<div>
<div >
<input value={this.state.inputValue} onChange={(e)=>{
this.setState({
inputValue: e.target.value
})
}}/>
<button onClick={this.search.bind(this)}>搜索</button>
</div>
{this.state.resultList.map((item, index)=>{
return (
<div key={index}>
{item.title},¥{item.price}
</div>
)
})}
</div>
)
}
search(){
let keyword = this.state.inputValue;
console.log(keyword)
let goods = this.state.goods;
let resultList = []
goods.map((item)=>{
if(item.title.includes(keyword)){
resultList.push(item)
}
})
this.setState({resultList})
}
}
export default Search
vim Nav01.js
render() {
const { navs, selId } = this.state;
return (
<div>
<Link to={`/search`}>搜索</Link>
<div style={{display:"flex", flexDirection:"row"}}>
{navs.map((item, index) =>{
***
}}
</div>
</div>
)
}
vim App.js
class App extends React.Component{
render(){
return (
<BrowserRouter>
<Switch>
<Route path="/search" component={Search}></Route>
<Route path="/list/:id" component={GoodsList} />
<Route exact path="/" component={Nav01} />
</Switch>
</BrowserRouter>
)
}
}
结果:
主界面
点击搜索界面
搜索产品
3 注意事项
- 安装包
npm i axios --save npm i react-router-dom@5.2.0 --save
- 错误
Array.prototype.map() expects a return value from arrow function goodsList.map((item)=>{ if(item.classify === id){ goods.push(item) } return goods })
- child in a list should have a unique “key” prop
{navs.map((item, index)=>{ if(item.pid === selId){ return ( <Link key={index} to={`/list/${item.id}`}> <div key={index}> {item.name} </div> </Link> ) }else { return ( <div key={index}> </div> ) } }) }
- 当前选中二级分类后产品在 /list/{number} 页面显示, 也可以在Nave01.js 下面再加一层展示具体产品列表的功能。
- 当前只是模拟商城的基础功能,后续可以在此基础上新增 登录注册、加购物车流程;也可以通过本案例学习完成一个 TodoList 小应用。
4 说明
软件版本:
node 16.13.1
create-react-app 5.0.0
react-router-dom@5.2.0
axios 0.25.0
参考文档:
React基础入门+综合案例
react 官网
React基础入门教程
withRouter’ is not exported from ‘react-router-dom’