This commit is contained in:
码农搬砖工 2025-04-23 18:23:41 +08:00
parent 3e5003be39
commit 9018a4f868
1158 changed files with 78916 additions and 0 deletions

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 leejimqiu
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

BIN
__MACOSX/._LICENSE Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
__MACOSX/mock/._.DS_Store Normal file

Binary file not shown.

BIN
__MACOSX/pages/._.DS_Store Normal file

Binary file not shown.

BIN
__MACOSX/static/._.DS_Store Normal file

Binary file not shown.

44
api/request.js Normal file
View File

@ -0,0 +1,44 @@
import config from '~/config';
const { baseUrl } = config;
const delay = config.isMock ? 500 : 0;
function request(url, method = 'GET', data = {}) {
const header = {
'content-type': 'application/json',
// 有其他content-type需求加点逻辑判断处理即可
};
// 获取token有就丢进请求头
const tokenString = wx.getStorageSync('access_token');
if (tokenString) {
header.Authorization = `Bearer ${tokenString}`;
}
return new Promise((resolve, reject) => {
wx.request({
url: baseUrl + url,
method,
data,
dataType: 'json', // 微信官方文档中介绍会对数据进行一次JSON.parse
header,
success(res) {
setTimeout(() => {
// HTTP状态码为200才视为成功
if (res.code === 200) {
resolve(res);
} else {
// wx.request的特性只要有响应就会走success回调所以在这里判断状态非200的均视为请求失败
reject(res);
}
}, delay);
},
fail(err) {
setTimeout(() => {
// 断网、服务器挂了都会fail回调直接reject即可
reject(err);
}, delay);
},
});
});
}
// 导出请求和服务地址
export default request;

66
app.js Normal file
View File

@ -0,0 +1,66 @@
// app.js
import config from './config';
import Mock from './mock/index';
import createBus from './utils/eventBus';
import { connectSocket, fetchUnreadNum } from './mock/chat';
if (config.isMock) {
Mock();
}
App({
onLaunch() {
const updateManager = wx.getUpdateManager();
updateManager.onCheckForUpdate((res) => {
// console.log(res.hasUpdate)
});
updateManager.onUpdateReady(() => {
wx.showModal({
title: '更新提示',
content: '新版本已经准备好,是否重启应用?',
success(res) {
if (res.confirm) {
updateManager.applyUpdate();
}
},
});
});
this.getUnreadNum();
this.connect();
},
globalData: {
userInfo: null,
unreadNum: 0, // 未读消息数量
socket: null, // SocketTask 对象
},
/** 全局事件总线 */
eventBus: createBus(),
/** 初始化WebSocket */
connect() {
const socket = connectSocket();
socket.onMessage((data) => {
data = JSON.parse(data);
if (data.type === 'message' && !data.data.message.read) this.setUnreadNum(this.globalData.unreadNum + 1);
});
this.globalData.socket = socket;
},
/** 获取未读消息数量 */
getUnreadNum() {
fetchUnreadNum().then(({ data }) => {
this.globalData.unreadNum = data;
this.eventBus.emit('unread-num-change', data);
});
},
/** 设置未读消息数量 */
setUnreadNum(unreadNum) {
this.globalData.unreadNum = unreadNum;
this.eventBus.emit('unread-num-change', unreadNum);
},
});

75
app.json Normal file
View File

@ -0,0 +1,75 @@
{
"pages": ["pages/home/index", "pages/message/index", "pages/my/index"],
"usingComponents": {
"t-toast": "tdesign-miniprogram/toast/toast"
},
"subpackages": [
{
"root": "pages/search",
"name": "search",
"pages": ["index"]
},
{
"root": "pages/my/info-edit",
"name": "edit",
"pages": ["index"]
},
{
"root": "pages/chat",
"name": "chat",
"pages": ["index"]
},
{
"root": "pages/login",
"name": "login",
"pages": ["login"]
},
{
"root": "pages/loginCode",
"name": "loginCode",
"pages": ["loginCode"]
},
{
"root": "pages/dataCenter",
"name": "dataCenter",
"pages": ["index"]
},
{
"root": "pages/setting",
"name": "setting",
"pages": ["index"]
},
{
"root": "pages/release",
"name": "release",
"pages": ["index"]
}
],
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "Weixin",
"navigationBarTextStyle": "black"
},
"tabBar": {
"custom": true,
"list": [
{
"pagePath": "pages/home/index",
"text": "首页"
},
{
"pagePath": "pages/message/index",
"text": "随访"
},
{
"pagePath": "pages/my/index",
"text": "我2的"
}
]
},
"resolveAlias": {
"~/*": "/*"
},
"sitemapLocation": "sitemap.json"
}

10
app.less Normal file
View File

@ -0,0 +1,10 @@
/**app.wxss**/
page {
background-color: #f3f3f3;
--td-brand-color: #0091cc; // 任何你想要的主题色
}
.page {
height: 100vh;
background-color: #fff;
}

22
behaviors/useToast.js Normal file
View File

@ -0,0 +1,22 @@
import Toast, { hideToast } from 'tdesign-miniprogram/toast/index';
const useToastBehavior = Behavior({
methods: {
onShowToast(selector, message) {
Toast({
context: this,
selector,
message,
});
},
onHideToast(selector) {
hideToast({
context: this,
selector,
});
},
},
});
export default useToastBehavior;

9
components/card/index.js Normal file
View File

@ -0,0 +1,9 @@
Component({
properties: {
url: String,
desc: String,
tags: Array,
},
data: {},
methods: {},
});

View File

@ -0,0 +1,7 @@
{
"component": true,
"usingComponents": {
"t-image": "tdesign-miniprogram/image/image",
"t-tag": "tdesign-miniprogram/tag/tag"
}
}

View File

@ -0,0 +1,27 @@
@import '/variable.less';
.home-card {
display: inline-flex;
flex-direction: column;
width: 340rpx;
height: 488rpx;
border-radius: 9px;
background: @bg-color-white;
&__image {
width: 340rpx;
height: 340rpx;
}
&__info {
padding: 32rpx;
font-weight: 400;
font-size: @font-size-small;
}
&__tag-group {
display: flex;
gap: 16rpx;
margin-top: 16rpx;
}
}

View File

@ -0,0 +1,9 @@
<view class="home-card">
<t-image t-class="home-card__image" src="{{url}}" mode="aspectFill" />
<view class="home-card__info">
<text>{{desc}}</text>
<view class="home-card__tag-group">
<t-tag wx:for="{{tags}}" wx:key="index" size="small" variant="light" theme="{{item.theme}}">{{item.text}}</t-tag>
</view>
</view>
</view>

109
components/nav/index.js Normal file
View File

@ -0,0 +1,109 @@
Component({
options: {
styleIsolation: 'shared',
},
properties: {
navType: {
type: String,
value: 'title',
},
titleText: String,
},
data: {
visible: false,
sidebar: [
{
title: '首页',
url: 'pages/home/index',
isSidebar: true,
},
{
title: '搜索页',
url: 'pages/search/index',
isSidebar: false,
},
{
title: '发布页',
url: 'pages/release/index',
isSidebar: false,
},
{
title: '消息列表页',
url: 'pages/message/index',
isSidebar: true,
},
{
title: '对话页',
url: 'pages/chat/index',
isSidebar: false,
},
{
title: '个人中心页',
url: 'pages/my/index',
isSidebar: true,
},
{
title: '个人信息表单页',
url: 'pages/my/info-edit/index',
isSidebar: false,
},
{
title: '设置页',
url: 'pages/setting/index',
isSidebar: false,
},
{
title: '数据图表页',
url: 'pages/dataCenter/index',
isSidebar: false,
},
{
title: '登录注册页',
url: 'pages/login/login',
isSidebar: false,
},
],
statusHeight: 0,
},
lifetimes: {
ready() {
const statusHeight = wx.getWindowInfo().statusBarHeight;
this.setData({ statusHeight });
},
},
methods: {
openDrawer() {
this.setData({
visible: true,
});
},
itemClick(e) {
const that = this;
const { isSidebar, url } = e.detail.item;
if (isSidebar) {
wx.switchTab({
url: `/${url}`,
}).then(() => {
// 防止点回tab时sidebar依旧是展开模式
that.setData({
visible: false,
});
});
} else {
wx.navigateTo({
url: `/${url}`,
}).then(() => {
that.setData({
visible: false,
});
});
}
},
searchTurn() {
wx.navigateTo({
url: `/pages/search/index`,
});
},
},
});

View File

@ -0,0 +1,9 @@
{
"component": true,
"usingComponents": {
"t-navbar": "tdesign-miniprogram/navbar/navbar",
"t-icon": "tdesign-miniprogram/icon/icon",
"t-drawer": "tdesign-miniprogram/drawer/drawer",
"t-search": "tdesign-miniprogram/search/search"
}
}

30
components/nav/index.less Normal file
View File

@ -0,0 +1,30 @@
@import '/variable.less';
.home-navbar {
.t-navbar {
&__left {
margin-left: 12rpx;
}
}
&__icon {
padding: 12rpx;
}
&__left {
display: flex;
align-items: center;
padding: 0 16rpx;
.t-search {
--td-search-height: 64rpx;
--td-search-font-size: @font-size-mini;
width: 375rpx;
.t-icon {
font-size: @font-size-default !important;
}
}
}
--td-drawer-title-font-size: 48rpx;
}

23
components/nav/index.wxml Normal file
View File

@ -0,0 +1,23 @@
<view class="home-navbar">
<t-navbar title="{{ navType === 'search' ? '' : titleText }}">
<view slot="left">
<view class="home-navbar__left">
<t-icon class="home-navbar__icon" bind:tap="openDrawer" name="view-list" size="48rpx" />
<t-search
shape="round"
placeholder="请搜索你想要的内容"
bindtap="searchTurn"
wx:if="{{navType === 'search'}}"
/>
</view>
</view>
</t-navbar>
<t-drawer
style="padding-top: {{statusHeight}}px;"
visible="{{visible}}"
items="{{sidebar}}"
placement="left"
title="页面目录"
bind:item-click="itemClick"
/>
</view>

4
config.js Normal file
View File

@ -0,0 +1,4 @@
export default {
isMock: true,
baseUrl: '',
};

6
config/index.js Normal file
View File

@ -0,0 +1,6 @@
/** 是否使用mock代替api返回 */
export const config = {
useMock: true,
};
export default { config };

57
custom-tab-bar/index.js Normal file
View File

@ -0,0 +1,57 @@
const app = getApp();
Component({
data: {
value: '', // 初始值设置为空,避免第一次加载时闪烁
unreadNum: 0, // 未读消息数量
list: [
{
icon: 'home',
value: 'index',
label: '首页',
},
{
icon: 'chat',
value: 'notice',
label: '随访',
},
{
icon: 'user',
value: 'my',
label: '我1的',
},
],
},
lifetimes: {
ready() {
const pages = getCurrentPages();
const curPage = pages[pages.length - 1];
if (curPage) {
const nameRe = /pages\/(\w+)\/index/.exec(curPage.route);
if (nameRe === null) return;
if (nameRe[1] && nameRe) {
this.setData({
value: nameRe[1],
});
}
}
// 同步全局未读消息数量
this.setUnreadNum(app.globalData.unreadNum);
app.eventBus.on('unread-num-change', (unreadNum) => {
this.setUnreadNum(unreadNum);
});
},
},
methods: {
handleChange(e) {
const { value } = e.detail;
wx.switchTab({ url: `/pages/${value}/index` });
},
/** 设置未读消息数量 */
setUnreadNum(unreadNum) {
this.setData({ unreadNum });
},
},
});

View File

@ -0,0 +1,7 @@
{
"component": true,
"usingComponents": {
"t-tab-bar": "tdesign-miniprogram/tab-bar/tab-bar",
"t-tab-bar-item": "tdesign-miniprogram/tab-bar-item/tab-bar-item"
}
}

10
custom-tab-bar/index.less Normal file
View File

@ -0,0 +1,10 @@
@import '/variable.less';
.custom-tab-bar {
--td-tab-bar-height: @tab-bar-height;
&-item {
margin: 0;
padding: 16rpx 24rpx;
}
}

View File

@ -0,0 +1,5 @@
<t-tab-bar value="{{ value }}" theme="tag" split="{{ false }}" bind:change="handleChange">
<t-tab-bar-item icon="home" value="home">首页</t-tab-bar-item>
<t-tab-bar-item icon="chat" value="message">随访</t-tab-bar-item>
<t-tab-bar-item icon="user" value="my">我的</t-tab-bar-item>
</t-tab-bar>

284
ec-canvas/ec-canvas.js Normal file
View File

