diff --git a/app.js b/app.js
index 1ed57c4..dc53c84 100644
--- a/app.js
+++ b/app.js
@@ -1,4 +1,5 @@
// app.js
+import api from './utils/api.js';
App({
onLaunch() {
// 展示本地存储能力
@@ -15,5 +16,6 @@ App({
},
globalData: {
userInfo: null
- }
+ },
+ $api: api,
})
diff --git a/app.json b/app.json
index f289833..e13ed22 100644
--- a/app.json
+++ b/app.json
@@ -8,7 +8,11 @@
],
"usingComponents": {
"t-tab-bar": "/components/tab-bar/tab-bar",
- "t-tab-bar-item": "/components/tab-bar/tab-bar-item"
+ "t-tab-bar-item": "/components/tab-bar/tab-bar-item",
+ "t-cell": "/components/cell/cell",
+ "t-swipe-cell": "/components/swipe-cell/swipe-cell",
+ "t-tabs": "/components/tabs/tabs",
+ "t-tab-panel": "/components/tabs/tab-panel"
},
"window": {
"backgroundTextStyle": "light",
@@ -18,4 +22,4 @@
},
"style": "v2",
"sitemapLocation": "sitemap.json"
-}
\ No newline at end of file
+}
diff --git a/components/behaviors/dom.d.ts b/components/behaviors/dom.d.ts
new file mode 100644
index 0000000..ae80eca
--- /dev/null
+++ b/components/behaviors/dom.d.ts
@@ -0,0 +1,2 @@
+declare const _default: string;
+export default _default;
diff --git a/components/behaviors/dom.js b/components/behaviors/dom.js
new file mode 100644
index 0000000..4aa85ff
--- /dev/null
+++ b/components/behaviors/dom.js
@@ -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);
+ }
+ });
+ },
+ },
+});
diff --git a/components/behaviors/touch.d.ts b/components/behaviors/touch.d.ts
new file mode 100644
index 0000000..ae80eca
--- /dev/null
+++ b/components/behaviors/touch.d.ts
@@ -0,0 +1,2 @@
+declare const _default: string;
+export default _default;
diff --git a/components/behaviors/touch.js b/components/behaviors/touch.js
new file mode 100644
index 0000000..cbabccc
--- /dev/null
+++ b/components/behaviors/touch.js
@@ -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 = getDirection(this.offsetX, this.offsetY);
+ },
+ },
+});
diff --git a/components/cell/README.md b/components/cell/README.md
new file mode 100644
index 0000000..4bdc541
--- /dev/null
+++ b/components/cell/README.md
@@ -0,0 +1,57 @@
+---
+title: Cell 单元格
+description: 用于各个类别行的信息展示。
+spline: data
+isComponent: true
+---
+
+


+## 引入
+
+全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
+
+```json
+"usingComponents": {
+ "t-cell": "tdesign-miniprogram/cell/cell"
+}
+```
+
+## 代码演示
+
+### 单行单元格
+
+
+
+{{ base }}
+
+### 多行单元格
+
+
+
+{{ multiple }}
+
+## 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-description', 't-class-note', 't-class-hover', 't-class-image', 't-class-left', 't-class-left-icon', 't-class-right', 't-class-right-icon']` | 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 | - | 右侧内容
diff --git a/components/cell/cell.d.ts b/components/cell/cell.d.ts
new file mode 100644
index 0000000..92eb1c9
--- /dev/null
+++ b/components/cell/cell.d.ts
@@ -0,0 +1,14 @@
+import { SuperComponent } from '../common/src/index';
+export default class Cell extends SuperComponent {
+ externalClasses: string[];
+ options: {
+ multipleSlots: boolean;
+ };
+ properties: import("./type").TdCellProps;
+ data: {
+ prefix: string;
+ classPrefix: string;
+ };
+ onClick(e: any): void;
+ jumpLink(urlKey?: string, link?: string): void;
+}
diff --git a/components/cell/cell.js b/components/cell/cell.js
new file mode 100644
index 0000000..7950416
--- /dev/null
+++ b/components/cell/cell.js
@@ -0,0 +1,51 @@
+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-left-icon`,
+ `${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;
diff --git a/components/cell/cell.json b/components/cell/cell.json
new file mode 100644
index 0000000..049940c
--- /dev/null
+++ b/components/cell/cell.json
@@ -0,0 +1,6 @@
+{
+ "component": true,
+ "usingComponents": {
+ "t-icon": "../icon/icon"
+ }
+}
diff --git a/components/cell/cell.wxml b/components/cell/cell.wxml
new file mode 100644
index 0000000..c3ba655
--- /dev/null
+++ b/components/cell/cell.wxml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+ {{ title}}
+
+
+ *
+
+
+
+
+ {{description}}
+
+
+
+
+
+ {{note}}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/cell/cell.wxss b/components/cell/cell.wxss
new file mode 100644
index 0000000..fa30bf4
--- /dev/null
+++ b/components/cell/cell.wxss
@@ -0,0 +1,121 @@
+.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-icon {
+ font-size: 48rpx;
+}
+.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;
+}
diff --git a/components/cell/props.d.ts b/components/cell/props.d.ts
new file mode 100644
index 0000000..ad657e5
--- /dev/null
+++ b/components/cell/props.d.ts
@@ -0,0 +1,3 @@
+import { TdCellProps } from './type';
+declare const props: TdCellProps;
+export default props;
diff --git a/components/cell/props.js b/components/cell/props.js
new file mode 100644
index 0000000..8e741e8
--- /dev/null
+++ b/components/cell/props.js
@@ -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;
diff --git a/components/cell/type.d.ts b/components/cell/type.d.ts
new file mode 100644
index 0000000..00d874b
--- /dev/null
+++ b/components/cell/type.d.ts
@@ -0,0 +1,72 @@
+export interface TdCellProps {
+ align?: {
+ type: StringConstructor;
+ value?: 'top' | 'middle' | 'bottom';
+ required?: boolean;
+ };
+ arrow?: {
+ type: BooleanConstructor;
+ value?: boolean;
+ required?: boolean;
+ };
+ bordered?: {
+ type: BooleanConstructor;
+ value?: boolean;
+ required?: boolean;
+ };
+ description?: {
+ type: StringConstructor;
+ value?: string;
+ required?: boolean;
+ };
+ externalClasses?: {
+ type: ArrayConstructor;
+ value?: ['t-class', 't-class-title', 't-class-note', 't-class-description', 't-class-thumb', 't-class-hover', 't-class-left', 't-class-right'];
+ required?: boolean;
+ };
+ hover?: {
+ type: BooleanConstructor;
+ value?: boolean;
+ required?: boolean;
+ };
+ image?: {
+ type: StringConstructor;
+ value?: string;
+ required?: boolean;
+ };
+ jumpType?: {
+ type: StringConstructor;
+ value?: 'switchTab' | 'reLaunch' | 'redirectTo' | 'navigateTo';
+ required?: boolean;
+ };
+ leftIcon?: {
+ type: StringConstructor;
+ value?: string;
+ required?: boolean;
+ };
+ note?: {
+ type: StringConstructor;
+ value?: string;
+ required?: boolean;
+ };
+ required?: {
+ type: BooleanConstructor;
+ value?: boolean;
+ required?: boolean;
+ };
+ rightIcon?: {
+ type: StringConstructor;
+ value?: string;
+ required?: boolean;
+ };
+ title?: {
+ type: StringConstructor;
+ value?: string;
+ required?: boolean;
+ };
+ url?: {
+ type: StringConstructor;
+ value?: string;
+ required?: boolean;
+ };
+}
diff --git a/components/cell/type.js b/components/cell/type.js
new file mode 100644
index 0000000..cb0ff5c
--- /dev/null
+++ b/components/cell/type.js
@@ -0,0 +1 @@
+export {};
diff --git a/components/mixins/page-scroll.d.ts b/components/mixins/page-scroll.d.ts
new file mode 100644
index 0000000..efe4f63
--- /dev/null
+++ b/components/mixins/page-scroll.d.ts
@@ -0,0 +1,7 @@
+///
+///
+declare type IPageScrollOption = WechatMiniprogram.Page.IPageScrollOption;
+declare type Scroller = (this: WechatMiniprogram.Component.TrivialInstance, event?: IPageScrollOption) => void;
+export declare const pageScrollMixin: (scroller: Scroller) => string;
+export declare const getRect: (context: any, selector: string) => Promise;
+export {};
diff --git a/components/mixins/page-scroll.js b/components/mixins/page-scroll.js
new file mode 100644
index 0000000..2cf9fc4
--- /dev/null
+++ b/components/mixins/page-scroll.js
@@ -0,0 +1,50 @@
+const getCurrentPage = function () {
+ const pages = getCurrentPages();
+ return pages[pages.length - 1];
+};
+const onPageScroll = function (event) {
+ const page = getCurrentPage();
+ if (!page)
+ return;
+ const { pageScroller } = page;
+ pageScroller.forEach((scroller) => {
+ if (typeof scroller === 'function') {
+ scroller(event);
+ }
+ });
+};
+export const pageScrollMixin = (scroller) => {
+ let bindScroller = scroller;
+ return Behavior({
+ attached() {
+ const page = getCurrentPage();
+ if (!page)
+ return;
+ bindScroller = scroller.bind(this);
+ if (Array.isArray(page.pageScroller)) {
+ page.pageScroller.push(bindScroller);
+ }
+ else {
+ page.pageScroller =
+ typeof page.onPageScroll === 'function' ? [page.onPageScroll.bind(page), bindScroller] : [bindScroller];
+ }
+ page.onPageScroll = onPageScroll;
+ },
+ detached() {
+ var _a;
+ const page = getCurrentPage();
+ if (!page)
+ return;
+ page.pageScroller = ((_a = page.pageScroller) === null || _a === void 0 ? void 0 : _a.filter((item) => item !== scroller)) || [];
+ },
+ });
+};
+export const getRect = function (context, selector) {
+ return new Promise((resolve) => {
+ wx.createSelectorQuery()
+ .in(context)
+ .select(selector)
+ .boundingClientRect()
+ .exec((rect = []) => resolve(rect[0]));
+ });
+};
diff --git a/components/mixins/transition.d.ts b/components/mixins/transition.d.ts
new file mode 100644
index 0000000..8c23e35
--- /dev/null
+++ b/components/mixins/transition.d.ts
@@ -0,0 +1 @@
+export default function transition(): string;
diff --git a/components/mixins/transition.js b/components/mixins/transition.js
new file mode 100644
index 0000000..ee5215a
--- /dev/null
+++ b/components/mixins/transition.js
@@ -0,0 +1,123 @@
+import config from '../common/config';
+const { prefix } = config;
+export default function transition() {
+ return Behavior({
+ properties: {
+ visible: {
+ type: Boolean,
+ value: null,
+ observer: 'watchVisible',
+ },
+ appear: Boolean,
+ name: {
+ type: String,
+ value: 'fade',
+ },
+ durations: {
+ type: Number,
+ optionalTypes: [Array],
+ },
+ },
+ data: {
+ transitionClass: '',
+ transitionDurations: 300,
+ className: '',
+ realVisible: false,
+ },
+ created() {
+ this.status = '';
+ this.transitionT = 0;
+ },
+ attached() {
+ this.durations = this.getDurations();
+ if (this.data.visible) {
+ this.enter();
+ }
+ this.inited = true;
+ },
+ detached() {
+ clearTimeout(this.transitionT);
+ },
+ methods: {
+ watchVisible(curr, prev) {
+ if (this.inited && curr !== prev) {
+ curr ? this.enter() : this.leave();
+ }
+ },
+ getDurations() {
+ const { durations } = this.data;
+ if (Array.isArray(durations)) {
+ return durations.map((item) => Number(item));
+ }
+ return [Number(durations), Number(durations)];
+ },
+ enter() {
+ const { name } = this.data;
+ const [duration] = this.durations;
+ this.status = 'entering';
+ this.setData({
+ realVisible: true,
+ transitionClass: `${prefix}-${name}-enter ${prefix}-${name}-enter-active`,
+ });
+ setTimeout(() => {
+ this.setData({
+ transitionClass: `${prefix}-${name}-enter-active ${prefix}-${name}-enter-to`,
+ });
+ }, 30);
+ if (typeof duration === 'number' && duration > 0) {
+ this.transitionT = setTimeout(this.entered.bind(this), duration + 30);
+ }
+ },
+ entered() {
+ this.customDuration = false;
+ clearTimeout(this.transitionT);
+ this.status = 'entered';
+ this.setData({
+ transitionClass: '',
+ });
+ },
+ leave() {
+ const { name } = this.data;
+ const [, duration] = this.durations;
+ this.status = 'leaving';
+ this.setData({
+ transitionClass: `${prefix}-${name}-leave ${prefix}-${name}-leave-active`,
+ });
+ clearTimeout(this.transitionT);
+ setTimeout(() => {
+ this.setData({
+ transitionClass: `${prefix}-${name}-leave-active ${prefix}-${name}-leave-to`,
+ });
+ }, 30);
+ if (typeof duration === 'number' && duration > 0) {
+ this.customDuration = true;
+ this.transitionT = setTimeout(this.leaved.bind(this), duration + 30);
+ }
+ },
+ leaved() {
+ this.customDuration = false;
+ this.triggerEvent('leaved');
+ clearTimeout(this.transitionT);
+ this.status = 'leaved';
+ this.setData({
+ transitionClass: '',
+ });
+ },
+ onTransitionEnd() {
+ if (this.customDuration) {
+ return;
+ }
+ clearTimeout(this.transitionT);
+ if (this.status === 'entering' && this.data.visible) {
+ this.entered();
+ }
+ else if (this.status === 'leaving' && !this.data.visible) {
+ this.leaved();
+ this.setData({
+ realVisible: false,
+ });
+ }
+ },
+ },
+ });
+}
diff --git a/components/sticky/README.md b/components/sticky/README.md
new file mode 100644
index 0000000..ec56105
--- /dev/null
+++ b/components/sticky/README.md
@@ -0,0 +1,56 @@
+---
+title: Sticky 吸顶容器
+description: 用于常驻页面顶部的信息、操作展示。
+spline: data
+isComponent: true
+---
+
+


