初始化

This commit is contained in:
2024-12-06 16:18:22 +08:00
commit 884dd70d83
751 changed files with 60883 additions and 0 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,349 @@
module.exports = (function() {
var __MODS__ = {};
var __DEFINE__ = function(modId, func, req) { var m = { exports: {}, _tempexports: {} }; __MODS__[modId] = { status: 0, func: func, req: req, m: m }; };
var __REQUIRE__ = function(modId, source) { if(!__MODS__[modId]) return require(source); if(!__MODS__[modId].status) { var m = __MODS__[modId].m; m._exports = m._tempexports; var desp = Object.getOwnPropertyDescriptor(m, "exports"); if (desp && desp.configurable) Object.defineProperty(m, "exports", { set: function (val) { if(typeof val === "object" && val !== m._exports) { m._exports.__proto__ = val.__proto__; Object.keys(val).forEach(function (k) { m._exports[k] = val[k]; }); } m._tempexports = val }, get: function () { return m._tempexports; } }); __MODS__[modId].status = 1; __MODS__[modId].func(__MODS__[modId].req, m, m.exports); } return __MODS__[modId].m.exports; };
var __REQUIRE_WILDCARD__ = function(obj) { if(obj && obj.__esModule) { return obj; } else { var newObj = {}; if(obj != null) { for(var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) newObj[k] = obj[k]; } } newObj.default = obj; return newObj; } };
var __REQUIRE_DEFAULT__ = function(obj) { return obj && obj.__esModule ? obj.default : obj; };
__DEFINE__(1692578436876, function(require, module, exports) {
var has = Object.prototype.hasOwnProperty
, prefix = '~';
/**
* Constructor to create a storage for our `EE` objects.
* An `Events` instance is a plain object whose properties are event names.
*
* @constructor
* @private
*/
function Events() {}
//
// We try to not inherit from `Object.prototype`. In some engines creating an
// instance in this way is faster than calling `Object.create(null)` directly.
// If `Object.create(null)` is not supported we prefix the event names with a
// character to make sure that the built-in object properties are not
// overridden or used as an attack vector.
//
if (Object.create) {
Events.prototype = Object.create(null);
//
// This hack is needed because the `__proto__` property is still inherited in
// some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5.
//
if (!new Events().__proto__) prefix = false;
}
/**
* Representation of a single event listener.
*
* @param {Function} fn The listener function.
* @param {*} context The context to invoke the listener with.
* @param {Boolean} [once=false] Specify if the listener is a one-time listener.
* @constructor
* @private
*/
function EE(fn, context, once) {
this.fn = fn;
this.context = context;
this.once = once || false;
}
/**
* Add a listener for a given event.
*
* @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
* @param {(String|Symbol)} event The event name.
* @param {Function} fn The listener function.
* @param {*} context The context to invoke the listener with.
* @param {Boolean} once Specify if the listener is a one-time listener.
* @returns {EventEmitter}
* @private
*/
function addListener(emitter, event, fn, context, once) {
if (typeof fn !== 'function') {
throw new TypeError('The listener must be a function');
}
var listener = new EE(fn, context || emitter, once)
, evt = prefix ? prefix + event : event;
if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;
else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);
else emitter._events[evt] = [emitter._events[evt], listener];
return emitter;
}
/**
* Clear event by name.
*
* @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
* @param {(String|Symbol)} evt The Event name.
* @private
*/
function clearEvent(emitter, evt) {
if (--emitter._eventsCount === 0) emitter._events = new Events();
else delete emitter._events[evt];
}
/**
* Minimal `EventEmitter` interface that is molded against the Node.js
* `EventEmitter` interface.
*
* @constructor
* @public
*/
function EventEmitter() {
this._events = new Events();
this._eventsCount = 0;
}
/**
* Return an array listing the events for which the emitter has registered
* listeners.
*
* @returns {Array}
* @public
*/
EventEmitter.prototype.eventNames = function eventNames() {
var names = []
, events
, name;
if (this._eventsCount === 0) return names;
for (name in (events = this._events)) {
if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);
}
if (Object.getOwnPropertySymbols) {
return names.concat(Object.getOwnPropertySymbols(events));
}
return names;
};
/**
* Return the listeners registered for a given event.
*
* @param {(String|Symbol)} event The event name.
* @returns {Array} The registered listeners.
* @public
*/
EventEmitter.prototype.listeners = function listeners(event) {
var evt = prefix ? prefix + event : event
, handlers = this._events[evt];
if (!handlers) return [];
if (handlers.fn) return [handlers.fn];
for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {
ee[i] = handlers[i].fn;
}
return ee;
};
/**
* Return the number of listeners listening to a given event.
*
* @param {(String|Symbol)} event The event name.
* @returns {Number} The number of listeners.
* @public
*/
EventEmitter.prototype.listenerCount = function listenerCount(event) {
var evt = prefix ? prefix + event : event
, listeners = this._events[evt];
if (!listeners) return 0;
if (listeners.fn) return 1;
return listeners.length;
};
/**
* Calls each of the listeners registered for a given event.
*
* @param {(String|Symbol)} event The event name.
* @returns {Boolean} `true` if the event had listeners, else `false`.
* @public
*/
EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
var evt = prefix ? prefix + event : event;
if (!this._events[evt]) return false;
var listeners = this._events[evt]
, len = arguments.length
, args
, i;
if (listeners.fn) {
if (listeners.once) this.removeListener(event, listeners.fn, undefined, true);
switch (len) {
case 1: return listeners.fn.call(listeners.context), true;
case 2: return listeners.fn.call(listeners.context, a1), true;
case 3: return listeners.fn.call(listeners.context, a1, a2), true;
case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true;
case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
}
for (i = 1, args = new Array(len -1); i < len; i++) {
args[i - 1] = arguments[i];
}
listeners.fn.apply(listeners.context, args);
} else {
var length = listeners.length
, j;
for (i = 0; i < length; i++) {
if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true);
switch (len) {
case 1: listeners[i].fn.call(listeners[i].context); break;
case 2: listeners[i].fn.call(listeners[i].context, a1); break;
case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break;
case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break;
default:
if (!args) for (j = 1, args = new Array(len -1); j < len; j++) {
args[j - 1] = arguments[j];
}
listeners[i].fn.apply(listeners[i].context, args);
}
}
}
return true;
};
/**
* Add a listener for a given event.
*
* @param {(String|Symbol)} event The event name.
* @param {Function} fn The listener function.
* @param {*} [context=this] The context to invoke the listener with.
* @returns {EventEmitter} `this`.
* @public
*/
EventEmitter.prototype.on = function on(event, fn, context) {
return addListener(this, event, fn, context, false);
};
/**
* Add a one-time listener for a given event.
*
* @param {(String|Symbol)} event The event name.
* @param {Function} fn The listener function.
* @param {*} [context=this] The context to invoke the listener with.
* @returns {EventEmitter} `this`.
* @public
*/
EventEmitter.prototype.once = function once(event, fn, context) {
return addListener(this, event, fn, context, true);
};
/**
* Remove the listeners of a given event.
*
* @param {(String|Symbol)} event The event name.
* @param {Function} fn Only remove the listeners that match this function.
* @param {*} context Only remove the listeners that have this context.
* @param {Boolean} once Only remove one-time listeners.
* @returns {EventEmitter} `this`.
* @public
*/
EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {
var evt = prefix ? prefix + event : event;
if (!this._events[evt]) return this;
if (!fn) {
clearEvent(this, evt);
return this;
}
var listeners = this._events[evt];
if (listeners.fn) {
if (
listeners.fn === fn &&
(!once || listeners.once) &&
(!context || listeners.context === context)
) {
clearEvent(this, evt);
}
} else {
for (var i = 0, events = [], length = listeners.length; i < length; i++) {
if (
listeners[i].fn !== fn ||
(once && !listeners[i].once) ||
(context && listeners[i].context !== context)
) {
events.push(listeners[i]);
}
}
//
// Reset the array, or remove it completely if we have no more listeners.
//
if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;
else clearEvent(this, evt);
}
return this;
};
/**
* Remove all listeners, or those of the specified event.
*
* @param {(String|Symbol)} [event] The event name.
* @returns {EventEmitter} `this`.
* @public
*/
EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {
var evt;
if (event) {
evt = prefix ? prefix + event : event;
if (this._events[evt]) clearEvent(this, evt);
} else {
this._events = new Events();
this._eventsCount = 0;
}
return this;
};
//
// Alias methods names because people roll like that.
//
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
EventEmitter.prototype.addListener = EventEmitter.prototype.on;
//
// Expose the prefix.
//
EventEmitter.prefixed = prefix;
//
// Allow `EventEmitter` to be imported as module namespace.
//
EventEmitter.EventEmitter = EventEmitter;
//
// Expose the module.
//
if ('undefined' !== typeof module) {
module.exports = EventEmitter;
}
}, function(modId) {var map = {}; return __REQUIRE__(map[modId], modId); })
return __REQUIRE__(1692578436876);
})()
//miniprogram-npm-outsideDeps=[]
//# sourceMappingURL=index.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,89 @@
---
title: ActionSheet 动作面板
description: 由用户操作后触发的一种特定的模态弹出框 ,呈现一组与当前情境相关的两个或多个选项。
spline: data
isComponent: true
---
## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
```json
"usingComponents": {
"t-action-sheet": "tdesign-miniprogram/action-sheet/action-sheet",
}
```
## 代码演示
### 基础用法
```html
<t-action-sheet id="t-action-sheet" items="{{items}}" visible="{{visible}}" bind:selected="onSelect" bind:cancel="onCancel" bind:close="onClose" bind:visible-change="onVisibleChange" />
```
### 支持自定义
```html
<t-action-sheet id="t-action-sheet-slot" visible="{{visible}}" bind:selected="onSelect" bind:cancel="onCancel" bind:close="onClose" bind:visible-change="onVisibleChange">
<view class="slot-wrap">我是自定义的内容</view>
</t-action-sheet>
```
### 支持指令调用
```javascript
import ActionSheet, { ActionSheetTheme } from 'tdesign-miniprogram/action-sheet/index';
// 指令调用不同于组件引用不需要传入visible
const basicListOption: ActionSheetShowOption = {
theme: ActionSheetTheme.List,
selector: '#t-action-sheet',
items: [
{
label: '默认选项',
},
{
label: '失效选项',
disabled: true,
},
{
label: '警告选项',
color: '#e34d59',
},
],
};
const handler = ActionSheet.show(basicListOption);
```
指令调用的关闭如下
```javascript
handler.close();
```
## API
### ActionSheet Props
名称 | 类型 | 默认值 | 说明 | 必传
-- | -- | -- | -- | --
cancel-text | String | 取消 | 设置取消按钮的文本 | N
count | Number | 8 | 设置每页展示菜单的数量,仅当 type=grid 时有效 | N
items | Array | - | 必需。菜单项。TS 类型:`Array<string | ActionSheetItem>` `interface ActionSheetItem {label: string; color?: string; disabled?: boolean; icon?: string; }`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/action-sheet/type.ts) | Y
show-cancel | Boolean | true | 是否显示取消按钮 | N
theme | String | list | 展示类型,列表和表格形式展示。可选项:list/grid | N
visible | Boolean | null | 必需。显示与隐藏 | Y
default-visible | Boolean | false | 必需。显示与隐藏。非受控属性 | Y
external-classes | Array | - | 组件类名,分别用于设置 组件外层元素、组件内容部分、取消按钮 等元素类名。`['t-class', 't-class-content', 't-class-cancel']` | N
### ActionSheet Events
名称 | 参数 | 描述
-- | -- | --
visible-change | `(visible: Boolean)` | 当浮层隐藏或显示时触发。
cancel | - | 点击取消按钮时触发
close | - | 关闭时触发
selected | `(selected: ActionSheetItem | String, index: Number)` | 选择菜单项时触发
@@ -0,0 +1,87 @@
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;
};
import { chunk } from '../common/utils';
import { SuperComponent, wxComponent } from '../common/src/index';
import config from '../common/config';
import { ActionSheetTheme, show } from './show';
import props from './props';
const { prefix } = config;
const name = `${prefix}-action-sheet`;
let ActionSheet = class ActionSheet extends SuperComponent {
constructor() {
super(...arguments);
this.externalClasses = [`${prefix}-class`, `${prefix}-class-content`, `${prefix}-class-cancel`];
this.properties = Object.assign({}, props);
this.data = {
prefix,
classPrefix: name,
gridThemeItems: [],
currentSwiperIndex: 0,
};
this.controlledProps = [
{
key: 'visible',
event: 'visible-change',
},
];
this.methods = {
onSwiperChange(e) {
const { detail: { current }, } = e;
this.setData({
currentSwiperIndex: current,
});
},
splitGridThemeActions() {
if (this.data.theme !== ActionSheetTheme.Grid)
return;
this.setData({
gridThemeItems: chunk(this.data.items, this.data.count),
});
},
show() {
this.splitGridThemeActions();
this._trigger('visible-change', { visible: true });
},
resetData(cb) {
this.setData(Object.assign({}, this.initialData), cb);
},
memoInitialData() {
this.initialData = Object.assign(Object.assign({}, this.properties), this.data);
},
close() {
this._trigger('visible-change', { visible: false });
},
onPopupVisibleChange({ detail }) {
if (!detail.visible) {
this._trigger('visible-change', { visible: false });
}
},
onSelect(event) {
const { currentSwiperIndex, items, gridThemeItems, count } = this.data;
const { index } = event.currentTarget.dataset;
const isSwiperMode = items.length > count;
const item = isSwiperMode ? gridThemeItems[currentSwiperIndex][index] : items[index];
const realIndex = isSwiperMode ? index + currentSwiperIndex * count : index;
if (item) {
this.triggerEvent('selected', { selected: item, index: realIndex });
this._trigger('visible-change', { visible: false });
}
},
onCancel() {
this.triggerEvent('cancel');
},
};
}
ready() {
this.memoInitialData();
}
};
ActionSheet.show = show;
ActionSheet = __decorate([
wxComponent()
], ActionSheet);
export default ActionSheet;
@@ -0,0 +1,12 @@
{
"component": true,
"usingComponents": {
"t-icon": "../icon/icon",
"t-popup": "../popup/popup",
"t-swiper": "../swiper/swiper",
"t-swiper-item": "../swiper/swiper-item",
"t-image": "../image/image",
"t-grid": "../grid/grid",
"t-grid-item": "../grid/grid-item"
}
}
@@ -0,0 +1,32 @@
<wxs src="./action-sheet.wxs" module="this" />
<import src="./template/action-sheet-list.wxml" />
<import src="./template/action-sheet-grid.wxml" />
<view id="{{classPrefix}}" class="{{classPrefix}} {{prefix}}-class">
<t-popup visible="{{visible}}" placement="bottom" bind:visible-change="onPopupVisibleChange">
<view class="{{classPrefix}}__content {{prefix}}-class-content">
<block wx:if="{{gridThemeItems.length}}">
<template is="grid" data="{{classPrefix, prefix, gridThemeItems, count, currentSwiperIndex}}" />
</block>
<block wx:elif="{{items && items.length}}">
<view class="{{classPrefix}}__list" wx:for="{{ items }}" wx:key="index">
<template
is="list"
data="{{index, classPrefix, listThemeItemClass: this.getListThemeItemClass({ item, prefix, classPrefix }), item}}"
/>
</view>
</block>
</view>
<slot />
<view wx:if="{{showCancel}}" class="{{classPrefix}}__footer {{classPrefix}}__safe">
<view class="{{classPrefix}}__gap-{{theme}}" />
<view
class="{{classPrefix}}__cancel {{prefix}}-class-cancel"
hover-class="{{classPrefix}}__cancel--hover"
hover-stay-time="70"
bind:tap="onCancel"
>
{{ cancelText }}
</view>
</view>
</t-popup>
</view>
@@ -0,0 +1,19 @@
var getListThemeItemClass = function (props) {
var classPrefix = props.classPrefix;
var item = props.item;
var prefix = props.prefix;
var classList = [classPrefix + '__list-item'];
if (item.disabled) {
classList.push(prefix + '-is-disabled');
}
return classList.join(' ');
};
var isImage = function (name) {
return name.indexOf('/') !== -1;
};
module.exports = {
getListThemeItemClass: getListThemeItemClass,
isImage: isImage,
};
@@ -0,0 +1,134 @@
.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-action-sheet .flex-center {
display: flex;
align-items: center;
justify-content: center;
}
.t-action-sheet .ellipsis {
word-wrap: normal;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.t-action-sheet__grid {
padding: 48rpx 0 16rpx 0;
}
.t-action-sheet__grid-item {
margin-bottom: 32rpx;
}
.t-action-sheet__list {
background-color: #fff;
border-bottom: 1rpx solid #f6f6f6;
}
.t-action-sheet__list:last-child {
border-bottom: none;
}
.t-action-sheet__list-item {
height: 96rpx;
display: flex;
align-items: center;
justify-content: center;
}
.t-action-sheet__list-item.t-is-disabled {
color: rgba(0, 0, 0, 0.26);
}
.t-action-sheet__list-item-text {
font-size: 32rpx;
word-wrap: normal;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.t-action-sheet__list-item-icon {
margin-right: 16rpx;
}
.t-action-sheet__swiper-wrap {
position: relative;
background-color: #fff;
}
.t-action-sheet__square {
height: 148rpx;
margin-bottom: 32rpx;
}
.t-action-sheet__square-image {
width: 72rpx;
height: 72rpx;
padding: 10rpx;
}
.t-action-sheet__square-text {
width: 100%;
margin-top: 10rpx;
font-size: 28rpx;
color: rgba(0, 0, 0, 0.9);
text-align: center;
word-wrap: normal;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.t-action-sheet__footer {
background-color: #fff;
}
.t-action-sheet__gap-list {
height: 16rpx;
background-color: #f3f3f3;
}
.t-action-sheet__gap-grid {
height: 1rpx;
background-color: #f3f3f3;
}
.t-action-sheet__cancel {
display: flex;
align-items: center;
justify-content: center;
height: 96rpx;
}
.t-action-sheet__dots {
position: absolute;
left: 50%;
bottom: 32rpx;
transform: translateX(-50%);
display: flex;
flex-direction: row;
}
.t-action-sheet__dots-item {
width: 16rpx;
height: 16rpx;
background-color: #dcdcdc;
border-radius: 50%;
margin: 0 16rpx;
transition: all 0.4s ease-in;
}
.t-action-sheet__dots-item.t-is-active {
background-color: #0052d9;
}
.t-action-sheet__safe {
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
@@ -0,0 +1,3 @@
import ActionSheet from './action-sheet';
export * from './show';
export default ActionSheet;
@@ -0,0 +1,30 @@
const props = {
cancelText: {
type: String,
value: '取消',
},
count: {
type: Number,
value: 8,
},
items: {
type: Array,
},
showCancel: {
type: Boolean,
value: true,
},
theme: {
type: String,
value: 'list',
},
visible: {
type: Boolean,
value: null,
},
defaultVisible: {
type: Boolean,
value: false,
},
};
export default props;
@@ -0,0 +1,28 @@
export var ActionSheetTheme;
(function (ActionSheetTheme) {
ActionSheetTheme["List"] = "list";
ActionSheetTheme["Grid"] = "grid";
})(ActionSheetTheme || (ActionSheetTheme = {}));
const getInstance = function (context, selector = '#t-action-sheet') {
if (!context) {
const pages = getCurrentPages();
const page = pages[pages.length - 1];
context = page.$$basePage || page;
}
const instance = context === null || context === void 0 ? void 0 : context.selectComponent(selector);
if (!instance) {
return null;
}
return instance;
};
export const show = function (options) {
const { context, selector } = options;
const instance = getInstance(context, selector);
if (!instance) {
return Promise.reject(new Error('未找到ActionSheet组件, 请检查selector是否正确'));
}
instance.resetData(() => {
instance.setData(Object.assign({}, options), instance.show);
});
return instance;
};
@@ -0,0 +1,46 @@
<import src="./action-sheet-item.wxml" />
<template name="grid">
<block wx:if="{{gridThemeItems.length === 1}}">
<t-grid align="center" t-class="{{classPrefix}}__grid" column="{{count / 2}}" class="{{classPrefix}}__single-wrap">
<t-grid-item
t-class="{{classPrefix}}__grid-item"
class="{{classPrefix}}__square"
wx:for="{{gridThemeItems[0]}}"
wx:key="index"
bind:tap="onSelect"
data-index="{{index}}"
>
<template is="item" data="{{classPrefix, item}}" />
</t-grid-item>
</t-grid>
</block>
<block wx:elif="{{gridThemeItems.length > 1}}">
<view class="{{classPrefix}}__swiper-wrap">
<t-swiper height="{{456}}" autoplay="{{false}}" current="{{currentSwiperIndex}}" bindchange="onSwiperChange">
<t-swiper-item wx:for="{{gridThemeItems}}" wx:key="index">
<t-grid align="center" t-class="{{classPrefix}}__grid" column="{{count / 2}}">
<t-grid-item
t-class="{{classPrefix}}__grid-item"
class="{{classPrefix}}__square"
wx:for="{{item}}"
wx:key="index"
data-index="{{index}}"
bind:tap="onSelect"
>
<template is="item" data="{{classPrefix, item}}" />
</t-grid-item>
</t-grid>
</t-swiper-item>
</t-swiper>
<view class="{{classPrefix}}__nav">
<view class="{{classPrefix}}__dots">
<view
wx:for="{{gridThemeItems.length}}"
wx:key="index"
class="{{classPrefix}}__dots-item {{index === currentSwiperIndex ? prefix + '-is-active' : ''}}"
/>
</view>
</view>
</view>
</block>
</template>
@@ -0,0 +1,17 @@
<wxs src="../action-sheet.wxs" module="this" />
<template name="item">
<block>
<t-image
slot="image"
wx:if="{{ this.isImage(item.icon) }}"
lazy
class="{{classPrefix}}__square-image"
src="{{item.icon}}"
mode="aspectFill"
/>
<t-icon slot="image" wx:else name="{{item.icon}}" class="{{classPrefix}}__square-image" size="72rpx" />
</block>
<view slot="text" style="{{ item.color ? 'color: ' + item.color : '' }}" class="{{classPrefix}}__square-text">
{{item.label}}
</view>
</template>
@@ -0,0 +1,11 @@
<template name="list">
<view
data-index="{{index}}"
style="{{ item.color ? 'color: ' + item.color : '' }}"
class="{{listThemeItemClass}}"
bind:tap="onSelect"
>
<t-icon wx:if="{{item.icon}}" name="{{item.icon}}" class="{{classPrefix}}__list-item-icon" size="48rpx"></t-icon>
<view class="{{classPrefix}}__list-item-text">{{item.label || item}}</view>
</view>
</template>
@@ -0,0 +1,137 @@
---
title: Avatar 头像
description: 用于展示用户头像信息,除了纯展示也可点击进入个人详情等操作。
spline: data
isComponent: true
---
## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
```json
"usingComponents": {
"t-avatar": "tdesign-miniprogram/avatar/avatar",
"t-avatar-group": "tdesign-miniprogram/avatar/avatar-group"
}
```
## 代码演示
### 基础头像
头像样式可为默认头像、微信头像圆形、方形、自定义文字
<img src="https://tdesign.gtimg.com/miniprogram/readme/avatar-2.png" width="375px" height="50%">
```html
<!-- 默认 -->
<t-avatar icon="user" />
<!-- 圆形 + 用户头像图 -->
<t-avatar shape="circle" image="{{xxxx.jpg}}" />
<!-- 自定义文字 -->
<t-avatar alt="A" t-class-alt="alt-example" />
```
### 特殊头像
<img src="https://tdesign.gtimg.com/miniprogram/readme/avatar-1.png" width="375px" height="50%">
```html
<!-- 纯展示 从上往下 -->
<t-avatar-group
cascading="left-up"
max="5"
collapseAvatar="+5"
size="small"
t-class="border-example-show"
>
<t-avatar
wx:for="{{['aaa.jpg', 'bbb.jpg', 'ccc.jpg', 'ddd.jpg', 'eee.jpg', 'fff.jpg']}}"
wx:for-item="pic"
wx:key="index"
image="{{pic}}"
size="small"
t-class-image="img-small"
t-class="small"
/>
</t-avatar-group>
<!-- 带操作 从下往上 -->
<t-avatar-group max="3" size="small" class="border-example-operate">
<t-avatar
wx:for="{{['aaa.jpg', 'bbb.jpg', 'ccc.jpg', 'ddd.jpg', 'eee.jpg', 'fff.jpg']}}"
wx:for-item="pic"
wx:key="index"
image="{{pic}}"
t-class-image="img-small"
t-class="small"
/>
<t-avatar
slot="collapseAvatar"
icon="user-add"
t-class-icon="img-small"
t-class-alt="alt-example1"
bindtap="onAddTap"
t-class="small"
/>
</t-avatar-group>
```
```js
onAddTap() {
wx.showToast({ title: '您按下了添加', icon: 'none', duration: 1000 });
},
```
### 不同尺寸的头像
头像大小尺寸及消息提醒,`size` 值:`small/medium/large` 或具体 `rpx` 值。
<img src="https://tdesign.gtimg.com/miniprogram/readme/avatar-3.png" width="375px" height="50%">
```html
<!-- 48rpx自定义文字头像 -->
<t-avatar alt="A" t-class-alt="alt-example" size="48rpx" />
<!-- S号自定义文字头像 -->
<t-avatar alt="A" t-class-alt="alt-example" size="small" />
<!-- M号带消息提示头像 -->
<t-avatar image="{{'aaa.jpg'}}" size="medium" badge-props="{{{count: 2}}}" />
<!-- L号头像 -->
<t-avatar image="{{'aaa.jpg'}}" size="large" />
```
## API
### Avatar Props
名称 | 类型 | 默认值 | 说明 | 必传
-- | -- | -- | -- | --
alt | String | - | 头像替换文本,仅当图片加载失败时有效 | N
badge-props | Object | - | 头像右上角提示信息,继承 Badge 组件的全部特性。如:小红点,或者数字。TS 类型:`BadgeProps`[Badge API Documents](./badge?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/avatar/type.ts) | N
external-classes | Array | - | 组件类名,用于设置组件外层元素类名。`['t-class']` | N
hide-on-load-failed | Boolean | false | 加载失败时隐藏图片 | N
icon | String / Slot | - | 图标 | N
image | String | - | 图片地址 | N
shape | String | circle | 形状。可选项:circle/round。TS 类型:`ShapeEnum ` `type ShapeEnum = 'circle' | 'round'`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/avatar/type.ts) | N
size | String | - | 尺寸,示例值:small/medium/large/24px/38px 等,默认为 large | N
### Avatar Events
名称 | 参数 | 描述
-- | -- | --
error | \- | 图片加载失败时触发
### AvatarGroup Props
名称 | 类型 | 默认值 | 说明 | 必传
-- | -- | -- | -- | --
cascading | String | 'right-up' | 图片之间的层叠关系,可选值:左侧图片在上和右侧图片在上。可选项:left-up/right-up。TS 类型:`CascadingValue` `type CascadingValue = 'left-up' | 'right-up'`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/avatar/type.ts) | N
collapse-avatar | String / Slot | - | 头像数量超出时,会出现一个头像折叠元素。该元素内容可自定义。默认为 `+N`。示例:`+5``...`, `更多` | N
external-classes | Array | - | 组件类名,用于设置组件外层元素类名。`['t-class', 't-class-image', 't-class-content']` | N
max | Number | - | 能够同时显示的最多头像数量 | N
size | String | medium | 尺寸,示例值:small/medium/large/24px/38px 等。优先级低于 Avatar.size | N
@@ -0,0 +1,20 @@
const props = {
cascading: {
type: String,
value: 'right-up',
},
collapseAvatar: {
type: String,
},
externalClasses: {
type: Array,
},
max: {
type: Number,
},
size: {
type: String,
value: 'medium',
},
};
export default props;
@@ -0,0 +1,89 @@
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;
};
import { SuperComponent, wxComponent } from '../common/src/index';
import config from '../common/config';
import avatarGroupProps from './avatar-group-props';
const { prefix } = config;
const name = `${prefix}-avatar-group`;
let AvatarGroup = class AvatarGroup extends SuperComponent {
constructor() {
super(...arguments);
this.externalClasses = [`${prefix}-class`, `${prefix}-class-content`, `${prefix}-class-image`];
this.properties = avatarGroupProps;
this.data = {
prefix,
classPrefix: name,
hasChild: true,
length: 0,
};
this.options = {
multipleSlots: true,
};
this.relations = {
'./avatar': {
type: 'descendant',
linked() {
this.children = this.getRelationNodes('./avatar');
},
},
};
this.methods = {
handleHasChild(children, hasChild) {
children.forEach((child) => {
child.updateIsChild(hasChild);
});
},
handleChildSlot(max, children, f) {
const query = this.createSelectorQuery();
const slotName = `.${this.data.classPrefix}__collapse--slot`;
query.select(slotName).boundingClientRect();
query.exec((res) => {
const isSlot = !!res[0].width;
f(max, children, isSlot);
});
},
handleChildMax(max, children, isSlotElement) {
const len = children.length;
if (!max || max > len)
return;
const slotElement = isSlotElement ? children.pop() : '';
const leftChildren = children.splice(max, len - max, isSlotElement && slotElement);
leftChildren.forEach((child) => {
child.updateShow();
});
},
handleChildSize(size, children) {
if (!size)
return;
children.forEach((child) => {
child.updateSize(size);
});
},
handleChildCascading(cascading, children) {
if (cascading === 'right-up')
return;
const defaultZIndex = 100;
children.forEach((child, index) => {
child.updateCascading(defaultZIndex - index * 10);
});
},
};
}
ready() {
this.setData({
length: this.children.length,
});
this.handleHasChild(this.children, this.data.hasChild);
this.handleChildSlot(this.properties.max, this.children, this.handleChildMax);
this.handleChildSize(this.properties.size, this.children);
this.handleChildCascading(this.properties.cascading, this.children);
}
};
AvatarGroup = __decorate([
wxComponent()
], AvatarGroup);
export default AvatarGroup;
@@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"t-avatar": "./avatar"
}
}
@@ -0,0 +1,18 @@
<wxs src="./avatar-group.wxs" module="this" />
<view
class="{{classPrefix}} {{this.getAvatarGroupOuterClass(classPrefix, size)}} {{prefix}}-class"
style="{{this.getAvatarGroupSizePx(size)}}"
>
<slot />
<!-- 自定义折叠元素 -->
<view class="{{classPrefix}}__collapse--slot {{collapseAvatar ? '{{prefix}}-is-hidden' : ''}}">
<slot name="collapseAvatar" />
</view>
<!-- 默认折叠元素 -->
<view class="{{classPrefix}}__collapse--default" wx:if="{{max && (max < length)}}">
<t-avatar t-class-image="{{prefix}}-class-image" t-class-content="{{prefix}}-class-content" size="{{size}}"
>{{collapseAvatar || '+N'}}</t-avatar
>
</view>
</view>
@@ -0,0 +1,17 @@
module.exports = {
getAvatarGroupOuterClass: function (classPrefix, size) {
var isIncludePx = size.indexOf('px') > -1;
var classNames = [classPrefix + '--content', isIncludePx ? '' : classPrefix + '--' + size];
return classNames.join(' ');
},
getAvatarGroupSizePx: function (size) {
var isIncludePx = size.indexOf('px') > -1;
if (isIncludePx) {
return 'width:' + size + ';height:' + size + ';';
}
},
getZIndex: function (cascading) {
var zIndex = cascading === 'right-up' ? 100 : 0;
return 'z-index:' + zIndex + ';';
},
};
@@ -0,0 +1,78 @@
.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-avatar-group {
display: block;
}
.t-avatar-group--content {
display: flex;
}
.t-avatar-group--large .t-size-l {
width: 96rpx;
height: 96rpx;
font-weight: 600;
font-size: 36rpx;
}
.t-avatar-group--medium .t-size-m {
width: 80rpx;
height: 80rpx;
font-weight: 600;
font-size: 32rpx;
}
.t-avatar-group--small .t-size-s {
width: 64rpx;
height: 64rpx;
font-weight: 600;
font-size: 24rpx;
}
.t-avatar-group__collapse--slot {
float: left;
}
.t-avatar-group__collapse--slot:not(:empty) + .t-avatar-group__collapse--default {
display: none;
float: left;
}
.t-avatar-group__collapse--slot:empty + .t-avatar-group__collapse--default {
display: block;
float: left;
}
.t-avatar-group .t-is-hidden {
display: none;
}
.t-avatar-group .alt-default {
background-color: #d4e3fc;
color: #0052d9;
}
.t-avatar-group .alt-default-l {
font-size: 64rpx;
}
.t-avatar-group .alt-default-m {
font-size: 48rpx;
}
.t-avatar-group .alt-default-s {
font-size: 32rpx;
}
@@ -0,0 +1,74 @@
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;
};
import { SuperComponent, wxComponent } from '../common/src/index';
import config from '../common/config';
import avatarProps from './props';
const { prefix } = config;
const name = `${prefix}-avatar`;
let Avatar = class Avatar extends SuperComponent {
constructor() {
super(...arguments);
this.options = {
multipleSlots: true,
};
this.externalClasses = [
`${prefix}-class`,
`${prefix}-class-image`,
`${prefix}-class-icon`,
`${prefix}-class-alt`,
`${prefix}-class-content`,
];
this.properties = avatarProps;
this.data = {
prefix,
classPrefix: name,
isShow: true,
zIndex: 0,
isChild: false,
};
this.relations = {
'./avatar-group': {
type: 'ancestor',
linked(target) {
this.parent = target;
},
},
};
this.methods = {
updateIsChild(isChild) {
this.setData({
isChild,
});
},
updateShow() {
this.setData({
isShow: false,
});
},
updateSize(size) {
if (this.properties.size)
return;
this.setData({ size });
},
updateCascading(zIndex) {
this.setData({ zIndex });
},
};
}
onLoadError(e) {
if (this.properties.hideOnLoadFailed) {
this.setData({
isShow: false,
});
}
this.triggerEvent('error', e.detail);
}
};
Avatar = __decorate([
wxComponent()
], Avatar);
export default Avatar;
@@ -0,0 +1,8 @@
{
"component": true,
"usingComponents": {
"t-icon": "../icon/icon",
"t-badge": "../badge/badge",
"t-image": "../image/image"
}
}
@@ -0,0 +1,43 @@
<wxs src="./avatar.wxs" module="this" />
<view
class="{{classPrefix}}__wrapper {{this.getTClass(size)}} {{prefix}}-class"
style="{{this.getStyles(isShow, zIndex)}}"
>
<view
class="{{this.getAvatarOuterClass(classPrefix, size, shape)}} {{prefix}}-class-image"
style="{{this.getAvatarSizePx(size)}}"
>
<t-image
wx:if="{{image}}"
class="{{prefix}}-image"
t-class-load="{{prefix}}-class-alt"
t-class="{{classPrefix}}__image"
src="{{image}}"
mode="aspectFill"
binderror="onLoadError"
loadFailed="{{alt}}"
/>
<view
wx:elif="{{icon}}"
class="{{classPrefix}}__icon {{this.getIconClass(classPrefix, size)}} {{prefix}}-class-icon"
>
<t-icon name="{{icon}}" />
</view>
<view wx:else class="{{classPrefix}}__text {{prefix}}-class-content">
<slot />
</view>
</view>
<t-badge
class="{{prefix}}-badge-host {{prefix}}-badge__{{shape === 'circle' ? 'circle' : 'round'}}"
wx:if="{{badgeProps.dot || badgeProps.count}}"
color="{{badgeProps.color}}"
count="{{badgeProps.count}}"
max-count="{{badgeProps.maxCount || 100}}"
dot="{{badgeProps.dot}}"
content="{{badgeProps.content}}"
size="{{badgeProps.size}}"
visible="{{badgeProps.visible}}"
offset="{{badgeProps.offset}}"
/>
</view>
@@ -0,0 +1,29 @@
module.exports = {
getTClass: function (size) {
var isIncludePx = size.indexOf('px') > -1;
return isIncludePx ? '' : 't-size-' + (size || 'medium').slice(0, 1);
},
getAvatarOuterClass: function (classPrefix, size, shape) {
var isIncludePx = size.indexOf('px') > -1;
var classNames = [
classPrefix,
classPrefix + (shape === 'round' ? '--round' : '--circle'),
isIncludePx ? '' : 't-size-' + (size || 'medium').slice(0, 1),
];
return classNames.join(' ');
},
getAvatarSizePx: function (size = 'medium') {
var pxIndex = size.indexOf('px');
if (pxIndex > -1) {
return 'width:' + size + ';height:' + size + ';font-size:' + ((size.slice(0, pxIndex) / 8) * 3 + 2) + 'px;';
}
},
getStyles: function (isShow, zIndex) {
var styles = 'z-index:' + zIndex + ';';
return styles + (isShow ? '' : 'display: none;');
},
getIconClass: function (classPrefix, size) {
if (size.indexOf('px') > -1) return;
return classPrefix + '__icon--default-' + (size || 'medium').slice(0, 1);
},
};
@@ -0,0 +1,94 @@
.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-avatar {
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
font-weight: 600;
}
.t-avatar__wrapper {
float: left;
position: relative;
background-color: #d4e3fc;
color: #0052d9;
border-radius: 999rpx;
}
.t-avatar__wrapper .t-badge-host {
position: absolute;
}
.t-avatar__wrapper .t-badge__round {
top: -10%;
right: -10%;
}
.t-avatar__wrapper .t-badge__circle {
top: -5%;
right: -5%;
}
.t-avatar.t-size-l {
width: 128rpx;
height: 128rpx;
font-size: 52rpx;
}
.t-avatar.t-size-m {
width: 96rpx;
height: 96rpx;
font-size: 40rpx;
}
.t-avatar.t-size-s {
width: 64rpx;
height: 64rpx;
font-size: 28rpx;
}
.t-avatar .t-image,
.t-avatar__image {
width: 100%;
height: 100%;
}
.t-avatar--circle {
border-radius: 999rpx;
overflow: hidden;
}
.t-avatar--round {
border-radius: 10rpx;
overflow: hidden;
}
.t-avatar__text,
.t-avatar__icon {
font-size: inherit;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.t-avatar__text:empty,
.t-avatar__icon:empty {
width: 0;
height: 0;
}
@@ -0,0 +1,32 @@
const props = {
alt: {
type: String,
value: '',
},
badgeProps: {
type: Object,
},
externalClasses: {
type: Array,
},
hideOnLoadFailed: {
type: Boolean,
value: false,
},
icon: {
type: String,
},
image: {
type: String,
value: '',
},
shape: {
type: String,
value: 'circle',
},
size: {
type: String,
value: '',
},
};
export default props;
@@ -0,0 +1,62 @@
---
title: BackTop 返回顶部
description: 用于当页面过长往下滑动时,帮助用户快速回到页面顶部。
spline: navigation
isComponent: true
---
## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
```json
"usingComponents": {
"t-back-top": "tdesign-miniprogram/back-top/back-top",
}
```
## 代码演示
### 圆型返回顶部
<img src="https://tdesign.gtimg.com/miniprogram/readme/backtop-1.png" width="375px" height="50%">
```html
<!-- 圆白底 -->
<t-back-top theme="round" text="顶部"></t-back-top>
<!-- 圆黑底 -->
<t-back-top theme="round-dark" text="顶部"></t-back-top>
<!-- 圆白底纯图标 -->
<t-back-top theme="round" text=""></t-back-top>
<!-- 圆黑底纯图标 -->
<t-back-top theme="round-dark" text=""></t-back-top>
```
### 半圆型返回顶部
<img src="https://tdesign.gtimg.com/miniprogram/readme/backtop-2.png" width="375px" height="50%">
```html
<!-- 半圆白底 -->
<t-back-top theme="half-round" text="顶部"></t-back-top>
<!-- 半圆黑底 -->
<t-back-top theme="half-round-dark" text="顶部"></t-back-top>
```
## API
### BackTop Props
| 名称 | 类型 | 默认值 | 说明 | 必传 |
| ---------------- | ------------- | --------- | ------------------------------------------------------------------------------------------------------- | ---- |
| external-classes | Array | - | 组件类名,分别用于设置外层元素、图标、文本内容等元素类名。`['t-class', 't-class-icon', 't-class-text']` | N |
| fixed | Boolean | true | 是否绝对定位固定到屏幕右下方 | N |
| icon | String / Slot | 'backtop' | 图标 | N |
| text | String | '' | 文案 | N |
| theme | String | round | 预设的样式类型。可选项:round/half-round/round-dark/half-round-dark | N |
### BackTop Events
| 名称 | 参数 | 描述 |
| ------ | ---- | -------- |
| to-top | - | 点击触发 |
@@ -0,0 +1,33 @@
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;
};
import { SuperComponent, wxComponent } from '../common/src/index';
import config from '../common/config';
import props from './props';
const { prefix } = config;
const name = `${prefix}-back-top`;
let BackTop = class BackTop extends SuperComponent {
constructor() {
super(...arguments);
this.externalClasses = ['t-class', 't-class-icon', 't-class-text'];
this.properties = props;
this.data = {
prefix,
classPrefix: name,
};
}
toTop() {
this.triggerEvent('to-top');
wx.pageScrollTo({
scrollTop: 0,
duration: 300,
});
}
};
BackTop = __decorate([
wxComponent()
], BackTop);
export default BackTop;
@@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"t-icon": "../icon/icon"
}
}
@@ -0,0 +1,8 @@
<view
class="{{prefix}}-class {{classPrefix}} {{fixed ? prefix + '-is-fixed' : ''}} {{prefix + '-is-' + theme}}"
bindtap="toTop"
>
<t-icon wx:if="{{!!icon}}" class="{{classPrefix}}__icon {{prefix}}-class-icon" name="{{icon}}" />
<view wx:if="{{!!text}}" class="{{classPrefix}}__text {{prefix}}-class-text"> {{text}} </view>
<slot />
</view>
@@ -0,0 +1,116 @@
.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-back-top {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: transparent;
overflow: hidden;
box-sizing: border-box;
transition: height 0.2s;
height: auto;
}
.t-back-top.t-is-fixed {
position: fixed;
right: 32rpx;
bottom: 133rpx;
}
.t-back-top.t-is-round,
.t-back-top.t-is-round-dark {
width: 96rpx;
height: 96rpx;
border-radius: 50%;
}
.t-back-top.t-is-round .t-back-top__icon,
.t-back-top.t-is-round-dark .t-back-top__icon {
margin: 0;
border-radius: 0;
background-color: transparent;
}
.t-back-top.t-is-round .t-back-top__text,
.t-back-top.t-is-round-dark .t-back-top__text {
padding: 0;
margin-top: 0;
}
.t-back-top.t-is-round,
.t-back-top.t-is-half-round {
background-color: #ffffff;
color: #333;
border: 1rpx solid;
border-color: #ddd;
}
.t-back-top.t-is-round .t-back-top__icon,
.t-back-top.t-is-half-round .t-back-top__icon,
.t-back-top.t-is-round .t-back-top__text,
.t-back-top.t-is-half-round .t-back-top__text {
color: #333;
}
.t-back-top.t-is-round-dark,
.t-back-top.t-is-half-round-dark {
background-color: #000;
color: #fff;
}
.t-back-top.t-is-round-dark .t-back-top__icon,
.t-back-top.t-is-half-round-dark .t-back-top__icon,
.t-back-top.t-is-round-dark .t-back-top__text,
.t-back-top.t-is-half-round-dark .t-back-top__text {
color: #fff;
}
.t-back-top.t-is-half-round,
.t-back-top.t-is-half-round-dark {
width: 120rpx;
height: 80rpx;
border-radius: 120rpx 0 0 120rpx;
flex-direction: row;
right: 0;
}
.t-back-top.t-is-half-round .t-back-top__icon,
.t-back-top.t-is-half-round-dark .t-back-top__icon {
margin: 0;
border-radius: 0;
background-color: transparent;
}
.t-back-top.t-is-half-round .t-back-top__text,
.t-back-top.t-is-half-round-dark .t-back-top__text {
padding: 0;
margin-left: 8rpx;
width: 2em;
}
.t-back-top__text {
font-size: 20rpx;
color: #666;
line-height: 24rpx;
}
.t-back-top__icon {
display: flex;
justify-content: center;
align-items: center;
color: #666;
font-size: 32rpx;
}
@@ -0,0 +1,22 @@
const props = {
externalClasses: {
type: Array,
},
fixed: {
type: Boolean,
value: true,
},
icon: {
type: String,
value: 'backtop',
},
text: {
type: String,
value: '',
},
theme: {
type: String,
value: 'round',
},
};
export default props;
@@ -0,0 +1,2 @@
;
export {};
@@ -0,0 +1,87 @@
---
title: Badge 徽标
description: 用于告知用户,该区域的状态变化或者待处理任务的数量。
spline: data
isComponent: true
---
## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
```json
"usingComponents": {
"t-badge": "tdesign-miniprogram/badge/badge"
}
```
## 代码演示
### 普通徽标
<img src="https://tdesign.gtimg.com/miniprogram/readme/badge-1.png" width="375px" height="50%">
```html
<!-- 红点提示 -->
<t-badge dot content="消息" />
<!-- 数字提示 -->
<t-badge count="{{16}}" content="消息" />
<!-- 文字提示 -->
<t-badge count="New">
<text style="padding: 0 10px">消息</text>
</t-badge>
<!-- 角标提示 -->
<t-badge count="···">
<text style="padding: 0 10px">消息</text>
</t-badge>
<!-- 按钮提示 -->
<t-button t-class="size-mini" size="small" variant="outline">小按钮</t-button>
```
### 单元格徽标
<img src="https://tdesign.gtimg.com/miniprogram/readme/badge-2.png" width="375px" height="50%">
```html
<!-- 单元格提示 -->
<t-cell title="单行标题" hover arrow>
<view class="cell-badge-wrap" slot="note">
<t-badge dot />
</view>
</t-cell>
```
### 标签栏徽标
<img src="https://tdesign.gtimg.com/miniprogram/readme/badge-3.png" width="375px" height="50%">
```html
<!-- tabbar提示 -->
<t-tab-bar value="label1" bindchange="onChange" class="mb-12" t-class="tab-bar-wrapper">
<t-tab-bar-item badge-props="{{{count: 16}}}" value="label1" icon="app">文字</t-tab-bar-item>
<t-tab-bar-item badge-props="{{{dot: true}}}" value="label2" icon="app">文字 </t-tab-bar-item>
<t-tab-bar-item badge-props="{{{count: 'New'}}}" value="label3" icon="app">文字 </t-tab-bar-item>
<t-tab-bar-item badge-props="{{{count: '···'}}}" value="label4" icon="app">文字 </t-tab-bar-item>
</t-tab-bar>
```
## API
### Badge Props
| 名称 | 类型 | 默认值 | 说明 | 必传 |
| ---------------- | ---------------------- | ------ | ----------------------------------------------------------------------------------------------------------------- | -------- |
| color | String | - | 颜色 | N |
| content | String | - | 徽标内容,示例:`content='自定义内容'`。也可以使用默认插槽定义 | N |
| count | String / Number / Slot | 0 | 徽标右上角内容。可以是数字,也可以是文字。如:'new'/3/99+。特殊:值为空表示使用插槽渲染 | N |
| dot | Boolean | false | 是否为红点 | N |
| external-classes | Array | - | 组件类名,分别用于设置外层元素、默认内容、右上角内容等元素类名。`['t-class', 't-class-content', 't-class-count']` | N |
| max-count | Number | 99 | 封顶的数字值 | N |
| offset | Array | - | 设置状态点的位置偏移,示例:[-10, 20] 或 ['10em', '8rem']。TS 类型:`Array<string | number>` | N |
| shape | String | circle | 形状。可选项:circle/square/round/ribbon | N |
| show-zero | Boolean | false | 当数值为 0 时,是否展示徽标 | N |
| size | String | medium | 尺寸。可选项:small/medium | N |
@@ -0,0 +1,29 @@
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;
};
import { SuperComponent, wxComponent } from '../common/src/index';
import config from '../common/config';
import props from './props';
const { prefix } = config;
const name = `${prefix}-badge`;
let Badge = class Badge extends SuperComponent {
constructor() {
super(...arguments);
this.options = {
multipleSlots: true,
};
this.externalClasses = [`${prefix}-class`, `${prefix}-class-count`, `${prefix}-class-content`];
this.properties = props;
this.data = {
classPrefix: name,
value: '',
};
}
};
Badge = __decorate([
wxComponent()
], Badge);
export default Badge;
@@ -0,0 +1,5 @@
{
"component": true,
"usingComponents": {}
}
@@ -0,0 +1,15 @@
<wxs src="./badge.wxs" module="this" />
<view class="{{this.getBadgeOuterClass({shape})}} t-class">
<view class="{{classPrefix}}__content t-class-content">
<slot wx:if="{{!content}}" class="{{classPrefix}}__content-slot" />
<text wx:else class="{{classPrefix}}__content-text">{{content}}</text>
</view>
<view
wx:if="{{count !== 'slot' && this.isShowBadge({dot,count,visible})}}"
class="{{this.getBadgeInnerClass({dot, size, shape, count})}} t-has-count t-class-count"
style="{{this.getBadgeStyles({color, offset})}}"
>{{ this.getBadgeValue({dot, count, maxCount}) }}
</view>
<slot name="count" wx:if="{{count === 'slot' || !count}}" />
</view>
@@ -0,0 +1,51 @@
var getBadgeValue = function (props) {
if (props.dot) {
return '';
}
if (isNaN(props.count) || isNaN(props.maxCount)) {
return props.count;
}
return parseInt(props.count) > props.maxCount ? props.maxCount + '+' : props.count;
};
var getBadgeStyles = function (props) {
var styleStr = '';
styleStr += 'background:' + props.color + ';';
props.offset[0] && (styleStr += 'top:' + props.offset[0] + ';');
props.offset[1] && (styleStr += 'right:' + props.offset[1] + ';');
return styleStr;
};
var getBadgeOuterClass = function (props) {
var baseClass = 't-badge';
var classNames = [baseClass, props.shape === 'ribbon' ? baseClass + '__ribbon--outer' : ''];
return classNames.join(' ');
};
var getBadgeInnerClass = function (props) {
var baseClass = 't-badge';
var classNames = [
baseClass + '--basic',
props.dot ? baseClass + '--dot' : '',
props.size === 'small' ? baseClass + '--small' : '',
baseClass + '--' + props.shape,
!props.dot && props.count ? baseClass + '--count' : '',
];
return classNames.join(' ');
};
var isShowBadge = function (props) {
if (props.dot) {
return true;
}
if (!props.visible && !isNaN(props.count) && parseInt(props.count) === 0) {
return false;
}
return true;
};
module.exports.getBadgeValue = getBadgeValue;
module.exports.getBadgeStyles = getBadgeStyles;
module.exports.getBadgeOuterClass = getBadgeOuterClass;
module.exports.getBadgeInnerClass = getBadgeInnerClass;
module.exports.isShowBadge = isShowBadge;
@@ -0,0 +1,97 @@
.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-badge {
position: relative;
display: inline-block;
}
.t-badge--basic {
display: inline-block;
z-index: 100;
font-size: 20rpx;
color: #fff;
background-color: #e34d59;
height: 32rpx;
padding: 0 8rpx;
text-align: center;
line-height: 32rpx;
font-weight: normal;
}
.t-badge--dot {
height: 20rpx;
border-radius: 8rpx;
min-width: 20rpx;
padding: 0;
}
.t-badge--count {
min-width: 32rpx;
white-space: nowrap;
box-sizing: border-box;
}
.t-badge--small {
transform: translate(50%, -50%) scale(0.75);
}
.t-badge--circle {
border-radius: 32rpx;
}
.t-badge--round {
border-radius: 8rpx;
}
.t-badge__ribbon--outer {
position: absolute;
top: 0;
right: 0;
}
.t-badge--ribbon {
transform: rotate(45deg);
}
.t-badge--ribbon::before {
content: '';
position: absolute;
width: 0;
height: 0;
bottom: 0;
left: -32rpx;
border-bottom: 32rpx solid #e34d59;
border-left: 32rpx solid transparent;
}
.t-badge--ribbon::after {
content: '';
position: absolute;
width: 0;
height: 0;
bottom: 0;
right: -32rpx;
border-bottom: 32rpx solid #e34d59;
border-right: 32rpx solid transparent;
}
.t-badge__content:not(:empty) + .t-has-count {
transform: translate(50%, -50%);
position: absolute;
right: 0;
top: 0;
}
@@ -0,0 +1,3 @@
export * from './type';
export * from './props';
export * from './badge';
@@ -0,0 +1,42 @@
const props = {
color: {
type: String,
value: '',
},
content: {
type: String,
value: '',
},
count: {
type: String,
optionalTypes: [Number],
value: 0,
},
dot: {
type: Boolean,
value: false,
},
externalClasses: {
type: Array,
},
maxCount: {
type: Number,
value: 99,
},
offset: {
type: Array,
},
shape: {
type: String,
value: 'circle',
},
showZero: {
type: Boolean,
value: false,
},
size: {
type: String,
value: 'medium',
},
};
export default props;
@@ -0,0 +1,2 @@
;
export {};
@@ -0,0 +1,27 @@
export default Behavior({
methods: {
gettingBoundingClientRect(selector, all) {
return new Promise((resolve, reject) => {
try {
wx.createSelectorQuery()
.in(this)[all ? 'selectAll' : 'select'](selector)
.boundingClientRect((rect) => {
if (all && Array.isArray(rect) && rect.length) {
resolve(rect);
}
else if (!all && rect) {
resolve(rect);
}
else {
reject();
}
})
.exec();
}
catch (err) {
reject(err);
}
});
},
},
});
@@ -0,0 +1,35 @@
const MinDistance = 10;
const getDirection = (x, y) => {
if (x > y && x > MinDistance) {
return 'horizontal';
}
if (y > x && y > MinDistance) {
return 'vertical';
}
return '';
};
export default Behavior({
methods: {
resetTouchStatus() {
this.direction = '';
this.deltaX = 0;
this.deltaY = 0;
this.offsetX = 0;
this.offsetY = 0;
},
touchStart(event) {
this.resetTouchStatus();
const [touch] = event.touches;
this.startX = touch.clientX;
this.startY = touch.clientY;
},
touchMove(event) {
const [touch] = event.touches;
this.deltaX = touch.clientX - this.startX;
this.deltaY = touch.clientY - this.startY;
this.offsetX = Math.abs(this.deltaX);
this.offsetY = Math.abs(this.deltaY);
this.direction = this.direction || getDirection(this.offsetX, this.offsetY);
},
},
});
@@ -0,0 +1,46 @@
---
title: ButtonGroup
description: 按钮组
spline: base
isComponent: true
---
### 特性及兼容性
## 引入
### 引入组件
`app.json``page.json` 中引入组件:
```json
"usingComponents": {
"t-button-group": "tdesign-miniprogram/button-group/button-group"
}
```
## 用法
### 组件方式
```html
<!-- page.wxml -->
<t-button-group>
<t-button theme="ghost">置底按钮</t-button>
<t-button theme="primary">置底按钮</t-button>
</t-button-group>
```
## API
### `<t-button-group>` 组件
组件路径:`tdesign-miniprogram/button-group/button-group`
#### Props
| 属性 | 值类型 | 默认值 | 必传 | 说明 |
| ---- | ---------- | ------- | ----------- | ---- | ---------- |
| type | `'default' | 'menu'` | `'default'` | N | 按钮组样式 |
@@ -0,0 +1,35 @@
import TComponent from '../common/component';
import config from '../common/config';
import { canIUseFormFieldButton } from '../common/version';
const { prefix } = config;
const name = `${prefix}-button-group`;
TComponent({
behaviors: canIUseFormFieldButton() ? ['wx://form-field-button'] : [],
properties: {
type: {
type: String,
value: 'default',
},
},
data: {
className: '',
},
observers: {
type() {
this.setClass();
},
},
lifetimes: {
attached() {
this.setClass();
},
},
methods: {
setClass() {
const classList = [`${name}`, `${name}--${this.data.type}`];
this.setData({
className: classList.join(' '),
});
},
},
});
@@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}
@@ -0,0 +1,3 @@
<view class="{{className}}">
<slot></slot>
</view>
@@ -0,0 +1,47 @@
.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-button-group {
display: inline-flex;
width: 100%;
background: #fff;
}
.t-button-group--menu t-button:not(:first-child)::before {
position: absolute;
top: 20px/2;
height: 24px;
left: 0;
content: '';
width: 0;
border-left: solid #e6e6e6 1px;
}
.t-button-group t-button {
flex: 1;
/* stylelint-disable-next-line */
-webkit-flex: 1;
position: relative;
}
@@ -0,0 +1,117 @@
---
title: Button 按钮
description: 用于开启一个闭环的操作任务,如“删除”对象、“购买”商品等。
spline: base
isComponent: true
---
## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
```json
"usingComponents": {
"t-button": "tdesign-miniprogram/button/button",
"t-button-group": "tdesign-miniprogram/button-group/button-group"
}
```
## 代码演示
### 基础按钮
<img src="https://tdesign.gtimg.com/miniprogram/readme/button-1.png" width="375px" height="50%">
```html
<t-button theme="primary" size="large">强按钮</t-button>
<t-button theme="primary" size="large" variant="plain">弱按钮</t-button>
<t-button size="large" variant="plain">次按钮</t-button>
<t-button theme="primary" size="large" icon="app" variant="plain">带图标按钮</t-button>
<t-button theme="danger" size="large">强告警按钮</t-button>
<t-button theme="danger" size="large" variant="plain">弱告警按钮</t-button>
<view class="box">
<t-button ghost size="large">幽灵按钮</t-button>
</view>
<t-button variant="text" size="large">文字按钮</t-button>
<t-button theme="primary" size="large" shape="square" block>通栏按钮</t-button>
<t-button-group>
<t-button size="large" block shape="square">次按钮</t-button>
<t-button theme="primary" size="large" block shape="square">主按钮</t-button>
</t-button-group>
```
### 不同状态的按钮
<img src="https://tdesign.gtimg.com/miniprogram/readme/button-2.png" width="375px" height="50%">
```html
<t-button theme="primary" size="large" disabled>强按钮</t-button>
<t-button theme="primary" size="large" variant="plain" disabled>弱按钮</t-button>
<t-button size="large" variant="plain" disabled>次按钮</t-button>
<t-button theme="primary" size="large" icon="app" disabled>带图标按钮</t-button>
<t-button theme="danger" size="large" disabled>强告警按钮</t-button>
<t-button theme="danger" size="large" variant="plain" disabled>弱告警按钮</t-button>
<view class="box">
<t-button ghost size="large" disabled>幽灵按钮</t-button>
</view>
<t-button variant="text" size="large" disabled>文字按钮</t-button>
<t-button theme="primary" size="large" shape="square" block disabled>通栏按钮</t-button>
<t-button-group>
<t-button size="large" shape="square" block disabled>次按钮</t-button>
<t-button theme="primary" size="large" block shape="square" disabled>主按钮</t-button>
</t-button-group>
```
### 不同尺寸的按钮
<img src="https://tdesign.gtimg.com/miniprogram/readme/button-3.png" width="375px" height="50%">
```html
<t-button theme="primary" size="large">按钮 44</t-button>
<t-button theme="primary" style="margin-left: 16px">按钮 40</t-button>
<t-button theme="primary" size="small" style="margin-left: 16px">按钮 36</t-button>
```
## API
### Button Props
名称 | 类型 | 默认值 | 说明 | 必传
-- | -- | -- | -- | --
block | Boolean | false | 是否为块级元素 | N
content | String / Slot | - | 按钮内容 | N
custom-dataset | Any | - | 自定义 dataset,可通过 event.currentTarget.dataset.custom 获取。TS 类型:`any` | N
disabled | Boolean | false | 是否禁用按钮 | N
external-classes | Array | - | 组件类名。`['t-class', 't-class-icon', 't-class-loading']` | N
ghost | Boolean | false | 是否为幽灵按钮(镂空按钮) | N
icon | String | - | 图标名称 | N
icon-props | Object | {} | 图标属性,透传至 icon | N
loading | Boolean | false | 是否显示为加载状态 | N
shape | String | rectangle | 按钮形状,有 4 种:长方形、正方形、圆角长方形、圆形。可选项:rectangle/square/round/circle | N
size | String | medium | 组件尺寸。可选项:small/medium/large。TS 类型:`SizeEnum` | N
theme | String | default | 组件风格,依次为品牌色、危险色。可选项:default/primary/danger | N
type | String | - | 同小程序的 formType。可选项:submit/reset | N
variant | String | base | 按钮形式,基础、线框、文字。可选项:base/outline/text | N
open-type | String | - | 微信开放能力。<br />具体释义:<br />`contact` 打开客服会话,如果用户在会话中点击消息卡片后返回小程序,可以从 bindcontact 回调中获得具体信息,<a href="https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/customer-message/customer-message.html">具体说明</a> *小程序插件中不能使用*);<br />`share` 触发用户转发,使用前建议先阅读<a href="https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/share.html#使用指引">使用指引</a><br />`getPhoneNumber` 获取用户手机号,可以从 bindgetphonenumber 回调中获取到用户信息,<a href="https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html">具体说明</a> *小程序插件中不能使用*);<br />`getUserInfo` 获取用户信息,可以从 bindgetuserinfo 回调中获取到用户信息 (*小程序插件中不能使用*);<br />`launchApp` 打开APP,可以通过 app-parameter 属性设定向 APP 传的参数<a href="https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/launchApp.html">具体说明</a><br />`openSetting` 打开授权设置页;<br />`feedback` 打开“意见反馈”页面,用户可提交反馈内容并上传<a href="https://developers.weixin.qq.com/miniprogram/dev/api/base/debug/wx.getLogManager.html">日志</a>,开发者可以登录<a href="https://mp.weixin.qq.com/">小程序管理后台</a>后进入左侧菜单“客服反馈”页面获取到反馈内容;<br />`chooseAvatar` 获取用户头像,可以从 bindchooseavatar 回调中获取到头像信息。<br />[小程序官方文档](https://developers.weixin.qq.com/miniprogram/dev/component/button.html)。可选项:contact/share/getPhoneNumber/getUserInfo/launchApp/openSetting/feedback/chooseAvatar | N
hover-stop-propagation | Boolean | false | 指定是否阻止本节点的祖先节点出现点击态 | N
hover-start-time | Number | 20 | 按住后多久出现点击态,单位毫秒 | N
hover-stay-time | Number | 70 | 手指松开后点击态保留时间,单位毫秒 | N
lang | String | en | 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文。。<br />具体释义:<br />`en` 英文;<br />`zh_CN` 简体中文;<br />`zh_TW` 繁体中文。<br />[小程序官方文档](https://developers.weixin.qq.com/miniprogram/dev/component/button.html)。可选项:en/zh_CN/zh_TW | N
session-from | String | - | 会话来源,open-type="contact"时有效 | N
send-message-title | String | 当前标题 | 会话内消息卡片标题,open-type="contact"时有效 | N
send-message-path | String | 当前分享路径 | 会话内消息卡片点击跳转小程序路径,open-type="contact"时有效 | N
send-message-img | String | 截图 | 会话内消息卡片图片,open-type="contact"时有效 | N
app-parameter | String | - | 打开 APP 时,向 APP 传递的参数,open-type=launchApp时有效 | N
show-message-card | Boolean | false | 是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,用户点击后可以快速发送小程序消息,open-type="contact"时有效 | N
bindgetuserinfo | Eventhandle | - | 用户点击该按钮时,会返回获取到的用户信息,回调的 detail 数据与<a href="https://developers.weixin.qq.com/miniprogram/dev/api/open-api/user-info/wx.getUserInfo.html">wx.getUserInfo</a>返回的一致,open-type="getUserInfo"时有效 | N
bindcontact | Eventhandle | - | 客服消息回调,open-type="contact"时有效 | N
bindgetphonenumber | Eventhandle | - | 获取用户手机号回调,open-type=getPhoneNumber时有效 | N
binderror | Eventhandle | - | 当使用开放能力时,发生错误的回调,open-type=launchApp时有效 | N
bindopensetting | Eventhandle | - | 在打开授权设置页后回调,open-type=openSetting时有效 | N
bindlaunchapp | Eventhandle | - | 打开 APP 成功的回调,open-type=launchApp时有效 | N
bindchooseavatar | Eventhandle | - | 获取用户头像回调,open-type=chooseAvatar时有效 | N
### Button Events
名称 | 参数 | 描述
-- | -- | --
tap | `event.detail = event.detail` | 点击时触发
@@ -0,0 +1,89 @@
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;
};
import { SuperComponent, wxComponent } from '../common/src/index';
import config from '../common/config';
import props from './props';
import { canIUseFormFieldButton } from '../common/version';
const { prefix } = config;
const name = `${prefix}-button`;
let Button = class Button extends SuperComponent {
constructor() {
super(...arguments);
this.externalClasses = [`${prefix}-class`, `${prefix}-class-icon`, `${prefix}-class-loading`];
this.behaviors = canIUseFormFieldButton() ? ['wx://form-field-button'] : [];
this.properties = props;
this.data = {
prefix,
className: '',
classPrefix: name,
};
this.observers = {
'theme, size, plain, block, shape, disabled, loading'() {
this.setClass();
},
};
this.lifetimes = {
attached() {
this.setClass();
},
};
this.methods = {
setClass() {
const classList = [
name,
`${prefix}-class`,
`${name}--${this.data.theme || 'default'}`,
`${name}--size-${this.data.size.slice(0, 1)}`,
];
classList.push(`${name}--${this.data.shape}`);
if (this.data.block) {
classList.push(`${prefix}-is-block`);
}
if (this.data.disabled) {
classList.push(`${prefix}-is-disabled`);
}
classList.push(`${name}--${this.data.variant}`);
if (this.data.ghost) {
classList.push(`${name}--ghost`);
}
this.setData({
className: classList.join(' '),
});
},
getuserinfo(e) {
this.triggerEvent('getuserinfo', e.detail);
},
contact(e) {
this.triggerEvent('contact', e.detail);
},
getphonenumber(e) {
this.triggerEvent('getphonenumber', e.detail);
},
error(e) {
this.triggerEvent('error', e.detail);
},
opensetting(e) {
this.triggerEvent('opensetting', e.detail);
},
launchapp(e) {
this.triggerEvent('launchapp', e.detail);
},
chooseavatar(e) {
this.triggerEvent('chooseavatar', e.detail);
},
handleTap(e) {
if (this.data.disabled)
return;
this.triggerEvent('tap', e.detail);
},
};
}
};
Button = __decorate([
wxComponent()
], Button);
export default Button;
@@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"t-icon": "../icon/icon"
}
}
@@ -0,0 +1,43 @@
<button
data-custom="{{ customDataset }}"
class="{{className}} {{prefix}}-class"
form-type="{{type}}"
open-type="{{disabled ? '' : openType}}"
hover-stop-propagation="{{hoverStopPropagation}}"
hover-start-time="{{hoverStartTime}}"
hover-stay-time="{{hoverStayTime}}"
lang="{{lang}}"
session-from="{{sessionFrom}}"
hover-class="{{variant == 'text' ? 'none' : 'button-hover'}}"
send-message-title="{{sendMessageTitle}}"
send-message-path="{{sendMessagePath}}"
send-message-img="{{sendMessageImg}}"
app-parameter="{{appParameter}}"
show-message-card="{{showMessageCard}}"
catch:tap="handleTap"
bind:getuserinfo="getuserinfo"
bind:contact="contact"
bind:getphonenumber="getphonenumber"
bind:error="error"
bind:opensetting="opensetting"
bind:launchapp="launchapp"
bind:chooseavatar="chooseavatar"
>
<t-icon
wx:if="{{icon || iconProps.name}}"
name="{{icon || iconProps.name}}"
prefix="{{iconProps.prefix}}"
size="{{iconProps.size}}"
color="{{iconProps.color}}"
customStyle="{{iconProps.customStyle}}"
class="{{classPrefix}}__icon {{prefix}}-class-icon"
></t-icon>
<view wx:if="{{loading}}" class="{{classPrefix}}--loading {{prefix}}-class-loading">
<view class="{{classPrefix}}__circular"></view>
</view>
<view class="{{classPrefix}}__content">
<slot name="content" />
<block>{{content}}</block>
<slot />
</view>
</button>
@@ -0,0 +1,248 @@
.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-button {
display: inline-flex;
align-items: center;
justify-content: center;
position: relative;
white-space: nowrap;
text-align: center;
background-image: none;
border: 1px solid transparent;
cursor: pointer;
transition: all 0.3s;
user-select: none;
touch-action: manipulation;
font-size: 28rpx;
height: 80rpx;
border-radius: 8rpx;
color: rgba(0, 0, 0, 0.9);
border-color: #dcdcdc;
background-color: #fff;
outline: none;
font-family: PingFang SC, Microsoft YaHei, Arial Regular;
/* stylelint-disable-next-line */
-webkit-appearance: none;
}
.t-button::after {
background-color: #000;
content: ' ';
opacity: 0;
top: 0;
right: 0;
bottom: 0;
left: 0;
position: absolute;
}
.t-button:not(.t-is-disabled):active::after {
opacity: 0.1;
}
.t-button--default {
color: rgba(0, 0, 0, 0.9);
background-color: #ffffff;
border: 1px solid #dcdcdc;
}
.t-button--default.t-is-disabled {
color: rgba(0, 0, 0, 0.26);
}
.t-button--primary {
color: #fff;
background-color: #0052d9;
border: 1px solid #0052d9;
}
.t-button--primary.t-is-disabled {
background-color: #bbd3fb;
border-color: #bbd3fb;
}
.t-button--danger {
color: #fff;
background-color: #e34d59;
border: 1px solid #e34d59;
}
.t-button--danger.t-is-disabled {
background-color: #f8b9be;
border-color: #f8b9be;
}
.t-button--text {
color: #0052d9;
background: none;
border: 0;
}
.t-button--text.t-button--size-default {
width: auto;
height: auto;
line-height: normal;
padding: 0;
}
.t-button--text.t-is-disabled {
color: #bbd3fb;
}
.t-button--ghost {
background-color: transparent;
border: 1px solid #fff;
color: #fff;
}
.t-button--ghost.t-is-disabled {
color: rgba(255, 255, 255, 0.35);
border-color: rgba(255, 255, 255, 0.35);
}
.t-button--plain {
background-color: transparent;
}
.t-button--plain.t-button--primary {
color: #0052d9;
}
.t-button--plain.t-button--primary.t-is-disabled {
background-color: transparent;
color: #bbd3fb;
}
.t-button--plain.t-button--danger {
color: #e34d59;
}
.t-button--plain.t-button--danger.t-is-disabled {
background-color: transparent;
color: #f8b9be;
}
.t-button--base {
height: 80rpx;
line-height: 80rpx;
padding-left: 31rpx;
padding-right: 31rpx;
font-size: 28rpx;
}
.t-button--size-l {
height: 88rpx;
line-height: 88rpx;
}
.t-button--size-l .t-button__icon {
font-size: 48rpx;
}
.t-button--size-l .t-button--loading {
width: 48rpx;
height: 48rpx;
}
.t-button--size-l .t-button--loading + .t-button__content:not(:empty),
.t-button--size-l .t-button__icon + .t-button__content:not(:empty) {
margin-left: 16rpx;
}
.t-button--size-m .t-button__icon {
font-size: 44rpx;
}
.t-button--size-m .t-button--loading {
width: 44rpx;
height: 44rpx;
}
.t-button--size-m .t-button--loading + .t-button__content:not(:empty),
.t-button--size-m .t-button__icon + .t-button__content:not(:empty) {
margin-left: 8rpx;
}
.t-button--size-s {
height: 72rpx;
line-height: 72rpx;
}
.t-button--size-s .t-button__icon {
font-size: 40rpx;
}
.t-button--size-s .t-button--loading {
width: 40rpx;
height: 40rpx;
}
.t-button--size-s .t-button--loading + .t-button__content:not(:empty),
.t-button--size-s .t-button__icon + .t-button__content:not(:empty) {
margin-left: 8rpx;
}
.t-button__icon {
border-radius: 8rpx;
}
.t-button--round.t-button--size-l {
border-radius: 44rpx;
}
.t-button--round.t-button--size-m {
border-radius: 40rpx;
}
.t-button--round.t-button--size-s {
border-radius: 36rpx;
}
.t-button--square {
padding: 0;
}
.t-button--square.t-button--size-l {
width: 88rpx;
}
.t-button--square.t-button--size-m {
width: 80rpx;
}
.t-button--square.t-button--size-s {
width: 72rpx;
}
.t-button--circle {
padding: 0;
}
.t-button--circle.t-button--size-l {
border-radius: 50%;
width: 88rpx;
}
.t-button--circle.t-button--size-m {
border-radius: 50%;
width: 80rpx;
}
.t-button--circle.t-button--size-s {
border-radius: 50%;
width: 72rpx;
}
.t-button.t-is-block {
display: flex;
width: 100%;
}
.t-button.t-is-disabled {
cursor: not-allowed;
}
.t-button--loading {
box-sizing: border-box;
animation: rotate 0.8s linear infinite;
}
.t-button--loading .t-button__circular {
border-radius: 50%;
width: 100%;
height: 100%;
opacity: 1;
background: conic-gradient(from 90deg at 50% 50%, rgba(255, 255, 255, 0) 0% 0deg, currentColor 360deg, #ffffff 100% 360deg);
mask: radial-gradient(transparent calc(50% - 1rpx), #fff 50%);
/* stylelint-disable-next-line */
-webkit-mask: radial-gradient(transparent calc(50% - 1rpx), #fff 50%);
}
.t-button.button-hover:after {
border-radius: 8rpx;
}
.t-button-group .t-button {
border: 0;
border-radius: 0;
box-shadow: 0;
width: 100%;
height: 100%;
}
@@ -0,0 +1,3 @@
export * from './props';
export * from './type';
export * from './button';
@@ -0,0 +1,98 @@
const props = {
block: {
type: Boolean,
value: false,
},
content: {
type: String,
},
customDataset: {
type: null,
},
disabled: {
type: Boolean,
value: false,
},
externalClasses: {
type: Array,
},
ghost: {
type: Boolean,
value: false,
},
icon: {
type: String,
value: '',
},
iconProps: {
type: Object,
value: {},
},
loading: {
type: Boolean,
value: false,
},
shape: {
type: String,
value: 'rectangle',
},
size: {
type: String,
value: 'medium',
},
theme: {
type: String,
value: 'default',
},
type: {
type: String,
},
variant: {
type: String,
value: 'base',
},
openType: {
type: String,
},
hoverStopPropagation: {
type: Boolean,
value: false,
},
hoverStartTime: {
type: Number,
value: 20,
},
hoverStayTime: {
type: Number,
value: 70,
},
lang: {
type: String,
value: 'en',
},
sessionFrom: {
type: String,
value: '',
},
sendMessageTitle: {
type: String,
value: '',
},
sendMessagePath: {
type: String,
value: '',
},
sendMessageImg: {
type: String,
value: '',
},
appParameter: {
type: String,
value: '',
},
showMessageCard: {
type: Boolean,
value: false,
},
};
export default props;
@@ -0,0 +1,28 @@
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;
};
import { SuperComponent, wxComponent } from '../common/src/index';
import config from '../common/config';
import props from './props';
const { prefix } = config;
const name = `${prefix}-cell-group`;
let CellGroup = class CellGroup extends SuperComponent {
constructor() {
super(...arguments);
this.externalClasses = ['t-class'];
this.options = {
addGlobalClass: true,
};
this.properties = props;
this.data = {
classPrefix: name,
};
}
};
CellGroup = __decorate([
wxComponent()
], CellGroup);
export default CellGroup;
@@ -0,0 +1,3 @@
{
"component": true
}
@@ -0,0 +1,4 @@
<view wx:if="{{ title }}" class="{{ classPrefix }}__title"> {{ title }} </view>
<view class="t-class {{ classPrefix }} {{ bordered ? classPrefix + '--bordered' : '' }}">
<slot />
</view>
@@ -0,0 +1,63 @@
.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-cell-group {
position: relative;
}
.t-cell-group__title {
font-family: PingFangSC-Regular;
font-size: 28rpx;
color: #888888;
text-align: left;
line-height: 90rpx;
background-color: #fbfbfb;
padding-left: 32rpx;
}
.t-cell-group--bordered::before {
position: absolute;
box-sizing: border-box;
content: ' ';
pointer-events: none;
right: 0;
left: 0;
top: 0;
border-top: 1px solid #e6e6e6;
transform: scaleY(0.5);
z-index: 1;
}
.t-cell-group--bordered::after {
position: absolute;
box-sizing: border-box;
content: ' ';
pointer-events: none;
right: 0;
left: 0;
bottom: 0;
border-bottom: 1px solid #e6e6e6;
transform: scaleY(0.5);
z-index: 1;
}
@@ -0,0 +1,14 @@
const props = {
bordered: {
type: Boolean,
},
externalClasses: {
type: Array,
},
title: {
type: String,
value: '',
required: true,
},
};
export default props;
@@ -0,0 +1,2 @@
;
export {};
@@ -0,0 +1,107 @@
---
title: Cell 单元格
description: 用于各个类别行的信息展示。
spline: data
isComponent: true
---
## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
```json
"usingComponents": {
"t-cell": "tdesign-miniprogram/cell/cell"
}
```
## 代码演示
### 单行单元格
<img src="https://tdesign.gtimg.com/miniprogram/readme/cell-1.png" width="375px" height="50%">
```html
<!-- 单行 默认 -->
<t-cell title="单行标题" hover />
<!-- 单行 必须 -->
<t-cell title="单行标题" required />
<!-- 单行 辅助信息 -->
<t-cell title="单行标题" hover note="辅助信息" />
<!-- 单行 箭头 -->
<t-cell title="单行标题" hover arrow />
<!-- 单行 自定义辅助信息-slot -->
<t-cell title="单行标题" hover arrow>
<t-badge count="{{16}}" slot="note" />
</t-cell>
<!-- 单行 左侧icon-slot -->
<t-cell title="单行标题" hover>
<t-icon name="app" slot="left-icon" />
</t-cell>
```
### 多行单元格
<img src="https://tdesign.gtimg.com/miniprogram/readme/cell-2.png" width="375px" height="50%">
```html
<!-- 多行 -->
<t-cell title="多行标题" description="一段很长很长的内容文字" />
<!-- 多行 带图标 -->
<t-cell title="多行带图标" description="说明文字" note="辅助信息" arrow t-class-left="t-class-left">
<t-icon class="icon-center title-icon" name="app" slot="left-icon" />
</t-cell>
<!-- 多行 带头像 -->
<t-cell
title="多行带头像"
arrow
description="一段很长很长很长的内容文字"
t-class-image="title-image"
>
<view class="avatar" slot="left-icon">
<open-data type="userAvatarUrl" />
</view>
</t-cell>
<!-- 多行 带图片 -->
<t-cell
title="多行带图片"
description="一段很长很长的内容文字"
align="top"
t-class-image="title-image-large"
image="xxx.svg"
/>
```
## API
### Cell Props
名称 | 类型 | 默认值 | 说明 | 必传
-- | -- | -- | -- | --
align | String | middle | 内容的对齐方式,默认居中对齐。可选项:top/middle/bottom | N
arrow | Boolean | false | 是否显示右侧箭头 | N
bordered | Boolean | true | 是否显示下边框 | N
description | String / Slot | - | 下方内容描述 | N
external-classes | Array | - | 组件类名,分别用于设置 组件外层类名、标题类名、右侧说明文字类名、下方描述内容类名、图片类名、激活态类名、左侧图标类名、右侧图标类名 等。`['t-class', 't-class-title', 't-class-note', 't-class-description', 't-class-thumb', 't-class-hover', 't-class-left', 't-class-right']` | N
hover | Boolean | - | 是否开启点击反馈 | N
image | String / Slot | - | 主图 | N
jump-type | String | navigateTo | 链接跳转类型。可选项:switchTab/reLaunch/redirectTo/navigateTo | N
left-icon | String / Slot | - | 左侧图标,出现在单元格标题的左侧 | N
note | String / Slot | - | 和标题同行的说明文字 | N
required | Boolean | false | 是否显示表单必填星号 | N
right-icon | String / Slot | - | 最右侧图标 | N
title | String / Slot | - | 标题 | N
url | String | - | 点击后跳转链接地址。如果值为空,则表示不需要跳转 | N
### Cell Events
名称 | 参数 | 描述
-- | -- | --
click | - | 右侧内容
@@ -0,0 +1,50 @@
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;
};
import { SuperComponent, wxComponent } from '../common/src/index';
import config from '../common/config';
import props from './props';
const { prefix } = config;
const name = `${prefix}-cell`;
let Cell = class Cell extends SuperComponent {
constructor() {
super(...arguments);
this.externalClasses = [
`${prefix}-class`,
`${prefix}-class-title`,
`${prefix}-class-description`,
`${prefix}-class-note`,
`${prefix}-class-hover`,
`${prefix}-class-image`,
`${prefix}-class-left`,
`${prefix}-class-right`,
`${prefix}-class-right-icon`,
];
this.options = {
multipleSlots: true,
};
this.properties = props;
this.data = {
prefix,
classPrefix: name,
};
}
onClick(e) {
this.triggerEvent('click', e.detail);
this.jumpLink();
}
jumpLink(urlKey = 'url', link = 'jumpType') {
const url = this.data[urlKey];
const jumpType = this.data[link];
if (url) {
wx[jumpType]({ url });
}
}
};
Cell = __decorate([
wxComponent()
], Cell);
export default Cell;
@@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"t-icon": "../icon/icon"
}
}
@@ -0,0 +1,38 @@
<view
class="{{prefix}}-class {{classPrefix}} {{ hover ? classPrefix + '--hover' : ''}} {{ !bordered ? classPrefix + '--borderless' : ''}} {{classPrefix}}--{{align}}"
hover-class="{{classPrefix}}--hover-class"
hover-stay-time="70"
bind:tap="onClick"
>
<view class="{{classPrefix}}__left {{prefix}}-class-left">
<image wx:if="{{ image }}" class="{{classPrefix}}__left-image t-class-image" src="{{ image }}" />
<slot wx:else name="left-icon" />
</view>
<view class="{{classPrefix}}__title {{prefix}}-class-title">
<view class="{{classPrefix}}__title-text">
<block wx:if="{{ title }}"> {{ title}} </block>
<slot wx:else name="title" />
<block wx:if="{{required}}">
<text decode class="{{classPrefix}}--required">&nbsp;*</text>
</block>
</view>
<view class="{{classPrefix}}__description {{prefix}}-class-description">
<view wx:if="{{ description }}" class="{{classPrefix}}__description-text">{{description}}</view>
<slot wx:else name="description" />
</view>
</view>
<view class="{{classPrefix}}__note {{prefix}}-class-note">
<text wx:if="{{ note }}">{{note}}</text>
<slot wx:else name="note" />
</view>
<view class="{{classPrefix}}__right {{prefix}}-class-right">
<t-icon wx:if="{{ arrow }}" name="chevron-right" class="{{classPrefix}}__right-icon {{prefix}}-class-right-icon" />
<block wx:else>
<t-icon name="{{rightIcon}}" class="{{classPrefix}}__right-icon {{prefix}}-class-right-icon" />
<slot name="right-icon" />
</block>
</view>
</view>
@@ -0,0 +1,118 @@
.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-cell {
position: relative;
display: flex;
box-sizing: border-box;
width: 100%;
padding: 24rpx 32rpx;
font-size: 32rpx;
line-height: 48rpx;
color: rgba(0, 0, 0, 0.9);
background-color: #ffffff;
}
.t-cell::after {
position: absolute;
box-sizing: border-box;
content: ' ';
pointer-events: none;
right: 0;
left: 0;
bottom: 0;
border-bottom: 1px solid #e7e7e7;
transform: scaleY(0.5);
left: 32rpx;
}
.t-cell--borderless::after {
display: none;
}
.t-cell__description {
font-size: 28rpx;
line-height: 44rpx;
color: rgba(0, 0, 0, 0.4);
}
.t-cell__description-text {
margin-top: 8rpx;
}
.t-cell__note {
display: flex;
align-items: center;
justify-content: flex-end;
overflow: hidden;
color: rgba(0, 0, 0, 0.4);
}
.t-cell__title,
.t-cell__note {
flex: 1 1 auto;
}
.t-cell__title:empty,
.t-cell__note:empty {
display: none;
}
.t-cell__title-text {
display: flex;
}
.t-cell__left,
.t-cell__right {
display: flex;
align-items: center;
font-size: 48rpx;
line-height: 48rpx;
}
.t-cell__left:not(:empty) {
margin-right: 16rpx;
}
.t-cell__left-image {
height: 112rpx;
width: 112rpx;
}
.t-cell__right {
margin-left: 8rpx;
color: #bbb;
}
.t-cell__right-icon {
color: #bbb;
font-size: 48rpx;
line-height: 48rpx;
}
.t-cell--hover.t-cell--hover-class {
background-color: #f2f3f5;
}
.t-cell--required {
font-size: 32rpx;
color: #e34d59;
}
.t-cell--middle {
align-items: center;
}
.t-cell--top {
align-items: flex-start;
}
.t-cell--bottom {
align-items: flex-end;
}
@@ -0,0 +1,51 @@
const props = {
align: {
type: String,
value: 'middle',
},
arrow: {
type: Boolean,
value: false,
},
bordered: {
type: Boolean,
value: true,
},
description: {
type: String,
},
externalClasses: {
type: Array,
},
hover: {
type: Boolean,
},
image: {
type: String,
},
jumpType: {
type: String,
value: 'navigateTo',
},
leftIcon: {
type: String,
},
note: {
type: String,
},
required: {
type: Boolean,
value: false,
},
rightIcon: {
type: String,
},
title: {
type: String,
},
url: {
type: String,
value: '',
},
};
export default props;
@@ -0,0 +1 @@
export {};
@@ -0,0 +1,59 @@
---
title: checkbox-group
description: 组合多选框
spline: form
isComponent: true
---
### 特性及兼容性
## 引入
### 引入组件
`app.json``page.json` 中引入组件:
```json
"usingComponents": {
"t-checkbox": "tdesign-miniprogram/checkbox/checkbox",
"t-checkbox-group": "tdesign-miniprogram/checkbox-group/checkbox-group"
}
```
## 用法
### 组件方式
```html
<!-- page.wxml -->
<t-checkbox-group defaultValue="checkbox1" bind:change="onChange">
<t-checkbox title="单行标题" value="checkbox1" />
<t-checkbox title="单行标题" label="辅助信息" value="checkbox2" />
</t-checkbox-group>
```
<t-checkbox title="单行标题" value="checkbox1" defaultChecked="{{true}}"/>
## API
### `<t-checkbox-group>` 组件
组件路径:`tdesign-miniprogram/checkbox-group/checkbox-group`
#### Props
| 属性 | 值类型 | 默认值 | 必传 | 说明 |
| -------- | --------- | ------ | ---- | ---------------------- |
| value | `Array` | `[]` | N | 当前选中项的标识符 |
| name | `String` | - | N | 在表单内提交时的标识符 |
### Slots
| 名称 | 说明 |
| ---- | ----------------- |
| 默认 | `t-checkbox` 组件 |
#### Events
| 事件 | event.detail | 说明 |
| ----------- | -------------------------- | ------------------------ |
| bind:change | {names:当前选中项的标识符} | 当绑定值变化时触发的事件 |
@@ -0,0 +1,148 @@
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;
};
import { SuperComponent, wxComponent } from '../common/src/index';
import config from '../common/config';
import Props from '../checkbox/checkbox-group-props';
const { prefix } = config;
const name = `${prefix}-checkbox-group`;
let CheckBoxGroup = class CheckBoxGroup extends SuperComponent {
constructor() {
super(...arguments);
this.externalClasses = ['t-class'];
this.relations = {
'../checkbox/checkbox': {
type: 'descendant',
},
};
this.data = {
prefix,
classPrefix: name,
checkboxOptions: [],
};
this.properties = Object.assign(Object.assign({}, Props), { customStyle: String });
this.observers = {
value() {
this.updateChildren();
},
};
this.lifetimes = {
attached() {
this.initWithOptions();
},
ready() {
this.setCheckall();
},
};
this.controlledProps = [
{
key: 'value',
event: 'change',
},
];
this.$checkAll = null;
this.methods = {
getChilds() {
let items = this.getRelationNodes('../checkbox/checkbox');
if (!items.length) {
items = this.selectAllComponents(`.${prefix}-checkbox-option`);
}
return items || [];
},
updateChildren() {
const items = this.getChilds();
const { value } = this.data;
if (items.length > 0) {
items.forEach((item) => {
!item.data.checkAll &&
item.setData({
checked: value === null || value === void 0 ? void 0 : value.includes(item.data.value),
});
});
if (items.some((item) => item.data.checkAll)) {
this.setCheckall();
}
}
},
updateValue({ value, checked, checkAll, indeterminate }) {
let { value: newValue } = this.data;
const { max } = this.data;
const keySet = new Set(this.getChilds().map((item) => item.data.value));
newValue = newValue.filter((value) => keySet.has(value));
if (max && checked && newValue.length === max)
return;
if (checkAll) {
const items = this.getChilds();
newValue =
!checked && indeterminate
? items.map((item) => item.data.value)
: items
.filter(({ data }) => {
if (data.disabled) {
return newValue.includes(data.value);
}
return checked && !data.checkAll;
})
.map(({ data }) => data.value);
}
else if (checked) {
newValue = newValue.concat(value);
}
else {
const index = newValue.findIndex((v) => v === value);
newValue.splice(index, 1);
}
this._trigger('change', { value: newValue });
},
initWithOptions() {
const { options } = this.data;
if (!(options === null || options === void 0 ? void 0 : options.length) || !Array.isArray(options))
return;
const checkboxOptions = options.map((item) => {
const isLabel = ['number', 'string'].includes(typeof item);
return isLabel
? {
label: `${item}`,
value: item,
}
: Object.assign({}, item);
});
this.setData({
checkboxOptions,
});
},
handleInnerChildChange(e) {
var _a;
const { item } = e.target.dataset;
const { checked } = e.detail;
const rect = {};
if (item.checkAll) {
rect.indeterminate = (_a = this.$checkAll) === null || _a === void 0 ? void 0 : _a.data.indeterminate;
}
this.updateValue(Object.assign(Object.assign(Object.assign({}, item), { checked }), rect));
},
setCheckall() {
const items = this.getChilds();
if (!this.$checkAll) {
this.$checkAll = items.find((item) => item.data.checkAll);
}
if (!this.$checkAll)
return;
const { value } = this.data;
const valueSet = new Set(value.filter((val) => val !== this.$checkAll.data.value));
const isCheckall = items.every((item) => (item.data.checkAll ? true : valueSet.has(item.data.value)));
this.$checkAll.setData({
checked: valueSet.size > 0,
indeterminate: !isCheckall,
});
},
};
}
};
CheckBoxGroup = __decorate([
wxComponent()
], CheckBoxGroup);
export default CheckBoxGroup;
@@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"t-checkbox": "../checkbox/checkbox"
}
}
@@ -0,0 +1,14 @@
<view class="{{ classPrefix }} {{prefix}}-class" style="{{customStyle}}">
<slot />
<block wx:for="{{checkboxOptions}}" wx:key="value">
<t-checkbox
class="{{prefix}}-checkbox-option"
label="{{item.label || item.text || ''}}"
value="{{item.value || ''}}"
check-all="{{item.checkAll}}"
disabled="{{item.disabled}}"
data-item="{{item}}"
bind:change="handleInnerChildChange"
></t-checkbox>
</block>
</view>
@@ -0,0 +1,98 @@
---
title: Checkbox 复选框
description: 用于预设的一组选项中执行多项选择,并呈现选择结果。
spline: form
isComponent: true
---
## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
```json
"usingComponents": {
"t-checkbox": "tdesign-miniprogram/checkbox/checkbox",
"t-checkbox-group": "tdesign-miniprogram/checkbox-group/checkbox-group"
}
```
## 代码演示
### 基础复选框
<img src="https://tdesign.gtimg.com/miniprogram/readme/checkbox.png" width="375px" height="50%">
```html
<t-checkbox-group defaultValue="{{demoCheckbox1}}" bind:change="onChange">
<t-checkbox value="checkbox1" label="多选" />
<t-checkbox value="checkbox2" label="多选" />
<t-checkbox value="checkbox3" label="多选" />
<t-checkbox
value="checkbox4"
label="多选多选多选多选多选多选多选多选多选多选多选多选多选多选多选多选多选选多选多选多选多选"
max-label-row="2"
></t-checkbox>
<t-checkbox value="checkbox5" label="多选" max-content-row="2">
多选多选多选多选多选多选多选多选多选多选多选多选多选多选多选多选多选选多选多选多选选多选多选多选多选
</t-checkbox>
</t-checkbox-group>
<t-checkbox defaultChecked="{{true}}" label="多选" />
```
```js
Page({
data: {
demoCheckbox1: ['checkbox2', 'checkbox3'],
},
onChange(event) {
console.log('checkbox', event.detail.value);
},
});
```
## API
### Checkbox Props
名称 | 类型 | 默认值 | 说明 | 必传
-- | -- | -- | -- | --
align | String | left | 多选框和内容相对位置。可选项:left/right | N
check-all | Boolean | false | 用于标识是否为「全选选项」。单独使用无效,需在 CheckboxGroup 中使用 | N
checked | Boolean | false | 是否选中 | N
default-checked | Boolean | undefined | 是否选中。非受控属性 | N
color | String | #0052d9 | 多选框颜色 | N
content | String / Slot | - | 多选框内容 | N
content-disabled | Boolean | - | 是否禁用组件内容(content)触发选中 | N
disabled | Boolean | undefined | 是否禁用组件 | N
external-classes | Array | - | 组件类名,分别用于设置 组件外层、多选框图标、主文案、内容 等元素类名。`['t-class', 't-class-icon', 't-class-label', 't-class-content', 't-class-border']` | N
icon | Array | - | 自定义选中图标和非选中图标。示例:[选中态图标地址,非选中态图标地址]。TS 类型:`Array<string>` | N
indeterminate | Boolean | false | 是否为半选 | N
label | String / Slot | - | 主文案 | N
max-content-row | Number | 5 | 内容最大行数限制 | N
max-label-row | Number | 3 | 主文案最大行数限制 | N
name | String | - | HTML 元素原生属性 | N
readonly | Boolean | false | 只读状态 | N
value | String / Number | - | 多选框的值。TS 类型:`string | number` | N
### Checkbox Events
名称 | 参数 | 描述
-- | -- | --
change | `(checked: boolean)` | 值变化时触发
### CheckboxGroup Props
名称 | 类型 | 默认值 | 说明 | 必传
-- | -- | -- | -- | --
disabled | Boolean | false | 是否禁用组件 | N
max | Number | undefined | 支持最多选中的数量 | N
name | String | - | 统一设置内部复选框 HTML 属性 | N
options | Array | [] | 以配置形式设置子元素。示例1:`['北京', '上海']` ,示例2: `[{ label: '全选', checkAll: true }, { label: '上海', value: 'shanghai' }]`。checkAll 值为 true 表示当前选项为「全选选项」。TS 类型:`Array<CheckboxOption>` `type CheckboxOption = string | number | CheckboxOptionObj` `interface CheckboxOptionObj { label?: string; value?: string | number; disabled?: boolean; checkAll?: true }`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/checkbox/type.ts) | N
value | Array | [] | 选中值。TS 类型:`CheckboxGroupValue` `type CheckboxGroupValue = Array<string | number>`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/checkbox/type.ts) | N
default-value | Array | undefined | 选中值。非受控属性。TS 类型:`CheckboxGroupValue` `type CheckboxGroupValue = Array<string | number>`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/checkbox/type.ts) | N
### CheckboxGroup Events
名称 | 参数 | 描述
-- | -- | --
change | `(value: CheckboxGroupValue, context: CheckboxGroupChangeContext)` | 值变化时触发。`context.current` 表示当前变化的数据项,如果是全选则为空;`context.type` 表示引起选中数据变化的是选中或是取消选中。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/checkbox/type.ts)。<br/>`interface CheckboxGroupChangeContext { e: Event; current: string | number; option: CheckboxOption | TdCheckboxProps; type: 'check' | 'uncheck' }`<br/>
@@ -0,0 +1,27 @@
const props = {
disabled: {
type: Boolean,
value: false,
},
max: {
type: Number,
value: undefined,
},
name: {
type: String,
value: '',
},
options: {
type: Array,
value: [],
},
value: {
type: Array,
value: null,
},
defaultValue: {
type: Array,
value: [],
},
};
export default props;
@@ -0,0 +1,85 @@
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;
};
import { SuperComponent, wxComponent } from '../common/src/index';
import config from '../common/config';
import Props from './props';
const { prefix } = config;
const classPrefix = `${prefix}-checkbox`;
let CheckBox = class CheckBox extends SuperComponent {
constructor() {
super(...arguments);
this.externalClasses = [
`${prefix}-class`,
`${prefix}-class-label`,
`${prefix}-class-icon`,
`${prefix}-class-content`,
`${prefix}-class-border`,
];
this.behaviors = ['wx://form-field'];
this.relations = {
'../checkbox-group/checkbox-group': {
type: 'ancestor',
linked(parent) {
const { value, disabled } = parent.data;
const valueSet = new Set(value);
const data = {
disabled: disabled || this.data.disabled,
};
data.checked = valueSet.has(this.data.value);
if (this.data.checkAll) {
data.checked = valueSet.size > 0;
}
this.setData(data);
},
},
};
this.options = {
multipleSlots: true,
};
this.properties = Object.assign(Object.assign({}, Props), { theme: {
type: String,
value: 'default',
}, borderless: {
type: Boolean,
value: false,
} });
this.data = {
prefix,
classPrefix,
};
this.controlledProps = [
{
key: 'checked',
event: 'change',
},
];
this.methods = {
onChange(e) {
const { disabled, readonly } = this.data;
if (disabled || readonly)
return;
const { target } = e.currentTarget.dataset;
const { contentDisabled } = this.data;
if (target === 'text' && contentDisabled) {
return;
}
const checked = !this.data.checked;
const [parent] = this.getRelationNodes('../checkbox-group/checkbox-group');
if (parent) {
parent.updateValue(Object.assign(Object.assign({}, this.data), { checked }));
}
else {
this._trigger('change', { checked });
}
},
};
}
};
CheckBox = __decorate([
wxComponent()
], CheckBox);
export default CheckBox;
@@ -0,0 +1,7 @@
{
"component": true,
"usingComponents": {
"t-cell": "../cell/cell",
"t-icon": "../icon/icon"
}
}
@@ -0,0 +1,47 @@
<view
class="{{classPrefix}} {{prefix}}-class {{classPrefix}}--{{align}} {{classPrefix}}--{{theme}} {{checked ? prefix + '-is-actived' : ''}}"
>
<!-- icon -->
<view
wx:if="{{theme == 'default'}}"
class="{{classPrefix}}__icon-{{align}} {{prefix}}-class-icon"
data-target="icon"
bind:tap="onChange"
>
<block wx:if="{{icon.length > 0}}">
<view class="{{classPrefix}}__icon">
<image src="{{checked ? icon[0] : icon[1]}}" class="{{classPrefix}}__icon-image" webp />
</view>
</block>
<block wx:else>
<t-icon
color="{{checked && !disabled ? color : ''}}"
name="{{checked ? (indeterminate ? 'minus-circle-filled' : 'check-circle-filled') : 'circle'}}"
class="{{classPrefix}}__btn {{checked ? prefix + '-is-checked' : ''}} {{disabled ? prefix + '-is-disabled' : ''}}"
/>
</block>
</view>
<!-- 文本内容 -->
<view
class="{{classPrefix}}__content {{disabled ? prefix + '-is-disabled' : ''}}"
data-target="text"
bind:tap="onChange"
>
<!-- title -->
<view class="{{classPrefix}}__title {{prefix}}-class-label" style="-webkit-line-clamp:{{maxLabelRow}}">
{{label}}
<slot />
<slot name="label" />
</view>
<!-- content -->
<view class="{{classPrefix}}__description {{prefix}}-class-content " style="-webkit-line-clamp:{{maxContentRow}}">
{{content}}
<slot name="content" />
</view>
</view>
<!-- 内置下边框 -->
<view
wx:if="{{theme == 'default' && !borderless}}"
class="{{classPrefix}}__border {{classPrefix}}__border--{{align}} {{prefix}}-class-border"
/>
</view>
@@ -0,0 +1,132 @@
.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-checkbox {
display: flex;
flex-direction: row;
font-size: 32rpx;
padding: 32rpx 32rpx;
position: relative;
background: white;
}
.t-checkbox--right {
flex-direction: row-reverse;
}
.t-checkbox .limit-title-row {
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
}
.t-checkbox .image-center {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.t-checkbox__icon-left {
margin-right: 20rpx;
width: 40rpx;
}
.t-checkbox__icon-right {
right: 0px;
display: contents;
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.t-checkbox__icon-image {
width: 48rpx;
height: 48rpx;
vertical-align: sub;
}
.t-checkbox__icon {
line-height: 48rpx;
}
.t-checkbox__btn {
font-size: 48rpx;
display: block;
line-height: 40rpx;
color: #dcdcdc;
width: 48rpx;
}
.t-checkbox__content {
flex: 1;
line-height: 48rpx;
margin-right: 10px;
}
.t-checkbox__title {
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
}
.t-checkbox__description {
color: rgba(0, 0, 0, 0.4);
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
font-size: 28rpx;
line-height: 44rpx;
}
.t-checkbox__btn.t-is-checked {
color: #0052d9;
}
.t-checkbox__btn.t-is-disabled {
cursor: not-allowed;
color: #dcdcdc;
}
.t-checkbox__content.t-is-disabled {
cursor: not-allowed;
color: rgba(0, 0, 0, 0.26);
}
.t-checkbox__border {
position: absolute;
bottom: 0;
border-top: 1rpx solid #e7e7e7;
width: 100%;
}
.t-checkbox__border--left {
left: 80rpx;
width: calc(100% - 80rpx);
}
.t-checkbox__border--right {
right: 80rpx;
width: calc(100% - 80rpx);
}
.t-checkbox--tag {
font-size: 28rpx;
padding-top: 16rpx;
padding-bottom: 16rpx;
text-align: center;
background-color: #f3f3f3;
border-radius: 8rpx;
}
.t-checkbox--tag.t-is-actived {
color: #0052d9;
background-color: #ecf2fe;
}
.t-checkbox--tag .t-checkbox__content {
margin-right: 0;
}
@@ -0,0 +1,66 @@
const props = {
align: {
type: String,
value: 'left',
},
checkAll: {
type: Boolean,
value: false,
},
checked: {
type: Boolean,
value: null,
},
defaultChecked: {
type: Boolean,
value: false,
},
color: {
type: String,
value: '#0052d9',
},
content: {
type: String,
},
contentDisabled: {
type: Boolean,
},
disabled: {
type: Boolean,
value: undefined,
},
externalClasses: {
type: Array,
},
icon: {
type: Array,
},
indeterminate: {
type: Boolean,
value: false,
},
label: {
type: String,
},
maxContentRow: {
type: Number,
value: 5,
},
maxLabelRow: {
type: Number,
value: 3,
},
name: {
type: String,
value: '',
},
readonly: {
type: Boolean,
value: false,
},
value: {
type: String,
optionalTypes: [Number],
},
};
export default props;
@@ -0,0 +1,83 @@
---
title: Collapse 折叠面板
description: 用于对复杂区域进行分组和隐藏 常用于订单信息展示等
spline: data
isComponent: true
---
## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
```json
"usingComponents": {
"t-collapse": "tdesign-miniprogram/collapse/collapse",
"t-collapse-panel": "tdesign-miniprogram/collapse/collapse-panel"
}
```
## 代码演示
### 基本使用
```html
<t-collapse defaultValue="{{[0]}}">
<t-collapse-panel header="折叠面板标题" header-right-content value="{{0}}">
此处可自定义内容此处可自定义内容此处可自定义内容此处可自定义内容此处可自定义内容此处可自定义内容此处可自定义内容此处可自定义内容此处可自定义内容此处可自定义内容此处可自定义内容此处可自定义内容此处可自定义内容此处可自定义内容可自定义内容
</t-collapse-panel>
</t-collapse>
```
### 受控用法
```html
<t-collapse value="{{activeValues}}" bind:change="handleChange">
<t-collapse-panel header="折叠面板标题" value="{{0}}">
此处可自定义内容此处可自定义内容此处可自定义内容此处可自定义内容此处可自定义内容此处可自定义内容此处可自定义内容此处可自定义内容此处可自定义内容此处可自定义内容此处可自定义内容此处可自定义内容此处可自定义内容此处可自定义内容可自定义内容
</t-collapse-panel>
</t-collapse>
```
```js
Page({
data: {
activeValues: [0],
},
handleChange(e) {
this.setData({
activeValues: e.detail.value,
});
},
});
```
## API
### Collapse Props
名称 | 类型 | 默认值 | 说明 | 必传
-- | -- | -- | -- | --
default-expand-all | Boolean | false | 默认是否展开全部 | N
disabled | Boolean | - | 是否禁用面板展开/收起操作 | N
expand-icon | Boolean / Slot | true | 展开图标。值为 undefined 或 false 则不显示展开图标;值为 true 显示默认图标;值类型为函数,则表示完全自定义展开图标 | N
expand-mutex | Boolean | false | 每个面板互斥展开,每次只展开一个面板 | N
value | Array | - | 展开的面板集合。TS 类型:`CollapseValue` `type CollapseValue = Array<string | number>`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/collapse/type.ts) | N
default-value | Array | undefined | 展开的面板集合。非受控属性。TS 类型:`CollapseValue` `type CollapseValue = Array<string | number>`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/collapse/type.ts) | N
### Collapse Events
名称 | 参数 | 描述
-- | -- | --
change | `(value: CollapseValue)` | 切换面板时触发,返回变化的值
### CollapsePanel Props
名称 | 类型 | 默认值 | 说明 | 必传
-- | -- | -- | -- | --
content | String / Slot | - | 折叠面板内容 | N
disabled | Boolean | undefined | 禁止当前面板展开,优先级大于 Collapse 的同名属性 | N
expand-icon | Boolean / Slot | undefined | 当前折叠面板展开图标,优先级大于 Collapse 的同名属性 | N
external-classes | Array | - | 组件类名,用于组件外层元素、标题、内容。`['t-class', 't-class-header', 't-class-content']` | N
header | String / Slot | - | 面板头内容 | N
header-right-content | String / Slot | - | 面板头的右侧区域,一般用于呈现面板操作 | N
value | String / Number | - | 当前面板唯一标识,如果值为空则取当前面下标兜底作为唯一标识 | N
@@ -0,0 +1,27 @@
const props = {
content: {
type: String,
},
disabled: {
type: Boolean,
value: null,
},
expandIcon: {
type: Boolean,
value: true,
},
externalClasses: {
type: Array,
},
header: {
type: String,
},
headerRightContent: {
type: String,
},
value: {
type: String,
optionalTypes: [Number],
},
};
export default props;
@@ -0,0 +1,118 @@
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;
};
import { SuperComponent, wxComponent } from '../common/src/index';
import config from '../common/config';
import props from './collapse-panel-props';
const { prefix } = config;
const name = `${prefix}-collapse-panel`;
const nextTick = () => new Promise((resolve) => setTimeout(resolve, 20));
let CollapsePanel = class CollapsePanel extends SuperComponent {
constructor() {
super(...arguments);
this.externalClasses = [`${prefix}-class`, `${prefix}-class-content`, `${prefix}-class-header`];
this.options = {
multipleSlots: true,
};
this.relations = {
'./collapse': {
type: 'ancestor',
linked(target) {
this.parent = target;
const { value, defaultExpandAll, expandMutex, expandIcon, disabled } = target.properties;
const activeValues = defaultExpandAll && !expandMutex ? [this.properties.value] : value;
this.setData({
ultimateExpandIcon: expandIcon || this.properties.expandIcon,
ultimateDisabled: this.properties.disabled == null ? disabled : this.properties.disabled,
});
this.updateExpanded(activeValues);
},
},
};
this.properties = props;
this.data = {
prefix,
contentHeight: 0,
expanded: false,
classPrefix: name,
classBasePrefix: prefix,
ultimateExpandIcon: false,
ultimateDisabled: false,
};
this.methods = {
set(data) {
this.setData(data);
return new Promise((resolve) => wx.nextTick(resolve));
},
updateExpanded(activeValues) {
if (!this.parent) {
return Promise.resolve()
.then(nextTick)
.then(() => {
const data = { transition: true };
if (this.data.expanded) {
data.contentHeight = 'auto';
}
this.setData(data);
});
}
const { value } = this.properties;
const expanded = activeValues.includes(value);
if (expanded === this.properties.expanded)
return;
this.setData({ expanded });
this.updateStyle(expanded);
},
getRect(selector, all) {
return new Promise((resolve) => {
wx.createSelectorQuery()
.in(this)[all ? 'selectAll' : 'select'](selector)
.boundingClientRect((rect) => {
if (all && Array.isArray(rect) && rect.length) {
resolve(rect);
}
if (!all && rect) {
resolve(rect);
}
})
.exec();
});
},
updateStyle(expanded) {
return this.getRect(`.${name}__content`)
.then((rect) => rect.height)
.then((height) => {
if (expanded) {
return this.set({
contentHeight: height ? `${height}px` : 'auto',
});
}
return this.set({ contentHeight: `${height}px` })
.then(nextTick)
.then(() => this.set({ contentHeight: 0 }));
});
},
onClick() {
const { ultimateDisabled } = this.data;
const { value } = this.properties;
if (ultimateDisabled)
return;
this.parent.switch(value);
},
onTransitionEnd() {
if (this.data.expanded) {
this.setData({
contentHeight: 'auto',
});
}
},
};
}
};
CollapsePanel = __decorate([
wxComponent()
], CollapsePanel);
export default CollapsePanel;
@@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"t-cell": "../cell/cell"
}
}
@@ -0,0 +1,31 @@
<wxs src="../common/utils.wxs" module="utils" />
<view class="{{classPrefix}} {{prefix}}-class">
<t-cell
title="{{header}}"
note="{{headerRightContent}}"
bordered
right-icon="{{ ultimateExpandIcon ? (expanded ? 'chevron-up' : 'chevron-down') : '' }}"
class="{{classPrefix}}__title"
t-class="{{classPrefix}}__header {{prefix}}-class-header"
t-class-title="class-title {{ultimateDisabled ? 'class-title--disabled' : ''}}"
t-class-note="class-note {{ultimateDisabled ? 'class-note--disabled' : ''}}"
t-class-right-icon="class-right-icon {{ultimateDisabled ? 'class-right-icon--disabled' : ''}}"
t-class-hover="class-header-hover"
bind:click="onClick"
>
<slot name="header" slot="title" />
<slot name="header-right-content" slot="note" />
<slot name="expand-icon" slot="right-icon" />
</t-cell>
<view class="{{classPrefix}}__wrapper" style="height: {{contentHeight}};" bind:transitionend="onTransitionEnd">
<view
class="{{classPrefix}}__content {{classPrefix}}__content--{{expanded ? 'active' : ''}} {{prefix}}-class-content"
>
{{content}}
<slot />
<slot name="content" />
</view>
</view>
</view>
<!-- parentDisabled -->
@@ -0,0 +1,92 @@
.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-collapse-panel {
overflow: hidden;
transition: height 200ms ease-in-out;
box-shadow: inset 0 -1px 0 0 #eeeeee;
background-color: #fff;
}
.t-collapse-panel--active {
height: auto;
}
.t-collapse-panel--disabled {
pointer-events: none;
}
.t-collapse-panel--disabled .t-collapse-panel__content,
.t-collapse-panel--disabled .t-collapse-panel__header {
opacity: 0.3;
}
.t-collapse-panel__header {
position: relative;
display: flex;
justify-content: space-between;
align-items: center;
padding-left: 32rpx;
height: 96rpx;
box-shadow: inset 0 -1px 0 0 #eeeeee;
color: #000000;
}
.t-collapse-panel__header-right {
display: inline-flex;
align-items: center;
height: 100%;
}
.t-collapse-panel__header-icon {
height: 100%;
padding-left: 8px;
width: 44px;
padding-right: 8px;
color: rgba(0, 0, 0, 0.4);
}
.t-collapse-panel__extra {
font-size: 32rpx;
}
.t-collapse-panel__body {
box-shadow: inset 0 -1px 0 0 #eeeeee;
}
.t-collapse-panel__wrapper {
transition: height 200ms ease-in-out;
}
.t-collapse-panel__content {
color: #000000;
font-size: 28rpx;
padding: 32rpx;
line-height: 1.5;
}
.class-title {
font-size: 32rpx;
}
.class-title--disabled {
color: rgba(0, 0, 0, 0.26);
}
.class-note--disabled {
color: rgba(0, 0, 0, 0.26) !important;
}
.class-right-icon--disabled {
color: rgba(0, 0, 0, 0.26) !important;
}
@@ -0,0 +1,69 @@
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;
};
import { SuperComponent, wxComponent } from '../common/src/index';
import config from '../common/config';
import props from './props';
const { prefix } = config;
const name = `${prefix}-collapse`;
let Collapse = class Collapse extends SuperComponent {
constructor() {
super(...arguments);
this.options = {
addGlobalClass: true,
};
this.externalClasses = [`${prefix}-class`];
this.relations = {
'./collapse-panel': {
type: 'descendant',
linked() {
},
},
};
this.controlledProps = [
{
key: 'value',
event: 'change',
},
];
this.properties = props;
this.data = {
prefix,
classPrefix: name,
};
this.observers = {
'value, expandMutex '() {
this.updateExpanded();
},
};
this.methods = {
updateExpanded() {
const panels = this.getRelationNodes('./collapse-panel');
if (panels.length === 0)
return;
panels.forEach((child) => {
child.updateExpanded(this.properties.value);
});
},
switch(panelValue) {
const { expandMutex, value: activeValues } = this.properties;
let value = [];
const hit = activeValues.indexOf(panelValue);
if (hit > -1) {
value = activeValues.filter((item) => item !== panelValue);
}
else {
value = expandMutex ? [panelValue] : activeValues.concat(panelValue);
}
this._trigger('change', { value });
},
};
}
};
Collapse = __decorate([
wxComponent()
], Collapse);
export default Collapse;
@@ -0,0 +1,3 @@
{
"component": true
}
@@ -0,0 +1,3 @@
<view class="{{prefix}}-class {{ classPrefix }} {{ border ? 'hairline--top-bottom' : '' }}">
<slot />
</view>
@@ -0,0 +1,49 @@
.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-collapse__title {
font-size: 28rpx;
padding: 12px;
padding-top: 24px;
color: #999;
}
.hairline--top-bottom:after {
position: absolute;
box-sizing: border-box;
transform-origin: center;
content: ' ';
pointer-events: none;
top: -50%;
right: -50%;
bottom: -50%;
left: -50%;
border: 0 solid #eee;
transform: scale(0.5);
}
.hairline--top-bottom:after {
border-width: 1px 0;
}
@@ -0,0 +1,4 @@
export { default as Collapse } from './collapse';
export * from './type';
export * from './props';
export * from './collapse-panel-props';

Some files were not shown because too many files have changed in this diff Show More