@ -0,0 +1,284 @@
import WxCanvas from './wx-canvas';
import * as echarts from './echarts';
let ctx;
function compareVersion(v1, v2) {
v1 = v1.split('.')
v2 = v2.split('.')
const len = Math.max(v1.length, v2.length)
while (v1.length < len) {
v1.push('0')
}
while (v2.length < len) {
v2.push('0')
}
for (let i = 0; i < len; i++) {
const num1 = parseInt(v1[i])
const num2 = parseInt(v2[i])
if (num1 > num2) {
return 1
} else if (num1 < num2) {
return -1
}
}
return 0
}
Component({
properties: {
canvasId: {
type: String,
value: 'ec-canvas'
},
ec: {
type: Object
},
forceUseOldCanvas: {
type: Boolean,
value: false
}
},
data: {
isUseNewCanvas: false
},
ready: function () {
// Disable prograssive because drawImage doesn't support DOM as parameter
// See https://developers.weixin.qq.com/miniprogram/dev/api/canvas/CanvasContext.drawImage.html
echarts.registerPreprocessor(option => {
if (option && option.series) {
if (option.series.length > 0) {
option.series.forEach(series => {
series.progressive = 0;
});
}
else if (typeof option.series === 'object') {
option.series.progressive = 0;
}
}
});
if (!this.data.ec) {
console.warn('组件需绑定 ec 变量,例:<ec-canvas id="mychart-dom-bar" '
+ 'canvas-id="mychart-bar" ec="{{ ec }}"></ec-canvas>');
return;
}
if (!this.data.ec.lazyLoad) {
this.init();
}
},
methods: {
init: function (callback) {
const version = wx.getSystemInfoSync().SDKVersion
const canUseNewCanvas = compareVersion(version, '2.9.0') >= 0;
const forceUseOldCanvas = this.data.forceUseOldCanvas;
const isUseNewCanvas = canUseNewCanvas && !forceUseOldCanvas;
this.setData({ isUseNewCanvas });
if (forceUseOldCanvas && canUseNewCanvas) {
console.warn('开发者强制使用旧canvas,建议关闭');
}
if (isUseNewCanvas) {
// console.log('微信基础库版本大于2.9.0,开始使用<canvas type="2d"/>');
// 2.9.0 可以使用 <canvas type="2d"></canvas>
this.initByNewWay(callback);
} else {
const isValid = compareVersion(version, '1.9.91') >= 0
if (!isValid) {
console.error('微信基础库版本过低,需大于等于 1.9.91。'
+ '参见https://github.com/ecomfe/echarts-for-weixin'
+ '#%E5%BE%AE%E4%BF%A1%E7%89%88%E6%9C%AC%E8%A6%81%E6%B1%82');
return;
} else {
console.warn('建议将微信基础库调整大于等于2.9.0版本。升级后绘图将有更好性能');
this.initByOldWay(callback);
}
}
},
initByOldWay(callback) {
// 1.9.91 <= version < 2.9.0:原来的方式初始化
ctx = wx.createCanvasContext(this.data.canvasId, this);
const canvas = new WxCanvas(ctx, this.data.canvasId, false);
if (echarts.setPlatformAPI) {
echarts.setPlatformAPI({
createCanvas: () => canvas,
});
} else {
echarts.setCanvasCreator(() => canvas);
};
// const canvasDpr = wx.getSystemInfoSync().pixelRatio // 微信旧的canvas不能传入dpr
const canvasDpr = 1
var query = wx.createSelectorQuery().in(this);
query.select('.ec-canvas').boundingClientRect(res => {
if (typeof callback === 'function') {
this.chart = callback(canvas, res.width, res.height, canvasDpr);
}
else if (this.data.ec && typeof this.data.ec.onInit === 'function') {
this.chart = this.data.ec.onInit(canvas, res.width, res.height, canvasDpr);
}
else {
this.triggerEvent('init', {
canvas: canvas,
width: res.width,
height: res.height,
canvasDpr: canvasDpr // 增加了dpr可方便外面echarts.init
});
}
}).exec();
},
initByNewWay(callback) {
// version >= 2.9.0:使用新的方式初始化
const query = wx.createSelectorQuery().in(this)
query
.select('.ec-canvas')
.fields({ node: true, size: true })
.exec(res => {
const canvasNode = res[0].node
this.canvasNode = canvasNode
const canvasDpr = wx.getSystemInfoSync().pixelRatio
const canvasWidth = res[0].width
const canvasHeight = res[0].height
const ctx = canvasNode.getContext('2d')
const canvas = new WxCanvas(ctx, this.data.canvasId, true, canvasNode)
if (echarts.setPlatformAPI) {
echarts.setPlatformAPI({
createCanvas: () => canvas,
loadImage: (src, onload, onerror) => {
if (canvasNode.createImage) {
const image = canvasNode.createImage();
image.onload = onload;
image.onerror = onerror;
image.src = src;
return image;
}
console.error('加载图片依赖 `Canvas.createImage()` API要求小程序基础库版本在 2.7.0 及以上。');
// PENDING fallback?
}
})
} else {
echarts.setCanvasCreator(() => canvas)
}
if (typeof callback === 'function') {
this.chart = callback(canvas, canvasWidth, canvasHeight, canvasDpr)
} else if (this.data.ec && typeof this.data.ec.onInit === 'function') {
this.chart = this.data.ec.onInit(canvas, canvasWidth, canvasHeight, canvasDpr)
} else {
this.triggerEvent('init', {
canvas: canvas,
width: canvasWidth,
height: canvasHeight,
dpr: canvasDpr
})
}
})
},
canvasToTempFilePath(opt) {
if (this.data.isUseNewCanvas) {
// 新版
const query = wx.createSelectorQuery().in(this)
query
.select('.ec-canvas')
.fields({ node: true, size: true })
.exec(res => {
const canvasNode = res[0].node
opt.canvas = canvasNode
wx.canvasToTempFilePath(opt)
})
} else {
// 旧的
if (!opt.canvasId) {
opt.canvasId = this.data.canvasId;
}
ctx.draw(true, () => {
wx.canvasToTempFilePath(opt, this);
});
}
},
touchStart(e) {
if (this.chart && e.touches.length > 0) {
var touch = e.touches[0];
var handler = this.chart.getZr().handler;
handler.dispatch('mousedown', {
zrX: touch.x,
zrY: touch.y,
preventDefault: () => {},
stopImmediatePropagation: () => {},
stopPropagation: () => {}
});
handler.dispatch('mousemove', {
zrX: touch.x,
zrY: touch.y,
preventDefault: () => {},
stopImmediatePropagation: () => {},
stopPropagation: () => {}
});
handler.processGesture(wrapTouch(e), 'start');
}
},
touchMove(e) {
if (this.chart && e.touches.length > 0) {
var touch = e.touches[0];
var handler = this.chart.getZr().handler;
handler.dispatch('mousemove', {
zrX: touch.x,
zrY: touch.y,
preventDefault: () => {},
stopImmediatePropagation: () => {},
stopPropagation: () => {}
});
handler.processGesture(wrapTouch(e), 'change');
}
},
touchEnd(e) {
if (this.chart) {
const touch = e.changedTouches ? e.changedTouches[0] : {};
var handler = this.chart.getZr().handler;
handler.dispatch('mouseup', {
zrX: touch.x,
zrY: touch.y,
preventDefault: () => {},
stopImmediatePropagation: () => {},
stopPropagation: () => {}
});
handler.dispatch('click', {
zrX: touch.x,
zrY: touch.y,
preventDefault: () => {},
stopImmediatePropagation: () => {},
stopPropagation: () => {}
});
handler.processGesture(wrapTouch(e), 'end');
}
}
}
});
function wrapTouch(event) {
for (let i = 0; i < event.touches.length; ++i) {
const touch = event.touches[i];
touch.offsetX = touch.x;
touch.offsetY = touch.y;
}
return event;
}

4
ec-canvas/ec-canvas.json Normal file
View File

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

4
ec-canvas/ec-canvas.wxml Normal file
View File

@ -0,0 +1,4 @@
<!-- 新的接口对其了H5 -->
<canvas wx:if="{{isUseNewCanvas}}" type="2d" class="ec-canvas" canvas-id="{{ canvasId }}" bindinit="init" bindtouchstart="{{ ec.disableTouch ? '' : 'touchStart' }}" bindtouchmove="{{ ec.disableTouch ? '' : 'touchMove' }}" bindtouchend="{{ ec.disableTouch ? '' : 'touchEnd' }}"></canvas>
<!-- 旧的 -->
<canvas wx:else class="ec-canvas" canvas-id="{{ canvasId }}" bindinit="init" bindtouchstart="{{ ec.disableTouch ? '' : 'touchStart' }}" bindtouchmove="{{ ec.disableTouch ? '' : 'touchMove' }}" bindtouchend="{{ ec.disableTouch ? '' : 'touchEnd' }}"></canvas>

4
ec-canvas/ec-canvas.wxss Normal file
View File

@ -0,0 +1,4 @@
.ec-canvas {
width: 100%;
height: 100%;
}

45
ec-canvas/echarts.js Normal file

File diff suppressed because one or more lines are too long

111
ec-canvas/wx-canvas.js Normal file
View File