+## 引入
+
+全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
+
+```json
+"usingComponents": {
+ "t-sticky": "/components/sticky/sticky"
+}
+```
+
+## 代码演示
+
+将内容包裹在 `Sticky` 组件内
+
+
+
+### 基础吸顶
+
+{{ base }}
+
+
+### 吸顶距离
+
+{{ offset }}
+
+### 指定容器
+
+{{ container }}
+
+
+
+## API
+
+### Sticky Props
+
+| 名称 | 类型 | 默认值 | 说明 | 必传 |
+| ---------------- | -------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------- | ---- |
+| container | Function | - | 函数返回容器对应的 NodesRef 节点,将对应节点指定为组件的外部容器,滚动时组件会始终保持在容器范围内,当组件即将超出容器底部时,会返回原位置。 | N |
+| disabled | Boolean | false | 是否禁用组件 | N |
+| external-classes | Array | - | 根结点外部样式。`['t-class']` | N |
+| offset-top | Number | 0 | 吸顶时与顶部的距离,单位`px` | N |
+| z-index | Number | 99 | 吸顶时的 z-index | N |
+
+### Sticky Events
+
+| 名称 | 参数 | 描述 |
+| ------ | --------------------------------------------------- | ------------------------------------------------------ |
+| scroll | `(detail: { scrollTop: number, isFixed: boolean })` | 滚动时触发,scrollTop: 距离顶部位置,isFixed: 是否吸顶 |
diff --git a/components/sticky/index.d.ts b/components/sticky/index.d.ts
new file mode 100644
index 0000000..a6df66d
--- /dev/null
+++ b/components/sticky/index.d.ts
@@ -0,0 +1,3 @@
+export * from './props';
+export * from './type';
+export * from './sticky';
diff --git a/components/sticky/index.js b/components/sticky/index.js
new file mode 100644
index 0000000..a6df66d
--- /dev/null
+++ b/components/sticky/index.js
@@ -0,0 +1,3 @@
+export * from './props';
+export * from './type';
+export * from './sticky';
diff --git a/components/sticky/props.d.ts b/components/sticky/props.d.ts
new file mode 100644
index 0000000..175af72
--- /dev/null
+++ b/components/sticky/props.d.ts
@@ -0,0 +1,3 @@
+import { TdStickyProps } from './type';
+declare const props: TdStickyProps;
+export default props;
diff --git a/components/sticky/props.js b/components/sticky/props.js
new file mode 100644
index 0000000..7e5cb71
--- /dev/null
+++ b/components/sticky/props.js
@@ -0,0 +1,21 @@
+const props = {
+ container: {
+ type: null,
+ },
+ disabled: {
+ type: Boolean,
+ value: false,
+ },
+ externalClasses: {
+ type: Array,
+ },
+ offsetTop: {
+ type: Number,
+ value: 0,
+ },
+ zIndex: {
+ type: Number,
+ value: 99,
+ },
+};
+export default props;
diff --git a/components/sticky/sticky.d.ts b/components/sticky/sticky.d.ts
new file mode 100644
index 0000000..c2c0138
--- /dev/null
+++ b/components/sticky/sticky.d.ts
@@ -0,0 +1,30 @@
+import { SuperComponent } from '../common/src/index';
+import type { TdStickyProps } from './type';
+export interface StickyProps extends TdStickyProps {
+}
+export default class Sticky extends SuperComponent {
+ externalClasses: string[];
+ properties: TdStickyProps;
+ behaviors: string[];
+ observers: {
+ 'offsetTop, disabled, container'(): void;
+ };
+ data: {
+ prefix: string;
+ containerStyle: string;
+ contentStyle: string;
+ classPrefix: string;
+ };
+ ready(): void;
+ methods: {
+ onScroll(event?: {
+ scrollTop: number;
+ }): void;
+ setDataAfterDiff(data: {
+ isFixed: boolean;
+ height?: number;
+ transform?: number;
+ }): void;
+ getContainerRect(): Promise;
+ };
+}
diff --git a/components/sticky/sticky.js b/components/sticky/sticky.js
new file mode 100644
index 0000000..08999ef
--- /dev/null
+++ b/components/sticky/sticky.js
@@ -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 props from './props';
+import config from '../common/config';
+import { pageScrollMixin, getRect } from '../mixins/page-scroll';
+const { prefix } = config;
+const ContainerClass = `.${prefix}-sticky`;
+let Sticky = class Sticky extends SuperComponent {
+ constructor() {
+ super(...arguments);
+ this.externalClasses = [`${prefix}-class`];
+ this.properties = props;
+ this.behaviors = [
+ pageScrollMixin(function (event) {
+ this.onScroll(event);
+ }),
+ ];
+ this.observers = {
+ 'offsetTop, disabled, container'() {
+ this.onScroll();
+ },
+ };
+ this.data = {
+ prefix,
+ containerStyle: '',
+ contentStyle: '',
+ classPrefix: `.${prefix}-sticky`,
+ };
+ this.methods = {
+ onScroll(event) {
+ const { scrollTop } = event || {};
+ const { container, offsetTop, disabled } = this.properties;
+ if (disabled) {
+ this.setDataAfterDiff({
+ isFixed: false,
+ transform: 0,
+ });
+ return;
+ }
+ this.scrollTop = scrollTop || this.scrollTop;
+ if (typeof container === 'function') {
+ Promise.all([getRect(this, ContainerClass), this.getContainerRect()]).then(([root, container]) => {
+ if (!root || !container)
+ return;
+ if (offsetTop + root.height > container.height + container.top) {
+ this.setDataAfterDiff({
+ isFixed: false,
+ transform: container.height - root.height,
+ });
+ }
+ else if (offsetTop >= root.top) {
+ this.setDataAfterDiff({
+ isFixed: true,
+ height: root.height,
+ transform: 0,
+ });
+ }
+ else {
+ this.setDataAfterDiff({ isFixed: false, transform: 0 });
+ }
+ });
+ return;
+ }
+ getRect(this, ContainerClass).then((root) => {
+ if (!root)
+ return;
+ if (offsetTop >= root.top) {
+ this.setDataAfterDiff({ isFixed: true, height: root.height });
+ this.transform = 0;
+ }
+ else {
+ this.setDataAfterDiff({ isFixed: false });
+ }
+ });
+ },
+ setDataAfterDiff(data) {
+ const { offsetTop } = this.properties;
+ const { containerStyle: prevContainerStyle, contentStyle: prevContentStyle } = this.data;
+ const { isFixed, height, transform } = data;
+ wx.nextTick(() => {
+ let containerStyle = '';
+ let contentStyle = '';
+ if (isFixed) {
+ containerStyle += `height:${height}px;`;
+ contentStyle += `position:fixed;top:${offsetTop}px`;
+ }
+ if (transform) {
+ const translate = `translate3d(0, ${transform}px, 0)`;
+ contentStyle += `-webkit-transform:${translate};transform:${translate};`;
+ }
+ if (prevContainerStyle !== containerStyle || prevContentStyle !== contentStyle) {
+ this.setData({ containerStyle, contentStyle });
+ }
+ this.triggerEvent('scroll', {
+ scrollTop: this.scrollTop,
+ isFixed,
+ });
+ });
+ },
+ getContainerRect() {
+ const nodesRef = this.properties.container();
+ return new Promise((resolve) => nodesRef.boundingClientRect(resolve).exec());
+ },
+ };
+ }
+ ready() {
+ this.onScroll();
+ }
+};
+Sticky = __decorate([
+ wxComponent()
+], Sticky);
+export default Sticky;
diff --git a/components/sticky/sticky.json b/components/sticky/sticky.json
new file mode 100644
index 0000000..a89ef4d
--- /dev/null
+++ b/components/sticky/sticky.json
@@ -0,0 +1,4 @@
+{
+ "component": true,
+ "usingComponents": {}
+}
diff --git a/components/sticky/sticky.wxml b/components/sticky/sticky.wxml
new file mode 100644
index 0000000..c1781f1
--- /dev/null
+++ b/components/sticky/sticky.wxml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/components/sticky/sticky.wxss b/components/sticky/sticky.wxss
new file mode 100644
index 0000000..730de8a
--- /dev/null
+++ b/components/sticky/sticky.wxss
@@ -0,0 +1,33 @@
+.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-sticky {
+ position: relative;
+}
+.t-sticky__content {
+ width: 100%;
+}
diff --git a/components/sticky/type.d.ts b/components/sticky/type.d.ts
new file mode 100644
index 0000000..acdbedb
--- /dev/null
+++ b/components/sticky/type.d.ts
@@ -0,0 +1,27 @@
+export interface TdStickyProps {
+ container?: {
+ type: null;
+ value?: null;
+ required?: boolean;
+ };
+ disabled?: {
+ type: BooleanConstructor;
+ value?: boolean;
+ required?: boolean;
+ };
+ externalClasses?: {
+ type: ArrayConstructor;
+ value?: ['t-class'];
+ required?: boolean;
+ };
+ offsetTop?: {
+ type: NumberConstructor;
+ value?: number;
+ required?: boolean;
+ };
+ zIndex?: {
+ type: NumberConstructor;
+ value?: number;
+ required?: boolean;
+ };
+}
diff --git a/components/sticky/type.js b/components/sticky/type.js
new file mode 100644
index 0000000..95da36c
--- /dev/null
+++ b/components/sticky/type.js
@@ -0,0 +1,2 @@
+;
+export {};
diff --git a/components/swipe-cell/README.md b/components/swipe-cell/README.md
new file mode 100644
index 0000000..0fd1156
--- /dev/null
+++ b/components/swipe-cell/README.md
@@ -0,0 +1,46 @@
+---
+title: SwipeCell 滑动操作
+description: 用于承载列表中的更多操作,通过左右滑动来展示,按钮的宽度固定高度根据列表高度而变化。
+spline: message
+isComponent: true
+---
+
+


