您现在的位置是:亿华云 > 系统运维

超详细的 React 组件设计过程 - 仿抖音订单组件

亿华云2025-10-03 16:53:53【系统运维】1人已围观

简介前言作为数据驱动的领导者react/vue等MVVM框架的出现,帮我们减少了工作中大量的冗余代码, 一切皆组件的思想深得人心。组件就是对一些具有相同业务场景和交互模式代码的抽象,这就需要我们对组件进行

前言

作为数据驱动的超详程仿领导者react/vue等MVVM框架的出现,帮我们减少了工作中大量的冗余代码, 一切皆组件的思想深得人心。

组件就是组组件对一些具有相同业务场景和交互模式代码的抽象,这就需要我们对组件进行规范的设计过封装,掌握高质量组件设计的抖音订单思路和方法可以帮助我们提高日常的开发效率。我们将会通过实战抖音订单组件详细的超详程仿介绍组件的设计思路和方法,对新手特别友好,组组件希望对前端新手们和有一定工作经验的设计过朋友有一定帮助~

前期准备

在组件设计之前,希望你对css、抖音订单js具有一定的超详程仿基础。在我们的组组件组件设计时需要用到的开源组件库有:

(有不了解的小伙伴可以自行查阅资料学习一下,在后面用到的设计过时候也会说明的)axios   它是一个基于 promise 的网络请求库,用于获取后端数据,抖音订单是超详程仿前端常用的香港云服务器数据请求工具;react-weui、weui  weui是组组件微信官方制作的一个基础样式UI库,我们可以通过阅读官方文档直接使用里面的设计过样式,而 react-weui就是将这些样式封装成我们可以直接使用的组件;styled-components  称之为css in js,现在正在成为在 React 中设计组件样式的新方法。

另外,我们还用到在线接口工具 ​​faskmock​​ 模拟ajax请求。它更加真实的模拟了前端开发中后端提供数据的方式。

正文

在这我们先来看看组件实现后的组件效果:

1. 组件设计思路

在这个组件中我们需要实现的业务有:

(目前我们就暂时实现以下效果,该页面的其他功能笔者将会在后期慢慢完善~)tab切换:点击tab,该tab添加上红色下划线样式,并将该tab状态下的订单展示在下方。设置loading状态:在数据还在请求中时,显示loading图标搜索订单:在当前tab下搜索商品标题含有输入内容的订单。删除订单:删除指定订单,由于数据是在fastmock中请求得到,因此删除只相对于前端。实现Empty(空状态)组件当当前状态下订单数量为 0 时,显示该组件,站群服务器否则显示列表组件。

根据我们的需求,可以划分出5个组件模块组成整个页面:

页面级别组件,它是其他组件的父组件;显示数据列表组件,单个数据组件;空状态组件;推荐商品列表组件

在<Myoeder/>组件中请求数据,将对应的数组数据通过props传给<OrderList/>组件和<RecommendList/>组件;<OrderList/>组件再将单个数据传给<OrderNote/>组件。这样就规范的完成了父组件请求数据,子组件搭建样式的分工合作了。

分析完组件组成接下来完成组件目录的搭建:

2. 实现 Myorder 组件

首先我们先根据需求将组件框架写好,这样后面写业务逻辑会更清晰:

这个页面级别组件包括固定在顶部的搜索框+导航栏,以及​​OrderList​​和​​RecommendList​​组件,因此可以写出如下组件框架:

import React from react

import OrderList from ../OrderList

import RecommendList from ../RecommendList

import { OrderWrapper } from ./style

import fanhui from ../../assets/images/fanhui.svg

import gengduo from ../../assets/images/gengduo.svg

import sousuo from ../../assets/images/sousuo.svg