@ -0,0 +1,111 @@
export default class WxCanvas {
constructor(ctx, canvasId, isNew, canvasNode) {
this.ctx = ctx;
this.canvasId = canvasId;
this.chart = null;
this.isNew = isNew
if (isNew) {
this.canvasNode = canvasNode;
}
else {
this._initStyle(ctx);
}
// this._initCanvas(zrender, ctx);
this._initEvent();
}
getContext(contextType) {
if (contextType === '2d') {
return this.ctx;
}
}
// canvasToTempFilePath(opt) {
// if (!opt.canvasId) {
// opt.canvasId = this.canvasId;
// }
// return wx.canvasToTempFilePath(opt, this);
// }
setChart(chart) {
this.chart = chart;
}
addEventListener() {
// noop
}
attachEvent() {
// noop
}
detachEvent() {
// noop
}
_initCanvas(zrender, ctx) {
zrender.util.getContext = function () {
return ctx;
};
zrender.util.$override('measureText', function (text, font) {
ctx.font = font || '12px sans-serif';
return ctx.measureText(text);
});
}
_initStyle(ctx) {
ctx.createRadialGradient = () => {
return ctx.createCircularGradient(arguments);
};
}
_initEvent() {
this.event = {};
const eventNames = [{
wxName: 'touchStart',
ecName: 'mousedown'
}, {
wxName: 'touchMove',
ecName: 'mousemove'
}, {
wxName: 'touchEnd',
ecName: 'mouseup'
}, {
wxName: 'touchEnd',
ecName: 'click'
}];
eventNames.forEach(name => {
this.event[name.wxName] = e => {
const touch = e.touches[0];
this.chart.getZr().handler.dispatch(name.ecName, {
zrX: name.wxName === 'tap' ? touch.clientX : touch.x,
zrY: name.wxName === 'tap' ? touch.clientY : touch.y,
preventDefault: () => {},
stopImmediatePropagation: () => {},
stopPropagation: () => {}
});
};
});
}
set width(w) {
if (this.canvasNode) this.canvasNode.width = w
}
set height(h) {
if (this.canvasNode) this.canvasNode.height = h
}
get width() {
if (this.canvasNode)
return this.canvasNode.width
return 0
}
get height() {
if (this.canvasNode)
return this.canvasNode.height
return 0
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,52 @@
:: BASE_DOC ::
## API
### ActionSheet Props
name | type | default | description | required
-- | -- | -- | -- | --
style | Object | - | CSS(Cascading Style Sheets) | N
custom-style | Object | - | CSS(Cascading Style Sheets)used to set style on virtual component | N
align | String | center | `0.29.0`。options: center/left | N
cancel-text | String | - | \- | N
count | Number | 8 | \- | N
description | String | - | `0.29.0` | N
items | Array | - | required。Typescript`Array<string \| ActionSheetItem>` `interface ActionSheetItem {label: string; color?: string; disabled?: boolean;icon?: string;suffixIcon?: string; }`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/action-sheet/type.ts) | Y
popup-props | Object | {} | Typescript`PopupProps`[Popup API Documents](./popup?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/action-sheet/type.ts) | N
show-cancel | Boolean | true | \- | N
show-overlay | Boolean | true | \- | N
theme | String | list | options: list/grid | N
using-custom-navbar | Boolean | false | \- | N
visible | Boolean | false | required | Y
default-visible | Boolean | undefined | required。uncontrolled property | Y
### ActionSheet Events
name | params | description
-- | -- | --
cancel | \- | \-
close | `(trigger: TriggerSource)` | [see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/action-sheet/type.ts)。<br/>`type TriggerSource = 'overlay' \| 'command' \| 'select' `<br/>
selected | `(selected: ActionSheetItem \| string, index: number)` | \-
### ActionSheet External Classes
className | Description
-- | --
t-class | \-
t-class-cancel | \-
t-class-content | \-
### CSS Variables
The component provides the following CSS variables, which can be used to customize styles.
Name | Default Value | Description
-- | -- | --
--td-action-sheet-border-color | @gray-color-1 | -
--td-action-sheet-border-radius | @radius-extra-large | -
--td-action-sheet-cancel-color | @font-gray-1 | -
--td-action-sheet-cancel-height | 96rpx | -
--td-action-sheet-color | @font-gray-1 | -
--td-action-sheet-description-color | @font-gray-3 | -
--td-action-sheet-list-item-disabled-color | @font-gray-4 | -
--td-action-sheet-list-item-height | 112rpx | -
--td-action-sheet-text-align | center | -

View File

@ -0,0 +1,140 @@
---
title: ActionSheet 动作面板
description: 由用户操作后触发的一种特定的模态弹出框 ,呈现一组与当前情境相关的两个或多个选项。
spline: data
isComponent: true
---
<span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20lines-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20functions-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20statements-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20branches-89%25-blue" /></span>
<div style="background: #ecf2fe; display: flex; align-items: center; line-height: 20px; padding: 14px 24px; border-radius: 3px; color: #555a65">
<svg fill="none" viewBox="0 0 16 16" width="16px" height="16px" style="margin-right: 5px">
<path fill="#0052d9" d="M8 15A7 7 0 108 1a7 7 0 000 14zM7.4 4h1.2v1.2H7.4V4zm.1 2.5h1V12h-1V6.5z" fillOpacity="0.9"></path>
</svg>
该组件于 0.9.0 版本上线,请留意版本。
</div>
## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
```json
"usingComponents": {
"t-action-sheet": "tdesign-miniprogram/action-sheet/action-sheet",
}
```
## 代码演示
<a href="https://developers.weixin.qq.com/s/EM7cxim37USn" title="在开发者工具中预览效果" target="_blank" rel="noopener noreferrer"> 在开发者工具中预览效果 </a>
<blockquote style="background-color: #d9e1ff; font-size: 15px; line-height: 26px;margin: 16px 0 0;padding: 16px; border-radius: 6px; color: #0052d9" >
<p>Tips: 请确保开发者工具为打开状态。导入开发者工具后依次执行npm i > 构建npm包 > 勾选 "将JS编译成ES5"</p>
</blockquote>
### 组件类型
列表型动作面板
{{ list }}
宫格型动作面板
{{ grid }}
### 组件状态
宫格型动作面板
{{ status }}
### 组件样式
列表型对齐方式
{{ align }}
### 支持指令调用
```javascript
import ActionSheet, { ActionSheetTheme } from 'tdesign-miniprogram/action-sheet/index';
// 指令调用不同于组件引用不需要传入visible
const basicListOption: ActionSheetShowOption = {
theme: ActionSheetTheme.List,
selector: '#t-action-sheet',
items: [
{
label: '默认选项',
},
{
label: '失效选项',
disabled: true,
},
{
label: '警告选项',
color: '#e34d59',
},
],
};
const handler = ActionSheet.show(basicListOption);
```
指令调用的关闭如下
```javascript
handler.close();
```
## API
### ActionSheet Props
名称 | 类型 | 默认值 | 描述 | 必传
-- | -- | -- | -- | --
style | Object | - | 样式 | N
custom-style | Object | - | 样式,一般用于开启虚拟化组件节点场景 | N
align | String | center | `0.29.0`。水平对齐方式。可选项center/left | N
cancel-text | String | - | 设置取消按钮的文本 | N
count | Number | 8 | 设置每页展示菜单的数量,仅当 type=grid 时有效 | N
description | String | - | `0.29.0`。动作面板描述文字 | N
items | Array | - | 必需。菜单项。TS 类型:`Array<string \| ActionSheetItem>` `interface ActionSheetItem {label: string; color?: string; disabled?: boolean;icon?: string;suffixIcon?: string; }`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/action-sheet/type.ts) | Y
popup-props | Object | {} | popupProps透传。TS 类型:`PopupProps`[Popup API Documents](./popup?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/action-sheet/type.ts) | N
show-cancel | Boolean | true | 是否显示取消按钮 | N
show-overlay | Boolean | true | 是否显示遮罩层 | N
theme | String | list | 展示类型列表和表格形式展示。可选项list/grid | N
using-custom-navbar | Boolean | false | 是否使用了自定义导航栏 | N
visible | Boolean | false | 必需。显示与隐藏 | Y
default-visible | Boolean | undefined | 必需。显示与隐藏。非受控属性 | Y
### ActionSheet Events
名称 | 参数 | 描述
-- | -- | --
cancel | \- | 点击取消按钮时触发
close | `(trigger: TriggerSource)` | 关闭时触发。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/action-sheet/type.ts)。<br/>`type TriggerSource = 'overlay' \| 'command' \| 'select' `<br/>
selected | `(selected: ActionSheetItem \| string, index: number)` | 选择菜单项时触发
### ActionSheet External Classes
类名 | 描述
-- | --
t-class | 根节点样式类
t-class-cancel | 取消样式类
t-class-content | 内容样式类
### CSS Variables
组件提供了下列 CSS 变量,可用于自定义样式。
名称 | 默认值 | 描述
-- | -- | --
--td-action-sheet-border-color | @gray-color-1 | -
--td-action-sheet-border-radius | @radius-extra-large | -
--td-action-sheet-cancel-color | @font-gray-1 | -
--td-action-sheet-cancel-height | 96rpx | -
--td-action-sheet-color | @font-gray-1 | -
--td-action-sheet-description-color | @font-gray-3 | -
--td-action-sheet-list-item-disabled-color | @font-gray-4 | -
--td-action-sheet-list-item-height | 112rpx | -
--td-action-sheet-text-align | center | -

View File

@ -0,0 +1,87 @@
import { SuperComponent } from '../common/src/index';
export default class ActionSheet extends SuperComponent {
static show: (options: import("./show").ActionSheetShowOption) => WechatMiniprogram.Component.TrivialInstance;
behaviors: string[];
externalClasses: string[];
properties: {
align?: {
type: StringConstructor;
value?: "center" | "left";
};
cancelText?: {
type: StringConstructor;
value?: string;
};
count?: {
type: NumberConstructor;
value?: number;
};
description?: {
type: StringConstructor;
value?: string;
};
items: {
type: ArrayConstructor;
value?: (string | import("./type").ActionSheetItem)[];
required?: boolean;
};
popupProps?: {
type: ObjectConstructor;
value?: import("../popup").TdPopupProps;
};
showCancel?: {
type: BooleanConstructor;
value?: boolean;
};
showOverlay?: {
type: BooleanConstructor;
value?: boolean;
};
theme?: {
type: StringConstructor;
value?: "list" | "grid";
};
usingCustomNavbar?: {
type: BooleanConstructor;
value?: boolean;
};
visible: {
type: BooleanConstructor;
value?: boolean;
required?: boolean;
};
defaultVisible: {
type: BooleanConstructor;
value?: boolean;
required?: boolean;
};
};
data: {
prefix: string;
classPrefix: string;
gridThemeItems: any[];
currentSwiperIndex: number;
defaultPopUpProps: {};
defaultPopUpzIndex: number;
};
controlledProps: {
key: string;
event: string;
}[];
observers: {
'visible, items'(visible: boolean): void;
};
methods: {
init(): void;
memoInitialData(): void;
splitGridThemeActions(): void;
show(options: any): void;
close(): void;
onPopupVisibleChange({ detail }: {
detail: any;
}): void;
onSwiperChange(e: WechatMiniprogram.TouchEvent): void;
onSelect(event: WechatMiniprogram.TouchEvent): void;
onCancel(): void;
};
}

View File

@ -0,0 +1,111 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { chunk } from '../common/utils';
import { SuperComponent, wxComponent } from '../common/src/index';
import config from '../common/config';
import { ActionSheetTheme, show } from './show';
import props from './props';
import useCustomNavbar from '../mixins/using-custom-navbar';
const { prefix } = config;
const name = `${prefix}-action-sheet`;
let ActionSheet = class ActionSheet extends SuperComponent {
constructor() {
super(...arguments);
this.behaviors = [useCustomNavbar];
this.externalClasses = [`${prefix}-class`, `${prefix}-class-content`, `${prefix}-class-cancel`];
this.properties = Object.assign({}, props);
this.data = {
prefix,
classPrefix: name,
gridThemeItems: [],
currentSwiperIndex: 0,
defaultPopUpProps: {},
defaultPopUpzIndex: 11500,
};
this.controlledProps = [
{
key: 'visible',
event: 'visible-change',
},
];
this.observers = {
'visible, items'(visible) {
if (!visible)
return;
this.init();
},
};
this.methods = {
init() {
this.memoInitialData();
this.splitGridThemeActions();
},
memoInitialData() {
this.initialData = Object.assign(Object.assign({}, this.properties), this.data);
},
splitGridThemeActions() {
if (this.data.theme !== ActionSheetTheme.Grid)
return;
this.setData({
gridThemeItems: chunk(this.data.items, this.data.count),
});
},
show(options) {
this.setData(Object.assign(Object.assign(Object.assign({}, this.initialData), options), { visible: true }));
this.splitGridThemeActions();
this.autoClose = true;
this._trigger('visible-change', { visible: true });
},
close() {
this.triggerEvent('close', { trigger: 'command' });
this._trigger('visible-change', { visible: false });
},
onPopupVisibleChange({ detail }) {
if (!detail.visible) {
this.triggerEvent('close', { trigger: 'overlay' });
this._trigger('visible-change', { visible: false });
}
if (this.autoClose) {
this.setData({ visible: false });
this.autoClose = false;
}
},
onSwiperChange(e) {
const { current } = e.detail;
this.setData({
currentSwiperIndex: current,
});
},
onSelect(event) {
const { currentSwiperIndex, items, gridThemeItems, count, theme } = this.data;
const { index } = event.currentTarget.dataset;
const isSwiperMode = theme === ActionSheetTheme.Grid;
const item = isSwiperMode ? gridThemeItems[currentSwiperIndex][index] : items[index];
const realIndex = isSwiperMode ? index + currentSwiperIndex * count : index;
if (item) {
this.triggerEvent('selected', { selected: item, index: realIndex });
if (!item.disabled) {
this.triggerEvent('close', { trigger: 'select' });
this._trigger('visible-change', { visible: false });
}
}
},
onCancel() {
this.triggerEvent('cancel');
if (this.autoClose) {
this.setData({ visible: false });
this.autoClose = false;
}
},
};
}
};
ActionSheet.show = show;
ActionSheet = __decorate([
wxComponent()
], ActionSheet);
export default ActionSheet;

View File

@ -0,0 +1,10 @@
{
"component": true,
"styleIsolation": "apply-shared",
"usingComponents": {
"t-icon": "../icon/icon",
"t-popup": "../popup/popup",
"t-grid": "../grid/grid",
"t-grid-item": "../grid-item/grid-item"
}
}

View File

@ -0,0 +1,49 @@
<wxs src="./action-sheet.wxs" module="_this" />
<wxs src="../common/utils.wxs" module="_" />
<import src="./template/list.wxml" />
<import src="./template/grid.wxml" />
<view id="{{classPrefix}}" style="{{_._style([style, customStyle])}}" class="{{classPrefix}} class {{prefix}}-class">
<t-popup
visible="{{visible}}"
placement="bottom"
usingCustomNavbar="{{usingCustomNavbar}}"
bind:visible-change="onPopupVisibleChange"
show-overlay="{{showOverlay}}"
z-index="{{ popupProps.zIndex || defaultPopUpzIndex }}"
overlay-props="{{ popupProps.overlayProps || defaultPopUpProps }}"
>
<view
class="{{_.cls(classPrefix + '__content', [['grid', gridThemeItems.length]])}} {{prefix}}-class-content"
tabindex="0"
>
<view wx:if="{{description}}" tabindex="0" class="{{_.cls(classPrefix + '__description', [align])}}"
>{{description}}</view
>
<block wx:if="{{gridThemeItems.length}}">
<template is="grid" data="{{classPrefix, prefix, gridThemeItems, count, currentSwiperIndex}}" />
</block>
<view wx:elif="{{items && items.length}}" class="{{classPrefix}}__list">
<block wx:for="{{ items }}" wx:key="index">
<template
is="list"
data="{{index, classPrefix, listThemeItemClass: _.cls(classPrefix + '__list-item', [align, [disabled, item.disabled]]), item}}"
/>
</block>
</view>
</view>
<slot />
<view wx:if="{{showCancel}}" class="{{classPrefix}}__footer">
<view class="{{classPrefix}}__gap-{{theme}}" />
<view
class="{{classPrefix}}__cancel {{prefix}}-class-cancel"
hover-class="{{classPrefix}}__cancel--hover"
hover-stay-time="70"
bind:tap="onCancel"
aria-role="button"
>
{{ cancelText || '取消' }}
</view>
</view>
</t-popup>
</view>

View File

