基于react和antd二次封装公共搜索组件

基于react和antd二次封装公共搜索组件


前言

你是否曾经在使用 React 和 Ant Design 构建前端应用时,发现自己反复编写相似的组件代码?是否曾感到组件的维护和定制变得繁琐?如果是的话,你并不孤单,因为这是前端开发中常见的问题之一。

在本篇技术分享博客中,我们将探讨如何通过二次封装 Ant Design 组件来提高 React 应用的开发效率和可维护性。我们将分享实用的技巧和最佳实践,帮助你更好地理解组件封装的重要性,以及如何精确地进行二次封装,使你的项目变得更加高效、灵活和易于维护。

无论你是 React 初学者还是经验丰富的前端工程师,本博客都将为你提供有价值的见解。让我们一起深入探讨这个令人兴奋的主题,为构建更好的前端应用打下坚实的基础。


提示:以下是本篇文章正文内容,下面案例可供参考

一、为什么 React 组件封装很重要?

React 组件封装是前端开发中的关键概念,它涉及将可复用的 UI 元素打包成独立的组件,以便在整个应用程序中重复使用。以下是一些关于 React 组件封装重要性的观点,可以包括在你的文章中:

  1. 代码复用和可维护性: React 组件封装允许你将功能性和界面元素封装在一个独立的单元中。这意味着你可以轻松地在项目中重复使用这些组件,从而减少了重复编写相似代码的需求。这不仅提高了代码复用性,还使代码更易于维护,因为你只需在一个地方进行更改,即可在整个应用程序中应用更新。

  2. 可定制性: 通过封装组件,你可以提供一组可配置的属性(props),使组件能够满足不同项目的需求。这增加了组件的灵活性,可以根据不同情况进行自定义。

  3. 降低错误率: 组件封装有助于减少人为错误的发生。当你构建并测试一个组件一次后,它可以在多个地方使用,减少了复制粘贴代码可能导致的错误。

  4. 团队协作: 在团队环境中,组件封装有助于提高开发者之间的协作效率。团队成员可以更容易地理解和使用封装的组件,而不必深入了解组件的内部工作方式。

  5. 生态系统: React 社区拥有庞大的第三方组件库,这些库通常是通过组件封装来实现的。通过了解组件封装的原理,你可以更好地利用和贡献给这些生态系统。

  6. 未来扩展性: 随着项目的增长和演化,你可能需要对组件进行更新和扩展。良好封装的组件更容易扩展和维护,从而有助于项目的长期成功。

二、使用步骤

1.引入库

代码如下(示例):

// 引入 React 和 antd 的组件
import React, { Component, Fragment } from 'react';
import { Form, Select, Input } from 'antd';
const FormItem = Form.Item;
const Option = Select.Option;
@Form.create()

2.封装公共组件

代码如下(示例):

import React, { Component, Fragment } from 'react';
import { Form, Input, InputNumber, Select, Button, Icon } from 'antd';

const { FormItem } = Form;
const { Option } = Select;

export default class Search extends Component {
  state = {
    expandForm: false, // 控制搜索表单的展开和收起状态,默认为收起
  };

  minInput = {}; // 用于保存最小值输入框的引用
  maxInput = {}; // 用于保存最大值输入框的引用

  componentDidMount() {
    let { expandForm } = this.props;
    // 如果从父组件传递了expandForm属性,则在组件挂载时设置表单展开状态
    if (expandForm != undefined) {
      this.setState({ expandForm });
    }
  }

  // 用于清空表单内容的生命周期钩子
  componentWillReceiveProps(nextProps, nextContext) {
    if (nextProps.isReset != undefined && nextProps.isReset) {
      // 如果从父组件传递了isReset属性且为true,则重置表单字段
      this.props.form.resetFields();
    }
  }

  // 数字输入框的值改变事件处理函数
  inputnumOnChange = (e, val, type) => {
    if (val.onChange) {
      // 如果输入框定义了onChange属性,则调用它,并传递事件和类型
      val.onChange(e, type);
    }
  };

