From 0efe64d1bb0e6898426abdec21c71c3dbb9e6aed Mon Sep 17 00:00:00 2001 From: limqhz Date: Mon, 12 Dec 2022 18:05:49 +0800 Subject: [PATCH] =?UTF-8?q?=E7=9F=AD=E9=80=9A=E7=9F=A5=20+=20=E4=B8=8A?= =?UTF-8?q?=E9=83=A8=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/message/README.md | 74 +++++++++ components/message/api.md | 100 ++++++++++++ components/message/index.d.ts | 17 ++ components/message/index.js | 46 ++++++ components/message/message.d.ts | 38 +++++ components/message/message.interface.d.ts | 24 +++ components/message/message.interface.js | 7 + components/message/message.js | 180 ++++++++++++++++++++++ components/message/message.json | 7 + components/message/message.wxml | 51 ++++++ components/message/message.wxs | 16 ++ components/message/message.wxss | 89 +++++++++++ components/message/props.d.ts | 3 + components/message/props.js | 49 ++++++ components/message/type.d.ts | 70 +++++++++ components/message/type.js | 1 + components/toast/README.en-US.md | 25 +++ components/toast/README.md | 59 +++++++ components/toast/index.d.ts | 21 +++ components/toast/index.js | 31 ++++ components/toast/props.d.ts | 3 + components/toast/props.js | 40 +++++ components/toast/toast.d.ts | 25 +++ components/toast/toast.js | 78 ++++++++++ components/toast/toast.json | 8 + components/toast/toast.wxml | 36 +++++ components/toast/toast.wxss | 84 ++++++++++ components/toast/type.d.ts | 42 +++++ components/toast/type.js | 1 + pages/anniversary/create/index.json | 1 - pages/message/index.js | 77 +++------ pages/message/index.json | 6 +- pages/message/index.wxml | 6 +- pages/message/index.wxss | 5 +- 34 files changed, 1262 insertions(+), 58 deletions(-) create mode 100644 components/message/README.md create mode 100644 components/message/api.md create mode 100644 components/message/index.d.ts create mode 100644 components/message/index.js create mode 100644 components/message/message.d.ts create mode 100644 components/message/message.interface.d.ts create mode 100644 components/message/message.interface.js create mode 100644 components/message/message.js create mode 100644 components/message/message.json create mode 100644 components/message/message.wxml create mode 100644 components/message/message.wxs create mode 100644 components/message/message.wxss create mode 100644 components/message/props.d.ts create mode 100644 components/message/props.js create mode 100644 components/message/type.d.ts create mode 100644 components/message/type.js create mode 100644 components/toast/README.en-US.md create mode 100644 components/toast/README.md create mode 100644 components/toast/index.d.ts create mode 100644 components/toast/index.js create mode 100644 components/toast/props.d.ts create mode 100644 components/toast/props.js create mode 100644 components/toast/toast.d.ts create mode 100644 components/toast/toast.js create mode 100644 components/toast/toast.json create mode 100644 components/toast/toast.wxml create mode 100644 components/toast/toast.wxss create mode 100644 components/toast/type.d.ts create mode 100644 components/toast/type.js diff --git a/components/message/README.md b/components/message/README.md new file mode 100644 index 0000000..9e900cd --- /dev/null +++ b/components/message/README.md @@ -0,0 +1,74 @@ +--- +title: Message 消息通知 +description: 用于轻量级反馈或提示,不会打断用户操作。 +spline: message +isComponent: true +--- + + +## 引入 + +全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。 + +```json +"usingComponents": { + "t-message": "tdesign-miniprogram/message/message" +} +``` + +### 引入 API + +若以 API 形式调用 Message,则需在页面 `page.js` 中引入组件 API: + +```js +import Message from 'tdesign-miniprogram/message/index'; +``` + +## 代码演示 + +### 基础消息通知 + +弹窗内容为纯文本、标题和副标题、带输入框,用 API `Message.info` 方法调用反馈类对话框。 + + +{{ base }} + + +### 不同状态的消息通知 + +消息通知类型为普通(info)、警示(warning)、成功(success)、错误(error) + +{{ status-message }} + +### 自定义导航栏 + +当设置了 `navigationStyle = custom`,可以通过 offetset 来调整显示位置: + +{{ custom-navigation }} + +## API + +### Message Props + +| 名称 | 类型 | 默认值 | 说明 | 必传| +| -- | -- | -- | -- | -- | +| action | String / Slot | - | 操作 | N | +| align | String | left | 文本对齐方式。可选项:left/center | N | +| close-btn | String / Boolean / Slot | undefined | 关闭按钮,可以自定义。值为 true 显示默认关闭按钮,值为 false 不显示关闭按钮。值类型为 string 则直接显示值,如:“关闭”。也可以完全自定义按钮 | N | +| content | String / Slot | - | 用于自定义消息弹出内容 | N | +| duration | Number | 3000 | 消息内置计时器,计时到达时会触发 duration-end 事件。单位:毫秒。值为 0 则表示没有计时器。 | N | +| external-classes | Array | - | 样式类名,分别用于设置 组件外层、消息内容、左侧图标、操作按钮、关闭按钮等元素类名。`['t-class', 't-class-content', 't-class-icon', 't-class-action', 't-class-close-btn']` | N | +| icon | String / Boolean / Slot | true | 消息提醒前面的图标。值为 true 则根据 theme 显示对应的图标,值为 false 则不显示图标。值为 'info' 或 'bell' 则显示组件内置图标。也可以完全自定义图标节点。TS 类型:`boolean | 'info' | 'bell'` | N | +| marquee | Boolean / Object | false | 跑马灯效果。speed 指速度控制;loop 指循环播放次数,值为 -1 表示循环播放,值为 0 表示不循环播放;delay 表示延迟多久开始播放。TS 类型:`boolean | DrawMarquee`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/message/type.ts) | N | +| offset | Array | - | 相对于 placement 的偏移量,示例:[-10, 20] 或 ['10rpx', '8rpx']。TS 类型:`Array` | N | +| theme | String | info | 消息组件风格。可选项:info/success/warning/error。TS 类型:`MessageThemeList`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/message/type.ts) | N | +| visible | Boolean | false | 是否显示,隐藏时默认销毁组件 | N | +| z-index | Number | 15000 | 组件层级,样式默认为 15000 | N | + +### Message Events + +| 名称 | 参数 | 描述 | +| ---------------- | ---- | ---------------------------------------- | +| action-btn-click | - | 当操作按钮存在时,用户点击操作按钮时触发 | +| close-btn-click | - | 当关闭按钮存在时,用户点击关闭按钮触发 | +| duration-end | - | 计时结束后触发 | diff --git a/components/message/api.md b/components/message/api.md new file mode 100644 index 0000000..26e9582 --- /dev/null +++ b/components/message/api.md @@ -0,0 +1,100 @@ +# Message + +消息组件 + +### 特性及兼容性 + +无 + +## 引入 + +### 引入组件 + +在 `app.json` 或 `page.json` 中引入组件: + +```json +"usingComponents": { + "t-message": "tdesign-miniprogram/message/message" +} +``` + +### 引入 API + +若以 API 形式调用 Message,则需在页面 `page.js` 中引入组件 API: + +```js +import Message from 'tdesign-miniprogram/message/index'; +``` + +## 用法 + +### 消息提示 + +用 API `Message.info` 方法调用反馈类对话框 + +```html + + +``` + +```js +// page.js +Message.info({ + content: '消息内容', +}); +``` + +## API + +### `` 组件 + +组件路径:`tdesign-miniprogram/message/message` + +#### Props + +| 属性 | 值类型 | 默认值 | 说明 | +| --------------- | ----------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | --------------- | +| visible | Boolean | false | 是否显示,隐藏时默认销毁组件 | N | +| content | String / Slot | - | 用于自定义消息弹出内容。 | N | +| theme | String | info | 消息组件风格。可选值:info/success/warning/error。 | N | +| duration | Number | 3000 | 消息内置计时器,计时到达时会触发 duration-end 事件。单位:毫秒。值为 0 则表示没有计时器。 | N | +| offset | `Object` | - | 偏移量,默认[0,0] | +| closeBtn | String / Boolean /Slot | undefined | 关闭按钮,可以自定义。值为 true 显示默认关闭按钮,值为 false 不显示关闭按钮。值类型为 string 则直接显示值,如:“关闭”。也可以完全自定义按钮。 | N | +| externalClasses | Array | - | 样式类名,分别用于设置 组件外层、消息内容、左侧图标、操作按钮、关闭按钮等元素类名。`['t-class', 't-class-content', 't-class-icon', 't-class-action', 't-class-close-btn']` | N | +| icon | String / Boolean / Slot | true | 消息提醒前面的图标。值为 true 则根据 theme 显示对应的图标,值为 false 则不显示图标。值为 'info' 或 'bell' 则显示组件内置图标。也可以完全自定义图标节点。TS 类型:`boolean | 'warning_fill' | 'sound_fill'` N | +| marquee | Object | - | 跑马灯效果,delay 动画延迟时间 (s);speed 滚动速率 (px/s)。N | +| zIndex | Number | - | 元素层级,样式默认为 5000 | N | + +### Event + +| 事件名 | 说明 | 参数 | +| -------------- | ---------------------------------------- | ---------------- | +| closeBtnClick | 点击关闭 icon 时触发 | - | +| actionBtnClick | 点击按钮时触发, 可通过 self 拿到组件实例 | `{ self: this }` | + +### Slot + +| 事件名 | 说明 | +| -------- | ------------------- | +| icon | 左侧 icon 处 | +| action | 右侧操作按钮。 N | +| closeBtn | 按钮(关闭 icon)处 | + +### 外部样式 + +| class | 说明 | +| ----------------- | ----------- | +| t-class | 根节点 | +| t-class-content | 文本内容 | +| t-class-icon | 左侧 icon | +| t-class-action | 右侧 button | +| t-class-close-btn | 右侧 icon | + +### 编程式调用 + +| 方法 | type | 返回值 | 说明 | +| -------------------------- | ------- | ------ | ------------------------------------------------------------------------------------------------------------ | +| Message.info(`options`) | info | `void` | 弹出消息,参数参考 Props,额外可指定`{context: WechatMiniprogram.Component.TrivialInstance,selector: string}` | +| Message.success(`options`) | success | `void` | 弹出消息,参数参考 Props,额外可指定`{context: WechatMiniprogram.Component.TrivialInstance,selector: string}` | +| Message.warning(`options`) | warning | `void` | 弹出消息,参数参考 Props,额外可指定`{context: WechatMiniprogram.Component.TrivialInstance,selector: string}` | +| Message.error(`options`) | error | `void` | 弹出消息,参数参考 Props,额外可指定`{context: WechatMiniprogram.Component.TrivialInstance,selector: string}` | diff --git a/components/message/index.d.ts b/components/message/index.d.ts new file mode 100644 index 0000000..a8cf1e3 --- /dev/null +++ b/components/message/index.d.ts @@ -0,0 +1,17 @@ +/// +/// +/// +import { MessageProps } from './message.interface'; +declare type Context = WechatMiniprogram.Page.TrivialInstance | WechatMiniprogram.Component.TrivialInstance; +interface MessageActionOptionsType extends Optional { + context?: Context; + selector?: string; +} +declare const _default: { + info(options: MessageActionOptionsType): WechatMiniprogram.Component.TrivialInstance; + success(options: MessageActionOptionsType): WechatMiniprogram.Component.TrivialInstance; + warning(options: MessageActionOptionsType): WechatMiniprogram.Component.TrivialInstance; + error(options: MessageActionOptionsType): WechatMiniprogram.Component.TrivialInstance; + hide(options: MessageActionOptionsType): void; +}; +export default _default; diff --git a/components/message/index.js b/components/message/index.js new file mode 100644 index 0000000..02b775a --- /dev/null +++ b/components/message/index.js @@ -0,0 +1,46 @@ +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { + if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) + t[p[i]] = s[p[i]]; + } + return t; +}; +import { MessageType } from './message.interface'; +import { getInstance } from '../common/utils'; +const showMessage = function (options, theme = MessageType.info) { + const { context, selector = '#t-message' } = options, otherOptions = __rest(options, ["context", "selector"]); + const instance = getInstance(context, selector); + if (instance) { + instance.resetData(() => { + instance.setData(Object.assign({ theme }, otherOptions), instance.show.bind(instance)); + }); + return instance; + } + console.error('未找到组件,请确认 selector && context 是否正确'); +}; +export default { + info(options) { + return showMessage(options, MessageType.info); + }, + success(options) { + return showMessage(options, MessageType.success); + }, + warning(options) { + return showMessage(options, MessageType.warning); + }, + error(options) { + return showMessage(options, MessageType.error); + }, + hide(options) { + const { context, selector = '#t-message' } = Object.assign({}, options); + const instance = getInstance(context, selector); + if (!instance) { + return; + } + instance.hide(); + }, +}; diff --git a/components/message/message.d.ts b/components/message/message.d.ts new file mode 100644 index 0000000..0718969 --- /dev/null +++ b/components/message/message.d.ts @@ -0,0 +1,38 @@ +/// +import { SuperComponent, ComponentsOptionsType } from '../common/src/index'; +import { MessageProps } from './message.interface'; +export default class Message extends SuperComponent { + externalClasses: string[]; + options: ComponentsOptionsType; + properties: MessageProps; + data: { + prefix: string; + classPrefix: string; + visible: boolean; + loop: number; + animation: any[]; + showAnimation: any[]; + iconName: string; + wrapTop: number; + }; + observers: { + marquee(val: any): void; + }; + closeTimeoutContext: number; + nextAnimationContext: number; + resetAnimation: WechatMiniprogram.Animation; + showAnimation: WechatMiniprogram.AnimationExportResult; + hideAnimation: WechatMiniprogram.AnimationExportResult; + ready(): void; + memoInitalData(): void; + resetData(cb: () => void): void; + detached(): void; + setIcon(icon?: string | boolean): void; + checkAnimation(): void; + clearMessageAnimation(): void; + show(): void; + hide(): void; + reset(): void; + handleClose(): void; + handleBtnClick(): void; +} diff --git a/components/message/message.interface.d.ts b/components/message/message.interface.d.ts new file mode 100644 index 0000000..9dce180 --- /dev/null +++ b/components/message/message.interface.d.ts @@ -0,0 +1,24 @@ +export declare enum MessageType { + info = "info", + success = "success", + warning = "warning", + error = "error" +} +export interface MessageMarquee { + speed?: number; + loop?: number; + delay?: number; +} +export interface MessageProps { + visible?: boolean; + content: string; + align?: string; + theme?: MessageType; + icon?: boolean | string; + closeBtn?: boolean; + action?: string; + marquee?: MessageMarquee; + offset?: object; + duration?: number; + zIndex?: number; +} diff --git a/components/message/message.interface.js b/components/message/message.interface.js new file mode 100644 index 0000000..b345007 --- /dev/null +++ b/components/message/message.interface.js @@ -0,0 +1,7 @@ +export var MessageType; +(function (MessageType) { + MessageType["info"] = "info"; + MessageType["success"] = "success"; + MessageType["warning"] = "warning"; + MessageType["error"] = "error"; +})(MessageType || (MessageType = {})); diff --git a/components/message/message.js b/components/message/message.js new file mode 100644 index 0000000..1114ccc --- /dev/null +++ b/components/message/message.js @@ -0,0 +1,180 @@ +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 { getRect } from '../common/utils'; +const { prefix } = config; +const name = `${prefix}-message`; +const SHOW_DURATION = 500; +let Message = class Message extends SuperComponent { + constructor() { + super(...arguments); + this.externalClasses = ['t-class', 't-class-content', 't-class-icon', 't-class-action', 't-class-close-btn']; + this.options = { + styleIsolation: 'apply-shared', + multipleSlots: true, + }; + this.properties = Object.assign({}, props); + this.data = { + prefix, + classPrefix: name, + visible: false, + loop: -1, + animation: [], + showAnimation: [], + iconName: '', + wrapTop: -92, + }; + this.observers = { + marquee(val) { + if (JSON.stringify(val) === '{}') { + this.setData({ + marquee: { + speed: 50, + loop: -1, + delay: 5000, + }, + }); + } + }, + }; + this.closeTimeoutContext = 0; + this.nextAnimationContext = 0; + this.resetAnimation = wx.createAnimation({ + duration: 0, + timingFunction: 'linear', + }); + this.showAnimation = wx.createAnimation({ duration: SHOW_DURATION, timingFunction: 'ease' }).translateY(0).step().export(); + this.hideAnimation = wx + .createAnimation({ duration: SHOW_DURATION, timingFunction: 'ease' }) + .translateY(this.data.wrapTop) + .step() + .export(); + } + ready() { + this.memoInitalData(); + this.setIcon(); + } + memoInitalData() { + this.initalData = Object.assign(Object.assign({}, this.properties), this.data); + } + resetData(cb) { + this.setData(Object.assign({}, this.initalData), cb); + } + detached() { + this.clearMessageAnimation(); + } + setIcon(icon = this.properties.icon) { + if (!icon) { + this.setData({ iconName: '' }); + return; + } + if (typeof icon === 'string') { + this.setData({ + iconName: `${icon}`, + }); + return; + } + if (icon) { + let nextValue = 'notification'; + const { theme } = this.properties; + const themeMessage = { + info: 'error-circle', + success: 'check-circle', + warning: 'error-circle', + error: 'error-circle', + }; + nextValue = themeMessage[theme]; + this.setData({ iconName: nextValue }); + } + } + checkAnimation() { + if (!this.properties.marquee) { + return; + } + const speeding = this.properties.marquee.speed; + if (this.data.loop > 0) { + this.data.loop -= 1; + } + else if (this.data.loop === 0) { + this.setData({ animation: this.resetAnimation.translateX(0).step().export() }); + return; + } + if (this.nextAnimationContext) { + this.clearMessageAnimation(); + } + const warpID = `#${name}__text-wrap`; + const nodeID = `#${name}__text`; + Promise.all([getRect(this, nodeID), getRect(this, warpID)]).then(([nodeRect, wrapRect]) => { + this.setData({ + animation: this.resetAnimation.translateX(wrapRect.width).step().export(), + }, () => { + const durationTime = ((nodeRect.width + wrapRect.width) / speeding) * 1000; + const nextAnimation = wx + .createAnimation({ + duration: durationTime, + }) + .translateX(-nodeRect.width) + .step() + .export(); + setTimeout(() => { + this.nextAnimationContext = setTimeout(this.checkAnimation.bind(this), durationTime); + this.setData({ animation: nextAnimation }); + }, 20); + }); + }); + } + clearMessageAnimation() { + clearTimeout(this.nextAnimationContext); + this.nextAnimationContext = 0; + } + show() { + const { duration, icon, marquee } = this.properties; + this.setData({ visible: true, loop: marquee.loop }); + this.reset(); + this.setIcon(icon); + this.checkAnimation(); + if (duration && duration > 0) { + this.closeTimeoutContext = setTimeout(() => { + this.hide(); + this.triggerEvent('durationEnd', { self: this }); + }, duration); + } + const wrapID = `#${name}`; + getRect(this, wrapID).then((wrapRect) => { + this.setData({ wrapTop: -wrapRect.height }, () => { + this.setData({ showAnimation: this.showAnimation }); + }); + }); + } + hide() { + this.reset(); + this.setData({ showAnimation: this.hideAnimation }); + setTimeout(() => { + this.setData({ visible: false, animation: [] }); + }, SHOW_DURATION); + } + reset() { + if (this.nextAnimationContext) { + this.clearMessageAnimation(); + } + clearTimeout(this.closeTimeoutContext); + this.closeTimeoutContext = 0; + } + handleClose() { + this.hide(); + this.triggerEvent('closeBtnClick'); + } + handleBtnClick() { + this.triggerEvent('actionBtnClick', { self: this }); + } +}; +Message = __decorate([ + wxComponent() +], Message); +export default Message; diff --git a/components/message/message.json b/components/message/message.json new file mode 100644 index 0000000..ef9e100 --- /dev/null +++ b/components/message/message.json @@ -0,0 +1,7 @@ +{ + "component": true, + "usingComponents": { + "t-icon": "../icon/icon", + "t-button": "../button/button" + } +} diff --git a/components/message/message.wxml b/components/message/message.wxml new file mode 100644 index 0000000..cca30c6 --- /dev/null +++ b/components/message/message.wxml @@ -0,0 +1,51 @@ + + + + + + + + + + {{content}} + + + + + {{action}} + + + + + + diff --git a/components/message/message.wxs b/components/message/message.wxs new file mode 100644 index 0000000..44f5b56 --- /dev/null +++ b/components/message/message.wxs @@ -0,0 +1,16 @@ +var changeNumToStr = function (arr) { + return arr.map(function (item) { + return typeof item === 'number' ? item + 'rpx' : item; + }); +}; + +var getMessageStylesOffset = function (props) { + var arr = changeNumToStr(props.offset); + var styleOffset = ''; + styleOffset += 'top:' + arr[0] + ';'; + styleOffset += 'right:' + arr[1] + ';'; + styleOffset += 'left:' + arr[1] + ';'; + return styleOffset; +}; + +module.exports.getMessageStylesOffset = getMessageStylesOffset; diff --git a/components/message/message.wxss b/components/message/message.wxss new file mode 100644 index 0000000..96aa0a7 --- /dev/null +++ b/components/message/message.wxss @@ -0,0 +1,89 @@ +.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-message { + position: fixed; + top: 0; + left: 0; + right: 0; + display: flex; + justify-content: flex-start; + align-items: center; + z-index: 15000; + color: #0052d9; + padding: 24rpx 32rpx; + box-sizing: border-box; + border-radius: 8rpx; + font-size: 28rpx; + line-height: 1; + background: #ffffff; + box-shadow: 0px 1px 4px 0px rgba(0, 0, 0, 0.2); +} +.t-message__text { + display: inline-block; +} +.t-message__text-wrap { + flex: 1 1 auto; + overflow-x: hidden; + text-overflow: ellipsis; + line-height: 44rpx; +} +.t-message__text-nowrap { + word-break: keep-all; + white-space: nowrap; +} +.t-message--info { + color: #0052d9; +} +.t-message--success { + color: #00a870; +} +.t-message--warning { + color: #ed7b2f; +} +.t-message--error { + color: #e34d59; +} +.t-message .t-message__icon--left { + margin-right: 16rpx; +} +.t-message .t-message__icon--right, +.t-message .t-message__btn--right { + flex: 0 0 auto; + margin-left: 16rpx; +} +.t-message .t-message__btn--right { + font-size: inherit; + line-height: inherit; + height: 44rpx; + line-height: 44rpx; + border-radius: 8rpx; + border-color: inherit; + color: inherit; + min-height: 0; + background: transparent; +} diff --git a/components/message/props.d.ts b/components/message/props.d.ts new file mode 100644 index 0000000..c5a8f65 --- /dev/null +++ b/components/message/props.d.ts @@ -0,0 +1,3 @@ +import { TdMessageProps } from './type'; +declare const props: TdMessageProps; +export default props; diff --git a/components/message/props.js b/components/message/props.js new file mode 100644 index 0000000..4ee00a9 --- /dev/null +++ b/components/message/props.js @@ -0,0 +1,49 @@ +const props = { + action: { + type: String, + }, + align: { + type: String, + value: 'left', + }, + closeBtn: { + type: String, + optionalTypes: [Boolean], + value: undefined, + }, + content: { + type: String, + }, + duration: { + type: Number, + value: 3000, + }, + externalClasses: { + type: Array, + }, + icon: { + type: String, + optionalTypes: [Boolean], + value: true, + }, + marquee: { + type: null, + value: false, + }, + offset: { + type: Array, + }, + theme: { + type: String, + value: 'info', + }, + visible: { + type: Boolean, + value: false, + }, + zIndex: { + type: Number, + value: 15000, + }, +}; +export default props; diff --git a/components/message/type.d.ts b/components/message/type.d.ts new file mode 100644 index 0000000..3f49ddb --- /dev/null +++ b/components/message/type.d.ts @@ -0,0 +1,70 @@ +export interface TdMessageProps { + action?: { + type: StringConstructor; + value?: string; + required?: boolean; + }; + align?: { + type: StringConstructor; + value?: 'left' | 'center'; + required?: boolean; + }; + closeBtn?: { + type: StringConstructor; + optionalTypes: Array; + value?: string | boolean; + required?: boolean; + }; + content?: { + type: StringConstructor; + value?: string; + required?: boolean; + }; + duration?: { + type: NumberConstructor; + value?: number; + required?: boolean; + }; + externalClasses?: { + type: ArrayConstructor; + value?: ['t-class', 't-class-content', 't-class-icon', 't-class-action', 't-class-close-btn']; + required?: boolean; + }; + icon?: { + type: StringConstructor; + optionalTypes: Array; + value?: boolean | 'info' | 'bell'; + required?: boolean; + }; + marquee?: { + type: null; + value?: DrawMarquee | boolean; + required?: boolean; + }; + offset?: { + type: ArrayConstructor; + value?: Array; + required?: boolean; + }; + theme?: { + type: StringConstructor; + value?: MessageThemeList; + required?: boolean; + }; + visible?: { + type: BooleanConstructor; + value?: boolean; + required?: boolean; + }; + zIndex?: { + type: NumberConstructor; + value?: number; + required?: boolean; + }; +} +export interface DrawMarquee { + speed?: number; + loop?: number; + delay?: number; +} +export declare type MessageThemeList = 'info' | 'success' | 'warning' | 'error'; diff --git a/components/message/type.js b/components/message/type.js new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/components/message/type.js @@ -0,0 +1 @@ +export {}; diff --git a/components/toast/README.en-US.md b/components/toast/README.en-US.md new file mode 100644 index 0000000..90969a6 --- /dev/null +++ b/components/toast/README.en-US.md @@ -0,0 +1,25 @@ +:: BASE_DOC :: + +## API + +### Toast Props + +name | type | default | description | required +-- | -- | -- | -- | -- +direction | String | row | options:row/column | N +duration | Number | 2000 | \- | N +external-classes | Array | - | `['t-class']` | N +icon | String | - | \- | N +message | String / Slot | - | \- | N +overlay-props | Object | {} | \- | N +placement | String | middle | options: top/middle/bottom | N +prevent-scroll-through | Boolean | false | \- | N +show-overlay | Boolean | false | \- | N +theme | String | - | options:loading/success/fail | N + +### Toast Events + +name | params | description +-- | -- | -- +close | \- | \- +destory | \- | \- diff --git a/components/toast/README.md b/components/toast/README.md new file mode 100644 index 0000000..affc6c0 --- /dev/null +++ b/components/toast/README.md @@ -0,0 +1,59 @@ +--- +title: Toast 轻提示 +description: 用于轻量级反馈或提示,不会打断用户操作。 +spline: message +isComponent: true +--- + + +## 引入 + +全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。 + +```json +"usingComponents": { + "t-toast": "tdesign-miniprogram/toast/toast" +} +``` + +## 代码演示 + +### 基础提示 + +{{ base }} + +### 默认提示 + +{{ normal }} + +### 不同位置的提示 + +{{ display }} + +### 显示遮罩 +{{ cover }} + +### 手动关闭 +{{ close }} +## API +### Toast Props + +名称 | 类型 | 默认值 | 说明 | 必传 +-- | -- | -- | -- | -- +direction | String | row | 图标排列方式。可选项:row/column | N +duration | Number | 2000 | 弹窗显示毫秒数 | N +external-classes | Array | - | 组件类名。`['t-class']` | N +icon | String | - | 自定义图标 | N +message | String / Slot | - | 弹窗显示文字 | N +overlay-props | Object | {} | 遮罩层属性,透传至 Overlay | N +placement | String | middle | 弹窗展示位置。可选项: top/middle/bottom | N +prevent-scroll-through | Boolean | false | 防止滚动穿透,即不允许点击和滚动 | N +show-overlay | Boolean | false | 是否显示遮罩层 | N +theme | String | - | 提示类型。可选项:loading/success/fail | N + +### Toast Events + +名称 | 参数 | 描述 +-- | -- | -- +close | - | 轻提示隐藏的时候触发 +destory | - | 轻提示销毁的时候触发 diff --git a/components/toast/index.d.ts b/components/toast/index.d.ts new file mode 100644 index 0000000..1d9d0f4 --- /dev/null +++ b/components/toast/index.d.ts @@ -0,0 +1,21 @@ +// @ts-ignore +declare type Context = WechatMiniprogram.Page.TrivialInstance | WechatMiniprogram.Component.TrivialInstance; +declare type ToastType = 'loading' | 'success' | 'fail'; +declare type ToastPositionType = 'top' | 'middle' | 'bottom'; +declare type ToastDirectionType = 'row' | 'column'; +export declare type ToastOptionsType = { + context?: Context; + selector?: string; + icon?: string; + message?: string; + duration?: number; + theme?: ToastType; + placement?: ToastPositionType; + preventScrollThrough?: boolean; + direction?: ToastDirectionType; + close?: () => T; +}; +declare function Toast(options: ToastOptionsType): void; +declare function showToast(options?: ToastOptionsType): void; +declare function hideToast(options?: ToastOptionsType): void; +export { Toast as default, showToast, hideToast }; diff --git a/components/toast/index.js b/components/toast/index.js new file mode 100644 index 0000000..216f208 --- /dev/null +++ b/components/toast/index.js @@ -0,0 +1,31 @@ +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { + if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) + t[p[i]] = s[p[i]]; + } + return t; +}; +import { getInstance } from '../common/utils'; +function Toast(options) { + var _a; + const { context, selector = '#t-toast' } = options, Options = __rest(options, ["context", "selector"]); + const instance = getInstance(context, selector); + if (instance) { + instance.show(Object.assign(Object.assign({}, Options), { duration: (_a = Options.duration) !== null && _a !== void 0 ? _a : 2000 })); + } +} +function showToast(options = {}) { + Toast(options); +} +function hideToast(options = {}) { + const { context, selector = '#t-toast' } = options; + const instance = getInstance(context, selector); + if (instance) { + instance.hide(); + } +} +export { Toast as default, showToast, hideToast }; diff --git a/components/toast/props.d.ts b/components/toast/props.d.ts new file mode 100644 index 0000000..c6b0f86 --- /dev/null +++ b/components/toast/props.d.ts @@ -0,0 +1,3 @@ +import { TdToastProps } from './type'; +declare const props: TdToastProps; +export default props; diff --git a/components/toast/props.js b/components/toast/props.js new file mode 100644 index 0000000..3ff6f41 --- /dev/null +++ b/components/toast/props.js @@ -0,0 +1,40 @@ +const props = { + direction: { + type: String, + value: 'row', + }, + duration: { + type: Number, + value: 2000, + }, + externalClasses: { + type: Array, + }, + icon: { + type: String, + value: '', + }, + message: { + type: String, + }, + overlayProps: { + type: Object, + value: {}, + }, + placement: { + type: String, + value: 'middle', + }, + preventScrollThrough: { + type: Boolean, + value: false, + }, + showOverlay: { + type: Boolean, + value: false, + }, + theme: { + type: String, + }, +}; +export default props; diff --git a/components/toast/toast.d.ts b/components/toast/toast.d.ts new file mode 100644 index 0000000..91cc921 --- /dev/null +++ b/components/toast/toast.d.ts @@ -0,0 +1,25 @@ +/// +import { SuperComponent } from '../common/src/index'; +import { ToastOptionsType } from './index'; +declare type Timer = NodeJS.Timeout | null; +export default class Toast extends SuperComponent { + externalClasses: string[]; + options: { + multipleSlots: boolean; + }; + behaviors: string[]; + hideTimer: Timer; + data: { + prefix: string; + classPrefix: string; + typeMapIcon: string; + }; + properties: import("./type").TdToastProps; + detached(): void; + methods: { + show(options: ToastOptionsType): void; + hide(): void; + destroyed(): void; + }; +} +export {}; diff --git a/components/toast/toast.js b/components/toast/toast.js new file mode 100644 index 0000000..b461b73 --- /dev/null +++ b/components/toast/toast.js @@ -0,0 +1,78 @@ +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 transition from '../mixins/transition'; +const { prefix } = config; +const name = `${prefix}-toast`; +let Toast = class Toast extends SuperComponent { + constructor() { + super(...arguments); + this.externalClasses = [`${prefix}-class`]; + this.options = { + multipleSlots: true, + }; + this.behaviors = [transition()]; + this.hideTimer = null; + this.data = { + prefix, + classPrefix: name, + typeMapIcon: '', + }; + this.properties = props; + this.methods = { + show(options) { + if (this.hideTimer) + clearTimeout(this.hideTimer); + const iconMap = { + loading: 'loading', + success: 'check-circle', + fail: 'error-circle', + }; + const typeMapIcon = iconMap[options === null || options === void 0 ? void 0 : options.theme] || ''; + const defaultOptions = { + direction: props.direction.value, + duration: props.duration.value, + icon: props.icon.value, + message: props.message.value, + placement: props.placement.value, + preventScrollThrough: props.preventScrollThrough.value, + theme: props.theme.value, + }; + const data = Object.assign(Object.assign(Object.assign({}, defaultOptions), options), { visible: true, typeMapIcon }); + const { duration } = data; + this.setData(data); + if (duration > 0) { + this.hideTimer = setTimeout(() => { + this.hide(); + }, duration); + } + }, + hide() { + var _a, _b; + this.setData({ visible: false }); + (_b = (_a = this.data) === null || _a === void 0 ? void 0 : _a.close) === null || _b === void 0 ? void 0 : _b.call(_a); + this.triggerEvent('close'); + }, + destroyed() { + if (this.hideTimer) { + clearTimeout(this.hideTimer); + this.hideTimer = null; + } + this.triggerEvent('destory'); + }, + }; + } + detached() { + this.destroyed(); + } +}; +Toast = __decorate([ + wxComponent() +], Toast); +export default Toast; diff --git a/components/toast/toast.json b/components/toast/toast.json new file mode 100644 index 0000000..b60dbbc --- /dev/null +++ b/components/toast/toast.json @@ -0,0 +1,8 @@ +{ + "component": true, + "usingComponents": { + "t-icon": "../icon/icon", + "t-loading": "../loading/loading", + "t-overlay": "../overlay/overlay" + } +} diff --git a/components/toast/toast.wxml b/components/toast/toast.wxml new file mode 100644 index 0000000..bc91969 --- /dev/null +++ b/components/toast/toast.wxml @@ -0,0 +1,36 @@ + + + + + + {{message}} + + + + diff --git a/components/toast/toast.wxss b/components/toast/toast.wxss new file mode 100644 index 0000000..7aaf84f --- /dev/null +++ b/components/toast/toast.wxss @@ -0,0 +1,84 @@ +.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-toast { + position: fixed; + right: -50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 12001; + opacity: 1; + transition: opacity 300ms ease; + background-color: rgba(0, 0, 0, 0.6); + border-radius: 8rpx; + font-size: 28rpx; + color: white; + max-width: 374rpx; + width: fit-content; + box-sizing: border-box; +} +.t-toast--column { + padding: 48rpx; + min-width: 272rpx; + min-height: 260rpx; + border-radius: 16rpx; +} +.t-toast__content { + align-items: center; + line-height: 44rpx; +} +.t-toast__content--row { + display: flex; + text-align: left; + padding: 28rpx 44rpx; +} +.t-toast__content--column { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} +.t-toast__icon--row { + display: flex; +} +.t-toast__text { + overflow: hidden; + text-overflow: ellipsis; + -webkit-line-clamp: 3; + display: -webkit-box; + -webkit-box-orient: vertical; +} +.t-toast__text--column { + margin-top: 24rpx; +} +.t-toast__text--row { + margin-left: 12rpx; +} +.t-toast.t-fade-enter, +.t-toast.t-fade-leave-to { + opacity: 0; +} diff --git a/components/toast/type.d.ts b/components/toast/type.d.ts new file mode 100644 index 0000000..9887289 --- /dev/null +++ b/components/toast/type.d.ts @@ -0,0 +1,42 @@ +export interface TdToastProps { + direction?: { + type: StringConstructor; + value?: 'row' | 'column'; + }; + duration?: { + type: NumberConstructor; + value?: number; + }; + externalClasses?: { + type: ArrayConstructor; + value?: ['t-class']; + }; + icon?: { + type: StringConstructor; + value?: string; + }; + message?: { + type: StringConstructor; + value?: string; + }; + overlayProps?: { + type: ObjectConstructor; + value?: object; + }; + placement?: { + type: StringConstructor; + value?: 'top' | 'middle' | 'bottom'; + }; + preventScrollThrough?: { + type: BooleanConstructor; + value?: boolean; + }; + showOverlay?: { + type: BooleanConstructor; + value?: boolean; + }; + theme?: { + type: StringConstructor; + value?: 'loading' | 'success' | 'fail'; + }; +} diff --git a/components/toast/type.js b/components/toast/type.js new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/components/toast/type.js @@ -0,0 +1 @@ +export {}; diff --git a/pages/anniversary/create/index.json b/pages/anniversary/create/index.json index fe67fd6..d0e8daf 100644 --- a/pages/anniversary/create/index.json +++ b/pages/anniversary/create/index.json @@ -3,7 +3,6 @@ "t-date-time-picker": "/components/date-time-picker/date-time-picker", "t-picker": "/components/picker/picker", "t-picker-item": "/components/picker/picker-item", - "jh-lunar-picker": "/components/jh-lunar-picker/index", "t-switch": "/components/switch/switch", "t-button": "/components/button/button" } diff --git a/pages/message/index.js b/pages/message/index.js index b73fc1f..26bf446 100644 --- a/pages/message/index.js +++ b/pages/message/index.js @@ -1,4 +1,6 @@ // pages/message/index.js +import Toast from '../../components/toast/index'; +import Message from '../../components/message/index'; Page({ /** @@ -7,60 +9,27 @@ Page({ data: { aIconList: ['check-rectangle','star','notification-filled','circle'], }, - - /** - * 生命周期函数--监听页面加载 - */ - onLoad(options) { - + toast(option) { + Toast({ + context: this, + selector: '#t-toast', + ...option, + }); }, - - /** - * 生命周期函数--监听页面初次渲染完成 - */ - onReady() { - - }, - - /** - * 生命周期函数--监听页面显示 - */ - onShow() { - - }, - - /** - * 生命周期函数--监听页面隐藏 - */ - onHide() { - - }, - - /** - * 生命周期函数--监听页面卸载 - */ - onUnload() { - - }, - - /** - * 页面相关事件处理函数--监听用户下拉动作 - */ - onPullDownRefresh() { - - }, - - /** - * 页面上拉触底事件的处理函数 - */ - onReachBottom() { - - }, - - /** - * 用户点击右上角分享 - */ - onShareAppMessage() { - + startVipButton(e){ + this.toast({ + message: '已获得会员资格!', + theme: 'success', + placement: 'bottom', + direction: 'column', + }); + Message.info({ + context: this, + offset: [20, 32], + marquee: { speed: 50, loop: -1, delay: 5000 }, + icon: false, + content: '请关注微信公众号Quinn,回复"VIP"', + duration: -1, + }); } }) diff --git a/pages/message/index.json b/pages/message/index.json index b36ebcb..31350f3 100644 --- a/pages/message/index.json +++ b/pages/message/index.json @@ -1,5 +1,9 @@ { "usingComponents": { - "foot-tab": "../foot-tab/foot-tab" + "foot-tab": "../foot-tab/foot-tab", + "t-empty": "/components/empty/empty", + "t-button": "/components/button/button", + "t-toast": "/components/toast/toast", + "t-message": "/components/message/message" } } diff --git a/pages/message/index.wxml b/pages/message/index.wxml index 95710e7..5c9711e 100644 --- a/pages/message/index.wxml +++ b/pages/message/index.wxml @@ -1,5 +1,9 @@ -您有新的消息 + + + 开通会员 + + diff --git a/pages/message/index.wxss b/pages/message/index.wxss index 97b283a..50b023a 100644 --- a/pages/message/index.wxss +++ b/pages/message/index.wxss @@ -1 +1,4 @@ -/* pages/message/index.wxss */ \ No newline at end of file +/* pages/message/index.wxss */ +.empty-cls { + margin-top: 250rpx !important; +}