@ -0,0 +1,19 @@
var getListThemeItemClass = function (props) {
var classPrefix = props.classPrefix;
var item = props.item;
var prefix = props.prefix;
var classList = [classPrefix + '__list-item'];
if (item.disabled) {
classList.push(prefix + '-is-disabled');
}
return classList.join(' ');
};
var isImage = function (name) {
return name.indexOf('/') !== -1;
};
module.exports = {
getListThemeItemClass: getListThemeItemClass,
isImage: isImage,
};

View File

@ -0,0 +1,169 @@
.t-float-left {
float: left;
}
.t-float-right {
float: right;
}
@keyframes tdesign-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.hotspot-expanded.relative {
position: relative;
}
.hotspot-expanded::after {
content: '';
display: block;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
transform: scale(1.5);
}
.t-action-sheet__content {
color: var(--td-action-sheet-color, var(--td-text-color-primary, var(--td-font-gray-1, rgba(0, 0, 0, 0.9))));
border-top-left-radius: var(--td-action-sheet-border-radius, var(--td-radius-extra-large, 24rpx));
border-top-right-radius: var(--td-action-sheet-border-radius, var(--td-radius-extra-large, 24rpx));
background-color: var(--td-bg-color-container, var(--td-font-white-1, #ffffff));
overflow: hidden;
}
.t-action-sheet__content--grid {
padding-top: 16rpx;
}
.t-action-sheet__content:focus {
outline: 0;
}
.t-action-sheet__grid {
padding-bottom: 16rpx;
}
.t-action-sheet__grid--swiper {
padding-bottom: 48rpx;
}
.t-action-sheet__description {
color: var(--td-action-sheet-description-color, var(--td-text-color-placeholder, var(--td-font-gray-3, rgba(0, 0, 0, 0.4))));
line-height: 44rpx;
font-size: 28rpx;
text-align: var(--td-action-sheet-text-align, center);
padding: 24rpx 32rpx;
position: relative;
}
.t-action-sheet__description:focus {
outline: 0;
}
.t-action-sheet__description::after {
content: '';
display: block;
position: absolute;
top: unset;
bottom: 0;
left: unset;
right: unset;
background-color: var(--td-action-sheet-border-color, var(--td-border-level-1-color, var(--td-gray-color-3, #e7e7e7)));
}
.t-action-sheet__description::after {
height: 1px;
left: 0;
right: 0;
transform: scaleY(0.5);
}
.t-action-sheet__description--left {
text-align: left;
}
.t-action-sheet__description--left::after {
left: 32rpx;
}
.t-action-sheet__list-item {
display: flex;
align-items: center;
justify-content: center;
position: relative;
height: var(--td-action-sheet-list-item-height, 112rpx);
padding: 0 32rpx;
}
.t-action-sheet__list-item::after {
content: '';
display: block;
position: absolute;
top: unset;
bottom: 0;
left: unset;
right: unset;
background-color: var(--td-action-sheet-border-color, var(--td-border-level-1-color, var(--td-gray-color-3, #e7e7e7)));
}
.t-action-sheet__list-item::after {
height: 1px;
left: 0;
right: 0;
transform: scaleY(0.5);
}
.t-action-sheet__list-item:focus {
outline: 0;
}
.t-action-sheet__list-item--left {
justify-content: start;
}
.t-action-sheet__list-item--left::after {
left: 32rpx;
}
.t-action-sheet__list-item--disabled {
color: var(--td-action-sheet-list-item-disabled-color, var(--td-text-color-disabled, var(--td-font-gray-4, rgba(0, 0, 0, 0.26))));
}
.t-action-sheet__list-item-text {
font-size: var(--td-font-size-m, 32rpx);
word-wrap: normal;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.t-action-sheet__list-item-icon {
margin-right: 16rpx;
}
.t-action-sheet__list-item-icon--suffix {
margin-left: auto;
}
.t-action-sheet__swiper-wrap {
margin-top: 8rpx;
position: relative;
}
.t-action-sheet__footer {
background-color: var(--td-bg-color-container, var(--td-font-white-1, #ffffff));
}
.t-action-sheet__gap-list {
height: 16rpx;
background-color: var(--td-action-sheet-gap-color, var(--td-bg-color-page, var(--td-gray-color-1, #f3f3f3)));
}
.t-action-sheet__gap-grid {
height: 1rpx;
background-color: var(--td-action-sheet-border-color, var(--td-border-level-1-color, var(--td-gray-color-3, #e7e7e7)));
}
.t-action-sheet__cancel {
display: flex;
align-items: center;
justify-content: center;
color: var(--td-action-sheet-cancel-color, var(--td-text-color-primary, var(--td-font-gray-1, rgba(0, 0, 0, 0.9))));
height: var(--td-action-sheet-cancel-height, 96rpx);
}
.t-action-sheet__dots {
position: absolute;
left: 50%;
bottom: 32rpx;
transform: translateX(-50%);
display: flex;
flex-direction: row;
}
.t-action-sheet__dots-item {
width: 16rpx;
height: 16rpx;
background-color: #dcdcdc;
border-radius: 50%;
margin: 0 16rpx;
transition: all 0.4s ease-in;
}
.t-action-sheet__dots-item.t-is-active {
background-color: #0052d9;
}

View File

@ -0,0 +1,8 @@
/// <reference types="miniprogram-api-typings" />
import { ActionSheetItem, ActionSheetTheme, ActionSheetShowOption } from './show';
export { ActionSheetItem, ActionSheetTheme, ActionSheetShowOption };
declare const _default: {
show(options: ActionSheetShowOption): WechatMiniprogram.Component.TrivialInstance;
close(options: ActionSheetShowOption): void;
};
export default _default;

View File

@ -0,0 +1,10 @@
import { show, close, ActionSheetTheme } from './show';
export { ActionSheetTheme };
export default {
show(options) {
return show(options);
},
close(options) {
return close(options);
},
};

View File

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

View File

@ -0,0 +1,53 @@
const props = {
align: {
type: String,
value: 'center',
},
cancelText: {
type: String,
value: '',
},
count: {
type: Number,
value: 8,
},
description: {
type: String,
value: '',
},
items: {
type: Array,
required: true,
},
popupProps: {
type: Object,
value: {},
},
showCancel: {
type: Boolean,
value: true,
},
showOverlay: {
type: Boolean,
value: true,
},
theme: {
type: String,
value: 'list',
},
usingCustomNavbar: {
type: Boolean,
value: false,
},
visible: {
type: Boolean,
value: null,
required: true,
},
defaultVisible: {
type: Boolean,
value: false,
required: true,
},
};
export default props;

View File

@ -0,0 +1,31 @@
/// <reference types="miniprogram-api-typings" />
/// <reference types="miniprogram-api-typings" />
export interface ActionSheetItem {
label: string;
color?: string;
disabled?: boolean;
icon?: string;
}
declare type Context = WechatMiniprogram.Page.TrivialInstance | WechatMiniprogram.Component.TrivialInstance;
export declare enum ActionSheetTheme {
List = "list",
Grid = "grid"
}
interface ActionSheetProps {
align: 'center' | 'left';
cancelText?: string;
count?: number;
description: string;
items: Array<string | ActionSheetItem>;
showCancel?: boolean;
theme?: ActionSheetTheme;
visible: boolean;
defaultVisible?: boolean;
}
export interface ActionSheetShowOption extends Omit<ActionSheetProps, 'visible'> {
context?: Context;
selector?: string;
}
export declare const show: (options: ActionSheetShowOption) => WechatMiniprogram.Component.TrivialInstance;
export declare const close: (options: ActionSheetShowOption) => void;
export {};

View File

@ -0,0 +1,33 @@
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';
export var ActionSheetTheme;
(function (ActionSheetTheme) {
ActionSheetTheme["List"] = "list";
ActionSheetTheme["Grid"] = "grid";
})(ActionSheetTheme || (ActionSheetTheme = {}));
export const show = function (options) {
const _a = Object.assign({}, options), { context, selector = '#t-action-sheet' } = _a, otherOptions = __rest(_a, ["context", "selector"]);
const instance = getInstance(context, selector);
if (instance) {
instance.show(Object.assign({}, otherOptions));
return instance;
}
console.error('未找到组件,请确认 selector && context 是否正确');
};
export const close = function (options) {
const { context, selector = '#t-action-sheet' } = Object.assign({}, options);
const instance = getInstance(context, selector);
if (instance) {
instance.close();
}
};

View File

@ -0,0 +1,51 @@
<template name="grid">
<block wx:if="{{gridThemeItems.length === 1}}">
<t-grid align="center" t-class="{{classPrefix}}__grid" column="{{count / 2}}" class="{{classPrefix}}__single-wrap">
<t-grid-item
t-class="{{classPrefix}}__grid-item"
class="{{classPrefix}}__square"
wx:for="{{gridThemeItems[0]}}"
wx:key="index"
bind:tap="onSelect"
data-index="{{index}}"
icon="{{ { name: item.icon, color: item.color } }}"
text="{{item.label || ''}}"
image="{{item.image || ''}}"
style="--td-grid-item-text-color: {{item.color}}"
>
</t-grid-item>
</t-grid>
</block>
<block wx:elif="{{gridThemeItems.length > 1}}">
<view class="{{classPrefix}}__swiper-wrap">
<swiper style="height: 456rpx" autoplay="{{false}}" current="{{currentSwiperIndex}}" bindchange="onSwiperChange">
<swiper-item wx:for="{{gridThemeItems}}" wx:key="index">
<t-grid align="center" t-class="{{classPrefix}}__grid {{classPrefix}}__grid--swiper" column="{{count / 2}}">
<t-grid-item
t-class="{{classPrefix}}__grid-item"
class="{{classPrefix}}__square"
wx:for="{{item}}"
wx:key="index"
data-index="{{index}}"
bind:tap="onSelect"
icon="{{ { name: item.icon, color: item.color } }}"
text="{{item.label || ''}}"
image="{{item.image || ''}}"
style="--td-grid-item-text-color: {{item.color}}"
>
</t-grid-item>
</t-grid>
</swiper-item>
</swiper>
<view class="{{classPrefix}}__nav">
<view class="{{classPrefix}}__dots">
<view
wx:for="{{gridThemeItems.length}}"
wx:key="index"
class="{{classPrefix}}__dots-item {{index === currentSwiperIndex ? prefix + '-is-active' : ''}}"
/>
</view>
</view>
</view>
</block>
</template>

View File

@ -0,0 +1,20 @@
<template name="list">
<view
data-index="{{index}}"
style="{{ item.color ? 'color: ' + item.color : '' }}"
class="{{listThemeItemClass}}"
bind:tap="onSelect"
aria-role="{{ariaRole || 'button'}}"
aria-label="{{item.label || item}}"
tabindex="0"
>
<t-icon wx:if="{{item.icon}}" name="{{item.icon}}" class="{{classPrefix}}__list-item-icon" size="48rpx"></t-icon>
<view class="{{classPrefix}}__list-item-text">{{item.label || item}}</view>
<t-icon
wx:if="{{item.suffixIcon}}"
name="{{item.suffixIcon}}"
class="{{classPrefix}}__list-item-icon {{classPrefix}}__list-item-icon--suffix"
size="48rpx"
></t-icon>
</view>
</template>

View File

@ -0,0 +1,61 @@
import { PopupProps } from '../popup/index';
export interface TdActionSheetProps {
align?: {
type: StringConstructor;
value?: 'center' | 'left';
};
cancelText?: {
type: StringConstructor;
value?: string;
};
count?: {
type: NumberConstructor;
value?: number;
};
description?: {
type: StringConstructor;
value?: string;
};
items: {
type: ArrayConstructor;
value?: Array<string | ActionSheetItem>;
required?: boolean;
};
popupProps?: {
type: ObjectConstructor;
value?: PopupProps;
};
showCancel?: {
type: BooleanConstructor;
value?: boolean;
};
showOverlay?: {
type: BooleanConstructor;
value?: boolean;
};
theme?: {
type: StringConstructor;
value?: 'list' | 'grid';
};
usingCustomNavbar?: {
type: BooleanConstructor;
value?: boolean;
};
visible: {
type: BooleanConstructor;
value?: boolean;
required?: boolean;
};
defaultVisible: {
type: BooleanConstructor;
value?: boolean;
required?: boolean;
};
}
export interface ActionSheetItem {
label: string;
color?: string;
disabled?: boolean;
icon?: string;
suffixIcon?: string;
}

View File

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

View File

@ -0,0 +1,28 @@
import { SuperComponent, RelationsOptions } from '../common/src/index';
export default class AvatarGroup extends SuperComponent {
externalClasses: string[];
properties: import("./type").TdAvatarGroupProps;
data: {
prefix: string;
classPrefix: string;
hasChild: boolean;
length: number;
className: string;
};
options: {
multipleSlots: boolean;
};
relations: RelationsOptions;
lifetimes: {
attached(): void;
ready(): void;
};
observers: {
'cascading, size'(): void;
};
methods: {
setClass(): void;
handleMax(): void;
onCollapsedItemClick(e: WechatMiniprogram.CustomEvent): void;
};
}

View File

@ -0,0 +1,81 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { SuperComponent, wxComponent } from '../common/src/index';
import config from '../common/config';
import avatarGroupProps from './props';
const { prefix } = config;
const name = `${prefix}-avatar-group`;
let AvatarGroup = class AvatarGroup extends SuperComponent {
constructor() {
super(...arguments);
this.externalClasses = [`${prefix}-class`, `${prefix}-class-content`, `${prefix}-class-image`];
this.properties = avatarGroupProps;
this.data = {
prefix,
classPrefix: name,
hasChild: true,
length: 0,
className: '',
};
this.options = {
multipleSlots: true,
};
this.relations = {
'../avatar/avatar': {
type: 'descendant',
},
};
this.lifetimes = {
attached() {
this.setClass();
},
ready() {
this.setData({
length: this.$children.length,
});
this.handleMax();
},
};
this.observers = {
'cascading, size'() {
this.setClass();
},
};
this.methods = {
setClass() {
const { cascading, size } = this.properties;
const direction = cascading.split('-')[0];
const classList = [
name,
`${prefix}-class`,
`${name}-offset-${direction}`,
`${name}-offset-${direction}-${size.indexOf('px') > -1 ? 'medium' : size || 'medium'}`,
];
this.setData({
className: classList.join(' '),
});
},
handleMax() {
const { max } = this.data;
const len = this.$children.length;
if (!max || max > len)
return;
const restAvatars = this.$children.splice(max, len - max);
restAvatars.forEach((child) => {
child.hide();
});
},
onCollapsedItemClick(e) {
this.triggerEvent('collapsed-item-click', e.detail);
},
};
}
};
AvatarGroup = __decorate([
wxComponent()
], AvatarGroup);
export default AvatarGroup;

View File

@ -0,0 +1,7 @@
{
"component": true,
"styleIsolation": "shared",
"usingComponents": {
"t-avatar": "../avatar/avatar"
}
}

View File

@ -0,0 +1,21 @@
<wxs src="../common/utils.wxs" module="_" />
<view style="{{_._style([style, customStyle])}}" class="{{className}} class">
<slot />
<!-- 自定义折叠元素 -->
<view class="{{classPrefix}}__collapse--slot">
<slot name="collapse-avatar" />
</view>
<!-- 默认折叠元素 -->
<view class="{{classPrefix}}__collapse--default" wx:if="{{max && (max < length)}}" bindtap="onCollapsedItemClick">
<t-avatar
t-class-image="{{prefix}}-avatar--border {{prefix}}-avatar--border-{{size}} {{prefix}}-class-image"
t-class-content="{{prefix}}-class-content"
size="{{size}}"
shape="{{shape}}"
icon="{{ collapseAvatar ? '' : 'user-add'}}"
aria-role="none"
>{{collapseAvatar}}</t-avatar
>
</view>
</view>

View File

@ -0,0 +1,214 @@
.t-float-left {
float: left;
}
.t-float-right {
float: right;
}
@keyframes tdesign-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.hotspot-expanded.relative {
position: relative;
}
.hotspot-expanded::after {
content: '';
display: block;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
transform: scale(1.5);
}
.t-avatar-group {
display: inline-flex;
flex-wrap: wrap;
align-items: center;
}
.t-avatar-group-offset-left .t-avatar__wrapper,
.t-avatar-group-offset-right .t-avatar__wrapper {
padding: var(--td-avatar-group-line-spacing, 4rpx) 0;
}
.t-avatar-group-offset-left-small,
.t-avatar-group-offset-right-small {
--td-avatar-margin-left: var(--td-avatar-group-margin-left-small, -16rpx);
}
.t-avatar-group-offset-left-medium,
.t-avatar-group-offset-right-medium {
--td-avatar-margin-left: var(--td-avatar-group-margin-left-medium, -16rpx);
}
.t-avatar-group-offset-left-large,
.t-avatar-group-offset-right-large {
--td-avatar-margin-left: var(--td-avatar-group-margin-left-large, -16rpx);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(1) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 1);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(2) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 2);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(3) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 3);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(4) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 4);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(5) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 5);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(6) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 6);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(7) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 7);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(8) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 8);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(9) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 9);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(10) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 10);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(11) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 11);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(12) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 12);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(13) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 13);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(14) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 14);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(15) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 15);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(16) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 16);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(17) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 17);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(18) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 18);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(19) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 19);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(20) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 20);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(21) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 21);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(22) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 22);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(23) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 23);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(24) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 24);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(25) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 25);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(26) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 26);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(27) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 27);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(28) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 28);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(29) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 29);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(30) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 30);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(31) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 31);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(32) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 32);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(33) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 33);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(34) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 34);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(35) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 35);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(36) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 36);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(37) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 37);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(38) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 38);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(39) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 39);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(40) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 40);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(41) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 41);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(42) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 42);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(43) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 43);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(44) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 44);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(45) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 45);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(46) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 46);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(47) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 47);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(48) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 48);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(49) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 49);
}
.t-avatar-group-offset-left .t-avatar__wrapper:nth-child(50) {
z-index: calc(var(--td-avatar-group-init-z-index, 50) - 50);
}
.t-avatar-group__collapse--slot,
.t-avatar-group__collapse--default {
z-index: 0;
font-weight: 600;
}
.t-avatar-group__collapse--slot {
float: left;
}
.t-avatar-group__collapse--slot:not(:empty) + .t-avatar-group__collapse--default {
display: none;
float: left;
}
.t-avatar-group__collapse--slot:empty + .t-avatar-group__collapse--default {
display: block;
float: left;
}

