New Huajishe Check ChaoXing

This commit is contained in:
e2hang
2025-10-01 10:01:52 +08:00
parent 240b884eac
commit 80be8ae3cf
1094 changed files with 61709 additions and 0 deletions

View File

@@ -0,0 +1,66 @@
:: BASE_DOC ::
## API
### Slider Props
name | type | default | description | required
-- | -- | -- | -- | --
style | Object | - | CSS(Cascading Style Sheets) | N
custom-style | Object | - | CSS(Cascading Style Sheets)used to set style on virtual component | N
colors | Array | [] | `deprecated`。Typescript`Array<string>` | N
disabled | Boolean | undefined | \- | N
disabled-color | Array | [] | `deprecated`。Typescript`Array<string>` | N
label | String / Boolean | false | Typescript`string \| boolean` | N
marks | Object / Array | {} | Typescript`Record<number, string> \| Array<number>` | N
max | Number | 100 | \- | N
min | Number | 0 | \- | N
range | Boolean | false | \- | N
show-extreme-value | Boolean | false | \- | N
step | Number | 1 | \- | N
theme | String | default | `0.30.0`。options: default/capsule | N
value | Number / Array | 0 | Typescript`SliderValue` `type SliderValue = number \| Array<number>`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/slider/type.ts) | N
default-value | Number / Array | undefined | uncontrolled property。Typescript`SliderValue` `type SliderValue = number \| Array<number>`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/slider/type.ts) | N
vertical | Boolean | false | \- | N
### Slider Events
name | params | description
-- | -- | --
change | `(value: SliderValue)` | \-
dragend | `(value: SliderValue, e: TouchEvent)` | \-
dragstart | `(e: TouchEvent)` | \-
### Slider External Classes
className | Description
-- | --
t-class | \-
t-class-bar | \-
t-class-bar-active | \-
t-class-bar-disabled | \-
t-class-cursor | \-
### CSS Variables
The component provides the following CSS variables, which can be used to customize styles.
Name | Default Value | Description
-- | -- | --
--td-slider-active-color | @brand-color | -
--td-slider-bar-height | 8rpx | -
--td-slider-bar-width | 8rpx | -
--td-slider-capsule-bar-color | @bg-color-component | -
--td-slider-capsule-bar-heihgt | 48rpx | -
--td-slider-capsule-bar-width | 48rpx | -
--td-slider-capsule-line-heihgt | 36rpx | -
--td-slider-default-color | @bg-color-component | -
--td-slider-default-color | @bg-color-component-disabled | -
--td-slider-disabled-color | @brand-color-disabled | -
--td-slider-disabled-text-color | @text-color-disabled | -
--td-slider-dot-bg-color | #fff | -
--td-slider-dot-color | @component-border | -
--td-slider-dot-disabled-bg-color | #fff | -
--td-slider-dot-disabled-border-color | #f3f3f3 | -
--td-slider-dot-size | 40rpx | -
--td-slider-text-color | @text-color-primary | -

View File