+## 引入
+
+全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
+
+```json
+"usingComponents": {
+ "t-swipe-cell": "tdesign-miniprogram/swipe-cell/swipe-cell"
+}
+```
+
+## 代码演示
+
+
+
+### 往左滑动
+
+{{ left }}
+
+### 往右滑动
+
+{{ right }}
+
+## API
+
+### SwipeCell Props
+
+| 名称 | 类型 | 默认值 | 说明| 必传 |
+| -------- | --------------- | ------ | -- | --------------- |
+| disabled | Boolean | - | 是否禁用滑动| N |
+| left | Array / Slot | - | 左侧滑动操作项。所有行为同 `right`。TS 类型:`Array`| N |
+| opened | Boolean / Array | false | 操作项是否呈现为打开态,值为数组时表示分别控制左右滑动的展开和收起状态。TS 类型:`boolean| Array` | N |
+| right | Array / Slot | - | 右侧滑动操作项。有两种定义方式,一种是使用数组,二种是使用插槽。`right.text` 表示操作文本,`right.className` 表示操作项类名,`right.style` 表示操作项样式,`right.onClick` 表示点击操作项后执行的回调函数。示例:`[{ text: '删除', style: 'background-color: red', onClick: () => { /** TO DO */ } }]`。TS 类型:`Array`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/swipe-cell/type.ts) | N |
+
+### SwipeCell Events
+
+名称 | 参数 | 描述
+-- | -- | --
+click | `(action: SwipeActionItem, source: SwipeSource)` | 操作项点击时触发(插槽写法组件不触发,业务侧自定义内容和事件)。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/swipe-cell/type.ts)。
`type SwipeSource = 'left' | 'right'`
diff --git a/components/swipe-cell/props.d.ts b/components/swipe-cell/props.d.ts
new file mode 100644
index 0000000..9a3159c
--- /dev/null
+++ b/components/swipe-cell/props.d.ts
@@ -0,0 +1,3 @@
+import { TdSwipeCellProps } from './type';
+declare const props: TdSwipeCellProps;
+export default props;
diff --git a/components/swipe-cell/props.js b/components/swipe-cell/props.js
new file mode 100644
index 0000000..5298eef
--- /dev/null
+++ b/components/swipe-cell/props.js
@@ -0,0 +1,17 @@
+const props = {
+ disabled: {
+ type: Boolean,
+ },
+ left: {
+ type: Array,
+ },
+ opened: {
+ type: Boolean,
+ optionalTypes: [Array],
+ value: false,
+ },
+ right: {
+ type: Array,
+ },
+};
+export default props;
diff --git a/components/swipe-cell/swipe-cell.d.ts b/components/swipe-cell/swipe-cell.d.ts
new file mode 100644
index 0000000..4f7a37a
--- /dev/null
+++ b/components/swipe-cell/swipe-cell.d.ts
@@ -0,0 +1,23 @@
+import { SuperComponent } from '../common/src/index';
+export default class SwiperCell extends SuperComponent {
+ behaviors: string[];
+ externalClasses: string[];
+ options: {
+ multipleSlots: boolean;
+ };
+ properties: import("./type").TdSwipeCellProps;
+ data: {
+ wrapperStyle: string;
+ closed: boolean;
+ opened: boolean;
+ classPrefix: string;
+ };
+ attached(): void;
+ setSwipeWidth(): Promise;
+ detached(): void;
+ open(): void;
+ close(): void;
+ closeOther(): void;
+ onTap(): void;
+ onActionTap(event: any): void;
+}
diff --git a/components/swipe-cell/swipe-cell.js b/components/swipe-cell/swipe-cell.js
new file mode 100644
index 0000000..848d2da
--- /dev/null
+++ b/components/swipe-cell/swipe-cell.js
@@ -0,0 +1,77 @@
+var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
+};
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+import dom from '../behaviors/dom';
+import { SuperComponent, wxComponent } from '../common/src/index';
+import config from '../common/config';
+import props from './props';
+let ARRAY = [];
+const { prefix } = config;
+let SwiperCell = class SwiperCell extends SuperComponent {
+ constructor() {
+ super(...arguments);
+ this.behaviors = [dom];
+ this.externalClasses = ['t-class'];
+ this.options = {
+ multipleSlots: true,
+ };
+ this.properties = props;
+ this.data = {
+ wrapperStyle: '',
+ closed: true,
+ opened: false,
+ classPrefix: `.${prefix}-swipe-cell`,
+ };
+ }
+ attached() {
+ ARRAY.push(this);
+ wx.nextTick(() => {
+ this.setSwipeWidth();
+ });
+ }
+ setSwipeWidth() {
+ return __awaiter(this, void 0, void 0, function* () {
+ const rightRect = yield this.gettingBoundingClientRect(`${this.data.classPrefix}__right`);
+ const leftRect = yield this.gettingBoundingClientRect(`${this.data.classPrefix}__left`);
+ this.setData({
+ leftWidth: leftRect.width,
+ rightWidth: rightRect.width,
+ });
+ });
+ }
+ detached() {
+ ARRAY = ARRAY.filter((item) => item !== this);
+ }
+ open() {
+ this.setData({ opened: true });
+ }
+ close() {
+ this.setData({ opened: false });
+ }
+ closeOther() {
+ ARRAY.filter((item) => item !== this).forEach((item) => item.close());
+ }
+ onTap() {
+ this.close();
+ }
+ onActionTap(event) {
+ const { currentTarget: { dataset: { action }, }, } = event;
+ this.triggerEvent('click', action);
+ }
+};
+SwiperCell = __decorate([
+ wxComponent()
+], SwiperCell);
+export default SwiperCell;
diff --git a/components/swipe-cell/swipe-cell.json b/components/swipe-cell/swipe-cell.json
new file mode 100644
index 0000000..467ce29
--- /dev/null
+++ b/components/swipe-cell/swipe-cell.json
@@ -0,0 +1,3 @@
+{
+ "component": true
+}
diff --git a/components/swipe-cell/swipe-cell.wxml b/components/swipe-cell/swipe-cell.wxml
new file mode 100644
index 0000000..170fbf6
--- /dev/null
+++ b/components/swipe-cell/swipe-cell.wxml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+ {{item.text}}
+
+
+
+
+
+
+ {{item.text}}
+
+
+
+
diff --git a/components/swipe-cell/swipe-cell.wxs b/components/swipe-cell/swipe-cell.wxs
new file mode 100644
index 0000000..dbb7fec
--- /dev/null
+++ b/components/swipe-cell/swipe-cell.wxs
@@ -0,0 +1,176 @@
+var THRESHOLD = 0.3;
+var MIN_DISTANCE = 10;
+var owner;
+var state;
+
+var getState = function (ownerInstance) {
+ owner = ownerInstance;
+ state = owner.getState();
+ state.leftWidth = state.leftWidth || 0;
+ state.rightWidth = state.rightWidth || 0;
+ state.offset = state.offset || 0;
+ state.startOffset = state.startOffset || 0;
+ state.opened = state.opened || false;
+};
+
+var initRightWidth = function (newVal, oldVal, ownerInstance) {
+ getState(ownerInstance);
+ state.rightWidth = newVal;
+ initOpen(ownerInstance);
+};
+
+var initLeftWidth = function (newVal, oldVal, ownerInstance) {
+ getState(ownerInstance);
+ state.leftWidth = newVal;
+ initOpen(ownerInstance);
+};
+
+var initOpen = function (ownerInstance) {
+ getState(ownerInstance);
+ if (state.opened.constructor === 'Boolean') {
+ // opened为boolen类型,判断默认打开
+ if (state.opened && state.rightWidth > 0) {
+ swipeMove(-state.rightWidth);
+ } else if (state.opened && state.leftWidth > 0) {
+ swipeMove(state.leftWidth);
+ }
+ }
+
+ if (state.opened.constructor === 'Array') {
+ // opened为array类型,判断默认打开,同时设定左右action时优先打开右边
+ if (state.opened[1] && state.rightWidth > 0) {
+ swipeMove(-state.rightWidth);
+ } else if (state.opened[0] && state.leftWidth > 0) {
+ swipeMove(state.leftWidth);
+ }
+ }
+};
+
+var resetTouchStatus = function () {
+ state.direction = '';
+ state.deltaX = 0;
+ state.deltaY = 0;
+ state.offsetX = 0;
+ state.offsetY = 0;
+};
+
+var touchMove = function (event) {
+ var touchPoint = event.touches[0];
+ state.deltaX = touchPoint.clientX - state.startX;
+ state.deltaY = touchPoint.clientY - state.startY;
+ state.offsetX = Math.abs(state.deltaX);
+ state.offsetY = Math.abs(state.deltaY);
+ state.direction = state.direction || getDirection(state.offsetX, state.offsetY);
+};
+
+var getDirection = function (x, y) {
+ if (x > y && x > MIN_DISTANCE) {
+ return 'horizontal';
+ }
+ if (y > x && y > MIN_DISTANCE) {
+ return 'vertical';
+ }
+ return '';
+};
+
+var range = function (num, min, max) {
+ return Math.min(Math.max(num, min), max);
+};
+
+var swipeMove = function (_offset) {
+ if (_offset === undefined) _offset = 0;
+ state.offset = range(_offset, -state.rightWidth, +state.leftWidth);
+ var transform = 'translate3d(' + state.offset + 'px, 0, 0)';
+ var transition = state.dragging ? 'none' : 'transform .6s cubic-bezier(0.18, 0.89, 0.32, 1)';
+ owner.selectComponent('#wrapper').setStyle({
+ '-webkit-transform': transform,
+ '-webkit-transition': transition,
+ transform: transform,
+ transition: transition,
+ });
+};
+
+var close = function () {
+ swipeMove(0);
+};
+
+var onCloseChange = function (newVal, oldVal, ownerInstance) {
+ getState(ownerInstance);
+ if (newVal === oldVal) return;
+ if (newVal) {
+ close();
+ }
+};
+
+var onOpenedChange = function (newVal, oldVal, ownerInstance) {
+ getState(ownerInstance);
+ state.opened = newVal;
+ if (newVal === oldVal) return;
+ if (!newVal) {
+ close();
+ }
+};
+
+var touchStart = function (event) {
+ resetTouchStatus();
+ state.startOffset = state.offset;
+ var touchPoint = event.touches[0];
+ state.startX = touchPoint.clientX;
+ state.startY = touchPoint.clientY;
+ owner.callMethod('closeOther');
+};
+
+var startDrag = function (event, ownerInstance) {
+ getState(ownerInstance);
+ touchStart(event);
+};
+
+var onDrag = function (event, ownerInstance) {
+ getState(ownerInstance);
+ touchMove(event);
+ if (state.direction !== 'horizontal') {
+ return;
+ }
+ state.dragging = true;
+ swipeMove(state.startOffset + state.deltaX);
+};
+
+var open = function (position) {
+ var _offset = position === 'left' ? +state.leftWidth : -state.rightWidth;
+ owner.callMethod('open', { position: position });
+ swipeMove(_offset);
+};
+
+var endDrag = function (event, ownerInstance) {
+ getState(ownerInstance);
+ state.dragging = false;
+ // 左/右侧有可滑动区域,且当前不是已open状态,且滑动幅度超过阈值时open左/右侧(滚动到该侧的最边上)
+ if (
+ +state.rightWidth > 0 &&
+ -state.startOffset < +state.rightWidth &&
+ -state.offset > +state.rightWidth * THRESHOLD
+ ) {
+ open('right');
+ } else if (
+ +state.leftWidth > 0 &&
+ state.startOffset < +state.leftWidth &&
+ state.offset > +state.leftWidth * THRESHOLD
+ ) {
+ open('left');
+ } else {
+ // 仅在有发生侧滑的情况下自动关闭(由js控制是否异步关闭)
+ if (state.startOffset !== state.offset) {
+ close();
+ }
+ }
+};
+
+module.exports = {
+ initLeftWidth: initLeftWidth,
+ initRightWidth: initRightWidth,
+ startDrag: startDrag,
+ onDrag: onDrag,
+ endDrag: endDrag,
+ onCloseChange: onCloseChange,
+ onOpenedChange: onOpenedChange,
+};
diff --git a/components/swipe-cell/swipe-cell.wxss b/components/swipe-cell/swipe-cell.wxss
new file mode 100644
index 0000000..1d1ab98
--- /dev/null
+++ b/components/swipe-cell/swipe-cell.wxss
@@ -0,0 +1,45 @@
+.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-swipe-cell {
+ position: relative;
+ overflow: hidden;
+}
+.t-swipe-cell__left,
+.t-swipe-cell__right {
+ position: absolute;
+ top: 0;
+ height: 100%;
+}
+.t-swipe-cell__left {
+ left: 0;
+ transform: translate3d(-100%, 0, 0);
+}
+.t-swipe-cell__right {
+ right: 0;
+ transform: translate3d(100%, 0, 0);
+}
diff --git a/components/swipe-cell/type.d.ts b/components/swipe-cell/type.d.ts
new file mode 100644
index 0000000..27ab05d
--- /dev/null
+++ b/components/swipe-cell/type.d.ts
@@ -0,0 +1,30 @@
+export interface TdSwipeCellProps {
+ disabled?: {
+ type: BooleanConstructor;
+ value?: boolean;
+ required?: boolean;
+ };
+ left?: {
+ type: ArrayConstructor;
+ value?: Array;
+ required?: boolean;
+ };
+ opened?: {
+ type: BooleanConstructor;
+ optionalTypes: Array;
+ value?: boolean | Array;
+ required?: boolean;
+ };
+ right?: {
+ type: ArrayConstructor;
+ value?: Array;
+ required?: boolean;
+ };
+}
+export interface SwipeActionItem {
+ text: string;
+ className?: string;
+ style?: string;
+ onClick?: () => void;
+ [key: string]: any;
+}
diff --git a/components/swipe-cell/type.js b/components/swipe-cell/type.js
new file mode 100644
index 0000000..5f16a47
--- /dev/null
+++ b/components/swipe-cell/type.js
@@ -0,0 +1,3 @@
+;
+;
+export {};
diff --git a/components/tabs/README.en-US.md b/components/tabs/README.en-US.md
new file mode 100644
index 0000000..cb5f68b
--- /dev/null
+++ b/components/tabs/README.en-US.md
@@ -0,0 +1,34 @@
+:: BASE_DOC ::
+
+## API
+### Tabs Props
+
+name | type | default | description | required
+-- | -- | -- | -- | --
+animation | Object | - | Typescript:`TabAnimation` `type TabAnimation = { duration: number } & Record`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/tabs/type.ts) | N
+external-classes | Array | - | `['t-class', 't-class-item', 't-class-active', 't-class-track']` | N
+placement | String | top | options:left/top | N
+show-bottom-line | Boolean | true | \- | N
+sticky | Boolean | false | \- | N
+sticky-props | Object | - | Typescript:`StickyProps`,[Sticky API Documents](./sticky?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/tabs/type.ts) | N
+swipeable | Boolean | true | \- | N
+value | String / Number | - | Typescript:`TabValue` `type TabValue = string | number`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/tabs/type.ts) | N
+default-value | String / Number | undefined | uncontrolled property。Typescript:`TabValue` `type TabValue = string | number`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/tabs/type.ts) | N
+
+### Tabs Events
+
+name | params | description
+-- | -- | --
+change | `(value: TabValue, label: string)` | \-
+click | `(value: TabValue, label: string)` | \-
+scroll | `({ scrollTop: number, isFixed: boolean })` | \-
+
+### TabPanel Props
+
+name | type | default | description | required
+-- | -- | -- | -- | --
+destroy-on-hide | Boolean | true | \- | N
+disabled | Boolean | false | \- | N
+label | String | - | \- | N
+panel | String / Slot | - | \- | N
+value | String / Number | - | Typescript:`TabValue` | N
diff --git a/components/tabs/README.md b/components/tabs/README.md
new file mode 100644
index 0000000..1e97cfd
--- /dev/null
+++ b/components/tabs/README.md
@@ -0,0 +1,141 @@
+---
+title: Tabs 选项卡
+description: 用于内容分类后的展示切换。
+spline: navigation
+isComponent: true
+---
+
+