View File

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

View File

@ -0,0 +1,20 @@
const props = {
cascading: {
type: String,
value: 'left-up',
},
collapseAvatar: {
type: String,
},
max: {
type: Number,
},
shape: {
type: String,
},
size: {
type: String,
value: '',
},
};
export default props;

View File

@ -0,0 +1,24 @@
import { ShapeEnum } from '../common/common';
export interface TdAvatarGroupProps {
cascading?: {
type: StringConstructor;
value?: CascadingValue;
};
collapseAvatar?: {
type: StringConstructor;
value?: string;
};
max?: {
type: NumberConstructor;
value?: number;
};
shape?: {
type: StringConstructor;
value?: ShapeEnum;
};
size?: {
type: StringConstructor;
value?: string;
};
}
export declare type CascadingValue = 'left-up' | 'right-up';

View File

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

View File

@ -0,0 +1,91 @@
:: BASE_DOC ::
## API
### Avatar Props
name | type | default | description | required
-- | -- | -- | -- | --
style | Object | - | CSS(Cascading Style Sheets) | N
custom-style | Object | - | CSS(Cascading Style Sheets)used to set style on virtual component | N
alt | String | - | show it when url is not valid | N
badge-props | Object | - | Typescript`BadgeProps`[Badge API Documents](./badge?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/avatar/type.ts) | N
bordered | Boolean | false | \- | N
hide-on-load-failed | Boolean | false | hide image when loading image failed | N
icon | String / Object | - | \- | N
image | String | - | images url | N
image-props | Object | - | Typescript`ImageProps`[Image API Documents](./image?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/avatar/type.ts) | N
shape | String | - | shape。options: circle/round。Typescript`ShapeEnum`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N
size | String | - | size | N
### Avatar Events
name | params | description
-- | -- | --
error | - | trigger on image load failed
### Avatar External Classes
className | Description
-- | --
t-class | \-
t-class-alt | \-
t-class-content | \-
t-class-icon | \-
t-class-image | \-
### AvatarGroup Props
name | type | default | description | required
-- | -- | -- | -- | --
style | Object | - | CSS(Cascading Style Sheets) | N
custom-style | Object | - | CSS(Cascading Style Sheets)used to set style on virtual component | N
cascading | String | 'left-up' | multiple images cascading。options: left-up/right-up。Typescript`CascadingValue` `type CascadingValue = 'left-up' \| 'right-up'`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/avatar-group/type.ts) | N
collapse-avatar | String / Slot | - | [see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N
max | Number | - | \- | N
shape | String | - | shape。options: circle/round。Typescript`ShapeEnum`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N
size | String | - | size | N
### AvatarGroup Events
name | params | description
-- | -- | --
collapsed-item-click | - | \-
### AvatarGroup External Classes
className | Description
-- | --
t-class | \-
t-class-content | \-
t-class-image | \-
### CSS Variables
The component provides the following CSS variables, which can be used to customize styles.
Name | Default Value | Description
-- | -- | --
--td-avatar-group-init-z-index | @avatar-group-init-zIndex) - @i | -
--td-avatar-group-line-spacing | 4rpx | -
--td-avatar-group-margin-left-large | -16rpx | -
--td-avatar-group-margin-left-medium | -16rpx | -
--td-avatar-group-margin-left-small | -16rpx | -
--td-avatar-bg-color | @brand-color-light-active | -
--td-avatar-border-color | #fff | -
--td-avatar-border-width-large | 6rpx | -
--td-avatar-border-width-medium | 4rpx | -
--td-avatar-border-width-small | 2rpx | -
--td-avatar-circle-border-radius | @radius-circle | -
--td-avatar-content-color | @brand-color | -
--td-avatar-icon-large-font-size | 64rpx | -
--td-avatar-icon-medium-font-size | 48rpx | -
--td-avatar-icon-small-font-size | 40rpx | -
--td-avatar-large-width | 128rpx | -
--td-avatar-margin-left | 0 | -
--td-avatar-medium-width | 96rpx | -
--td-avatar-round-border-radius | @radius-default | -
--td-avatar-small-width | 80rpx | -
--td-avatar-text-large-font-size | @font-size-xl | -
--td-avatar-text-medium-font-size | @font-size-m | -
--td-avatar-text-small-font-size | @font-size-base | -

View File

