Ant Design学习——Slider

2021SC@SDUSC

Slider滑动输入条

用法:
滑动型输入器,展示当前值和可选范围。
当用户需要在数值区间/自定义区间内进行选择时,可为连续或离散值。

API

参数说明类型默认值
allowClear支持清除, 单选模式有效booleanfalse
defaultValue设置初始取值。当 range 为 false 时,使用 number,否则用 [number, number]number | [number, number]0 | [0, 0]
disabled值为 true 时,滑块为禁用状态booleanfalse
dots是否只能拖拽到刻度上booleanfalse
getTooltipPopupContainerTooltip 渲染父节点,默认渲染到 body 上(triggerNode) => HTMLElement() => document.body
includedmarks 不为空对象时有效,值为 true 时表示值为包含关系,false 表示并列booleantrue
marks刻度标记,key 的类型必须为 number 且取值在闭区间 [min, max] 内,每个标签可以单独设置样式object{ number: ReactNode } or { number: { style: CSSProperties, label: ReactNode } }
max最大值number100
min最小值number0
range双滑块模式boolean | rangefalse
reverse反向坐标轴booleanfalse
step步长,取值必须大于 0,并且可被 (max - min) 整除。当 marks 不为空对象时,可以设置 step 为 null,此时 Slider 的可选值仅有 marks 标出来的部分number | null1
tipFormatterSlider 会把当前值传给 tipFormatter,并在 Tooltip 中显示 tipFormatter 的返回值,若为 null,则隐藏 Tooltipvalue => ReactNode | nullIDENTITY
tooltipPlacement设置 Tooltip 展示位置。string-
tooltipVisible值为 true 时,Tooltip 将会始终显示;否则始终不显示,哪怕在拖拽及移入时boolean-
value设置当前取值。当 range 为 false 时,使用 number,否则用 [number, number]number | [number, number]-
vertical值为 true 时,Slider 为垂直方向booleanfalse
onAfterChangeonmouseup 触发时机一致,把当前值作为参数传入(value) => void-
onChange当 Slider 的值发生改变时,会触发 onChange 事件,并把改变后的值作为参数传入(value) => void-

range

参数说明类型默认值版本
draggableTrack范围刻度是否可被拖拽booleanfalse4.10.0

部分源码

SliderTooltip.tsx

import * as React from 'react';
import { useRef } from 'react';
import { composeRef } from 'rc-util/lib/ref';
import raf from 'rc-util/lib/raf';
import Tooltip, { TooltipProps } from '../tooltip';

const SliderTooltip = React.forwardRef<unknown, TooltipProps>((props, ref) => {
  const { visible } = props;
  const innerRef = useRef<any>(null);

  const rafRef = useRef<number | null>(null);

  function cancelKeepAlign() {
    raf.cancel(rafRef.current!);
    rafRef.current = null;
  }

  function keepAlign() {
    rafRef.current = raf(() => {
      innerRef.current?.forcePopupAlign();
      rafRef.current = null;
    });
  }

  React.useEffect(() => {
    if (visible) {
      keepAlign();
    } else {
      cancelKeepAlign();
    }

    return cancelKeepAlign;
  }, [visible, props.title]);

  return <Tooltip ref={composeRef(innerRef, ref)} {...props} />;
});

export default SliderTooltip;

运用到了raf
requestAnimationFrame(rAF)是浏览器用于定时循环操作的一个接口,类似于setTimeout,主要用途是按帧对网页进行重绘。
SliderTooltip结构较为简单,主要用到了tooltip,并设置了可见visible时就保持对齐的方法。
在这里插入图片描述
当 tooltipVisible 为 true 时,将始终显示 ToolTip;反之则始终不显示,即使在拖动、移入时也是如此。

index.tsx

import * as React from 'react';
import RcSlider, { Range as RcRange, Handle as RcHandle } from 'rc-slider';
import classNames from 'classnames';
import { TooltipPlacement } from '../tooltip';
import SliderTooltip from './SliderTooltip';
import { ConfigContext } from '../config-provider';

引入了react的slider,以及刚才提到的SliderTooltip。

export interface SliderMarks {
  [key: number]:
    | React.ReactNode
    | {
        style: React.CSSProperties;
        label: React.ReactNode;
      };
}

interface HandleGeneratorInfo {
  value?: number;
  dragging?: boolean;
  index: number;
}

export type HandleGeneratorFn = (config: {
  tooltipPrefixCls?: string;
  prefixCls?: string;
  info: HandleGeneratorInfo;
}) => React.ReactElement;

export interface SliderBaseProps {
  prefixCls?: string;
  tooltipPrefixCls?: string;
  reverse?: boolean;
  min?: number;
  max?: number;
  step?: null | number;
  marks?: SliderMarks;
  dots?: boolean;
  included?: boolean;
  disabled?: boolean;
  vertical?: boolean;
  tipFormatter?: null | ((value?: number) => React.ReactNode);
  className?: string;
  id?: string;
  style?: React.CSSProperties;
  tooltipVisible?: boolean;
  tooltipPlacement?: TooltipPlacement;
  getTooltipPopupContainer?: (triggerNode: HTMLElement) => HTMLElement;
  autoFocus?: boolean;
}

此处先设置了一些Slider的基础属性,比如可拖动性以及刻度标记。
Marks刻度标记,key 的类型必须为 number 且取值在闭区间 [min, max] 内,每个标签可以单独设置样式。使用Marks可标注分段式滑块。


以下代码可实现如下效果

import { Slider } from 'antd';