@@ -0,0 +1,142 @@
---
title: Slider 滑动选择器
description: 用于选择横轴上的数值、区间、档位。
spline: data
isComponent: true
---
<span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20lines-95%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20functions-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20statements-94%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20branches-82%25-blue" /></span>
## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
```json
"usingComponents": {
"t-slider": "tdesign-miniprogram/slider/slider"
}
```
## 代码演示
<img src="https://tdesign.gtimg.com/miniprogram/readme/slider.png" width="375px" height="50%">
<a href="https://developers.weixin.qq.com/s/2p6gkime7CSn" title="在开发者工具中预览效果" target="_blank" rel="noopener noreferrer"> 在开发者工具中预览效果 </a>
<blockquote style="background-color: #d9e1ff; font-size: 15px; line-height: 26px;margin: 16px 0 0;padding: 16px; border-radius: 6px; color: #0052d9" >
<p>Tips: 请确保开发者工具为打开状态。导入开发者工具后依次执行npm i > 构建npm包 > 勾选 "将JS编译成ES5"</p>
</blockquote>
### 组件类型
单游标滑块
{{ base }}
双游标滑块
{{ range }}
带数值滑动选择器
{{ label }}
带刻度滑动选择器
{{ step }}
### 组件状态
滑块禁用状态
{{ disabled }}
#### 特殊样式
胶囊型滑块
{{ capsule }}
#### 垂直状态
垂直方向的滑块
{{ vertical }}
## API
### Slider Props
名称 | 类型 | 默认值 | 描述 | 必传
-- | -- | -- | -- | --
style | Object | - | 样式 | N
custom-style | Object | - | 样式,一般用于开启虚拟化组件节点场景 | N
colors | Array | [] | 已废弃。颜色,[已选择, 未选择]。TS 类型:`Array<string>` | N
disabled | Boolean | undefined | 是否禁用组件 | N
disabled-color | Array | [] | 已废弃。禁用状态滑动条的颜色,[已选, 未选]。TS 类型:`Array<string>` | N
label | String / Boolean | false | 滑块当前值文本。<br />值为 true 显示默认文案;值为 false 不显示滑块当前值文本;<br />值为 `${value}%` 则表示组件会根据占位符渲染文案;<br />值类型为函数时,参数 `value` 标识滑块值,参数 `position=start` 表示范围滑块的起始值,参数 `position=end` 表示范围滑块的终点值。TS 类型:`string \| boolean` | N
marks | Object / Array | {} | 刻度标记,示例:`[0, 10, 40, 200]` 或者 `{ 5: '5¥', 10: '10%' }`。TS 类型:`Record<number, string> \| Array<number>` | N
max | Number | 100 | 滑块范围最大值 | N
min | Number | 0 | 滑块范围最小值 | N
range | Boolean | false | 双游标滑块 | N
show-extreme-value | Boolean | false | 是否边界值 | N
step | Number | 1 | 步长 | N
theme | String | default | `0.30.0`。滑块风格。可选项default/capsule | N
value | Number / Array | 0 | 滑块值。TS 类型:`SliderValue` `type SliderValue = number \| Array<number>`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/slider/type.ts) | N
default-value | Number / Array | undefined | 滑块值。非受控属性。TS 类型:`SliderValue` `type SliderValue = number \| Array<number>`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/slider/type.ts) | N
vertical | Boolean | false | 是否是垂直的滑块渲染垂直滑块时默认高度为400rpx可通过修改`--td-slider-bar-height`来自定义高度) | N
### Slider Events
名称 | 参数 | 描述
-- | -- | --
change | `(value: SliderValue)` | 滑块值变化时触发
dragend | `(value: SliderValue, e: TouchEvent)` | 结束拖动时触发
dragstart | `(e: TouchEvent)` | 开始拖动时触发
### Slider External Classes
类名 | 描述
-- | --
t-class | 根节点样式类
t-class-bar | 滑道底部样式类
t-class-bar-active | 滑道激活态样式类
t-class-bar-disabled | 滑道禁用态样式类
t-class-cursor | 游标样式类
## FAQ
当 slider 外层使用 `hidden` 包裹,需要在 `hidden = false` 时,重新调用组件的 `init` 方法才能正常渲染在t-popup/t-dialog中同理。如下
```html
<t-slider id="slider" />
```
```js
const $slider = this.selectComponent('#slider');
$slider.init();
```
### CSS Variables
组件提供了下列 CSS 变量,可用于自定义样式。
名称 | 默认值 | 描述
-- | -- | --
--td-slider-active-color | @brand-color | -
--td-slider-bar-height | 8rpx | vertical为true时默认为400rpx
--td-slider-bar-width | 8rpx | vertical为true时有效
--td-slider-capsule-bar-color | @bg-color-component | -
--td-slider-capsule-bar-heihgt | 48rpx | -
--td-slider-capsule-bar-width | 48rpx | vertical为true时有效
--td-slider-capsule-line-heihgt | 36rpx | -
--td-slider-default-color | @bg-color-component | -
--td-slider-default-color | @bg-color-component-disabled | -
--td-slider-disabled-color | @brand-color-disabled | -
--td-slider-disabled-text-color | @text-color-disabled | -
--td-slider-dot-bg-color | #fff | -
--td-slider-dot-color | @component-border | -
--td-slider-dot-disabled-bg-color | #fff | -
--td-slider-dot-disabled-border-color | #f3f3f3 | -
--td-slider-dot-size | 40rpx | -
--td-slider-text-color | @text-color-primary | -

View File

@@ -0,0 +1,3 @@
import { TdSliderProps } from './type';
declare const props: TdSliderProps;
export default props;

View File

@@ -0,0 +1,51 @@
const props = {
disabled: {
type: null,
value: undefined,
},
label: {
type: null,
value: false,
},
marks: {
type: null,
value: {},
},
max: {
type: Number,
value: 100,
},
min: {
type: Number,
value: 0,
},
range: {
type: Boolean,
value: false,
},
showExtremeValue: {
type: Boolean,
value: false,
},
step: {
type: Number,
value: 1,
},
theme: {
type: String,
value: 'default',
},
value: {
type: null,
value: null,
},
defaultValue: {
type: null,
value: 0,
},
vertical: {
type: Boolean,
value: false,
},
};
export default props;

View File

@@ -0,0 +1,66 @@
/// <reference types="miniprogram-api-typings" />
import { SuperComponent } from '../common/src/index';
import type { SliderValue } from './type';
declare type dataType = {
sliderStyles: string;
classPrefix: string;
initialLeft: number | null;
initialRight: number | null;
activeLeft: number;
activeRight: number;
maxRange: number;
lineLeft: number;
lineRight: number;
dotTopValue: number[];
blockSize: number;
isScale: boolean;
scaleArray: any[];
scaleTextArray: any[];
_value: SliderValue;
prefix: string;
isVisibleToScreenReader: boolean;
identifier: number[];
__inited: boolean;
};
export default class Slider extends SuperComponent {
externalClasses: string[];
options: {
pureDataPattern: RegExp;
};
properties: import("./type").TdSliderProps;
controlledProps: {
key: string;
event: string;
}[];
data: dataType;
observers: {
value(newValue: SliderValue): void;
_value(newValue: SliderValue): void;
marks(val: any): void;
};
lifetimes: {
created(): void;
attached(): void;
};
injectPageScroll(): void;
observerScrollTop(rest: any): void;
toggleA11yTips(): void;
renderLine(val: any): void;
triggerValue(value?: SliderValue): void;
handlePropsChange(newValue: SliderValue): void;
handleMark(marks: any): void;
setSingleBarWidth(value: number): void;
init(): Promise<void>;
stepValue(value: number): number;
onSingleLineTap(e: WechatMiniprogram.TouchEvent): void;
getSingleChangeValue(e: WechatMiniprogram.TouchEvent): number;
convertPosToValue(posValue: number, dir: 0 | 1): number;
onLineTap(e: WechatMiniprogram.TouchEvent): void;
onTouchStart(e: WechatMiniprogram.TouchEvent): void;
onTouchMoveLeft(e: WechatMiniprogram.TouchEvent): void;
onTouchMoveRight(e: WechatMiniprogram.TouchEvent): void;
setLineStyle(left: number, right: number): void;
onTouchEnd(e: WechatMiniprogram.TouchEvent): void;
getPagePosition(touch: any): any;
}
export {};

