美文网首页
Antd Pro2中使用Antd部分技巧总结(一)

Antd Pro2中使用Antd部分技巧总结(一)

作者: 敏0321 | 来源:发表于2019-11-04 21:32 被阅读0次

    Antd样式覆盖

    项目中肯定需要部分页面对原有的antd样式做修改,刚开始弄的时候遇到不少坑,后来查了方法和本项目中的写法,主要修改的思路是:

    1. 用chrome的开发者工具定位到要修改的div,查看class名
    2. 在对应的less样式下,增加 :global 字段,再写入对应的class名,做样式修改
    3. :global 需要包在自己页面的 module 类内,以防污染其他页面的全局样式
    // 这里采用了less作为css预处理器
    :global {
      // Tab 样式修改
      .ant-tabs-nav .ant-tabs-tab {
        line-height: 20px;
        padding: 13px 0 17px;
        margin: 0 47px 0 0;
        font-family: PingFangSC-Regular;
        font-size: 14px;
        color: #4a4a4a;
        text-align: center;
      }
    }
    

    单页面多表单取值

    当负责的页面涉及到需要很多表单的时候,例如绑定邮箱、手机的步骤验证或修改密码等,会出现单页面多表单这种情况。一般会分为两种:

    1. 一种是两个以上表单同时独立存在
    2. 一种是一个表单出现会销毁上一个表单
      情况1的处理
      以手机/邮箱注册为例
      Tabs+Form
      因为在Antd中,Tabs组件是带缓存的,所以在包含Tabs的页面中,“手机注册”和“邮箱注册”的表单是同时存在的,这时候要对提交按钮的方法做一下处理,防止出现提交当前页面的值去校验另一个页面的表单的情况。
      可以利用Form的getFieldsValue方法的第一个参数,自定义获取几组控件的值。
      例如:
      handleSubmitStepOne = e => {
        e.preventDefault();
        const { form, dispatch } = this.props;
        if (isSelectedEmail) {
          form.validateFields(['email', 'captchaEmail'], (errors, values) => {
            if (!errors) {
              // 你的业务逻辑
            }
          });
        } else {
          form.validateFields(['phone', 'country', 'captchaPhone'], (errors, values) => {
            if (!errors) {
              // 你的业务逻辑
            }
          });
        }
      };
    

    同时需要搭配tabs获取当前页面key的做法,来判断当前页面是哪个。

      情况2的处理
    以按照步骤条注册的表单为例

    带步骤条的表单
    针对这种场景有两种思路:
    1. 用变量控制FormItem
    2. 采用组件化的实现,抽离表单组件
      这里以带验证码按钮的抽离表单组件为例
      子组件需要提供如下方法:
    方法/参数 说明 类型
    type 可以让表单对应不同的校验规则或发送提示等,增加表单复用的可能性 “email”/“phone”
    getCaptcha 父组件需要传入的验证码发送接口,需要返回true或false表示发送成功或失败 Function
    getItemsValue 向父组件返回表单的值,父组件调用此方法 Function

    子组件写法

    import React, {Component} from 'react';
    import {Button, Col, Form, Input, message, Row} from "antd";
    import style from "./index.less";
    
    const FormItem = Form.Item;
    
    @Form.create()
    class VerifiedForm extends Component {
      state = {
        count: 0,
        captchaLoading: false,
      };
    
      componentWillUnmount() {
        clearInterval(this.interval);
      }
    
      // 向父组件传form表单的值
      getItemsValue = () => {
        let value = '';
        this.props.form.validateFields((err, values) => {
          if (!err) {
            value = values;
          }
        });
        return value;
      };
    
      // 获取验证码按钮点击
      onGetCaptcha = (type) => {
        this.setState({captchaLoading: true});
        // 获取到父组件传过来的验证码发送接口
        this.props.getCaptcha()
          .then(res => {
            if (res === true) {
              // 开始倒计时
              message.success(type === 'email' ? '邮箱验证码已发送' : '手机号验证码已发送');
              let count = 59;
              this.setState({count, captchaLoading: false});
              this.interval = setInterval(() => {
                count -= 1;
                this.setState({count});
                if (count === 0) {
                  clearInterval(this.interval);
                }
              }, 1000);
            } else {
              this.setState({captchaLoading: false});
            }
          })
      };
    
      render() {
        const {form: {getFieldDecorator}, type} = this.props;
        const {count, captchaLoading} = this.state;
        return (
          <Form onSubmit={this.handleSubmit}>
            <FormItem>
              <Row gutter={16}>
                <Col span={16}>
                  {getFieldDecorator('captcha', {
                    rules: [
                      {
                        required: true,
                        message: '验证码不能为空',
                      },
                    ],
                  })(<Input size="large" placeholder="请输入验证码" />)}
                </Col>
                <Col span={8}>
                  <Button
                    size="large"
                    style={{width: '100%'}}
                    disabled={count}
                    className={style.getCaptcha}
                    onClick={(e) => this.onGetCaptcha(type, e)}
                    loading={captchaLoading}
                  >
                    {count ? `${count} s` : '获取验证码'}
                  </Button>
                </Col>
              </Row>
            </FormItem>
          </Form>
        )
      }
    }
    
    export default VerifiedForm;
    

    “获取验证码”按钮的倒计时和恢复,以及表单校验的逻辑都可以在表单组件中完成。只把需要的验证码发送接口和获取表单值的方法暴露给父组件。

    父组件写法

    <div>
        <VerifiedForm
          // antd提供的方法获取到表单组件的ref
          wrappedComponentRef={form => {
            this.form = form;
          }}
          // sendEmailCaptcha方法中包含验证码发送接口
          getCaptcha={this.sendEmailCaptcha}
          type="email"
        />
        <Button
          size="large"
          type="primary"
          loading={loadingCheckBindEmailCaptcha}
          style={{ width: '100%', marginTop: 8 }}
          onClick={this.handleClick}
          disabled={!hasSendCaptcha}
        >
          下一步
        </Button>
    </div>
    

    提交表单的按钮需放在父组件,通过按钮handleClick方法调用表单组件的values值

    handleClick = () => {
        // 此处获取表单值
        const values = this.form.getItemsValue();
        // 业务逻辑
    }
    

    响应式布局

    这里用到了媒体查询,它有两种方式。

    1. 直接写在link中,根据设备尺寸的不同引入不同的CSS文件
    // 意思是当屏幕的宽度 大于等于400px的时候,应用styleA.css
    <link rel="stylesheet" type="text/css" href="styleA.css" media="screen and (min-width: 400px)">
    
    1. 写在<style>样式里
    @media screen and (max-width: 600px) { /*当屏幕尺寸小于600px时,应用下面的CSS样式*/
          .class {
              background: #ccc;
           }          
      }
    

    项目中用的是方式二,值得注意的是@media screen要放在对应的样式尾部,有层级关系!
    关键字

    类型 解释
    and 并关系,用于连接逻辑
    not 排除某种设备
    all 所有设备
    aural 听觉设备
    braille 点字触觉设备
    handled 便携设备,如手机、平板电脑
    print 打印预览图等
    projection 投影设备
    screen 显示器、笔记本、移动端等设备
    tty 如打字机或终端等设备
    tv 电视机等设备类型
    embossed 盲文打印机

    出现滚动条的高度计算

    首先明确

    • window.innerHeight: 获取浏览器窗口的高度
    • document.body.clientHeight: 获取body的高度
      出现这两种,一部分是为了解决不同浏览器的兼容性问题,还有移动web宽高的问题。在一般情况下两个值是相等的,但是在页面出现滚动条的情况下,innerHeight的计算会加入滚动条的height。
      所以在动态计算页面最小高度时,需要两者相减。参考如下代码:
    minHeight: `calc(100vh - 198px - ${window.innerHeight - document.body.clientHeight}px)`,
    

    多条件筛选

    按钮筛选案例

    针对react中使用多组按钮来控制筛选,可采用如下方法进行扩展。

    1. 全部按钮的value值为空字符
    2. 其余各个筛选按钮的value值对应后端传过来的值
      以“全部”、“iOS开发专家”、“Android开发专家”......这几个按钮为例。
        <RadioGroup
          value={identityStatus}
          onChange={e => this.handleChangeDataStatus(e)}
        >
          <RadioButton value="">全部</RadioButton>
          <RadioButton value="iOS开发专家">iOS开发专家</RadioButton>
          <RadioButton value="Android开发专家">Android开发专家</RadioButton>
          <RadioButton value="H5开发专家">H5开发专家</RadioButton>
          <RadioButton value="部署专家">部署专家</RadioButton>
          <RadioButton value="后端开发专家">后端开发专家</RadioButton>
        </RadioGroup>
    

    筛选方法

    // 两组按钮各自的选择状态
    const { reviewStatus, identityStatus } = this.state;
    // 过滤方法
    tempDataSource = tempDataSource.filter(item => {
      // 设定初始flag状态
      let flagReview = !reviewStatus;
      let flagIdentity = !identityStatus;
     // 第一组按钮过滤
      if (reviewStatus && item.reviewStatus) {
        flagReview = true;
      }
     // 第二组按钮过滤
      if (identityStatus && identityStatus === item.type) {
        flagIdentity = true;
      }
      return flagReview && flagIdentity;
    });
    this.setState({ dataSource: tempDataSource });
    

    相关文章

      网友评论

          本文标题:Antd Pro2中使用Antd部分技巧总结(一)

          本文链接:https://www.haomeiwen.com/subject/jandbctx.html