const marks = {
  0: '0°C',
  26: '26°C',
  37: '37°C',
  100: {
    style: {
      color: '#f50',
    },
    label: <strong>100°C</strong>,
  },
};

ReactDOM.render(
  <>
    <h4>included=true</h4>
    <Slider marks={marks} defaultValue={37} />
    <Slider range marks={marks} defaultValue={[26, 37]} />

    <h4>included=false</h4>
    <Slider marks={marks} included={false} defaultValue={37} />

    <h4>marks & step</h4>
    <Slider marks={marks} step={10} defaultValue={37} />

    <h4>step=null</h4>
    <Slider marks={marks} step={null} defaultValue={37} />
  </>,
  mountNode,
);

在这里插入图片描述
当 included=false 时,表明不同标记间为并列关系。
当 step=null 时,Slider 的可选值仅有 marks 标出来的部分。


以下接index

export interface SliderSingleProps extends SliderBaseProps {
  range?: false;
  value?: number;
  defaultValue?: number;
  onChange?: (value: number) => void;
  onAfterChange?: (value: number) => void;
  handleStyle?: React.CSSProperties;
  trackStyle?: React.CSSProperties;
}

export interface SliderRangeProps extends SliderBaseProps {
  range: true | SliderRange;
  value?: [number, number];
  defaultValue?: [number, number];
  onChange?: (value: [number, number]) => void;
  onAfterChange?: (value: [number, number]) => void;
  handleStyle?: React.CSSProperties[];
  trackStyle?: React.CSSProperties[];
}

两种slider,single和range,都继承自SliderBaseProps,相当于都有了Slider基础的属性,区别主要是range是双滑块因此值应该是个范围。
以下分别是single和range
在这里插入图片描述

const Slider = React.forwardRef<unknown, SliderSingleProps | SliderRangeProps>(
  (props, ref: any) => {
    const { getPrefixCls, direction, getPopupContainer } = React.useContext(ConfigContext);
    const [visibles, setVisibles] = React.useState<Visibles>({});

    const toggleTooltipVisible = (index: number, visible: boolean) => {
      setVisibles((prev: Visibles) => ({ ...prev, [index]: visible }));
    };

    const getTooltipPlacement = (tooltipPlacement?: TooltipPlacement, vertical?: boolean) => {
      if (tooltipPlacement) {
        return tooltipPlacement;
      }
      if (!vertical) {
        return 'top';
      }
      return direction === 'rtl' ? 'left' : 'right';
    };

    const handleWithTooltip: HandleGeneratorFn = ({
      tooltipPrefixCls,
      prefixCls,
      info: { value, dragging, index, ...restProps },
    }) => {
      const {
        tipFormatter,
        tooltipVisible,
        tooltipPlacement,
        getTooltipPopupContainer,
        vertical,
      } = props;
      const isTipFormatter = tipFormatter ? visibles[index] || dragging : false;
      const visible = tooltipVisible || (tooltipVisible === undefined && isTipFormatter);
      const rootPrefixCls = getPrefixCls();

      return (
        <SliderTooltip
          prefixCls={tooltipPrefixCls}
          title={tipFormatter ? tipFormatter(value) : ''}
          visible={visible}
          placement={getTooltipPlacement(tooltipPlacement, vertical)}
          transitionName={`${rootPrefixCls}-zoom-down`}
          key={index}
          overlayClassName={`${prefixCls}-tooltip`}
          getPopupContainer={getTooltipPopupContainer || getPopupContainer}
        >
          <RcHandle
            {...restProps}
            value={value}
            onMouseEnter={() => toggleTooltipVisible(index, true)}
            onMouseLeave={() => toggleTooltipVisible(index, false)}
          />
        </SliderTooltip>
      );
    };

    const {
      prefixCls: customizePrefixCls,
      tooltipPrefixCls: customizeTooltipPrefixCls,
      range,
      className,
      ...restProps
    } = props;
    const prefixCls = getPrefixCls('slider', customizePrefixCls);
    const tooltipPrefixCls = getPrefixCls('tooltip', customizeTooltipPrefixCls);
    const cls = classNames(className, {
      [`${prefixCls}-rtl`]: direction === 'rtl',
    });

    // make reverse default on rtl direction
    if (direction === 'rtl' && !restProps.vertical) {
      restProps.reverse = !restProps.reverse;
    }

    // extrack draggableTrack from range={{ ... }}
    let draggableTrack: boolean | undefined;
    if (typeof range === 'object') {
      draggableTrack = range.draggableTrack;
    }

    if (range) {
      return (
        <RcRange
          {...(restProps as SliderRangeProps)}
          step={restProps.step!}
          draggableTrack={draggableTrack}
          className={cls}
          ref={ref}
          handle={(info: HandleGeneratorInfo) =>
            handleWithTooltip({
              tooltipPrefixCls,
              prefixCls,
              info,
            })
          }
          prefixCls={prefixCls}
        />
      );
    }
    return (
      <RcSlider
        {...(restProps as SliderSingleProps)}
        step={restProps.step!}
        className={cls}
        ref={ref}
        handle={(info: HandleGeneratorInfo) =>
          handleWithTooltip({
            tooltipPrefixCls,
            prefixCls,
            info,
          })
        }
        prefixCls={prefixCls}
      />
    );
  },
);

forwardRef函数,用到了之前引入的tooltip,并利用react的slider进行实现。
其中
rtl用于方向的反转,从左到右变成从右到左。
draggableTrack用于设置范围刻度整体可拖动的属性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值