View File

@@ -0,0 +1,408 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { SuperComponent, wxComponent } from '../common/src/index';
import config from '../common/config';
import { trimSingleValue, trimValue } from './tool';
import props from './props';
import { getRect } from '../common/utils';
import Bus from '../common/bus';
const { prefix } = config;
const name = `${prefix}-slider`;
let Slider = class Slider extends SuperComponent {
constructor() {
super(...arguments);
this.externalClasses = [
`${prefix}-class`,
`${prefix}-class-bar`,
`${prefix}-class-bar-active`,
`${prefix}-class-bar-disabled`,
`${prefix}-class-cursor`,
];
this.options = {
pureDataPattern: /^__/,
};
this.properties = props;
this.controlledProps = [
{
key: 'value',
event: 'change',
},
];
this.data = {
sliderStyles: '',
classPrefix: name,
initialLeft: null,
initialRight: null,
activeLeft: 0,
activeRight: 0,
maxRange: 0,
lineLeft: 0,
lineRight: 0,
dotTopValue: [0, 0],
_value: 0,
blockSize: 20,
isScale: false,
scaleArray: [],
scaleTextArray: [],
prefix,
isVisibleToScreenReader: false,
identifier: [-1, -1],
__inited: false,
};
this.observers = {
value(newValue) {
this.handlePropsChange(newValue);
},
_value(newValue) {
this.bus.on('initial', () => this.renderLine(newValue));
this.toggleA11yTips();
},
marks(val) {
this.bus.on('initial', () => this.handleMark(val));
},
};
this.lifetimes = {
created() {
this.bus = new Bus();
},
attached() {
const { value } = this.properties;
if (!value)
this.handlePropsChange(0);
this.init();
this.injectPageScroll();
},
};
}
injectPageScroll() {
const { range, vertical } = this.properties;
if (!range || !vertical)
return;
const pages = getCurrentPages() || [];
let curPage = null;
if (pages && pages.length - 1 >= 0) {
curPage = pages[pages.length - 1];
}
if (!curPage)
return;
const originPageScroll = curPage === null || curPage === void 0 ? void 0 : curPage.onPageScroll;
curPage.onPageScroll = (rest) => {
originPageScroll === null || originPageScroll === void 0 ? void 0 : originPageScroll.call(this, rest);
this.observerScrollTop(rest);
};
}
observerScrollTop(rest) {
const { scrollTop } = rest || {};
this.pageScrollTop = scrollTop;
}
toggleA11yTips() {
this.setData({
isVisibleToScreenReader: true,
});
setTimeout(() => {
this.setData({
isVisibleToScreenReader: false,
});
}, 2000);
}
renderLine(val) {
const { min, max, range } = this.properties;
const { maxRange } = this.data;
if (range) {
const left = (maxRange * (val[0] - Number(min))) / (Number(max) - Number(min));
const right = (maxRange * (Number(max) - val[1])) / (Number(max) - Number(min));
this.setLineStyle(left, right);
}
else {
this.setSingleBarWidth(val);
}
}
triggerValue(value) {
if (this.preval === value)
return;
this.preval = value;
this._trigger('change', {
value: trimValue(value, this.properties),
});
}
handlePropsChange(newValue) {
const value = trimValue(newValue, this.properties);
const setValueAndTrigger = () => {
this.setData({
_value: value,
});
};
if (this.data.maxRange === 0) {
this.init().then(setValueAndTrigger);
return;
}
setValueAndTrigger();
}
handleMark(marks) {
const calcPos = (arr) => {
const { max, theme } = this.properties;
const { blockSize, maxRange } = this.data;
const margin = theme === 'capsule' ? blockSize / 2 : 0;
return arr.map((item) => ({
val: item,
left: Math.round((item / Number(max)) * maxRange) + margin,
}));
};
if ((marks === null || marks === void 0 ? void 0 : marks.length) && Array.isArray(marks)) {
this.setData({
isScale: true,
scaleArray: calcPos(marks),
scaleTextArray: [],
});
}
if (Object.prototype.toString.call(marks) === '[object Object]') {
const scaleArray = Object.keys(marks).map((item) => Number(item));
const scaleTextArray = scaleArray.map((item) => marks[item]);
this.setData({
isScale: scaleArray.length > 0,
scaleArray: calcPos(scaleArray),
scaleTextArray,
});
}
}
setSingleBarWidth(value) {
const { max, min, theme } = this.properties;
const { maxRange, blockSize } = this.data;
const halfBlock = theme === 'capsule' ? Number(blockSize) / 2 : 0;
const percentage = (Number(value) - Number(min)) / (Number(max) - Number(min));
const width = percentage * maxRange + halfBlock;
this.setData({
lineBarWidth: `${width}px`,
});
}
init() {
return __awaiter(this, void 0, void 0, function* () {
if (this.data.__inited)
return;
const line = yield getRect(this, '#sliderLine');
const { blockSize } = this.data;
const { theme, vertical } = this.properties;
const halfBlock = Number(blockSize) / 2;
const { top, bottom, right, left } = line;
let maxRange = vertical ? bottom - top : right - left;
let initialLeft = vertical ? top : left;
let initialRight = vertical ? bottom : right;
if (initialLeft === 0 && initialRight === 0)
return;
if (theme === 'capsule') {
maxRange = maxRange - Number(blockSize) - 6;
initialLeft -= halfBlock;
initialRight -= halfBlock;
}
this.setData({
maxRange,
initialLeft,
initialRight,
__inited: true,
});
this.bus.emit('initial');
});
}
stepValue(value) {
const { step, min, max } = this.properties;
const decimal = String(step).indexOf('.') > -1 ? String(step).length - String(step).indexOf('.') - 1 : 0;
const closestStep = trimSingleValue(Number((Math.round(value / Number(step)) * Number(step)).toFixed(decimal)), Number(min), Number(max));
return closestStep;
}
onSingleLineTap(e) {
const { disabled } = this.properties;
if (disabled)
return;
const isSingleLineTap = this.data.identifier[0] === -1;
if (isSingleLineTap) {
const [touch] = e.changedTouches;
this.data.identifier[0] = touch.identifier;
}
const value = this.getSingleChangeValue(e);
if (isSingleLineTap) {
this.data.identifier[0] = -1;
}
this.triggerValue(value);
}
getSingleChangeValue(e) {
const { min, max, theme, vertical } = this.properties;
const { initialLeft, maxRange, blockSize } = this.data;
const touch = e.changedTouches.find((item) => item.identifier === this.data.identifier[0]);
const pagePosition = this.getPagePosition(touch);
let offset = 0;
if (theme === 'capsule') {
offset = Number(blockSize);
if (vertical) {
offset *= 2;
}
offset += 6;
}
else if (vertical) {
offset = Number(blockSize);
}
const currentLeft = pagePosition - initialLeft - offset;
let value = 0;
if (currentLeft <= 0) {
value = Number(min);
}
else if (currentLeft >= maxRange) {
value = Number(max);
}
else {
value = (currentLeft / maxRange) * (Number(max) - Number(min)) + Number(min);
}
return this.stepValue(value);
}
convertPosToValue(posValue, dir) {
const { maxRange } = this.data;
const { max, min } = this.properties;
return dir === 0
? (posValue / maxRange) * (Number(max) - Number(min)) + Number(min)
: Number(max) - (posValue / maxRange) * (Number(max) - Number(min));
}
onLineTap(e) {
const { disabled, theme, vertical } = this.properties;
const { initialLeft, initialRight, maxRange, blockSize } = this.data;
if (disabled)
return;
const [touch] = e.changedTouches;
const pagePosition = this.getPagePosition(touch);
const halfBlock = theme === 'capsule' ? Number(blockSize) / 2 : 0;
const currentLeft = pagePosition - initialLeft;
const currentRight = -(pagePosition - initialRight);
if (currentLeft < 0 || currentRight > maxRange + Number(blockSize))
return;
Promise.all([getRect(this, '#leftDot'), getRect(this, '#rightDot')]).then(([leftDot, rightDot]) => {
const pageScrollTop = this.pageScrollTop || 0;
const leftDotPosition = vertical ? leftDot.top + pageScrollTop : leftDot.left;
const distanceLeft = Math.abs(pagePosition - leftDotPosition - halfBlock);
const rightDotPosition = vertical ? rightDot.top + pageScrollTop : rightDot.left;
const distanceRight = Math.abs(rightDotPosition - pagePosition + halfBlock);
const isMoveLeft = distanceLeft < distanceRight;
let offset = 0;
if (theme === 'capsule') {
offset = Number(blockSize);
if (vertical) {
offset *= 2;
}
offset += 6;
}
else if (vertical) {
offset = Number(blockSize);
}
if (isMoveLeft) {
const left = pagePosition - initialLeft - offset;
const leftValue = this.convertPosToValue(left, 0);
this.triggerValue([this.stepValue(leftValue), this.data._value[1]]);
}
else {
let right = -(pagePosition - initialRight);
if (vertical) {
right += offset / 2;
}
const rightValue = this.convertPosToValue(right, 1);
this.triggerValue([this.data._value[0], this.stepValue(rightValue)]);
}
});
}
onTouchStart(e) {
this.triggerEvent('dragstart', { e });
const [touch] = e.changedTouches;
if (e.currentTarget.id === 'rightDot') {
this.data.identifier[1] = touch.identifier;
}
else {
this.data.identifier[0] = touch.identifier;
}
}
onTouchMoveLeft(e) {
const { disabled, theme, vertical } = this.properties;
const { initialLeft, _value, blockSize } = this.data;
if (disabled)
return;
const touch = e.changedTouches.find((item) => item.identifier === this.data.identifier[0]);
const pagePosition = this.getPagePosition(touch);
let offset = 0;
if (theme === 'capsule') {
offset += Number(blockSize);
}
if (vertical) {
offset += Number(blockSize) + 6;
}
const currentLeft = pagePosition - initialLeft - offset;
const newData = [..._value];
const leftValue = this.convertPosToValue(currentLeft, 0);
newData[0] = this.stepValue(leftValue);
this.triggerValue(newData);
}
onTouchMoveRight(e) {
const { disabled, vertical } = this.properties;
const { initialRight, _value, blockSize } = this.data;
if (disabled)
return;
const touch = e.changedTouches.find((item) => item.identifier === this.data.identifier[1]);
const pagePosition = this.getPagePosition(touch);
let offset = 0;
if (vertical) {
offset += Number(blockSize) / 2 + 6;
}
const currentRight = -(pagePosition - initialRight - offset);
const newData = [..._value];
const rightValue = this.convertPosToValue(currentRight, 1);
newData[1] = this.stepValue(rightValue);
this.triggerValue(newData);
}
setLineStyle(left, right) {
const { theme } = this.properties;
const { blockSize, maxRange } = this.data;
const halfBlock = theme === 'capsule' ? Number(blockSize) / 2 : 0;
const [a, b] = this.data._value;
const cut = (v) => parseInt(v, 10);
this.setData({
dotTopValue: [a, b],
});
if (left + right <= maxRange) {
this.setData({
lineLeft: cut(left + halfBlock),
lineRight: cut(right + halfBlock),
});
}
else {
this.setData({
lineLeft: cut(maxRange + halfBlock - right),
lineRight: cut(maxRange - left + halfBlock * 1.5),
});
}
}
onTouchEnd(e) {
this.triggerEvent('dragend', { e, value: this.data._value });
if (e.currentTarget.id === 'rightDot') {
this.data.identifier[1] = -1;
}
else {
this.data.identifier[0] = -1;
}
}
getPagePosition(touch) {
const { pageX, pageY } = touch;
const { vertical } = this.properties;
return vertical ? pageY : pageX;
}
};
Slider = __decorate([
wxComponent()
], Slider);
export default Slider;

