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

结果:

react基础06--react综合案例-电商网站导航_redux

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

最下面新加一个 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,) =>{
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,)=>{
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

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,)=>{
return (
<div key={index}>
{item.title},{item.price}
</div>
)
})}
</div>
)
}
}

export default

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

结果:

react基础06--react综合案例-电商网站导航_redux_02


点击 手机-小米手机

react基础06--react综合案例-电商网站导航_react 前端案例_03

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,)=>{
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

vim Nav01.js

render() {
const { navs, selId } = this.state;
return (
<div>
<Link to={`/search`}>搜索</Link>
<div style={{display:"flex", flexDirection:"row"}}>
{navs.map((item,) =>{
***
}}
</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>
)
}
}

结果:

主界面

react基础06--react综合案例-电商网站导航_react案例电商网站导航_04


点击搜索界面

react基础06--react综合案例-电商网站导航_react案例电商网站导航_05


搜索产品

react基础06--react综合案例-电商网站导航_react.js_06

3 注意事项

  1. 安装包
npm i axios --save
npm
  1. 错误
Array.prototype.map() expects a return value from arrow function 

goodsList.map((item)=>{
if(item.classify === id){
goods.push(item)
}
return goods
})
  1. child in a list should have a unique “key” prop
{navs.map((item,)=>{
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>
)
}
})
}
  1. 当前选中二级分类后产品在 /list/{number} 页面显示, 也可以在Nave01.js 下面再加一层展示具体产品列表的功能。
  2. 当前只是模拟商城的基础功能,后续可以在此基础上新增 登录注册、加购物车流程;也可以通过本案例学习完成一个 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’​