  // 封装输入框和下拉选择框组件的渲染函数
  renderFormItem = (val, index) => {
    const { form: { getFieldDecorator } } = this.props;

    if (val.type === 'input') {
      // 渲染输入框
      return (
        <FormItem key={index} style={{ width: 230 }} label={val.label}>
          {getFieldDecorator(val.name)(<Input maxLength={250} style={{ width: 150 }} placeholder={val.placeholder} />)}
        </FormItem>
      );
    } else if (val.type === 'inputnum_double') {
      // 渲染数字输入框(双值)
      return (
        <FormItem key={index} style={{ width: val.width ? val.width : 270 }} label={val.label}>
          <div style={{ display: 'flex' }}>
            {getFieldDecorator(val.name1, {
              initialValue: val.initialValue1,
            })(<InputNumber
              style={{ width: val.inputWidth != undefined ? val.inputWidth : 80 }}
              placeholder={val.placeholder}
              min={val.min !== undefined ? val.min : 0}
              max={val.max !== undefined ? val.max : 9999999}
              precision={val.precision != undefined ? val.precision : 2}
              onChange={(e) => this.inputnumOnChange(e, val, 'min')}
            />)}
            <span style={{ width: 10, color: '#333333', textAlign: 'center' }}>-</span>
            {getFieldDecorator(val.name2, {
              initialValue: val.initialValue2,
            })(<InputNumber
              style={{ width: val.inputWidth != undefined ? val.inputWidth : 80 }}
              placeholder={val.placeholder}
              min={val.min !== undefined ? val.min : 0}
              max={val.max !== undefined ? val.max : 9999999}
              precision={val.precision != undefined ? val.precision : 2}
              onChange={(e) => this.inputnumOnChange(e, val, 'max')}
            />)}
          </div>
        </FormItem>
      );
    } else if (val.type === 'select') {
      // 渲染下拉选择框
      return (
        <FormItem key={index} style={{ width: val.width != undefined ? val.width : 230 }} label={val.label}>
          {getFieldDecorator(val.name, {
            rules: val.rules,
          })(
            <Select
              placeholder={val.placeholder}
              style={{ width: val.selectWidth != undefined ? val.selectWidth : 150 }}
              getPopupContainer={(triggerNode) => triggerNode.parentNode}
              onChange={(value) => {
                // 下拉选择框的值改变时的事件处理函数
                this.sldHandSeleChange(val, value);
                if (val.step === 1) {
                  // 如果定义了步骤为1,重置整个表单字段
                  this.props.form.resetFields();
                } else if (val.step === 2) {
                  // 如果定义了步骤为2,重置指定字段
                  this.props.form.resetFields(['cateId3']);
                }
              }}
            >
              {val.sel_data != null &&
                val.sel_data.map((items, indexs) => {
                  return (
                    <Option
                      key={indexs}
                      value={val.diy != undefined && val.diy ? items[val.sele_key] : items.key}
                    >
                      {val.diy != undefined && val.diy ? items[val.sele_name] : items.name}
                      {val.remark !== undefined &&
                        items[val.remark] !== undefined &&
                        items[val.remark] !== null &&
                        items[val.remark] !== '' ? (
                        '(' + items[val.remark] + ')'
                      ) : (
                        ''
                      )}
                    </Option>
                  );
                })}
            </Select>
          )}
        </FormItem>
      );
    }
  };

  // 搜索重置事件处理函数
  handleFormReset = () => {
    const { form } = this.props;
    form.resetFields();
    // 调用父组件传递的seaReset函数
    this.props.seaReset();
  };