@ -0,0 +1,151 @@
---
title: Avatar 头像
description: 用于展示用户头像信息,除了纯展示也可点击进入个人详情等操作。
spline: data
isComponent: true
---
<span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20lines-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20functions-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20statements-99%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20branches-85%25-blue" /></span>
## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
```json
"usingComponents": {
"t-avatar": "tdesign-miniprogram/avatar/avatar",
"t-avatar-group": "tdesign-miniprogram/avatar-group/avatar-group"
}
```
## 代码演示
<a href="https://developers.weixin.qq.com/s/a86Sfimw7VSO" title="在开发者工具中预览效果" target="_blank" rel="noopener noreferrer"> 在开发者工具中预览效果 </a>
<blockquote style="background-color: #d9e1ff; font-size: 15px; line-height: 26px;margin: 16px 0 0;padding: 16px; border-radius: 6px; color: #0052d9" >
<p>Tips: 请确保开发者工具为打开状态。导入开发者工具后依次执行npm i > 构建npm包 > 勾选 "将JS编译成ES5"</p>
</blockquote>
### 头像类型
图片头像
{{ image-avatar }}
字符头像
{{ character-avatar }}
图标头像
{{ icon-avatar }}
徽标头像
{{ badge-avatar }}
### 组合头像
纯展示
{{ exhibition }}
带操作
{{ action }}
### 头像尺寸
头像 large/medium/small 尺寸
{{ size }}
## API
### Avatar Props
名称 | 类型 | 默认值 | 描述 | 必传
-- | -- | -- | -- | --
style | Object | - | 样式 | N
custom-style | Object | - | 样式,一般用于开启虚拟化组件节点场景 | N
alt | String | - | 头像替换文本,仅当图片加载失败时有效 | N
badge-props | Object | - | 头像右上角提示信息,继承 Badge 组件的全部特性。如小红点或者数字。TS 类型:`BadgeProps`[Badge API Documents](./badge?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/avatar/type.ts) | N
bordered | Boolean | false | 已废弃。是否显示外边框 | N
hide-on-load-failed | Boolean | false | 加载失败时隐藏图片 | N
icon | String / Object | - | 图标。值为字符串表示图标名称,值为 `Object` 类型,表示透传至 `icon`。 | N
image | String | - | 图片地址 | N
image-props | Object | - | 透传至 Image 组件。TS 类型:`ImageProps`[Image API Documents](./image?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/avatar/type.ts) | N
shape | String | - | 形状。优先级高于 AvatarGroup.shape 。Avatar 单独存在时,默认值为 circle。如果父组件 AvatarGroup 存在,默认值便由 AvatarGroup.shape 决定。可选项circle/round。TS 类型:`ShapeEnum`。[通用类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N
size | String | - | 尺寸示例值small/medium/large/24px/38px 等。优先级高于 AvatarGroup.size 。Avatar 单独存在时,默认值为 medium。如果父组件 AvatarGroup 存在,默认值便由 AvatarGroup.size 决定 | N
### Avatar Events
名称 | 参数 | 描述
-- | -- | --
error | - | 图片加载失败时触发
### Avatar External Classes
类名 | 描述
-- | --
t-class | 根节点样式类
t-class-alt | 替代文本样式类
t-class-content | 内容样式类
t-class-icon | 图标样式类
t-class-image | 图片样式类
### AvatarGroup Props
名称 | 类型 | 默认值 | 描述 | 必传
-- | -- | -- | -- | --
style | Object | - | 样式 | N
custom-style | Object | - | 样式,一般用于开启虚拟化组件节点场景 | N
cascading | String | 'left-up' | 图片之间的层叠关系可选值左侧图片在上和右侧图片在上。可选项left-up/right-up。TS 类型:`CascadingValue` `type CascadingValue = 'left-up' \| 'right-up'`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/tree/develop/src/avatar-group/type.ts) | N
collapse-avatar | String / Slot | - | 头像数量超出时,会出现一个头像折叠元素。该元素内容可自定义。默认为 `+N`。示例:`+5``...`, `更多`。[通用类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N
max | Number | - | 能够同时显示的最多头像数量 | N
shape | String | - | 形状。优先级低于 Avatar.shape。可选项circle/round。TS 类型:`ShapeEnum`。[通用类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N
size | String | - | 尺寸示例值small/medium/large/24px/38px 等。优先级低于 Avatar.size | N
### AvatarGroup Events
名称 | 参数 | 描述
-- | -- | --
collapsed-item-click | - | 点击头像折叠元素触发
### AvatarGroup External Classes
类名 | 描述
-- | --
t-class | 根节点样式类
t-class-content | 内容样式类
t-class-image | 图片样式类
### CSS Variables
组件提供了下列 CSS 变量,可用于自定义样式。
名称 | 默认值 | 描述
-- | -- | --
--td-avatar-group-init-z-index | @avatar-group-init-zIndex) - @i | -
--td-avatar-group-line-spacing | 4rpx | -
--td-avatar-group-margin-left-large | -16rpx | -
--td-avatar-group-margin-left-medium | -16rpx | -
--td-avatar-group-margin-left-small | -16rpx | -
--td-avatar-bg-color | @brand-color-light-active | -
--td-avatar-border-color | #fff | -
--td-avatar-border-width-large | 6rpx | -
--td-avatar-border-width-medium | 4rpx | -
--td-avatar-border-width-small | 2rpx | -
--td-avatar-circle-border-radius | @radius-circle | -
--td-avatar-content-color | @brand-color | -
--td-avatar-icon-large-font-size | 64rpx | -
--td-avatar-icon-medium-font-size | 48rpx | -
--td-avatar-icon-small-font-size | 40rpx | -
--td-avatar-large-width | 128rpx | -
--td-avatar-margin-left | 0 | -
--td-avatar-medium-width | 96rpx | -
--td-avatar-round-border-radius | @radius-default | -
--td-avatar-small-width | 80rpx | -
--td-avatar-text-large-font-size | @font-size-xl | -
--td-avatar-text-medium-font-size | @font-size-m | -
--td-avatar-text-small-font-size | @font-size-base | -

View File

@ -0,0 +1,22 @@
/// <reference types="miniprogram-api-typings" />
import { SuperComponent, RelationsOptions } from '../common/src/index';
export default class Avatar extends SuperComponent {
options: WechatMiniprogram.Component.ComponentOptions;
externalClasses: string[];
properties: import("./type").TdAvatarProps;
data: {
prefix: string;
classPrefix: string;
isShow: boolean;
zIndex: number;
systemInfo: WechatMiniprogram.WindowInfo | WechatMiniprogram.SystemInfo;
};
relations: RelationsOptions;
observers: {
icon(icon: any): void;
};
methods: {
hide(): void;
onLoadError(e: WechatMiniprogram.CustomEvent): void;
};
}

View File

@ -0,0 +1,73 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { SuperComponent, wxComponent } from '../common/src/index';
import config from '../common/config';
import avatarProps from './props';
import { setIcon, systemInfo } from '../common/utils';
const { prefix } = config;
const name = `${prefix}-avatar`;
let Avatar = class Avatar extends SuperComponent {
constructor() {
super(...arguments);
this.options = {
multipleSlots: true,
};
this.externalClasses = [
`${prefix}-class`,
`${prefix}-class-image`,
`${prefix}-class-icon`,
`${prefix}-class-alt`,
`${prefix}-class-content`,
];
this.properties = avatarProps;
this.data = {
prefix,
classPrefix: name,
isShow: true,
zIndex: 0,
systemInfo,
};
this.relations = {
'../avatar-group/avatar-group': {
type: 'ancestor',
linked(parent) {
this.parent = parent;
this.setData({
shape: this.data.shape || parent.data.shape || 'circle',
size: this.data.size || parent.data.size,
bordered: true,
});
},
},
};
this.observers = {
icon(icon) {
const obj = setIcon('icon', icon, '');
this.setData(Object.assign({}, obj));
},
};
this.methods = {
hide() {
this.setData({
isShow: false,
});
},
onLoadError(e) {
if (this.properties.hideOnLoadFailed) {
this.setData({
isShow: false,
});
}
this.triggerEvent('error', e.detail);
},
};
}
};
Avatar = __decorate([
wxComponent()
], Avatar);
export default Avatar;

View File

@ -0,0 +1,9 @@
{
"component": true,
"styleIsolation": "shared",
"usingComponents": {
"t-icon": "../icon/icon",
"t-badge": "../badge/badge",
"t-image": "../image/image"
}
}

View File

@ -0,0 +1,54 @@
<import src="../common/template/icon.wxml" />
<wxs src="../common/utils.wxs" module="_" />
<wxs src="./avatar.wxs" module="_this" />
<view
class="{{classPrefix}}__wrapper class {{prefix}}-class"
style="{{_._style([_this.getStyles(isShow), style, customStyle])}}"
>
<t-badge
color="{{badgeProps.color || ''}}"
content="{{badgeProps.content || ''}}"
count="{{badgeProps.count || 0}}"
dot="{{badgeProps.dot || false}}"
max-count="{{badgeProps.maxCount || 99}}"
offset="{{badgeProps.offset || []}}"
shape="{{badgeProps.shape || 'circle'}}"
show-zero="{{badgeProps.showZero || false}}"
size="{{badgeProps.size || 'medium'}}"
t-class="{{badgeProps.tClass}}"
t-class-content="{{badgeProps.tClassContent}}"
t-class-count="{{badgeProps.tClassCount}}"
>
<view
class="{{_this.getClass(classPrefix, size || 'medium', shape, bordered)}} {{prefix}}-class-image"
style="{{_this.getSize(size, systemInfo)}}"
aria-label="{{ ariaLabel || alt ||'头像'}}"
aria-role="{{ ariaRole || 'img'}}"
aria-hidden="{{ ariaHidden }}"
>
<t-image
wx:if="{{image}}"
t-class="{{prefix}}-image {{classPrefix}}__image"
t-class-load="{{prefix}}-class-alt"
style="{{imageProps && imageProps.style || ''}}"
src="{{image}}"
mode="{{imageProps && imageProps.mode || 'aspectFill'}}"
lazy="{{imageProps && imageProps.lazy || false}}"
loading="{{imageProps && imageProps.loading || 'default'}}"
shape="{{imageProps && imageProps.shape || 'round'}}"
webp="{{imageProps && imageProps.webp || false}}"
error="{{alt || 'default'}}"
bind:error="onLoadError"
/>
<template
wx:elif="{{iconName || _.isNoEmptyObj(iconData)}}"
is="icon"
data="{{tClass: classPrefix + '__icon ' + prefix + '-class-icon', name: iconName, ...iconData}}"
/>
<view wx:else class="{{classPrefix}}__text {{prefix}}-class-content">
<slot />
</view>
</view>
</t-badge>
</view>

View File

@ -0,0 +1,30 @@
module.exports = {
getClass: function (classPrefix, size, shape, bordered) {
var hasPx = (size || '').indexOf('px') > -1;
var borderSize = hasPx ? 'medium' : size;
var classNames = [
classPrefix,
classPrefix + (shape === 'round' ? '--round' : '--circle'),
bordered ? classPrefix + '--border' + ' ' + classPrefix + '--border-' + borderSize : '',
hasPx ? '' : classPrefix + '--' + size,
];
return classNames.join(' ');
},
getSize: function (size = 'medium', systemInfo) {
var res = getRegExp('^([0-9]+)(px|rpx)$').exec(size);
if (res && res.length >= 3) {
var px = res[1];
if (res[2] === 'rpx') {
px = Math.floor((systemInfo.windowWidth * res[1]) / 750);
}
return 'width:' + size + ';height:' + size + ';font-size:' + ((px / 8) * 3 + 2) + 'px';
}
},
getStyles: function (isShow) {
return isShow ? '' : 'display: none;';
},
};

View File

@ -0,0 +1,104 @@
.t-float-left {
float: left;
}
.t-float-right {
float: right;
}
@keyframes tdesign-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.hotspot-expanded.relative {
position: relative;
}
.hotspot-expanded::after {
content: '';
display: block;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
transform: scale(1.5);
}
.t-avatar {
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
background-color: var(--td-avatar-bg-color, var(--td-brand-color-light-active, var(--td-primary-color-2, #d9e1ff)));
color: var(--td-avatar-content-color, var(--td-brand-color, var(--td-primary-color-7, #0052d9)));
}
.t-avatar__wrapper {
display: inline-flex;
position: relative;
vertical-align: top;
margin-left: var(--td-avatar-margin-left, 0);
}
.t-avatar--large {
width: var(--td-avatar-large-width, 128rpx);
height: var(--td-avatar-large-width, 128rpx);
font-size: var(--td-avatar-text-large-font-size, var(--td-font-size-xl, 40rpx));
}
.t-avatar--large .t-avatar__icon {
font-size: var(--td-avatar-icon-large-font-size, 64rpx);
}
.t-avatar--medium {
width: var(--td-avatar-medium-width, 96rpx);
height: var(--td-avatar-medium-width, 96rpx);
font-size: var(--td-avatar-text-medium-font-size, var(--td-font-size-m, 32rpx));
}
.t-avatar--medium .t-avatar__icon {
font-size: var(--td-avatar-icon-medium-font-size, 48rpx);
}
.t-avatar--small {
width: var(--td-avatar-small-width, 80rpx);
height: var(--td-avatar-small-width, 80rpx);
font-size: var(--td-avatar-text-small-font-size, var(--td-font-size-base, 28rpx));
}
.t-avatar--small .t-avatar__icon {
font-size: var(--td-avatar-icon-small-font-size, 40rpx);
}
.t-avatar .t-image,
.t-avatar__image {
width: 100%;
height: 100%;
}
.t-avatar--circle {
border-radius: var(--td-avatar-circle-border-radius, var(--td-radius-circle, 50%));
overflow: hidden;
}
.t-avatar--round {
border-radius: var(--td-avatar-round-border-radius, var(--td-radius-default, 12rpx));
overflow: hidden;
}
.t-avatar__text,
.t-avatar__icon {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.t-avatar__text:empty,
.t-avatar__icon:empty {
width: 0;
height: 0;
}
.t-avatar--border {
border-color: var(--td-avatar-border-color, #fff);
border-style: solid;
}
.t-avatar--border-small {
border-width: var(--td-avatar-border-width-small, 2rpx);
}
.t-avatar--border-medium {
border-width: var(--td-avatar-border-width-medium, 4rpx);
}
.t-avatar--border-large {
border-width: var(--td-avatar-border-width-large, 6rpx);
}

View File

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

View File

@ -0,0 +1,35 @@
const props = {
alt: {
type: String,
value: '',
},
badgeProps: {
type: Object,
},
bordered: {
type: Boolean,
value: false,
},
hideOnLoadFailed: {
type: Boolean,
value: false,
},
icon: {
type: null,
},
image: {
type: String,
value: '',
},
imageProps: {
type: Object,
},
shape: {
type: String,
},
size: {
type: String,
value: '',
},
};
export default props;

View File

@ -0,0 +1,41 @@
import { BadgeProps } from '../badge/index';
import { ImageProps } from '../image/index';
import { ShapeEnum } from '../common/common';
export interface TdAvatarProps {
alt?: {
type: StringConstructor;
value?: string;
};
badgeProps?: {
type: ObjectConstructor;
value?: BadgeProps;
};
bordered?: {
type: BooleanConstructor;
value?: boolean;
};
hideOnLoadFailed?: {
type: BooleanConstructor;
value?: boolean;
};
icon?: {
type: null;
value?: string | object;
};
image?: {
type: StringConstructor;
value?: string;
};
imageProps?: {
type: ObjectConstructor;
value?: ImageProps;
};
shape?: {
type: StringConstructor;
value?: ShapeEnum;
};
size?: {
type: StringConstructor;
value?: string;
};
}

View File

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

View File

@ -0,0 +1,41 @@
:: BASE_DOC ::
## API
### BackTop Props
name | type | default | description | required
-- | -- | -- | -- | --
style | Object | - | CSS(Cascading Style Sheets) | N
custom-style | Object | - | CSS(Cascading Style Sheets)used to set style on virtual component | N
fixed | Boolean | true | \- | N
icon | String / Boolean / Object / Slot | true | [see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N
scroll-top | Number | 0 | \- | N
text | String | '' | \- | N
theme | String | round | options: round/half-round/round-dark/half-round-dark | N
visibility-height | Number | 200 | \- | N
### BackTop Events
name | params | description
-- | -- | --
to-top | \- | \-
### BackTop External Classes
className | Description
-- | --
t-class | \-
t-class-icon | \-
t-class-text | \-
### CSS Variables
The component provides the following CSS variables, which can be used to customize styles.
Name | Default Value | Description
-- | -- | --
--td-back-top-round-bg-color | @font-white-1 | -
--td-back-top-round-border-color | @component-border | -
--td-back-top-round-border-radius | @radius-circle | -
--td-back-top-round-color | @font-gray-1 | -
--td-back-top-round-dark-bg-color | @gray-color-14 | -
--td-back-top-round-dark-color | @font-white-1 | -

View File

@ -0,0 +1,72 @@
---
title: BackTop 返回顶部
description: 用于当页面过长往下滑动时,帮助用户快速回到页面顶部。
spline: navigation
isComponent: true
---
<span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20lines-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20functions-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20statements-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20branches-100%25-blue" /></span>
## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
```json
"usingComponents": {
"t-back-top": "tdesign-miniprogram/back-top/back-top",
}
```
## 代码演示
<a href="https://developers.weixin.qq.com/s/2aR1demj7aS2" title="在开发者工具中预览效果" target="_blank" rel="noopener noreferrer"> 在开发者工具中预览效果 </a>
<blockquote style="background-color: #d9e1ff; font-size: 15px; line-height: 26px;margin: 16px 0 0;padding: 16px; border-radius: 6px; color: #0052d9" >
<p>Tips: 请确保开发者工具为打开状态。导入开发者工具后依次执行npm i > 构建npm包 > 勾选 "将JS编译成ES5"</p>
</blockquote>
<img src="https://tdesign.gtimg.com/miniprogram/readme/backtop-1.png" width="375px" height="50%">
### 基础返回顶部
{{ base }}
## API
### BackTop Props
名称 | 类型 | 默认值 | 描述 | 必传
-- | -- | -- | -- | --
style | Object | - | 样式 | N
custom-style | Object | - | 样式,一般用于开启虚拟化组件节点场景 | N
fixed | Boolean | true | 是否绝对定位固定到屏幕右下方 | N
icon | String / Boolean / Object / Slot | true | 图标。值为 `false` 表示不显示图标。不传表示使用默认图标 `'backtop'`。[通用类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N
scroll-top | Number | 0 | 页面滚动距离 | N
text | String | '' | 文案 | N
theme | String | round | 预设的样式类型。可选项round/half-round/round-dark/half-round-dark | N
visibility-height | Number | 200 | 滚动高度达到此参数值才出现 | N
### BackTop Events
名称 | 参数 | 描述
-- | -- | --
to-top | \- | 点击触发
### BackTop External Classes
类名 | 描述
-- | --
t-class | 根节点样式类
t-class-icon | 图标样式类
t-class-text | 文本样式类
### CSS Variables
组件提供了下列 CSS 变量,可用于自定义样式。
名称 | 默认值 | 描述
-- | -- | --
--td-back-top-round-bg-color | @font-white-1 | -
--td-back-top-round-border-color | @component-border | -
--td-back-top-round-border-radius | @radius-circle | -
--td-back-top-round-color | @font-gray-1 | -
--td-back-top-round-dark-bg-color | @gray-color-14 | -
--td-back-top-round-dark-color | @font-white-1 | -

View File

@ -0,0 +1,26 @@
import { SuperComponent, RelationsOptions } from '../common/src/index';
export default class BackTop extends SuperComponent {
externalClasses: string[];
options: {
multipleSlots: boolean;
};
properties: import("./type").TdBackTopProps;
relations: RelationsOptions;
data: {
prefix: string;
classPrefix: string;
_icon: any;
hidden: boolean;
};
observers: {
icon(): void;
scrollTop(value: number): void;
};
lifetimes: {
ready(): void;
};
methods: {
setIcon(v: any): void;
toTop(): void;
};
}

View File

@ -0,0 +1,73 @@
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 { calcIcon } from '../common/utils';
const { prefix } = config;
const name = `${prefix}-back-top`;
let BackTop = class BackTop extends SuperComponent {
constructor() {
super(...arguments);
this.externalClasses = [`${prefix}-class`, `${prefix}-class-icon`, `${prefix}-class-text`];
this.options = {
multipleSlots: true,
};
this.properties = props;
this.relations = {
'../pull-down-refresh/pull-down-refresh': {
type: 'ancestor',
},
};
this.data = {
prefix,
classPrefix: name,
_icon: null,
hidden: true,
};
this.observers = {
icon() {
this.setIcon();
},
scrollTop(value) {
const { visibilityHeight } = this.properties;
this.setData({ hidden: value < visibilityHeight });
},
};
this.lifetimes = {
ready() {
const { icon } = this.properties;
this.setIcon(icon);
},
};
this.methods = {
setIcon(v) {
this.setData({
_icon: calcIcon(v, 'backtop'),
});
},
toTop() {
var _a;
this.triggerEvent('to-top');
if (this.$parent) {
(_a = this.$parent) === null || _a === void 0 ? void 0 : _a.setScrollTop(0);
this.setData({ hidden: true });
}
else {
wx.pageScrollTo({
scrollTop: 0,
duration: 300,
});
}
},
};
}
};
BackTop = __decorate([
wxComponent()
], BackTop);
export default BackTop;

View File

@ -0,0 +1,7 @@
{
"component": true,
"styleIsolation": "apply-shared",
"usingComponents": {
"t-icon": "../icon/icon"
}
}

View File

@ -0,0 +1,17 @@
<import src="../common/template/icon.wxml" />
<wxs src="../common/utils.wxs" module="_" />
<view
style="{{_._style([style, customStyle])}}"
class="class {{prefix}}-class {{_.cls(classPrefix, [['fixed', fixed], theme])}}"
bindtap="toTop"
aria-role="button"
hidden="{{hidden}}"
>
<view class="{{classPrefix}}__icon" aria-hidden>
<slot name="icon" />
<template wx:if="{{_icon}}" is="icon" data="{{tClass: prefix + '-class-icon', ..._icon }}" />
</view>
<view wx:if="{{!!text}}" class="{{classPrefix}}__text--{{theme}} {{prefix}}-class-text">{{text}}</view>
<slot />
</view>

View File

@ -0,0 +1,91 @@
.t-float-left {
float: left;
}
.t-float-right {
float: right;
}
@keyframes tdesign-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.hotspot-expanded.relative {
position: relative;
}
.hotspot-expanded::after {
content: '';
display: block;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
transform: scale(1.5);
}
.t-back-top {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: transparent;
overflow: hidden;
box-sizing: border-box;
transition: height 0.2s;
height: auto;
}
.t-back-top--fixed {
position: fixed;
right: var(--td-spacer, 16rpx);
bottom: calc(var(--td-spacer-2, 32rpx) + env(safe-area-inset-bottom));
}
.t-back-top--round,
.t-back-top--round-dark {
width: 96rpx;
height: 96rpx;
border-radius: var(--td-back-top-round-border-radius, var(--td-radius-circle, 50%));
}
.t-back-top--round,
.t-back-top--half-round {
color: var(--td-back-top-round-color, var(--td-text-color-primary, var(--td-font-gray-1, rgba(0, 0, 0, 0.9))));
border: 1rpx solid var(--td-back-top-round-border-color, var(--td-component-border, var(--td-gray-color-4, #dcdcdc)));
background-color: var(--td-back-top-round-bg-color, var(--td-bg-color-container, var(--td-font-white-1, #ffffff)));
}
.t-back-top--round-dark,
.t-back-top--half-round-dark {
color: var(--td-back-top-round-dark-color, var(--td-text-color-anti, var(--td-font-white-1, #ffffff)));
background-color: var(--td-back-top-round-dark-bg-color, var(--td-gray-color-13, #242424));
}
.t-back-top--half-round,
.t-back-top--half-round-dark {
width: 120rpx;
height: 80rpx;
border-radius: 0;
border-top-left-radius: var(--td-back-top-half-round-border-radius, var(--td-radius-round, 999px));
border-bottom-left-radius: var(--td-back-top-half-round-border-radius, var(--td-radius-round, 999px));
flex-direction: row;
right: 0;
}
.t-back-top__text--round,
.t-back-top__text--round-dark,
.t-back-top__text--half-round,
.t-back-top__text--half-round-dark {
font-size: var(--td-font-size, 20rpx);
line-height: 24rpx;
}
.t-back-top__text--half-round,
.t-back-top__text--half-round-dark {
width: 48rpx;
}
.t-back-top__icon:not(:empty) + .t-back-top__text--half-round,
.t-back-top__icon:not(:empty) + .t-back-top__text--half-round-dark {
margin-left: 8rpx;
}
.t-back-top__icon {
display: flex;
justify-content: center;
align-items: center;
font-size: 44rpx;
}

View File

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

View File

@ -0,0 +1,31 @@
const props = {
fixed: {
type: Boolean,
value: true,
},
icon: {
type: null,
value: true,
},
scrollTop: {
type: Number,
value: 0,
},
style: {
type: String,
value: '',
},
text: {
type: String,
value: '',
},
theme: {
type: String,
value: 'round',
},
visibilityHeight: {
type: Number,
value: 200,
},
};
export default props;

View File

@ -0,0 +1,30 @@
export interface TdBackTopProps {
fixed?: {
type: BooleanConstructor;
value?: boolean;
};
icon?: {
type: null;
value?: string | boolean | object;
};
scrollTop?: {
type: NumberConstructor;
value?: number;
};
style?: {
type: StringConstructor;
value?: string;
};
text?: {
type: StringConstructor;
value?: string;
};
theme?: {
type: StringConstructor;
value?: 'round' | 'half-round' | 'round-dark' | 'half-round-dark';
};
visibilityHeight?: {
type: NumberConstructor;
value?: number;
};
}

View File

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

View File

@ -0,0 +1,45 @@
:: BASE_DOC ::
## API
### Badge Props
name | type | default | description | required
-- | -- | -- | -- | --
style | Object | - | CSS(Cascading Style Sheets) | N
custom-style | Object | - | CSS(Cascading Style Sheets)used to set style on virtual component | N
color | String | - | \- | N
content | String | - | \- | N
count | String / Number / Slot | 0 | [see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N
dot | Boolean | false | \- | N
max-count | Number | 99 | \- | N
offset | Array | - | Typescript`Array<string \| number>` | N
shape | String | circle | options: circle/square/bubble/ribbon | N
show-zero | Boolean | false | \- | N
size | String | medium | options: medium/large | N
### Badge External Classes
className | Description
-- | --
t-class | \-
t-class-content | \-
t-class-count | \-
### CSS Variables
The component provides the following CSS variables, which can be used to customize styles.
Name | Default Value | Description
-- | -- | --
--td-badge-basic-height | 32rpx | -
--td-badge-basic-padding | 8rpx | -
--td-badge-basic-width | 32rpx | -
--td-badge-bg-color | @error-color | -
--td-badge-border-radius | 4rpx | -
--td-badge-bubble-border-radius | 20rpx 20rpx 20rpx 1px | -
--td-badge-dot-size | 16rpx | -
--td-badge-font-size | @font-size-xs | -
--td-badge-font-weight | 600 | -
--td-badge-large-font-size | @font-size-s | -
--td-badge-large-height | 40rpx | -
--td-badge-large-padding | 10rpx | -
--td-badge-text-color | @font-white-1 | -

View File

@ -0,0 +1,86 @@
---
title: Badge 徽标
description: 用于告知用户,该区域的状态变化或者待处理任务的数量。
spline: data
isComponent: true
---
<span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20lines-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20functions-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20statements-100%25-blue" /></span><span class="coverages-badge" style="margin-right: 10px"><img src="https://img.shields.io/badge/coverages%3A%20branches-100%25-blue" /></span>
## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
```json
"usingComponents": {
"t-badge": "tdesign-miniprogram/badge/badge"
}
```
## 代码演示
<a href="https://developers.weixin.qq.com/s/TgaeQimG73SD" title="在开发者工具中预览效果" target="_blank" rel="noopener noreferrer"> 在开发者工具中预览效果 </a>
<blockquote style="background-color: #d9e1ff; font-size: 15px; line-height: 26px;margin: 16px 0 0;padding: 16px; border-radius: 6px; color: #0052d9" >
<p>Tips: 请确保开发者工具为打开状态。导入开发者工具后依次执行npm i > 构建npm包 > 勾选 "将JS编译成ES5"</p>
</blockquote>
### 组件类型
{{ base }}
### 组件样式
{{ theme }}
### 组件尺寸
{{ size }}
## FAQ
### 如何处理由 ribbon 徽标溢出导致页面出现横向滚动?
角标溢出问题建议从父容器组件处理。如 <a href="https://github.com/Tencent/tdesign-miniprogram/issues/3063" title="如 #3063 " target="_blank" rel="noopener noreferrer"> #3063 </a>,可以给父容器 `cell` 组件添加 `overflow: hidden`,处理溢出造成页面出现横向滚动的问题。
## API
### Badge Props
名称 | 类型 | 默认值 | 描述 | 必传
-- | -- | -- | -- | --
style | Object | - | 样式 | N
custom-style | Object | - | 样式,一般用于开启虚拟化组件节点场景 | N
color | String | - | 颜色 | N
content | String | - | 徽标内容,示例:`content='自定义内容'`。也可以使用默认插槽定义 | N
count | String / Number / Slot | 0 | 徽标右上角内容。可以是数字,也可以是文字。如:'new'/3/99+。特殊:值为空表示使用插槽渲染。[通用类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/src/common/common.ts) | N
dot | Boolean | false | 是否为红点 | N
max-count | Number | 99 | 封顶的数字值 | N
offset | Array | - | 设置状态点的位置偏移,示例:[-10, 20] 或 ['10em', '8rem']。TS 类型:`Array<string \| number>` | N
shape | String | circle | 形状。可选项circle/square/bubble/ribbon | N
show-zero | Boolean | false | 当数值为 0 时,是否展示徽标 | N
size | String | medium | 尺寸。可选项medium/large | N
### Badge External Classes
类名 | 描述
-- | --
t-class | 根节点样式类
t-class-content | 内容样式类
t-class-count | 计数样式类
### CSS Variables
组件提供了下列 CSS 变量,可用于自定义样式。
名称 | 默认值 | 描述
-- | -- | --
--td-badge-basic-height | 32rpx | -
--td-badge-basic-padding | 8rpx | -
--td-badge-basic-width | 32rpx | -
--td-badge-bg-color | @error-color | -
--td-badge-border-radius | 4rpx | -
--td-badge-bubble-border-radius | 20rpx 20rpx 20rpx 1px | -
--td-badge-dot-size | 16rpx | -
--td-badge-font-size | @font-size-xs | -
--td-badge-font-weight | 600 | -
--td-badge-large-font-size | @font-size-s | -
--td-badge-large-height | 40rpx | -
--td-badge-large-padding | 10rpx | -
--td-badge-text-color | @font-white-1 | -

View File

@ -0,0 +1,21 @@
import { SuperComponent } from '../common/src/index';
import type { TdBadgeProps } from './type';
export interface BadgeProps extends TdBadgeProps {
}
export default class Badge extends SuperComponent {
options: {
multipleSlots: boolean;
};
externalClasses: string[];
properties: TdBadgeProps;
data: {
prefix: string;
classPrefix: string;
value: string;
labelID: string;
descriptionID: string;
};
lifetimes: {
ready(): void;
};
}

View File

@ -0,0 +1,43 @@
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 { uniqueFactory } from '../common/utils';
const { prefix } = config;
const name = `${prefix}-badge`;
const getUniqueID = uniqueFactory('badge');
let Badge = class Badge extends SuperComponent {
constructor() {
super(...arguments);
this.options = {
multipleSlots: true,
};
this.externalClasses = [`${prefix}-class`, `${prefix}-class-count`, `${prefix}-class-content`];
this.properties = props;
this.data = {
prefix,
classPrefix: name,
value: '',
labelID: '',
descriptionID: '',
};
this.lifetimes = {
ready() {
const uniqueID = getUniqueID();
this.setData({
labelID: `${uniqueID}_label`,
descriptionID: `${uniqueID}_description`,
});
},
};
}
};
Badge = __decorate([
wxComponent()
], Badge);
export default Badge;

View File

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

View File

@ -0,0 +1,34 @@
<wxs src="./badge.wxs" module="_this" />
<wxs src="../common/utils.wxs" module="_" />
<!--
1. labelID 用于描述当前元素的文本
2. descriptionID 用于描述badge消息的文本
3. role=option一般用于多个内容合并焦点连续朗读
-->
<view
style="{{_._style([style, customStyle])}}"
class="{{_this.getBadgeOuterClass({shape})}} class {{prefix}}-class"
aria-labelledby="{{labelID}}"
aria-describedby="{{descriptionID}}"
aria-role="{{ ariaRole || 'option'}}"
>
<view id="{{labelID}}" class="{{classPrefix}}__content {{prefix}}-class-content" aria-hidden="true">
<slot wx:if="{{!content}}" class="{{classPrefix}}__content-slot" />
<text wx:else class="{{classPrefix}}__content-text">{{content}}</text>
</view>
<view
aria-hidden="true"
aria-label="{{ ariaLabel || _.getBadgeAriaLabel({dot, count, maxCount}) }}"
wx:if="{{_this.isShowBadge({dot,count,showZero})}}"
id="{{descriptionID}}"
class="{{_this.getBadgeInnerClass({dot, size, shape, count})}} {{prefix}}-has-count {{prefix}}-class-count"
style="{{_._style([_this.getBadgeStyles({color, offset})])}}"
aria-hidden="true"
aria-label="{{ ariaLabel || _.getBadgeAriaLabel({dot, count, maxCount}) }}"
>
{{ _this.getBadgeValue({dot, count, maxCount}) }}
</view>
<slot name="count" />
</view>

View File

@ -0,0 +1,71 @@
var getBadgeValue = function (props) {
if (props.dot) {
return '';
}
if (isNaN(props.count) || isNaN(props.maxCount)) {
return props.count;
}
return parseInt(props.count) > props.maxCount ? props.maxCount + '+' : props.count;
};
var hasUnit = function (unit) {
return (
unit.indexOf('px') > 0 ||
unit.indexOf('rpx') > 0 ||
unit.indexOf('em') > 0 ||
unit.indexOf('rem') > 0 ||
unit.indexOf('%') > 0 ||
unit.indexOf('vh') > 0 ||
unit.indexOf('vm') > 0
);
};
var getBadgeStyles = function (props) {
var styleStr = '';
if (props.color) {
styleStr += 'background:' + props.color + ';';
}
if (props.offset[0]) {
styleStr +=
'left: calc(100% + ' + (hasUnit(props.offset[0].toString()) ? props.offset[0] : props.offset[0] + 'px') + ');';
}
if (props.offset[1]) {
styleStr += 'top:' + (hasUnit(props.offset[1].toString()) ? props.offset[1] : props.offset[1] + 'px') + ';';
}
return styleStr;
};
var getBadgeOuterClass = function (props) {
var baseClass = 't-badge';
var classNames = [baseClass, props.shape === 'ribbon' ? baseClass + '__ribbon-outer' : ''];
return classNames.join(' ');
};
var getBadgeInnerClass = function (props) {
var baseClass = 't-badge';
var classNames = [
baseClass + '--basic',
props.dot ? baseClass + '--dot' : '',
baseClass + '--' + props.size,
baseClass + '--' + props.shape,
!props.dot && props.count ? baseClass + '--count' : '',
];
return classNames.join(' ');
};
var isShowBadge = function (props) {
if (props.dot) {
return true;
}
if (!props.showZero && !isNaN(props.count) && parseInt(props.count) === 0) {
return false;
}
if (props.count == null) return false;
return true;
};
module.exports.getBadgeValue = getBadgeValue;
module.exports.getBadgeStyles = getBadgeStyles;
module.exports.getBadgeOuterClass = getBadgeOuterClass;
module.exports.getBadgeInnerClass = getBadgeInnerClass;
module.exports.isShowBadge = isShowBadge;

View File

@ -0,0 +1,113 @@
.t-float-left {
float: left;
}
.t-float-right {
float: right;
}
@keyframes tdesign-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.hotspot-expanded.relative {
position: relative;
}
.hotspot-expanded::after {
content: '';
display: block;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
transform: scale(1.5);
}
.t-badge {
position: relative;
display: inline-flex;
align-items: start;
}
.t-badge--basic {
z-index: 100;
padding: 0 var(--td-badge-basic-padding, 8rpx);
font-size: var(--td-badge-font-size, var(--td-font-size-xs, var(--td-font-size, 20rpx)));
color: var(--td-badge-text-color, var(--td-text-color-anti, var(--td-font-white-1, #ffffff)));
background-color: var(--td-badge-bg-color, var(--td-error-color, var(--td-error-color-6, #d54941)));
text-align: center;
height: var(--td-badge-basic-height, 32rpx);
line-height: var(--td-badge-basic-height, 32rpx);
font-weight: var(--td-badge-font-weight, 600);
border-radius: var(--td-badge-border-radius, 4rpx);
}
.t-badge--dot {
height: var(--td-badge-dot-size, 16rpx);
border-radius: 50%;
min-width: var(--td-badge-dot-size, 16rpx);
padding: 0;
}
.t-badge--count {
min-width: var(--td-badge-basic-width, 32rpx);
white-space: nowrap;
box-sizing: border-box;
}
.t-badge--circle {
border-radius: calc(var(--td-badge-basic-height, 32rpx) / 2);
}
.t-badge__ribbon-outer {
position: absolute;
top: 0;
right: 0;
}
.t-badge--ribbon {
position: relative;
display: inline-block;
transform-origin: center center;
transform: translate(calc(50% - var(--td-badge-basic-height, 32rpx) + 1rpx), calc(-50% + var(--td-badge-basic-height, 32rpx) - 1rpx)) rotate(45deg);
border-radius: 0;
}
.t-badge--ribbon::before,
.t-badge--ribbon::after {
content: '';
position: absolute;
width: 0;
height: 0;
bottom: 0;
border-bottom: var(--td-badge-basic-height, 32rpx) solid var(--td-badge-bg-color, var(--td-error-color, var(--td-error-color-6, #d54941)));
font-size: 0;
}
.t-badge--ribbon::before {
left: calc(-1 * var(--td-badge-basic-height, 32rpx) + 1rpx);
border-left: var(--td-badge-basic-height, 32rpx) solid transparent;
}
.t-badge--ribbon::after {
right: calc(-1 * var(--td-badge-basic-height, 32rpx) + 1rpx);
border-right: var(--td-badge-basic-height, 32rpx) solid transparent;
}
.t-badge--bubble {
border-radius: var(--td-badge-bubble-border-radius, 20rpx 20rpx 20rpx 1px);
}
.t-badge--large {
font-size: var(--td-badge-large-font-size, var(--td-font-size-s, 24rpx));
height: var(--td-badge-large-height, 40rpx);
min-width: var(--td-badge-large-height, 40rpx);
line-height: var(--td-badge-large-height, 40rpx);
padding: 0 var(--td-badge-large-padding, 10rpx);
}
.t-badge--large.t-badge--circle {
border-radius: calc(var(--td-badge-large-height, 40rpx) / 2);
}
.t-badge__content:not(:empty) + .t-has-count {
transform-origin: center center;
transform: translate(-50%, -50%);
position: absolute;
left: 100%;
top: 0;
}
.t-badge__content-text {
display: block;
line-height: 48rpx;
color: var(--td-badge-content-text-color, var(--td-text-color-primary, var(--td-font-gray-1, rgba(0, 0, 0, 0.9))));
}

View File

@ -0,0 +1,3 @@
export * from './type';
export * from './props';
export * from './badge';

View File

@ -0,0 +1,3 @@
export * from './type';
export * from './props';
export * from './badge';

View File

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

View File

@ -0,0 +1,41 @@
const props = {
color: {
type: String,
value: '',
},
content: {
type: String,
value: '',
},
count: {
type: null,
value: 0,
},
dot: {
type: Boolean,
value: false,
},
externalClasses: {
type: Array,
},
maxCount: {
type: Number,
value: 99,
},
offset: {
type: Array,
},
shape: {
type: String,
value: 'circle',
},
showZero: {
type: Boolean,
value: false,
},
size: {
type: String,
value: 'medium',
},
};
export default props;

View File

@ -0,0 +1,42 @@
export interface TdBadgeProps {
color?: {
type: StringConstructor;
value?: string;
};
content?: {
type: StringConstructor;
value?: string;
};
count?: {
type: null;
value?: string | number;
};
dot?: {
type: BooleanConstructor;
value?: boolean;
};
externalClasses?: {
type: ArrayConstructor;
value?: ['t-class', 't-class-content', 't-class-count'];
};
maxCount?: {
type: NumberConstructor;
value?: number;
};
offset?: {
type: ArrayConstructor;
value?: Array<string | number>;
};
shape?: {
type: StringConstructor;
value?: 'circle' | 'square' | 'bubble' | 'ribbon';
};
showZero?: {
type: BooleanConstructor;
value?: boolean;
};
size?: {
type: StringConstructor;
value?: 'medium' | 'large';
};
}

View File

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

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