+## 引入
+
+全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
+
+```json
+"usingComponents": {
+ "t-tabs": "tdesign-miniprogram/tabs/tabs",
+ "t-tab-panel": "tdesign-miniprogram/tabs/tab-panel"
+}
+```
+
+## 主题定制
+
+CSS 变量名|说明
+--|--
+--td-tab-nav-bg-color | 选项卡背景颜色
+--td-tab-item-color | 选项卡字体颜色
+--td-tab-item-active-color | 选项卡激活时字体颜色
+--td-tab-item-disabled-color | 选项卡禁止状态时字体颜色
+--td-tab-track-color | 选项卡滑块颜色
+--td-tab-track-thickness | 选项卡滑块厚度(水平时为高度,垂直时为宽度)
+--td-tab-border-color | 选项卡底部边框颜色
+
+## 代码演示
+
+### 基础选项卡
+
+{{ base }}
+
+### 超过屏幕滚动
+{{ scroll }}
+
+### 无下划线
+{{ unline }}
+
+### 动画时间可调整
+{{ adjust-time }}
+
+### 选项卡状态
+{{ status }}
+
+### 竖向选项卡
+{{ vertical }}
+
+### 选中态文字尺寸规格
+{{ size }}
+
+
+
+
+
+
+### 受控用法
+
+```html
+
+ 标签一内容
+ 标签二内容
+
+```
+
+```js
+Page({
+ data: {
+ value: '0',
+ },
+ onTabsChange(e) {
+ this.setData({ value: e.detail.value })
+ },
+});
+```
+
+### 与 Popup 使用
+
+```html
+
+
+ 标签一内容
+ 标签二内容
+ 标签三内容
+
+
+```
+
+```js
+Page({
+ data: {
+ visible: false
+ },
+ showPopup() {
+ this.setData({
+ visible: true
+ }, () => {
+ const tabs = this.selectComponent('tabs');
+
+ tabs.setTrack(); // 这一步很重要,因为小程序的无法正确执行生命周期,所以需要手动设置下 tabs 的滑块
+ })
+ }
+})
+```
+
+## API
+### Tabs Props
+
+名称 | 类型 | 默认值 | 说明 | 必传
+-- | -- | -- | -- | --
+animation | Object | - | 动画效果设置。其中 duration 表示动画时长。TS 类型:`TabAnimation` `type TabAnimation = { duration: number } & Record`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/tabs/type.ts) | N
+external-classes | Array | - | 组件类名,分别用于设置 组件外层元素、选项卡单项、选项卡激活态、滚动条样式类名 等类名。`['t-class', 't-class-item', 't-class-active', 't-class-track']` | N
+placement | String | top | 选项卡位置。可选项:left/top | N
+show-bottom-line | Boolean | true | 是否展示底部激活线条 | N
+sticky | Boolean | false | 是否开启粘性布局 | N
+sticky-props | Object | - | 透传至 Sticky 组件。TS 类型:`StickyProps`,[Sticky API Documents](./sticky?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/tabs/type.ts) | N
+swipeable | Boolean | true | 是否可以滑动切换 | N
+value | String / Number | - | 激活的选项卡值。TS 类型:`TabValue` `type TabValue = string | number`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/tabs/type.ts) | N
+default-value | String / Number | undefined | 激活的选项卡值。非受控属性。TS 类型:`TabValue` `type TabValue = string | number`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/tabs/type.ts) | N
+
+### Tabs Events
+
+名称 | 参数 | 描述
+-- | -- | --
+change | `(value: TabValue, label: string)` | 激活的选项卡发生变化时触发
+click | `(value: TabValue, label: string)` | 点击 tab 选项卡时触发
+scroll | `({ scrollTop: number, isFixed: boolean })` | 页面滚动时触发,scrollTop: 距离顶部位置,isFixed: 是否吸顶
+
+### TabPanel Props
+
+名称 | 类型 | 默认值 | 说明 | 必传
+-- | -- | -- | -- | --
+destroy-on-hide | Boolean | true | 选项卡内容隐藏时是否销毁 | N
+disabled | Boolean | false | 是否禁用当前选项卡 | N
+label | String | - | 选项卡名称 | N
+panel | String / Slot | - | 用于自定义选项卡面板内容 | N
+value | String / Number | - | 选项卡的值,唯一标识。TS 类型:`TabValue` | N
diff --git a/components/tabs/props.d.ts b/components/tabs/props.d.ts
new file mode 100644
index 0000000..215fa49
--- /dev/null
+++ b/components/tabs/props.d.ts
@@ -0,0 +1,3 @@
+import { TdTabsProps } from './type';
+declare const props: TdTabsProps;
+export default props;
diff --git a/components/tabs/props.js b/components/tabs/props.js
new file mode 100644
index 0000000..da54bec
--- /dev/null
+++ b/components/tabs/props.js
@@ -0,0 +1,35 @@
+const props = {
+ animation: {
+ type: Object,
+ },
+ externalClasses: {
+ type: Array,
+ },
+ placement: {
+ type: String,
+ value: 'top',
+ },
+ showBottomLine: {
+ type: Boolean,
+ value: true,
+ },
+ sticky: {
+ type: Boolean,
+ value: false,
+ },
+ stickyProps: {
+ type: Object,
+ },
+ swipeable: {
+ type: Boolean,
+ value: true,
+ },
+ value: {
+ type: null,
+ value: null,
+ },
+ defaultValue: {
+ type: null,
+ },
+};
+export default props;
diff --git a/components/tabs/tab-panel-props.d.ts b/components/tabs/tab-panel-props.d.ts
new file mode 100644
index 0000000..9329be0
--- /dev/null
+++ b/components/tabs/tab-panel-props.d.ts
@@ -0,0 +1,3 @@
+import { TdTabPanelProps } from './type';
+declare const props: TdTabPanelProps;
+export default props;
diff --git a/components/tabs/tab-panel-props.js b/components/tabs/tab-panel-props.js
new file mode 100644
index 0000000..c2a6e07
--- /dev/null
+++ b/components/tabs/tab-panel-props.js
@@ -0,0 +1,21 @@
+const props = {
+ destroyOnHide: {
+ type: Boolean,
+ value: true,
+ },
+ disabled: {
+ type: Boolean,
+ value: false,
+ },
+ label: {
+ type: String,
+ value: '',
+ },
+ panel: {
+ type: String,
+ },
+ value: {
+ type: null,
+ },
+};
+export default props;
diff --git a/components/tabs/tab-panel.d.ts b/components/tabs/tab-panel.d.ts
new file mode 100644
index 0000000..7403133
--- /dev/null
+++ b/components/tabs/tab-panel.d.ts
@@ -0,0 +1,17 @@
+import { SuperComponent, RelationsOptions } from '../common/src/index';
+export default class TabPanel extends SuperComponent {
+ relations: RelationsOptions;
+ properties: import("./type").TdTabPanelProps;
+ data: {
+ prefix: string;
+ classPrefix: string;
+ active: boolean;
+ hide: boolean;
+ };
+ observers: {
+ label(): void;
+ };
+ getComputedName(): string;
+ update(): void;
+ render(active: Boolean, parent: any): void;
+}
diff --git a/components/tabs/tab-panel.js b/components/tabs/tab-panel.js
new file mode 100644
index 0000000..e24af40
--- /dev/null
+++ b/components/tabs/tab-panel.js
@@ -0,0 +1,54 @@
+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 props from './tab-panel-props';
+import config from '../common/config';
+const { prefix } = config;
+const name = `${prefix}-tab-panel`;
+let TabPanel = class TabPanel extends SuperComponent {
+ constructor() {
+ super(...arguments);
+ this.relations = {
+ './tabs': {
+ type: 'ancestor',
+ },
+ };
+ this.properties = props;
+ this.data = {
+ prefix,
+ classPrefix: name,
+ active: false,
+ hide: true,
+ };
+ this.observers = {
+ label() {
+ this.update();
+ },
+ };
+ }
+ getComputedName() {
+ if (this.properties.value != null) {
+ return `${this.properties.value}`;
+ }
+ return `${this.index}`;
+ }
+ update() {
+ if (this.parent) {
+ this.parent.updateTabs();
+ }
+ }
+ render(active, parent) {
+ this.setData({
+ active,
+ hide: !parent.animated && !active,
+ });
+ }
+};
+TabPanel = __decorate([
+ wxComponent()
+], TabPanel);
+export default TabPanel;
diff --git a/components/tabs/tab-panel.json b/components/tabs/tab-panel.json
new file mode 100644
index 0000000..a89ef4d
--- /dev/null
+++ b/components/tabs/tab-panel.json
@@ -0,0 +1,4 @@
+{
+ "component": true,
+ "usingComponents": {}
+}
diff --git a/components/tabs/tab-panel.wxml b/components/tabs/tab-panel.wxml
new file mode 100644
index 0000000..ab1f6f2
--- /dev/null
+++ b/components/tabs/tab-panel.wxml
@@ -0,0 +1,9 @@
+
+
+ {{panel}}
+
+
diff --git a/components/tabs/tab-panel.wxss b/components/tabs/tab-panel.wxss
new file mode 100644
index 0000000..2a5dd88
--- /dev/null
+++ b/components/tabs/tab-panel.wxss
@@ -0,0 +1,37 @@
+.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);
+}
+:host {
+ flex-shrink: 0;
+ width: 100%;
+ height: 100%;
+ box-sizing: border-box;
+}
+.t-tab-panel {
+ height: inherit;
+ width: inherit;
+}
diff --git a/components/tabs/tabs.d.ts b/components/tabs/tabs.d.ts
new file mode 100644
index 0000000..809620f
--- /dev/null
+++ b/components/tabs/tabs.d.ts
@@ -0,0 +1,49 @@
+///
+import { SuperComponent, RelationsOptions } from '../common/src/index';
+export default class Tabs extends SuperComponent {
+ behaviors: string[];
+ externalClasses: string[];
+ relations: RelationsOptions;
+ properties: import("./type").TdTabsProps;
+ controlledProps: {
+ key: string;
+ event: string;
+ }[];
+ observers: {
+ value(name: any): void;
+ animation(v: any): void;
+ placement(): void;
+ };
+ data: {
+ prefix: string;
+ classPrefix: string;
+ tabs: any[];
+ currentIndex: number;
+ trackStyle: string;
+ isScrollX: boolean;
+ isScrollY: boolean;
+ direction: string;
+ animate: {
+ duration: number;
+ };
+ offset: number;
+ };
+ created(): void;
+ attached(): void;
+ methods: {
+ adjustPlacement(): void;
+ };
+ updateTabs(cb: any): void;
+ setCurrentIndexByName(name: any): void;
+ setCurrentIndex(index: number): void;
+ getCurrentName(): any;
+ calcScrollOffset(containerWidth: number, targetLeft: number, targetWidth: number, offset: number, currentIndex: number): number;
+ setTrack(): void;
+ onTabTap(event: any): void;
+ onTouchStart(event: any): void;
+ onTouchMove(event: any): void;
+ onTouchEnd(): void;
+ onTouchScroll(event: WechatMiniprogram.CustomEvent): void;
+ changeIndex(index: any): void;
+ getAvailableTabIndex(deltaX: number): number;
+}
diff --git a/components/tabs/tabs.js b/components/tabs/tabs.js
new file mode 100644
index 0000000..d99a014
--- /dev/null
+++ b/components/tabs/tabs.js
@@ -0,0 +1,241 @@
+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 dom from '../behaviors/dom';
+import touch from '../behaviors/touch';
+import { SuperComponent, wxComponent } from '../common/src/index';
+import props from './props';
+import config from '../common/config';
+const { prefix } = config;
+const name = `${prefix}-tabs`;
+var Position;
+(function (Position) {
+ Position["top"] = "top";
+ Position["right"] = "right";
+ Position["bottom"] = "bottom";
+ Position["left"] = "left";
+})(Position || (Position = {}));
+const trackLineWidth = 30;
+let Tabs = class Tabs extends SuperComponent {
+ constructor() {
+ super(...arguments);
+ this.behaviors = [dom, touch];
+ this.externalClasses = [`${prefix}-class`, `${prefix}-class-item`, `${prefix}-class-active`, `${prefix}-class-track`];
+ this.relations = {
+ './tab-panel': {
+ type: 'descendant',
+ linked(target) {
+ this.children.push(target);
+ target.index = this.children.length - 1;
+ this.updateTabs();
+ },
+ unlinked(target) {
+ this.children = this.children.filter((item) => item.index !== target.index);
+ this.updateTabs(() => this.setTrack());
+ },
+ },
+ };
+ this.properties = props;
+ this.controlledProps = [
+ {
+ key: 'value',
+ event: 'change',
+ },
+ ];
+ this.observers = {
+ value(name) {
+ if (name !== this.getCurrentName()) {
+ this.setCurrentIndexByName(name);
+ }
+ },
+ animation(v) {
+ this.setData({ animate: v });
+ },
+ placement() {
+ this.adjustPlacement();
+ },
+ };
+ this.data = {
+ prefix,
+ classPrefix: name,
+ tabs: [],
+ currentIndex: -1,
+ trackStyle: '',
+ isScrollX: true,
+ isScrollY: false,
+ direction: 'X',
+ animate: { duration: 0 },
+ offset: 0,
+ };
+ this.methods = {
+ adjustPlacement() {
+ const { placement } = this.properties;
+ let isScrollX = false;
+ let isScrollY = false;
+ if (placement === Position.top || placement === Position.bottom) {
+ isScrollX = true;
+ }
+ else {
+ isScrollY = true;
+ }
+ this.setData({
+ isScrollX,
+ isScrollY,
+ direction: isScrollX ? 'X' : 'Y',
+ });
+ },
+ };
+ }
+ created() {
+ this.children = this.children || [];
+ }
+ attached() {
+ wx.nextTick(() => {
+ this.setTrack();
+ });
+ this.adjustPlacement();
+ this.gettingBoundingClientRect(`.${name}`, true).then((res) => {
+ this.containerWidth = res[0].width;
+ });
+ }
+ updateTabs(cb) {
+ const { children } = this;
+ this.setData({
+ tabs: children.map((child) => child.data),
+ }, cb);
+ this.setCurrentIndexByName(this.properties.value);
+ }
+ setCurrentIndexByName(name) {
+ const { children } = this;
+ const index = children.findIndex((child) => child.getComputedName() === `${name}`);
+ if (index > -1) {
+ this.setCurrentIndex(index);
+ }
+ }
+ setCurrentIndex(index) {
+ if (index <= -1 || index >= this.children.length)
+ return;
+ this.children.forEach((child, idx) => {
+ const isActive = index === idx;
+ if (isActive !== child.data.active) {
+ child.render(isActive, this);
+ }
+ });
+ if (this.data.currentIndex === index)
+ return;
+ this.setData({
+ currentIndex: index,
+ });
+ this.setTrack();
+ }
+ getCurrentName() {
+ if (this.children) {
+ const activeTab = this.children[this.data.currentIndex];
+ if (activeTab) {
+ return activeTab.getComputedName();
+ }
+ }
+ }
+ calcScrollOffset(containerWidth, targetLeft, targetWidth, offset, currentIndex) {
+ return currentIndex * targetWidth - (1 / 2) * containerWidth + targetWidth / 2;
+ }
+ setTrack() {
+ if (!this.properties.showBottomLine)
+ return;
+ const { children } = this;
+ if (!children)
+ return;
+ const { currentIndex, isScrollX, direction } = this.data;
+ if (currentIndex <= -1)
+ return;
+ this.gettingBoundingClientRect(`.${prefix}-tabs__item`, true)
+ .then((res) => {
+ const rect = res[currentIndex];
+ if (!rect)
+ return;
+ let count = 0;
+ let distance = 0;
+ for (const item of res) {
+ if (count < currentIndex) {
+ distance += isScrollX ? item.width : item.height;
+ count += 1;
+ }
+ }
+ if (this.containerWidth) {
+ const offset = this.calcScrollOffset(this.containerWidth, rect.left, rect.width, this.data.offset, currentIndex);
+ this.setData({
+ offset,
+ });
+ }
+ if (isScrollX) {
+ distance += (rect.width - trackLineWidth) / 2;
+ }
+ let trackStyle = `-webkit-transform: translate${direction}(${distance}px);
+ transform: translate${direction}(${distance}px);
+ `;
+ trackStyle += isScrollX ? `width: ${trackLineWidth}px;` : `height: ${rect.height}px;`;
+ this.setData({
+ trackStyle,
+ });
+ })
+ .catch((err) => {
+ this.triggerEvent('error', err);
+ });
+ }
+ onTabTap(event) {
+ const { index } = event.currentTarget.dataset;
+ this.changeIndex(index);
+ }
+ onTouchStart(event) {
+ if (!this.properties.swipeable)
+ return;
+ this.touchStart(event);
+ }
+ onTouchMove(event) {
+ if (!this.properties.swipeable)
+ return;
+ this.touchMove(event);
+ }
+ onTouchEnd() {
+ if (!this.properties.swipeable)
+ return;
+ const { direction, deltaX, offsetX } = this;
+ const minSwipeDistance = 50;
+ if (direction === 'horizontal' && offsetX >= minSwipeDistance) {
+ const index = this.getAvailableTabIndex(deltaX);
+ if (index !== -1) {
+ this.changeIndex(index);
+ }
+ }
+ }
+ onTouchScroll(event) {
+ this._trigger('scroll', event.detail);
+ }
+ changeIndex(index) {
+ const currentTab = this.data.tabs[index];
+ const { value, label } = currentTab;
+ if (!(currentTab === null || currentTab === void 0 ? void 0 : currentTab.disabled) && index !== this.data.currentIndex) {
+ this._trigger('change', { value, label });
+ }
+ this._trigger('click', { value, label });
+ }
+ getAvailableTabIndex(deltaX) {
+ const step = deltaX > 0 ? -1 : 1;
+ const { currentIndex, tabs } = this.data;
+ const len = tabs.length;
+ for (let i = step; currentIndex + step >= 0 && currentIndex + step < len; i += step) {
+ const newIndex = currentIndex + i;
+ if (newIndex >= 0 && newIndex < len && tabs[newIndex] && !tabs[newIndex].disabled) {
+ return newIndex;
+ }
+ }
+ return -1;
+ }
+};
+Tabs = __decorate([
+ wxComponent()
+], Tabs);
+export default Tabs;
diff --git a/components/tabs/tabs.json b/components/tabs/tabs.json
new file mode 100644
index 0000000..93d5828
--- /dev/null
+++ b/components/tabs/tabs.json
@@ -0,0 +1,6 @@
+{
+ "component": true,
+ "usingComponents": {
+ "t-sticky": "/components/sticky/sticky"
+ }
+}
diff --git a/components/tabs/tabs.wxml b/components/tabs/tabs.wxml
new file mode 100644
index 0000000..34e6a54
--- /dev/null
+++ b/components/tabs/tabs.wxml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+ {{item.label}}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/tabs/tabs.wxs b/components/tabs/tabs.wxs
new file mode 100644
index 0000000..ca86ad5
--- /dev/null
+++ b/components/tabs/tabs.wxs
@@ -0,0 +1,24 @@
+/* eslint-disable */
+/* utils */
+
+/**
+ * animate */
+// 为tab切换添加动画
+function animate(options) {
+ var result =
+ '-webkit-transition-duration: ' +
+ options.duration +
+ 's' +
+ ';transition-duration: ' +
+ options.duration +
+ 's';
+ result +=
+ options.direction === 'Y'
+ ? ';transform: translate3d( 0,' + -100 * options.currentIndex + '%, 0)'
+ : ';transform: translate3d( ' + -100 * options.currentIndex + '%,0, 0)';
+ return result;
+}
+
+module.exports = {
+ animate: animate,
+};
diff --git a/components/tabs/tabs.wxss b/components/tabs/tabs.wxss
new file mode 100644
index 0000000..9f89849
--- /dev/null
+++ b/components/tabs/tabs.wxss
@@ -0,0 +1,175 @@
+.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);
+}
+page {
+ --td-tab-nav-bg-color: #fff;
+ --td-tab-item-color: rgba(0, 0, 0, 0.6);
+ --td-tab-item-active-color: #0052d9;
+ --td-tab-item-disabled-color: #c8c9cc;
+ --td-tab-track-color: #0052d9;
+ --td-tab-track-thickness: 4rpx;
+ --td-tab-border-color: rgba(150, 95, 95, 0.12);
+}
+.t-tabs {
+ position: relative;
+ font-size: 28rpx;
+ background-color: #fff;
+}
+.t-tabs__wrapper {
+ display: flex;
+ overflow: hidden;
+}
+.t-tabs .t-is-active {
+ font-weight: 700;
+ color: var(--td-tab-item-active-color, #0052d9);
+}
+.t-tabs .t-is-disabled {
+ color: var(--td-tab-item-disabled-color, #c8c9cc);
+}
+.t-tabs__item {
+ flex: 1;
+ font-weight: 400;
+ color: var(--td-tab-item-color, rgba(0, 0, 0, 0.6));
+}
+.t-tabs__item--top,
+.t-tabs__item--bottom {
+ height: 92rpx;
+ line-height: 92rpx;
+ text-align: center;
+ min-width: 162rpx;
+}
+.t-tabs__item--left,
+.t-tabs__item--right {
+ text-align: center;
+ height: 108rpx;
+ line-height: 108rpx;
+ width: 208rpx;
+ background-color: #f3f3f3;
+}
+.t-tabs__item--left.t-is-active,
+.t-tabs__item--right.t-is-active {
+ background-color: #fff;
+}
+.t-tabs__content {
+ overflow: hidden;
+}
+.t-tabs__nav {
+ position: relative;
+ user-select: none;
+ width: 100%;
+ display: flex;
+ flex-wrap: nowrap;
+ align-items: center;
+}
+.t-tabs__nav--left,
+.t-tabs__nav--right {
+ flex-direction: column;
+}
+.t-tabs__track {
+ position: absolute;
+ font-weight: 600;
+ z-index: 1;
+ transition-duration: 0.3s;
+ background-color: var(--td-tab-track-color, #0052d9);
+}
+.t-tabs__track--left {
+ left: 0;
+ top: 0;
+ width: var(--td-tab-track-thickness, 4rpx);
+}
+.t-tabs__track--right {
+ right: 0;
+ top: 0;
+ width: var(--td-tab-track-thickness, 4rpx);
+}
+.t-tabs__scroll--top,
+.t-tabs__scroll--bottom {
+ height: 92rpx;
+ position: relative;
+ background-color: var(--td-tab-nav-bg-color, #fff);
+}
+.t-tabs__scroll--top::after,
+.t-tabs__scroll--bottom::after {
+ content: '';
+}
+.t-tabs__scroll--top {
+ border-bottom: solid 1rpx var(--td-tab-border-color, rgba(150, 95, 95, 0.12));
+}
+.t-tabs__scroll--left,
+.t-tabs__scroll--right {
+ width: 208rpx;
+ max-height: 100vh;
+}
+.t-tabs__content-inner {
+ display: block;
+}
+.t-tabs.t-tabs--top,
+.t-tabs.t-tabs--bottom {
+ flex-wrap: wrap;
+}
+.t-tabs.t-tabs--top .t-tabs__content-inner,
+.t-tabs.t-tabs--bottom .t-tabs__content-inner {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ display: flex;
+ transition-property: transform;
+}
+.t-tabs.t-tabs--top .t-tabs__track,
+.t-tabs.t-tabs--bottom .t-tabs__track {
+ left: 0;
+ bottom: 0;
+ height: var(--td-tab-track-thickness, 4rpx);
+}
+.t-tabs.t-tabs--top .t-tabs__content,
+.t-tabs.t-tabs--bottom .t-tabs__content {
+ width: 100%;
+}
+.t-tabs.t-tabs--bottom {
+ flex-direction: column-reverse;
+}
+.t-tabs.t-tabs--left .t-tabs__content-inner,
+.t-tabs.t-tabs--right .t-tabs__content-inner {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ transition-property: transform;
+}
+.t-tabs.t-tabs--left .t-tabs__content,
+.t-tabs.t-tabs--right .t-tabs__content {
+ width: calc(100% - 208rpx);
+ height: 100%;
+ position: absolute;
+ top: 0;
+ left: 208rpx;
+ overflow: hidden;
+}
+.t-tabs.t-tabs--right {
+ flex-direction: row-reverse;
+}
diff --git a/components/tabs/type.d.ts b/components/tabs/type.d.ts
new file mode 100644
index 0000000..38a3313
--- /dev/null
+++ b/components/tabs/type.d.ts
@@ -0,0 +1,65 @@
+import { StickyProps } from '../sticky/index';
+export interface TdTabsProps {
+ animation?: {
+ type: ObjectConstructor;
+ value?: TabAnimation;
+ };
+ externalClasses?: {
+ type: ArrayConstructor;
+ value?: ['t-class', 't-class-item', 't-class-active', 't-class-track'];
+ };
+ placement?: {
+ type: StringConstructor;
+ value?: 'left' | 'top';
+ };
+ showBottomLine?: {
+ type: BooleanConstructor;
+ value?: boolean;
+ };
+ sticky?: {
+ type: BooleanConstructor;
+ value?: boolean;
+ };
+ stickyProps?: {
+ type: ObjectConstructor;
+ value?: StickyProps;
+ };
+ swipeable?: {
+ type: BooleanConstructor;
+ value?: boolean;
+ };
+ value?: {
+ type: null;
+ value?: TabValue;
+ };
+ defaultValue?: {
+ type: null;
+ value?: TabValue;
+ };
+}
+export interface TdTabPanelProps {
+ destroyOnHide?: {
+ type: BooleanConstructor;
+ value?: boolean;
+ };
+ disabled?: {
+ type: BooleanConstructor;
+ value?: boolean;
+ };
+ label?: {
+ type: StringConstructor;
+ value?: string;
+ };
+ panel?: {
+ type: StringConstructor;
+ value?: string;
+ };
+ value?: {
+ type: null;
+ value?: TabValue;
+ };
+}
+export declare type TabAnimation = {
+ duration: number;
+} & Record;
+export declare type TabValue = string | number;
diff --git a/components/tabs/type.js b/components/tabs/type.js
new file mode 100644
index 0000000..cb0ff5c
--- /dev/null
+++ b/components/tabs/type.js
@@ -0,0 +1 @@
+export {};
diff --git a/pages/foot-tab/foot-tab.json b/pages/foot-tab/foot-tab.json
index ec11f61..20ec068 100644
--- a/pages/foot-tab/foot-tab.json
+++ b/pages/foot-tab/foot-tab.json
@@ -1,7 +1,5 @@
{
"component": true,
"usingComponents": {
- "t-tab-bar": "/components/tab-bar/tab-bar",
- "t-tab-bar-item": "/components/tab-bar/tab-bar-item"
}
}
diff --git a/pages/today/index.js b/pages/today/index.js
index 51c576b..1d4b6a8 100644
--- a/pages/today/index.js
+++ b/pages/today/index.js
@@ -1,11 +1,15 @@
// pages/today/index.js
+const app = getApp();
Page({
/**
* 页面的初始数据
*/
data: {
- aIconList: ['check-rectangle','star-filled','notification','info-circle'],
+ aIconList: ['check-rectangle', 'star-filled', 'notification', 'info-circle'],
+ taskList: [{'taskId':'1','title':'标题德外旗舰店1','note':'2022-11-11'},{'taskId':'2','title':'标题德外旗舰店2','note':'2022-11-11'}],
+ todayList: [{'taskId':'1','title':'标题德外旗舰店1','note':'2022-11-11'},{'taskId':'2','title':'标题德外旗舰店2','note':'2022-11-11'}],
+ delayList: [{'taskId':'1','title':'标题德外旗舰店1','note':'2022-11-11'}],
},
/**
@@ -26,41 +30,30 @@ Page({
* 生命周期函数--监听页面显示
*/
onShow() {
-
+ wx.showLoading({
+ title: '请稍候...',
+ mask: true,
+ })
+ console.log('请求中...')
+ app.$api.taskList({}).then(res =>{
+ console.log(res);
+ console.log(res.data);
+ this.setData({
+ taskList:res.data.taskList,
+ })
+ })
+ },
+ onEdit(e) {
+ console.log('收藏' + e.currentTarget.dataset.id);
+ },
+ onDelete(e) {
+ console.log('删除' + e.currentTarget.dataset.id);
+ },
+ onTabsChange(event) {
+ console.log(`Change tab, tab-panel value is ${event.detail.value}.`);
},
- /**
- * 生命周期函数--监听页面隐藏
- */
- onHide() {
-
+ onTabsClick(event) {
+ console.log(`Click tab, tab-panel value is ${event.detail.value}.`);
},
-
- /**
- * 生命周期函数--监听页面卸载
- */
- onUnload() {
-
- },
-
- /**
- * 页面相关事件处理函数--监听用户下拉动作
- */
- onPullDownRefresh() {
-
- },
-
- /**
- * 页面上拉触底事件的处理函数
- */
- onReachBottom() {
-
- },
-
- /**
- * 用户点击右上角分享
- */
- onShareAppMessage() {
-
- }
})
diff --git a/pages/today/index.wxml b/pages/today/index.wxml
index da94a01..ccb029c 100644
--- a/pages/today/index.wxml
+++ b/pages/today/index.wxml
@@ -1,5 +1,42 @@
-今日任务
+
+
+
+
+
+ 收藏
+ 删除
+
+
+
+
+
+
+
+ 删除
+
+
+
+
+
+
+
+ 删除
+
+
+
+
+
+
+
+
+
diff --git a/pages/today/index.wxss b/pages/today/index.wxss
index acffbb0..602d006 100644
--- a/pages/today/index.wxss
+++ b/pages/today/index.wxss
@@ -1 +1,52 @@
-/* pages/today/index.wxss */
\ No newline at end of file
+/* pages/today/index.wxss */
+.t-swipe-cell-demo-btn-wrapper {
+ height: 100%;
+}
+
+.t-swipe-cell-demo-btn {
+ display: inline-flex;
+ justify-content: center;
+ align-items: center;
+ width: 144rpx !important;
+ height: 100%;
+ text-align: center;
+ color: white;
+}
+
+.t-swipe-cell-demo-btn.delete-btn {
+ background-color: #e34d59;
+}
+
+.t-swipe-cell-demo-btn.edit-btn {
+ background-color: #ed7b2f;
+}
+
+.t-swipe-cell-demo-btn.favor-btn {
+ background-color: #0052d9;
+}
+
+.title-image-large {
+ margin-right: 8rpx;
+ width: 144rpx;
+ height: 144rpx;
+}
+
+.text_ath {
+ text-decoration:line-through
+}
+
+.custom-tabs t-tab-panel {
+ text-align: center;
+ justify-content: center;
+ height: 172rpx;
+ line-height: 172rpx;
+ color: rgba(0, 0, 0, 0.26);
+}
+
+.phone-box {
+ position: absolute;
+ bottom: 30rpx;
+ left: 30rpx;
+ width: 130rpx;
+ height: 130rpx;
+}
diff --git a/project.private.config.json b/project.private.config.json
index aa2ae36..1e99f25 100644
--- a/project.private.config.json
+++ b/project.private.config.json
@@ -2,6 +2,7 @@
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
"projectname": "quinn-wx",
"setting": {
- "compileHotReLoad": true
+ "compileHotReLoad": true,
+ "urlCheck": false
}
}
\ No newline at end of file
diff --git a/utils/api.js b/utils/api.js
new file mode 100644
index 0000000..5d8b485
--- /dev/null
+++ b/utils/api.js
@@ -0,0 +1,233 @@
+//testURL
+const BASE_URL = 'http://30.251.62.186:10393/mock/68a4cea5-9a96-4c33-b7b9-0f32269ef34f/test?apipost_id=872f12';
+//prodURL
+// const BASE_URL = 'https://api.hongyutiyu.top';
+
+function buildURL(url, needToken) {
+ let token = wx.getStorageSync('accessToken');
+
+ if (!needToken) {
+ return token ? url + (url.indexOf('?') >= 0 ? '&' : '?') + "access_token=" + token : url
+ }
+ return url + (url.indexOf('?') >= 0 ? '&' : '?');
+}
+
+export function fetchPost(url, params, needToken, multiple) {
+ url = buildURL(url, needToken);
+
+ // 如果url不存在,返回错误 TODO
+ // if (!url) {
+ // return new Promise((resolve, reject) => {
+ // reject();
+ // })
+ // }
+
+ console.log("网络请求", BASE_URL + url, params);
+
+ // 如果上传图片
+ if (multiple) {
+ return new Promise((resolve, reject) => {
+ wx.uploadFile({
+ url: BASE_URL + url,
+ filePath: params.filePath,
+ name: 'image',
+ formData: {},
+ success: function(response) {
+ console.log(response.data);
+ let res = JSON.parse(response.data);
+ console.log(res);
+ if (response.statusCode == 200) {
+ if (res.err_code == 0) {
+ // wx.hideLoading();
+ resolve(res);
+ } else {
+ if (res.err_code == 10003 || res.err_code == 10006 || res.err_code == 20006) {
+ // wx.removeStorageSync('accessToken');
+ // wx.redirectTo({
+ // url: '/pages/login/index',
+ // })
+ isUnLogin();
+ reject(res);
+ return;
+ } else if (res.err_code == 20005) {
+ wx.removeStorageSync('accessToken');
+ wx.removeStorageSync('history');
+ wx.hideLoading();
+ wx.showToast({
+ title: res.err_msg,
+ icon: 'none',
+ duration: 2000
+ })
+ reject(res);
+ } else {
+ wx.hideLoading();
+ wx.showToast({
+ title: res.err_msg,
+ icon: 'none',
+ duration: 2000
+ })
+ reject(res);
+ }
+ }
+ } else {
+ wx.hideLoading();
+ wx.showToast({
+ title: '网络错误',
+ icon: 'none',
+ })
+ reject(response);
+ }
+ },
+ fail: function(err) {
+ console.log(err);
+ wx.hideLoading();
+ wx.showToast({
+ title: '网络错误',
+ icon: 'none',
+ })
+ reject(response);
+ },
+ })
+ })
+ }
+
+ // 获取POST数据
+ return new Promise((resolve, reject) => {
+ wx.request({
+ url: BASE_URL + url,
+ data: params,
+ header: {
+ 'content-type': 'application/x-www-form-urlencoded'
+ },
+ method: 'POST',
+ success: function(res) {
+ console.log("POST返回数据", url,res);
+ if (res.data.err_code == 0) {
+ wx.hideLoading();
+ resolve(res.data);
+ } else {
+ if (res.data.err_code == 10003 || res.data.err_code == 10006 || res.data.err_code == 20006) {
+ // wx.removeStorageSync('accessToken');
+ // wx.redirectTo({
+ // url: '/pages/login/index',
+ // })
+ isUnLogin();
+ reject(res);
+ return;
+ } else if (res.data.err_code == 30022) {
+ reject(res);
+ } else if (res.data.err_code == 20005) {
+ wx.removeStorageSync('accessToken');
+ wx.removeStorageSync('history');
+ wx.hideLoading();
+ wx.showToast({
+ title: res.data.err_msg,
+ icon: 'none',
+ duration: 2000
+ })
+ reject(res);
+ } else {
+ wx.hideLoading();
+ wx.showToast({
+ title: res.data.err_msg,
+ icon: 'none',
+ duration: 2000
+ })
+ reject(res);
+ }
+
+ }
+ },
+ fail: function(res) {
+ wx.hideLoading();
+ wx.showToast({
+ title: '网络错误',
+ icon: 'none',
+ duration: 2000
+ })
+ reject(res);
+
+ },
+ })
+ })
+}
+
+// get请求
+export function fetchGet(url, params, needToken) {
+ url = buildURL(url, needToken);
+ // 如果url不存在,返回错误 TODO
+ // if (!url) {
+ // return new Promise((resolve, reject) => {
+ // reject();
+ // })
+ // }
+
+ console.log("网络请求", BASE_URL + url, params);
+ return new Promise((resolve, reject) => {
+ wx.request({
+ url: BASE_URL + url,
+ data: params,
+ method: 'GET',
+ success: function(res) {
+ console.log("GET返回数据", url, res);
+ if (res.statusCode == 200) {
+ if (res.data.err_code == 0) {
+ wx.hideLoading();
+ resolve(res.data);
+ } else {
+ if (res.data.err_code == 10003 || res.data.err_code == 10006 || res.data.err_code == 20006) {
+ isUnLogin();
+ reject(res);
+ return;
+ } else if (res.data.err_code == 20005) {
+ wx.removeStorageSync('accessToken');
+ wx.removeStorageSync('history');
+ wx.hideLoading();
+ wx.showToast({
+ title: res.data.err_msg,
+ icon: 'none',
+ duration: 2000
+ })
+ reject(res);
+ } else {
+ wx.hideLoading();
+ wx.showToast({
+ title: res.data.err_msg,
+ icon: 'none',
+ duration: 2000
+ })
+ reject(res);
+ }
+ }
+ } else {
+ wx.hideLoading();
+ reject(res)
+ wx.showToast({
+ title: '网络错误',
+ icon: 'none',
+ duration: 2000
+ })
+ }
+ },
+ fail: function(res) {
+ wx.hideLoading();
+ reject(res)
+ wx.showToast({
+ title: '网络错误',
+ icon: 'none',
+ duration: 2000
+ })
+ },
+ })
+ })
+}
+
+// 暴露接口
+export default {
+ /**
+ * 任务清单
+ */
+ taskList(params) {
+ return fetchGet('', params, false);
+ },
+}