  // 搜索事件处理函数
  handleSearch = (e) => {
    e.preventDefault();
    const { form } = this.props;
    form.validateFieldsAndScroll((err, fieldsValue) => {
      if (err) return;
// 处理组件的值
        if ((fieldsValue.hasOwnProperty('marketPriceEnd') &&  fieldsValue.hasOwnProperty('marketPriceStart')) {
				   	this.props.form.resetFields([
                        'marketPriceEnd','marketPriceStart'
				   	])
			   	}
         // 调用父组件传递的seaSubmit函数,将表单字段值作为参数传递
      this.props.seaSubmit(fieldsValue);
    });
  };

      // 渲染搜索表单的前半部分,索引小于4的表单项
    renderSearchFirst = (search_data) => {
      return search_data.map((item, index) => {
        // 如果表单项的索引小于4,调用renderFormItem函数渲染该表单项
        return index < 4 ? this.renderFormItem(item, index) : null;
      });
    };

   // 渲染搜索表单的后半部分,索引大于3的表单项
    renderSearchSecond = (search_data) => {
      return search_data.map((item, index) => {
        // 如果表单项的索引大于3,调用renderFormItem函数渲染该表单项
        return index > 3 ? this.renderFormItem(item, index) : null;
      });
        };
     // 切换搜索表单的展开和收起状态
  toggleForm = () => {
    const { expandForm } = this.state;
    this.setState(
      {
        expandForm: !expandForm,
      },
      () => {
        // 如果定义了moreSearchToggle属性,则调用它
        if (this.props.moreSearchToggle) this.props.moreSearchToggle();
      }
    );
  };

  // 渲染搜索表单
  renderSimpleForm() {
    const { search_data, top } = this.props;
    const { expandForm } = this.state;
    return (
      search_data.length > 0 && (
        <Form onSubmit={this.handleSearch} ref={'sld_common_search_part'} layout="inline">
          {this.renderSearchFirst(search_data)}
          {expandForm && (
            <Fragment>
              {this.renderSearchSecond(search_data)}
            </Fragment>
          )}
          <span style={{ position: 'absolute', right: search_data.length > 4 ? 20 : 0, top: top != undefined ? top : 0 }}>
            <Button type="primary" htmlType="submit">
              搜索
            </Button>
            <Button style={{ marginLeft: 3, marginBottom: 10 }} onClick={this.handleFormReset}>
              重置
            </Button>
            {search_data.length > 4 && (
              <a style={{ marginLeft: 3, fontSize: 12, color: '#FF6A12' }} onClick={this.toggleForm}>
                {expandForm ? '收起' : '展开'} <Icon type={expandForm ? 'up' : 'down'} />
              </a>
            )}
          </span>
        </Form>
      )
    );
  }

  render() {
    return this.renderSimpleForm();
  }
}

3.用法示例

代码如下(示例):

import React from 'react';
import Search from '@/Search'; // 导入外部的搜索组件

@Form.create() // 使用装饰器创建一个表单
export default class GoodsList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      formValues: {}, // 存储搜索条件的状态
      search: [
        {
          type: 'input',
          label: '商品名称',
          name: 'goodsName',
          placeholder: '请输入商品名称',
        },
        {
          type: 'inputnum_double',
          label: '市场价',
          name1: 'highPrice', // 输入框的最小值字段
          name2: 'PriceEnd', // 输入框的最大值字段
          initialValue1: '', // 初始的最小值
          initialValue2: '', // 初始的最大值
          placeholder: '请输入',
          onChange: (val, type) => {
            // 处理市场价范围的输入变化事件
            if (type === 'min') {
              let { search } = this.state;
              search[1].initialValue1 = val;
              this.setState({ search });
            } else if (type === 'max') {
              let { search } = this.state;
              search[1].initialValue2 = val;
              this.setState({ search });
            }
          },
        },
        {
          type: 'select',
          label: '商品类型',
          name: 'commodityType',
          placeholder: '请选择商品类型',
          sel_data: [
            { key: ' ', name: '全部' },
            { key: '1', name: '虚拟' },
            { key: '2', name: '实物' },
          ],
        },
      ],
    };
  }

  // 组件卸载时移除窗口大小改变的事件监听
  componentWillUnmount() {
    window.removeEventListener('resize', this.resize);
  }

  // 监听窗口大小变化的函数
  resize = () => {
    const { search_height } = this.state;
    if (this.refs.search_part !== undefined) {
      if (this.refs.search_part.clientHeight !== search_height) {
        this.setState({ search_height: this.refs.search_part.clientHeight });
      }
    }
  };

  // 搜索事件处理函数
  search = (data) => {
    let { search, formValues } = this.state;
    const values = { ...data };

    // 如果市场价的最小值大于最大值,则交换它们
    if (
      search_data[1].initialValue1 !== '' &&
      search_data[1].initialValue2 !== '' &&
      search_data[1].initialValue1 > search_data[1].initialValue2
    ) {
      let temp = search_data[1].initialValue1;
      search_data[1].initialValue1 = search_data[1].initialValue2;
      search_data[1].initialValue2 = temp;
      let temps = values.highPrice;
      values.highPrice = values.PriceEnd;
      values.PriceEnd = temps;
    }

    // 更新状态,包括搜索数据、搜索条件和参数
    this.setState({
      search,
      formValues: values,
      params: { pageSize: 10 },
    });

    // 调用获取列表数据的函数,并传入参数
    this.get_list({ pageSize: 10, ...values });
  };

  // 搜索重置事件处理函数
  seaReset = () => {
    let { search } = this.state;

    // 将市场价的最小值和最大值重置为空
    search_data[1].initialValue1 = '';
    search_data[1].initialValue2 = '';

    // 清空搜索条件
    this.setState({
      search,
      formValues: {},
      params: { pageSize: 10 },
    });

    // 调用获取列表数据的函数,并传入参数
    this.get_list({ pageSize: 10 });
  };

  // 点击展开/折叠更多搜索条件
  moreSearchToggle = () => {
    const { search_height } = this.state;
    if (this.refs.search_part !== undefined) {
      if (this.refs.search_part.clientHeight !== search_height) {
        this.setState({ search_height: this.refs.search_part.clientHeight });
      }
    }
  };

  render() {
    const { search, search_height } = this.state;
    return (
      <div ref={'search_part'}>
        {/* 渲染搜索组件,传递搜索数据、展开/折叠搜索条件、提交搜索和重置搜索的回调函数 */}
        <Search
          search_data={search}
          moreSearchToggle={() => this.moreSearchToggle()}
          seaSubmit={(data) => this.search(data)}
          seaReset={() => this.seaReset()}
        />
      </div>
    );
  }
}

你可以根据我的写法加上其他的antd组件

4.样式示例


总结

总而言之,React 组件封装是前端开发中不可或缺的一部分。在本文中,我们探讨了为什么它如此重要,并提供了一些有关如何更好地封装和应用组件的实用技巧。

通过组件封装,我们能够实现代码的复用,提高可维护性,减少错误,并更好地协作。它不仅可以在个人项目中发挥作用,还有助于更广泛的 React 社区生态系统的发展。

我鼓励你在你的下一个 React 项目中尝试这些技巧,并深入了解组件封装的概念。随着你的经验的增长,你将发现它们是构建出色前端应用的关键。

无论你是初学者还是有经验的开发者,都应该牢记 React 组件封装的价值,以便在不断变化的前端开发领域中脱颖而出。 谢谢你阅读这篇文章,希望它对你有所帮助!

  • 12
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你也喜欢写代码吗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值