# Slider 滑块/进度条

- 来源：[E10 UI 组件库](https://www.e-cology.com.cn/ui/slider/freepass)
- 平台：PC
- 维护者：赵俊飞
- 设计稿：http://pd.e-cology.com.cn/pd/E10/interface/e10xiaoguotu/PC/E10zjys/#s22
- Issue：http://gitlab.ecology10.cn/FRONTEND/weapp-ui/-/issues?state=all&search=[Slider]

## 代码演示

### 基础用法

用户可以使用滑块控件在某一范围内取值。当disabled为true时，滑块处于禁用状态。

```jsx
import React, { Component } from 'react';
import { constants, Slider } from '@weapp/ui';

const prefixCls = `${constants.uiPcClsPrefix}-demo-slider`;

type SelectDemoState = {
  value: number;
}

class SliderDemo extends Component<any, SelectDemoState> {
  constructor(props: any) {
    super(props);
    this.state = {
      value: 50,
    };
  }

  render() {
    function log(value: any) {
      console.log(value);
    }
    const style = { width: 600, margin: "50px 0", };

    return (
      <div className={prefixCls}>
        <div style={style}>
          <h3>普通使用</h3>
          <Slider showToolips defaultValue={20} onChange={log} />
        </div>
        <div style={style}>
          <h3>禁用</h3>
          <Slider showToolips defaultValue={30} showPercent onChange={log} disabled />
        </div>
      </div>
    );
  }
}

export default SliderDemo;
```

### 步长滑块

为滑块的间隔设定固定值，可针对每一步设定对应的圆点标记。

```jsx
import React, { Component } from 'react';
import { constants, Slider } from '@weapp/ui';

const prefixCls = `${constants.uiPcClsPrefix}-demo-slider`;

type SelectDemoState = {
  value: number;
}

const marks = {
  0: 0,
  10: 10,
  20: 20,
  30: 30,
  40: 40,
  50: 50,
  60: 60,
  70: 70,
  80: 80,
  90: 90,
  100: 100,
}
class SliderDemo extends Component<any, SelectDemoState> {
  constructor(props: any) {
    super(props);
    this.state = {
      value: 50,
    };
  }

  render() {
    function log(value: any) {
      console.log(value);
    }
    const style = { width: 600, margin: "50px 0", };
    return (
      <div className={prefixCls}>
        <div style={style}>
          <h3>步长, `step=10 dots`</h3>
          <Slider marks={marks} showToolips dots step={10} defaultValue={50} onBeforeChange={log} />
        </div>
        <div style={style}>
          <h3>步长，标记`step=20`</h3>
          <Slider showToolips step={20} defaultValue={40} onAfterChange={log} />
        </div>
        <div style={style}>
          <h3>步长, `step=10` 禁用</h3>
          <Slider dots step={10} defaultValue={30} disabled />
        </div>
      </div>
    );
  }
}

export default SliderDemo;
```

### 带输入框的滑块

滑块值和数组输入框组件保持同步，可以互相修改。

```jsx
import React, { Component } from 'react';
import { constants, Slider, Input, Layout } from '@weapp/ui';

const { InputNumber } = Input;
const { Row, Col } = Layout;

const prefixCls = `${constants.uiPcClsPrefix}-demo-slider`;

type SelectDemoState = {
  value: number;
}

class SliderDemo extends Component<any, SelectDemoState> {
  timer: any;
  constructor(props: any) {
    super(props);
    this.state = {
      value: 0,
    };
  }

  onChange = (value: React.ReactText) => {
    this.setState({ value: value as number })
  }

  render() {
    const { value } = this.state;
    const style = { width: 600, margin: "50px 0", };

    return (
      <div className={prefixCls}>
        <div style={style}>
          <h3>输入框联动滑块</h3>
          <Row style={{ display: 'flex', alignItems: 'center' }}>
            <Col span={12}>
              <Slider value={value} showToolips onChange={this.onChange} />
            </Col>
            <Col span={4}>
              <InputNumber value={value} onChange={this.onChange} style={{ margin: '0 16px' }} min={0} max={100} />
            </Col>
          </Row>
        </div>
      </div>
    );
  }
}

export default SliderDemo;
```

### 其他属性

设置 reverse 可以将滑块置反；startPoint 可以定义初始位置；showPercent 可以显示百分比；readOnly 设置只读。

```jsx
import React, { Component } from 'react';
import { constants, Slider } from '@weapp/ui';

const prefixCls = `${constants.uiPcClsPrefix}-demo-slider`;

type SelectDemoState = {
  value: number;
}

const marks = {
  0: 0,
  20: 20,
  40: 40,
  60: 60,
  80: 80,
  100: 100
}

class SliderDemo extends Component<any, SelectDemoState> {
  constructor(props: any) {
    super(props);
    this.state = {
      value: 50,
    };
  }

  render() {
    function log(value: any) {
      console.log(value); //eslint-disable-line
    }
    const style = { width: 600, margin: "50px 0", };

    return (
      <div className={prefixCls}>
        <div style={style}>
          <h3>反转使用</h3>
          <Slider showToolips step={10} marks={marks} defaultValue={10} onChange={log} reverse />
        </div>
        <div style={style}>
          <h3>定义起始位置 `startPoint=50`</h3>
          <Slider onChange={log} startPoint={50} />
        </div>
        <div style={style}>
          <h3>只读</h3>
          <Slider defaultValue={30} readOnly />
        </div>
        <div style={style}>
          <h3>显示百分比</h3>
          <Slider showPercent />
        </div>
      </div>
    );
  }
}

export default SliderDemo;
```

### 进度条(Progress)

进度条(默认左下角，支持自定义样式),可以设置每个阶段的文字状态。

```jsx
import React, { Component } from 'react';
import { Button, constants, Slider } from '@weapp/ui';

const { Progress } = Slider;

const prefixCls = `${constants.uiPcClsPrefix}-demo-slider`;

type SelectDemoState = {
  progressValue: number;
}

class SliderDemo extends Component<any, SelectDemoState> {
  timer: any;
  constructor(props: any) {
    super(props);
    this.state = {
      progressValue: 0,
    };
    this.timer = 0;
  }

  ticker = () => {
    if (this.timer) {
      return;
    }
    let progressValue = 0;
    let ticker = () => {
      this.timer = setTimeout(() => {
        progressValue += 1;
        if (progressValue >= 100) {
          // progressValue = 0;
          clearTimeout(this.timer);
          this.timer = null;
          ticker = () => { };
        }
        this.setState({
          progressValue
        });
        ticker();
      }, 1000 / 60);
    }
    ticker();
  }

  componentWillUnmount() {
    clearTimeout(this.timer);
    this.timer = null;
  }

  render() {

    const style = { width: 600, margin: "50px 0", };
    const textConfig = {
      text: { 0: '准备开始！', 20: '正在进行中……', 40: '一切顺利(^_^)', 60: '几乎要结束了！', 80: (<span style={{ color: "green" }}>完成!</span>) },
      className: "custom",
      // style: { color: '#369', background: "#acc", right: "0" },
    }
    return (
      <div className={prefixCls}>
        <div style={style}>
          <h3>进度条</h3>
          <Progress
            textConfig={textConfig}
            value={this.state.progressValue} />
          <div style={{ marginTop: 30 }}>
            <Button onClick={this.ticker} type="primary">开始运行</Button>
          </div>
        </div>

      </div>
    );
  }
}

export default SliderDemo;
```

### Range 滑动条（范围滑块）

通过提供一个包含值的数组给 value 属性，您可以设置滑块的起始和终止值。

```jsx
import React, { Component } from 'react';
import { constants, Slider } from '@weapp/ui';

const { Range } = Slider;

const prefixCls = `${constants.uiPcClsPrefix}-demo-slider`;

type SelectDemoState = {
  value: number;
}

class SliderDemo extends Component<any, SelectDemoState> {
  constructor(props: any) {
    super(props);
    this.state = {
      value: 50,
    };
  }

  render() {
    function log(value: any) {
      console.log(value); //eslint-disable-line
    }
    const style = { width: 600, margin: "50px 0", };
    return (
      <div className={prefixCls}>
        <div style={style}>
          <h3>基本使用</h3>
          <Range showToolips defaultValue={[0, 20]} onChange={log} />
        </div>
        <div style={style}>
          <h3>禁用</h3>
          <Range defaultValue={[10, 30]} disabled />
        </div>
        <div style={style}>
          <h3>只读</h3>
          <Range defaultValue={[15, 35]} readOnly />
        </div>
      </div>
    );
  }
}

export default SliderDemo;
```

### Range 步长滑动条

可以设置step ，控制滑动条间隔，当 dots 为 true 时，展示间隔小圆点。

```jsx
import React, { Component } from 'react';
import { constants, Slider } from '@weapp/ui';

const { Range } = Slider;

const prefixCls = `${constants.uiPcClsPrefix}-demo-slider`;

type SelectDemoState = {}

const marks = {
  0: 0,
  10: 10,
  20: 20,
  30: 30,
  40: 40,
  50: 50,
  60: 60,
  70: 70,
  80: 80,
  90: 90,
  100: 100,
}

class SliderDemo extends Component<any, SelectDemoState> {
  constructor(props: any) {
    super(props);
  }

  render() {
    function log(value: any) {
      console.log(value); //eslint-disable-line
    }
    const style = { width: 600, margin: "50px 0", };
    return (
      <div className={prefixCls}>
        <div style={style}>
          <h3>步长, `step=10，dots`</h3>
          <Range marks={marks} showToolips dots step={10} defaultValue={[20, 30]} onBeforeChange={log} />
        </div>
        <div style={style}>
          <h3>步长，标记`step=20`</h3>
          <Range showToolips step={20} defaultValue={[20, 40]} onAfterChange={log} />
        </div>
        <div style={style}>
          <h3>步长，禁用</h3>
          <Range disabled showToolips dots step={10} defaultValue={[20, 50]} />
        </div>
      </div>
    );
  }
}

export default SliderDemo;
```

### Range 其他属性

设置 reverse 可以将滑块置反；设置 allowCross 可以禁止两个滑块交叉。

```jsx
import React, { Component } from 'react';
import { constants, Slider } from '@weapp/ui';

const { Range } = Slider;

const prefixCls = `${constants.uiPcClsPrefix}-demo-slider`;

type SelectDemoState = {}

class SliderDemo extends Component<any, SelectDemoState> {
  constructor(props: any) {
    super(props);
  }

  render() {
    function log(value: any) {
      console.log(value); //eslint-disable-line
    }
    const style = { width: 600, margin: "50px 0", };
    return (
      <div className={prefixCls}>
        <div style={style}>
          <h3>反转使用</h3>
          <Range showToolips defaultValue={[0, 20]} onChange={log} reverse />
        </div>
        <div style={style}>
          <h3>禁止交叉</h3>
          <Range allowCross={false} showToolips defaultValue={[10, 40]} onChange={log} />
        </div>
        <div style={style}>
          <h3>范围可拖拽</h3>
          <Range draggableTrack={true} showToolips defaultValue={[0, 20]} onChange={log} />
        </div>
      </div>
    );
  }
}

export default SliderDemo;
```

### 垂直

垂直方向的 Range 和 Slider。

```jsx
import React, { Component } from 'react';
import { constants, Slider } from '@weapp/ui';

const { Range } = Slider;

const prefixCls = `${constants.uiPcClsPrefix}-demo-slider`;

type SelectDemoState = {}

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

class SliderDemo extends Component<any, SelectDemoState> {
  constructor(props: any) {
    super(props);
  }

  render() {
    function log(value: any) {
      console.log(value); //eslint-disable-line
    }
    const style = { height: 300, margin: "0 50px", display: 'inline-block' };
    return (
      <div className={prefixCls}>
        <div style={style}>
          <Slider showToolips onChange={log} vertical />
          <h4>垂直 Slider</h4>
        </div>
        <div style={style}>
          <Range vertical showToolips defaultValue={[10, 40]} onChange={log} />
          <h4>垂直 Range</h4>
        </div>
        <div style={style}>
          <Range vertical  marks={marks} showToolips defaultValue={[26, 37]} onChange={log} />
          <h4>垂直 Range，step</h4>
        </div>
      </div>
    );
  }
}

export default SliderDemo;
```

### 自定义样式

通过属性，控制滑块样式或者滑过区域的样式。当 included=false 时，表明不包含端点。

```jsx
import React, { Component } from 'react';
import { constants, Slider } from '@weapp/ui';

const prefixCls = `${constants.uiPcClsPrefix}-demo-slider`;

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

class SliderDemo extends Component<any> {

  render() {
    function log(value: any) {
      console.log(value);
    }
    const style = { width: 600, margin: "50px 0", };

    return (
      <div className={prefixCls}>
        <div style={style}>
          <h3>自定义样式</h3>
          <Slider
            showToolips 
            defaultValue={20} 
            
            handleStyle={{background:'#fff',borderColor:'#ff8f1f'}}
            trackStyle={{background:'#ff8f1f'}}
            onChange={log} />
        </div>
        <div style={style}>
          <h3>自定义marks</h3>
          <Slider
            showToolips 
            defaultValue={37} 
            
            marks={marks}
            onChange={log} />
        </div>
        <div style={style}>
          <h3>included=false</h3>
          <Slider
            showToolips 
            defaultValue={37} 
            
            marks={marks}
            included={false}
            onChange={log} />
        </div>
      </div>
    );
  }
}

export default SliderDemo;
```

## API

### 参数说明如下：

| 参数 | 说明 | 类型 | 是否必填 | 默认值 |
| --- | --- | --- | --- | --- |
| value | 当前数(受控值) | number | 否 |  |
| defaultValue | 当前数(默认值) | number | 否 |  |
| min | 最小值 | number | 否 | 0 |
| max | 最大值 | number | 否 | 100 |
| step | 步长 | number\null | 否 |  |
| prefixCls | class 前缀 | string | 否 |  |
| onChange | 拖动时回调 | (value: number) => void | 否 |  |
| onBeforeChange | 拖动前回调 | (value: number) => {} | 否 |  |
| onAfterChange | 拖动后回调 | (value: number) => void | 否 |  |
| vertical | 是否垂直显示 | boolean | 否 | false |
| included | 是否包含端点 | boolean | 否 | true |
| disabled | 禁用 | boolean | 否 | false |
| readOnly | 只读 | boolean | 否 | false |
| reverse | 反转 | boolean | 否 | false |
| startPoint | 起始位置 | number | 否 | 0 |
| marks | 刻度标记，key 的类型必须为 `number` 且取值在闭区间 min, max 内，每个标签可以单独设置样式 | object | 否 | { number: ReactNode } or { number: { style: CSSProperties, label: ReactNode } } |
| minimumTrackStyle |  | CSSProperties | 否 |  |
| trackStyle | 滑块滑过区域样式控制 | CSSProperties | 否 |  |
| handleStyle | 滑块样式 | CSSProperties | 否 |  |
#### 仅供 range 和 slider 使用的参数

| 参数 | 说明 | 类型 | 是否必填 | 默认值 |
| --- | --- | --- | --- | --- |
| showPercent | 显示百分比 | boolean | 否 | false |
| showToolips | 是否显示滑块顶部的 toolips | boolean | 否 | false |
#### 仅供 range 参数

| 参数 | 说明 | 类型 | 是否必填 | 默认值 |
| --- | --- | --- | --- | --- |
| draggableTrack | 范围刻度是否可被拖拽 | boolean | 否 | false |
#### 仅供 progress 使用的参数

| 参数 | 说明 | 类型 | 是否必填 | 默认值 |
| --- | --- | --- | --- | --- |
| textConfig | 进度条文本控制 | Object<> | 否 |  |