View File

@@ -0,0 +1,5 @@
{
"component": true,
"styleIsolation": "apply-shared",
"usingComponents": {}
}

View File

@@ -0,0 +1,159 @@
<wxs src="./slider.wxs" module="t" />
<wxs src="../common/utils.wxs" module="_" />
<view
style="{{_._style([style, customStyle])}}"
class="{{_.cls(classPrefix, [['top', label || scaleTextArray.length], ['disabled', disabled], ['range', range]])}} class {{prefix}}-class {{vertical ? classPrefix + '--vertical' : ''}}"
>
<block wx:if="{{!range}}">
<text wx:if="{{showExtremeValue}}" class="{{classPrefix}}__value {{classPrefix}}__value--min">
{{ label ? t.getValue(label, min) : min}}
</text>
<view
id="sliderLine"
class="{{_.cls(classPrefix + '__bar', [['disabled', disabled], theme, ['marks', isScale && theme == 'capsule']])}} {{prefix}}-class-bar"
bind:tap="onSingleLineTap"
>
<block wx:if="{{isScale}}">
<view
class="{{_.cls(classPrefix + '__scale-item', [['active', _value >= item.val], ['disabled', disabled], theme, ['hidden', (index == 0 || index == scaleArray.length - 1) && theme == 'capsule' || value == item.val]])}}"
wx:for="{{scaleArray}}"
wx:key="index"
style="{{vertical ? 'top' : 'left'}}:{{item.left}}px; {{vertical ? 'transform: translate(-50%, -50%);' : 'transform: translateX(-50%);'}}"
aria-hidden="{{true}}"
>
<view wx:if="{{scaleTextArray.length}}" class="{{_.cls(classPrefix + '__scale-desc', [theme])}}">
{{scaleTextArray[index]}}
</view>
</view>
</block>
<view
class="{{_.cls(classPrefix + '__line', [['disabled', disabled], theme, 'single'])}} {{prefix}}-class-bar-active"
style="{{vertical ? 'height' : 'width'}}: {{lineBarWidth}}"
>
<view
id="singleDot"
class="{{classPrefix}}__dot {{prefix}}-class-cursor"
catch:touchstart="onTouchStart"
catch:touchmove="onSingleLineTap"
catch:touchend="onTouchEnd"
catch:touchcancel="onTouchEnd"
>
<view
wx:if="{{label || isVisibleToScreenReader}}"
class="{{_.cls(classPrefix+'__dot-value', [['sr-only', !label]])}}"
aria-role="alert"
aria-live="assertive"
aria-hidden="{{!isVisibleToScreenReader}}"
>
{{t.getValue(label, _value) || _value}}
</view>
<view
class="{{classPrefix}}__dot-slider"
aria-role="slider"
aria-disabled="{{disabled}}"
aria-valuemax="{{max}}"
aria-valuemin="{{min}}"
aria-valuenow="{{_value}}"
aria-valuetext="{{t.getValue(label, _value) || _value}}"
></view>
</view>
</view>
</view>
<!-- <view wx:if="{{label}}" class="{{classPrefix}}__value {{classPrefix}}__value--right">
<text class="{{classPrefix}}__value--text"> {{t.getValue(label, _value)}}</text>
</view> -->
<text wx:if="{{showExtremeValue}}" class="{{classPrefix}}__value {{classPrefix}}__value--max">
{{ label ? t.getValue(label, max) : max}}
</text>
</block>
<!-- range选择器自定义 -->
<block wx:if="{{range}}">
<view wx:if="{{showExtremeValue}}" class="{{classPrefix}}__range-extreme {{classPrefix}}__range-extreme--min">
{{min}}
</view>
<view
id="sliderLine"
bind:tap="onLineTap"
class="{{_.cls(classPrefix + '__bar', [['disabled', disabled], theme, ['marks', isScale && theme == 'capsule']])}} {{prefix}}-class-bar"
>
<block wx:if="{{isScale}}">
<view
class="{{_.cls(classPrefix + '__scale-item', [['active', dotTopValue[1] >= item.val && item.val >= dotTopValue[0]], ['disabled', disabled], theme, ['hidden', (index == 0 || index == scaleArray.length - 1) && theme == 'capsule' || value == item.val]])}}"
wx:for="{{scaleArray}}"
wx:for-index="index"
wx:key="index"
style="{{vertical ? 'top' : 'left'}}:{{item.left}}px; {{vertical ? 'transform: translate(-50%, -50%);' : 'transform: translateX(-50%);'}}"
aria-hidden="{{true}}"
>
<view wx:if="{{scaleTextArray.length}}" class="{{_.cls(classPrefix + '__scale-desc', [theme])}}"
>{{scaleTextArray[index]}}</view
>
</view>
</block>
<view
class="{{_.cls(classPrefix + '__line', [['disabled', disabled], theme])}} {{prefix}}-class-bar-active"
style="{{vertical ? 'top' : 'left'}}: {{lineLeft}}px; {{vertical ? 'bottom' : 'right'}}: {{lineRight}}px"
>
<view
id="leftDot"
catch:touchstart="onTouchStart"
catch:touchmove="onTouchMoveLeft"
catch:touchend="onTouchEnd"
catch:touchcancel="onTouchEnd"
class="{{classPrefix}}__dot {{classPrefix}}__dot--left {{prefix}}-class-cursor"
>
<view
wx:if="{{label || isVisibleToScreenReader}}"
class="{{_.cls(classPrefix+'__dot-value', [['sr-only', !label]])}}"
aria-role="alert"
aria-live="assertive"
aria-hidden="{{!isVisibleToScreenReader}}"
>
{{t.getValue(label, dotTopValue[0]) || dotTopValue[0]}}
</view>
<view
class="{{classPrefix}}__dot-slider"
aria-role="slider"
aria-disabled="{{disabled}}"
aria-valuemax="{{max}}"
aria-valuemin="{{min}}"
aria-valuenow="{{dotTopValue[0]}}"
aria-valuetext="{{t.getValue(label, dotTopValue[0]) || dotTopValue[0]}}"
></view>
</view>
<view
id="rightDot"
catch:touchstart="onTouchStart"
catch:touchmove="onTouchMoveRight"
catch:touchend="onTouchEnd"
catch:touchcancel="onTouchEnd"
class="{{classPrefix}}__dot {{classPrefix}}__dot--right {{prefix}}-class-cursor"
>
<view
wx:if="{{label || isVisibleToScreenReader}}"
class="{{_.cls(classPrefix+'__dot-value', [['sr-only', !label]])}}"
aria-role="alert"
aria-live="assertive"
aria-hidden="{{!isVisibleToScreenReader}}"
>
{{t.getValue(label, dotTopValue[1]) || dotTopValue[1]}}
</view>
<view
class="{{classPrefix}}__dot-slider"
aria-role="slider"
aria-disabled="{{disabled}}"
aria-valuemax="{{max}}"
aria-valuemin="{{min}}"
aria-valuenow="{{dotTopValue[1]}}"
aria-valuetext="{{t.getValue(label, dotTopValue[1]) || dotTopValue[1]}}"
>
</view>
</view>
</view>
</view>
<view wx:if="{{showExtremeValue}}" class="{{classPrefix}}__range-extreme {{classPrefix}}__range-extreme--max">
{{max}}
</view>
</block>
</view>