export default function Myorder() {

return (

// 搜索 + 导航栏 部分

返回

placeholder="搜索订单"

/>

搜索

更多

  • 全部
  • 待支付
  • 待发货
  • 待收货/使用
  • 评价
  • 退款
  • // 订单列表组件

    // 推荐列表组件

    )

    }

    有了这个框架,我们来一步步往里面实现内容吧。

    2.1 实现tab切换效果

    首先来完成第一个需求:当点击某个​​tab​​时,如待支付,这个​​tab​​要有红色下划线效果。实现原理其实很简单,就是当我们触发该​​tab​​的点击事件时,就将我们事先写好的​​active​​样式加到该​​tab​​上。

    这里有两种方案:

    第一种实现方法是定义一个状态​​tab​​来控制每个​​

  • ​​的​​className​​的内容:import React,{ useState} from react
  • import { OrderWrapper } from ./style

    export default function Myorder() {

    const [tab,setTab] = useState(全部);

    const changeTab= (target) => {

    setTab(target);

    }

    return (

    ...

  • 全部
  • 待支付
  • 待发货
  • 待收货/使用
  • 评价
  • 退款
  • ...

    )

    }

    这种方法有一个明显的源码库缺点,就是只能为其添加一个样式名,当有多个样式类名时,就会出问题了,因此可以采用第二种方法。

    第二种方法就是用​​classnames​​ 了,也是比较推荐的方法,写法也比较简单。import classnames from classnames

    import { OrderWrapper } from ./style

    export default function Myorder() {

    const [tab,setTab] = useState(全部);

    const changeTab= (target) => {

    setTab(target);

    }

    return (

    ...

  • 全部
  • 待支付
  • 待发货
  • 待收货/使用
  • 评价
  • 退款
  • ...

    )

    }

    当有多个类名时,这样添加:

    <li className={ classnames(test,{ active:tab==="全部"})} onClick={ changeTab.bind(null,全部)}>全部</li>

    实现效果如图:

    2.2 获取数据

    这里准备了两个接口,用于获取订单数据推荐商品数据

    为了便于管理,我们将数据请求封装在api文件中:

    第一个接口获取订单数据

    。需要根据​​tab​​状态筛选获取的数据,这一步我们也写在接口文件中:import axios from axios

    // 请求订单数据

    export const getOrder = ({ tab}) =>

    axios

    .get(https://www.fastmock.site/mock/759aba4bef0b02794e330cccc1c88555/beers/order)

    .then ( res => {

    let result=res.data;

    if(tab){

    switch(tab) {

    case "待支付":

    result=result.filter(item => item.state=="待支付");

    break;

    case "待发货":

    result=result.filter(item => item.state=="待发货");

    break;

    case "待收货/使用":

    result=result.filter(item => item.state=="待收货/使用");

    break;

    case "评价":

    result=result.filter(item => item.state=="评价");

    break;

    case "退款":

    result=result.filter(item => item.state=="退款");

    break;

    default:

    break;

    }

    }

    return Promise.resolve({

    result

    });

    }

    )第二个接口获取推荐商品数据

    :import axios from axios

    // 请求推荐商品数据

    export const getCommend = () =>

    axios.get(https://www.fastmock.site/mock/759aba4bef0b02794e330cccc1c88555/beers/goods)

    接口准备好了,接下来我们将数据分配给子组件,接下来数据如何在页面上显示的任务就交给子组件​​<OrderList/>​​和​​<Recommend/>​​完成

    import React,{ useEffect, useState} from react

    import { OrderWrapper } from ./style

    import OrderList from ./OrderList

    import RecommendList from ./RecommendList

    export default function Myorder() {

    const [list,setList] =useState([]);

    const [recommend,setRecommend] = useState([]);

    // 从接口中获取推荐商品数据

    useEffect(()=> {

    (async()=> {

    const { data} = await getCommend();

    setRecommend([...data]);

    })()

    })

    // 从接口中获取订单数据,每次tab切换都重新拉取

    useEffect(()=>{

    (async()=>{

    const { result} = await getOrder({ tab});

    setList([

    ...result

    ])

    })()

    },[tab])

    return (

    ...

    { list.length>0 && }

    { recommend.length>0 && }

    }2.3 实现搜索功能

    搜索功能应该在对应的​​tab​​下进行,因此我们可以将输入的内容设置为一个​​状态​​,每次改变就根据​​tab​​内容和输入内容重新获取数据:

    api接口对订单数据的请求的封装中增加一个​​query​​限制:

    export const getOrder = ({ tab,query}) =>

    axios

    .get(https://www.fastmock.site/mock/759aba4bef0b02794e330cccc1c88555/beers/order)

    .then ( res => {

    let result=res.data;

    if(tab){

    switch(tab) {

    case "待支付":

    result=result.filter(item => item.state=="待支付");

    break;

    case "待发货":

    result=result.filter(item => item.state=="待发货");

    break;

    case "待收货/使用":

    result=result.filter(item => item.state=="待收货/使用");

    break;

    case "评价":

    result=result.filter(item => item.state=="评价");

    break;

    case "退款":

    result=result.filter(item => item.state=="退款");

    break;

    default:

    break;

    }

    }

    if(query) {

    result = result.filter(item => item.title.includes(query));

    }

    return Promise.resolve({

    result

    });

    }

    )

    而在组件的实现上,由于页面没有添加点击搜索的按钮,如果将​​input​​中的​​value​​直接和​​query​​状态绑定的话,每次用户输入一个字就会进行一次查询,触发太频繁,性能不够好,用户体验也不好。所以这里我的想法是每次输入完按下​​enter​​才进行搜索

    但是React中无法直接对​​input​​的​​enter​​事件进行处理。于是我在网上查阅到两种处理方式,第一种是通过 ​​e.nativeEvent​​ 来获取​​keyCode​​判断是否为 13 ,第二中方法是通过​​addEventListener​​注册事件来处理,要慎用。这里采用第一种方法来实现:

    import React,{ useState} from react

    import { OrderWrapper } from ./style

    export default function Myorder() {

    const [query,setQuery] = useState();

    const handleEnterKey = (e) => {

    if(e.nativeEvent.keyCode === 13){

    setQuery(e.target.value);

    }

    }

    return (

    ...

    placeholder="搜索订单"

    onKeyPress={ handleEnterKey}

    />

    ...

    )

    }2.4 设置loading状态

    在数据请求过程之,页面会空白,为了提升视觉上的效果,在这个时间段我们就设置一个​​loading​​样式,这个样式组件我们直接使用​​reacct-weui​​的​​Toast​​组件。

    我们增加一个​​loading​​状态来来控制​​Toast​​的显示。

    import React,{ useEffect, useState} from react

    import { OrderWrapper } from ./style

    import WeUI from react-weui

    const {

    Toast

    } = WeUI;

    export default function Myorder() {

    const [loading,setLoading]=useState(false);

    useEffect(()=>{

    setLoading(true);

    (async()=>{

    const { result} = await getOrder({ tab});

    setList([

    ...result

    ])

    setLoading(false);

    })()

    },[tab])

    return (

    ...

    加载中...

    { list.length>0 &&

    ...

    )

    }

    实现效果如图:

    2.5 实现Empty(空状态)组件

    空状态组件,顾名思义就是当请求到的数据为空或者是数据长度为 0 时,就显示该组件。这个组件实现起来比较简单,因此这里我们直接写在​​myorder​​组件中,用​​styled-components​​实现效果。

    import React,{ useEffect, useState} from react

    import { OrderWrapper,EmptyItem } from ./style

    import OrderList from ./OrderList

    import empty from ../../assets/images/empty.png

    export default function Myorder() {

    const [list,setList] = useState([]);

    ...

    return (

    ...

    { list.length>0&&}

    { list.length==0&&loading==false&&

    美好生活  触手可得

    暂无订单

    你还没有产生任何订单

    }

    ...

    )

    }

    完成上面这些业务,​​myorder​​组件就完成的差不多啦~

    3. 实现 OederList 组件

    这个组件只需要将父组件​​myorder​​传进来的数组数据通过 ​​map​​ 分配给 ​​OederNote​​,另外删除功能在它的子组件​​OrderNote​​上触发,需要通过它解构出​​deleteOrder​​函数传给​​OrderNote​​

    import React from react

    import { OrderListWrapper } from ./style

    export default function OrderList({ list,deleteOrder}) {

    return (

    美好生活  触手可得

    {

    list.map(item => (

    deleteOrder(item.id)}/>

    ))

    }

    )

    }

    4. 实现 OrderNote 组件

    该组件主要负责实现订单的展示效果,这里只展示部分代码

    import React from react

    import { NoteWrapper } from ./style

    const OrderNote = (props) => {

    const { data } =props;

    const { deleteOrder } =props

    return (

    ...

    )

    在这个组件可以触发删除订单的业务,具体如何删除我们只需要在父组件​​myOrder​​实现,然后将函数传递到​​OrderNote​​触发

    在​​myOrder​​组件添加​​deleteOrder​​函数:

    import React from react

    import OrderList from ./OrderList

    export default function Myorder() {

    const deleteOrder = (id) => {

    setList(list.filter(order => order.id!==id));

    }

    ...

    return (

    ...

    { list.length>0&&}

    ...

    )

    }

    5. 实现 RecommendList 组件

    该组件也是对从父组件​​Myorder​​获取来的数据进行展示,主要是做样式上的功夫。使用多列布局,将页面分为两列,并且不固定每个数据盒子的高度。

    最外层列表盒子加上属性:  column-count:2; 将页面分为两列列表中的每一个单独的小盒子添加属性:break-inside:avoid; 控制文本块分解成单独的列,以免项目列表的内容跨列,破坏整体的布局图片的宽度设置:width:100%

    多列布局注意上面三点就差不多了

    最后

    以上就是目前完成整个组件设计、封装的过程啦,后面会去继续学习下拉刷新、上拉加载等功能,慢慢完善这个组件。希望本篇文章对你也有帮助,你的

    很赞哦!(66)