View File

@@ -0,0 +1,10 @@
var REGEXP = getRegExp('[$][{value}]{7}');
function getValue(label, value) {
if (label && label === 'true') return value;
if (REGEXP.test(label)) return label.replace(REGEXP, value);
}
module.exports = {
getValue: getValue,
};

View File

@@ -0,0 +1,275 @@
.t-float-left {
float: left;
}
.t-float-right {
float: right;
}
@keyframes tdesign-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.hotspot-expanded.relative {
position: relative;
}
.hotspot-expanded::after {
content: '';
display: block;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
transform: scale(1.5);
}
.t-slider {
width: 100%;
font-size: 14px;
display: flex;
align-items: center;
}
.t-slider--disabled .t-slider__value,
.t-slider--disabled .t-slider__range-extreme,
.t-slider--disabled .t-slider__dot-value,
.t-slider--disabled .t-slider__scale-desc {
color: var(--td-slider-disabled-text-color, var(--td-text-color-disabled, var(--td-font-gray-4, rgba(0, 0, 0, 0.26))));
}
.t-slider--disabled .t-slider__dot {
background-color: var(--td-slider-dot-disabled-bg-color, #fff);
border-color: var(--td-slider-dot-disabled-border-color, #f3f3f3);
}
.t-slider--top {
padding-top: 40rpx;
}
.t-slider__line {
position: absolute;
top: 0;
height: var(--td-slider-bar-height, 8rpx);
border-radius: calc(var(--td-slider-bar-height, 8rpx) / 2);
background-color: var(--td-slider-active-color, var(--td-brand-color, var(--td-primary-color-7, #0052d9)));
}
.t-slider__line--disabled {
background-color: var(--td-slider-disabled-color, var(--td-brand-color-disabled, var(--td-primary-color-3, #b5c7ff)));
}
.t-slider__line--capsule {
height: var(--td-slider-capsule-line-heihgt, 36rpx);
}
.t-slider__line--capsule.t-slider__line--single {
border-top-left-radius: calc(var(--td-slider-capsule-line-heihgt, 36rpx) / 2);
border-bottom-left-radius: calc(var(--td-slider-capsule-line-heihgt, 36rpx) / 2);
}
.t-slider__dot {
border-radius: 50%;
border: 2rpx solid var(--td-slider-dot-color, var(--td-component-border, var(--td-gray-color-4, #dcdcdc)));
position: absolute;
top: 50%;
right: 0;
transform: translate3d(50%, -50%, 0);
z-index: 2;
background-color: var(--td-slider-dot-bg-color, #fff);
width: var(--td-slider-dot-size, 40rpx);
height: var(--td-slider-dot-size, 40rpx);
box-shadow: var(--td-shadow-1, 0 1px 10px rgba(0, 0, 0, 0.05), 0 4px 5px rgba(0, 0, 0, 0.08), 0 2px 4px -1px rgba(0, 0, 0, 0.12));
box-sizing: border-box;
}
.t-slider__dot--left {
left: 0;
transform: translate3d(-50%, -50%, 0);
}
.t-slider__dot-value {
position: relative;
left: 50%;
transform: translateX(-50%);
top: -52rpx;
text-align: center;
width: 96rpx;
height: 44rpx;
line-height: 44rpx;
}
.t-slider__value,
.t-slider__range-extreme,
.t-slider__dot-value {
color: var(--td-slider-text-color, var(--td-text-color-primary, var(--td-font-gray-1, rgba(0, 0, 0, 0.9))));
}
.t-slider__value--sr-only,
.t-slider__range-extreme--sr-only,
.t-slider__dot-value--sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
clip-path: inset(50%);
border: 0;
}
.t-slider__dot-slider {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
}
.t-slider__value--min {
margin-left: 32rpx;
}
.t-slider__value--max {
margin-right: 32rpx;
}
.t-slider__value--right {
flex-basis: 80rpx;
}
.t-slider__value--right__value--text {
margin-right: 32rpx;
text-align: right;
display: block;
}
.t-slider__bar {
margin: 16rpx 32rpx;
flex: 10;
background-clip: content-box;
height: var(--td-slider-bar-height, 8rpx);
border-radius: calc(var(--td-slider-bar-height, 8rpx) / 2);
position: relative;
background-color: var(--td-slider-default-color, var(--td-bg-color-component, var(--td-gray-color-3, #e7e7e7)));
}
.t-slider__bar--capsule {
height: var(--td-slider-capsule-bar-heihgt, 48rpx);
border-radius: calc(var(--td-slider-capsule-bar-heihgt, 48rpx) / 2);
background-color: var(--td-slider-capsule-bar-color, var(--td-bg-color-component, var(--td-gray-color-3, #e7e7e7)));
border: 6rpx solid var(--td-slider-capsule-bar-color, var(--td-bg-color-component, var(--td-gray-color-3, #e7e7e7)));
box-sizing: border-box;
}
.t-slider__bar--marks {
background-color: var(--td-slider-default-color, var(--td-bg-color-component, var(--td-gray-color-3, #e7e7e7)));
}
.t-slider__bar--disabled {
background-color: var(--td-slider-default-color, var(--td-bg-color-component-disabled, var(--td-gray-color-2, #eeeeee)));
}
.t-slider__range-extreme--min {
margin-left: 32rpx;
text-align: left;
}
.t-slider__range-extreme--max {
margin-right: 32rpx;
text-align: right;
}
.t-slider__scale-item {
background-color: var(--td-slider-default-color, var(--td-bg-color-component, var(--td-gray-color-3, #e7e7e7)));
width: var(--td-slider-bar-height, 8rpx);
height: 16rpx;
width: 16rpx;
border-radius: 50%;
position: absolute;
top: 50%;
margin-top: -8rpx;
z-index: 1;
}
.t-slider__scale-item--active {
background-color: var(--td-slider-active-color, var(--td-brand-color, var(--td-primary-color-7, #0052d9)));
}
.t-slider__scale-item--disabled {
background-color: var(--td-slider-default-color, var(--td-bg-color-component-disabled, var(--td-gray-color-2, #eeeeee)));
}
.t-slider__scale-item--active.t-slider__scale-item--disabled {
background-color: var(--td-slider-disabled-color, var(--td-brand-color-disabled, var(--td-primary-color-3, #b5c7ff)));
}
.t-slider__scale-item--capsule {
height: var(--td-slider-capsule-line-heihgt, 36rpx);
width: 4rpx;
border-radius: 0;
background-color: var(--td-slider-capsule-bar-color, var(--td-bg-color-component, var(--td-gray-color-3, #e7e7e7)));
margin-top: calc(-0.5 * var(--td-slider-capsule-line-heihgt, 36rpx));
}
.t-slider__scale-item--hidden {
background-color: transparent;
}
.t-slider__scale-desc {
position: absolute;
left: 50%;
color: var(--td-slider-text-color, var(--td-text-color-primary, var(--td-font-gray-1, rgba(0, 0, 0, 0.9))));
transform: translateX(-50%);
bottom: 32rpx;
}
.t-slider__scale-desc--capsule {
bottom: 46rpx;
}
.t-slider--vertical {
--td-slider-bar-height: 400rpx;
height: var(--td-slider-bar-height, 8rpx);
justify-content: center;
position: relative;
}
.t-slider--vertical .t-slider__bar {
flex: none;
height: 100%;
width: var(--td-slider-bar-width, 8rpx);
}
.t-slider--vertical .t-slider__bar--capsule {
width: var(--td-slider-capsule-bar-width, 48rpx);
border-radius: calc(var(--td-slider-capsule-bar-width, 48rpx) / 2);
}
.t-slider--vertical .t-slider__line {
width: 100%;
height: unset;
left: 0;
border-radius: calc(var(--td-slider-bar-width, 8rpx) / 2);
}
.t-slider--vertical .t-slider__line--capsule.t-slider__line--single {
border-top-left-radius: calc(var(--td-slider-capsule-line-heihgt, 36rpx) / 2);
border-top-right-radius: calc(var(--td-slider-capsule-line-heihgt, 36rpx) / 2);
}
.t-slider--vertical .t-slider__dot {
left: 50%;
top: 100%;
transform: translate(-50%, -50%);
}
.t-slider--vertical .t-slider__dot--left {
top: 0;
transform: translate(-50%, -50%);
left: 50%;
}
.t-slider--vertical .t-slider__dot--right {
left: 50%;
transform: translate(-50%, -50%);
top: 100%;
}
.t-slider--vertical .t-slider__dot-value {
left: 54rpx;
top: 50%;
transform: translate(0, -50%);
width: auto;
}
.t-slider--vertical .t-slider__range-extreme {
position: absolute;
left: 50%;
transform: translateX(-50%);
margin: 0;
}
.t-slider--vertical .t-slider__range-extreme--min {
top: 0;
}
.t-slider--vertical .t-slider__range-extreme--max {
bottom: 0;
}
.t-slider--vertical .t-slider__scale-item {
left: 50%;
margin-top: 0;
}
.t-slider--vertical .t-slider__scale-item--capsule {
height: 4rpx;
width: var(--td-slider-capsule-line-heihgt, 36rpx);
}
.t-slider--vertical .t-slider__scale-desc {
top: 50%;
transform: translateY(-50%);
bottom: unset;
left: 38rpx;
}
.t-slider--vertical .t-slider__scale-desc--capsule {
left: 52rpx;
}

View File

@@ -0,0 +1,2 @@
export declare const trimSingleValue: (value: any, min: number, max: number) => number;
export declare const trimValue: (value: number | number[], props: any) => number | number[];

View File

@@ -0,0 +1,23 @@
export const trimSingleValue = (value, min, max) => {
if (value < min) {
return min;
}
if (value > max) {
return max;
}
return value;
};
export const trimValue = (value, props) => {
const { min, max, range } = props;
if (range && Array.isArray(value)) {
value[0] = trimSingleValue(value[0], min, max);
value[1] = trimSingleValue(value[1], min, max);
return value[0] <= value[1] ? value : [value[1], value[0]];
}
if (range) {
return [min, max];
}
if (!range) {
return trimSingleValue(value, min, max);
}
};

View File

@@ -0,0 +1,51 @@
export interface TdSliderProps {
disabled?: {
type: BooleanConstructor;
value?: boolean;
};
label?: {
type: null;
value?: string | boolean;
};
marks?: {
type: null;
value?: Record<number, string> | Array<number>;
};
max?: {
type: NumberConstructor;
value?: number;
};
min?: {
type: NumberConstructor;
value?: number;
};
range?: {
type: BooleanConstructor;
value?: boolean;
};
showExtremeValue?: {
type: BooleanConstructor;
value?: boolean;
};
step?: {
type: NumberConstructor;
value?: number;
};
theme?: {
type: StringConstructor;
value?: 'default' | 'capsule';
};
value?: {
type: null;
value?: SliderValue;
};
defaultValue?: {
type: null;
value?: SliderValue;
};
vertical?: {
type: BooleanConstructor;
value?: boolean;
};
}
export declare type SliderValue = number | Array<number>;

View File

@@ -0,0 +1 @@
export {};