This commit is contained in:
Ling53666
2025-08-18 09:11:51 +08:00
commit 02554225da
2516 changed files with 133155 additions and 0 deletions

View File

@ -0,0 +1,144 @@
{
"modes": [
{
"title": "上门预约",
"page": "pages/shangmenyuyue/shangmenyuyue",
"launchMode": "common"
},
{
"title": "商品界面",
"page": "pages/shangpinjiemian/shangpinjiemian",
"launchMode": "common"
},
{
"title": "购物车",
"page": "pages/gouwuche/gouwuche",
"launchMode": "common"
},
{
"title": "pages/test/test",
"page": "pages/test/test",
"launchMode": "common"
},
{
"title": "我的订单",
"page": "pages/wodedingdan/wodedingdan",
"launchMode": "common"
},
{
"title": "甲情甲意",
"page": "pages/shouye/shouye",
"launchMode": "common"
},
{
"title": "认证美甲师",
"page": "pages/meijiashirenzheng/meijiashirenzheng",
"launchMode": "common"
},
{
"title": "我的评价",
"page": "pages/wodepingjia/wodepingjia",
"launchMode": "common"
},
{
"title": "评价",
"page": "pages/pingjia/pingjia",
"launchMode": "common"
},
{
"title": "我的收藏",
"page": "pages/wodeshoucang/wodeshoucang",
"launchMode": "common"
},
{
"title": "pages/test/test",
"page": "pages/test/test",
"launchMode": "common"
},
{
"title": "发布抢单",
"page": "pages/kehushangmenyuyueqiangdan/kehushangmenyuyueqiangdan",
"launchMode": "common"
},
{
"title": "我的预约",
"page": "pages/wodeyuyue/wodeyuyue",
"launchMode": "common"
},
{
"title": "pages/test1/test1",
"page": "pages/test1/test1",
"launchMode": "common"
},
{
"title": "店铺主页",
"page": "pages/dianpuzhuye/dianpuzhuye",
"launchMode": "common"
},
{
"title": "登录测试",
"page": "pages/denglutest/denglutest",
"launchMode": "common"
},
{
"title": "pages/test/test",
"page": "pages/test/test",
"launchMode": "common"
},
{
"title": "到店服务",
"page": "pages/daodianfuwu/daodianfuwu",
"launchMode": "common"
},
{
"title": "发布抢单",
"page": "pages/kehushangmenyuyueqiangdan/kehushangmenyuyueqiangdan",
"launchMode": "common"
},
{
"title": "我的预约",
"page": "pages/wodeyuyue/wodeyuyue",
"launchMode": "common"
},
{
"title": "咨询",
"page": "pages/zixunmeijiashi/zixunmeijiashi",
"launchMode": "common"
},
{
"title": "支付界面",
"page": "pages/zhifujiemian/zhifujiemian",
"launchMode": "common"
},
{
"title": "商品界面",
"page": "pages/shangpinjiemian/shangpinjiemian",
"launchMode": "common"
},
{
"title": "预约支付",
"page": "pages/yuyuezhifu/yuyuezhifu",
"launchMode": "common"
},
{
"title": "咨询",
"page": "pages/zixunmeijiashi/zixunmeijiashi",
"launchMode": "common"
},
{
"title": "pages/test/test",
"page": "pages/test/test",
"launchMode": "common"
},
{
"title": "pages/zhoubianshop/zhoubianshop",
"page": "pages/zhoubianshop/zhoubianshop",
"launchMode": "common"
},
{
"title": "pages/kechengxiangqing/kechengxiangqing",
"page": "pages/kechengxiangqing/kechengxiangqing",
"launchMode": "common"
}
]
}

View File

@ -0,0 +1,5 @@
{
"ignoreHttpDomainCheck": true,
"ignoreWebViewDomainCheck": true,
"ignoreCertificateDomainCheck": true
}

1
甲情_甲意/README.md Normal file
View File

@ -0,0 +1 @@
云开发空白模板

View File

@ -0,0 +1,57 @@
const cloud = require("@alipay/faas-server-sdk");
exports.main = async (event, context) => {
const {name, number, address,type,person } = event; // 从事件参数中获取传入的值
// 获取当前时间,并格式化成字符串
const currentTime = new Date();
const createTime = formatTime(currentTime); // formatTime 为自定义函数,见下面
const db = cloud.database();
// 通过 add 在 example 中添加文档
return await db.collection('mysql2').add({
data: {
name: name,
number: number,
address:address,
type:type,
person:person,
createTime: createTime, // 将 createTime 加入文档
},
});
};
// 自定义函数,用于将时间对象格式化成字符串
function formatTime(date) {
const year = date.getFullYear();
const month = padZero(date.getMonth() + 1);
const day = padZero(date.getDate());
const hour = padZero(date.getHours());
const minute = padZero(date.getMinutes());
const second = padZero(date.getSeconds());
return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
}
// 自定义函数,用于补齐数字前面的零
function padZero(num) {
return num < 10 ? '0' + num : num;
}

View File

@ -0,0 +1,12 @@
{
"name": "add01",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {},
"author": "",
"license": "ISC",
"dependencies": {
"@alipay/faas-server-sdk": "^1.0.0"
}
}

View File

@ -0,0 +1,9 @@
const cloud = require('@alipay/faas-server-sdk');
cloud.init();
exports.main = async (event, context) => {
const res = {
"ikun":"登陆成功"
}
return res;
};

View File

@ -0,0 +1,12 @@
{
"name": "demo02",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {},
"author": "",
"license": "ISC",
"dependencies": {
"@alipay/faas-server-sdk": "^1.0.0"
}
}

View File

@ -0,0 +1,16 @@
const cloud = require('@alipay/faas-server-sdk');
cloud.init();
exports.main = async (event, context) => {
const res = await cloud.openapi.alipayOpenAppQrcodeCreate.request({
bizContent: {
url_param: 'page/component/component-pages/view/view',
query_param: 'x=1',
describe: '二维码描述',
color: '0x00BFFF',
size: 's',
},
});
console.log('云调用结果:', res);
return res;
};

View File

@ -0,0 +1,12 @@
{
"name": "demo3",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {},
"author": "",
"license": "ISC",
"dependencies": {
"@alipay/faas-server-sdk": "^1.0.0"
}
}

View File

@ -0,0 +1,6 @@
exports.main = async (event, context) => {
let data = {
"message": "Hello World!"
};
return data;
};

View File

@ -0,0 +1,32 @@
const cloud = require('@alipay/faas-server-sdk');
exports.main = async (event, context) => {
try {
// 获取 cloud 环境中的 mongoDB 数据库对象
const db = cloud.database();
// 使用 where 条件查询集合对象test
const data = await db.collection('user')
// 使用 get 获取文档数据
.get();
return { success: true, msg: '查询成功', data };
} catch (err) {
return { success: false, msg: `查询失败 - ${err.toString()}` };
}
};

View File

@ -0,0 +1,12 @@
{
"name": "query",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {},
"author": "",
"license": "ISC",
"dependencies": {
"@alipay/faas-server-sdk": "^1.0.0"
}
}

View File

@ -0,0 +1,28 @@
const cloud = require('@alipay/faas-server-sdk');
exports.main = async (event, context) => {
try {
// 获取 cloud 环境中的 mongoDB 数据库对象
const db = cloud.database();
// 使用 where 条件查询集合对象test
const data = await db.collection('mysql3')
// 使用 get 获取文档数据
.get();
return { success: true, msg: '查询成功', data };
} catch (err) {
return { success: false, msg: `查询失败 - ${err.toString()}` };
}
};

View File

@ -0,0 +1,12 @@
{
"name": "queryAllShop",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {},
"author": "",
"license": "ISC",
"dependencies": {
"@alipay/faas-server-sdk": "^1.0.0"
}
}

View File

@ -0,0 +1,32 @@
const cloud = require('@alipay/faas-server-sdk');
exports.main = async (event, context) => {
try {
const { name } = event;
// 获取 cloud 环境中的 mongoDB 数据库对象
const db = cloud.database();
// 使用 where 条件查询集合对象test
const data = await db.collection('mysql3')
.where({
name: name,
})
// 使用 get 获取文档数据
.get();
return { success: true, msg: '查询成功', data };
} catch (err) {
return { success: false, msg: `查询失败 - ${err.toString()}` };
}
};

View File

@ -0,0 +1,12 @@
{
"name": "querySelectByName",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {},
"author": "",
"license": "ISC",
"dependencies": {
"@alipay/faas-server-sdk": "^1.0.0"
}
}

View File

@ -0,0 +1,28 @@
const cloud = require('@alipay/faas-server-sdk');
exports.main = async (event, context) => {
try {
// 获取 cloud 环境中的 mongoDB 数据库对象
const db = cloud.database();
const data = await db.collection('mysql3')
// 使用 get 获取文档数据
.get();
return { success: true, msg: '查询成功', data };
} catch (err) {
return { success: false, msg: `查询失败 - ${err.toString()}` };
}
};

View File

@ -0,0 +1,12 @@
{
"name": "sclect01",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {},
"author": "",
"license": "ISC",
"dependencies": {
"@alipay/faas-server-sdk": "^1.0.0"
}
}

View File

@ -0,0 +1,34 @@
const cloud = require('@alipay/faas-server-sdk');
exports.main = async (event, context) => {
try {
const { username , password } = event;
// 获取 cloud 环境中的 mongoDB 数据库对象
const db = cloud.database();
// 使用 where 条件查询集合对象test
const data = await db.collection('mysql1')
.where({
username: username,
password: password
})
// 使用 get 获取文档数据
.get();
return { success: true, msg: '查询成功', data };
} catch (err) {
return { success: false, msg: `查询失败 - ${err.toString()}` };
}
};

View File

@ -0,0 +1,12 @@
{
"name": "select",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {},
"author": "",
"license": "ISC",
"dependencies": {
"@alipay/faas-server-sdk": "^1.0.0"
}
}

View File

@ -0,0 +1,12 @@
{
"format": 2,
"compileOptions": {
"component2": true,
"enableNodeModuleBabelTransform": true
},
"miniprogramRoot": "./miniprogram",
"cloudbaseRoot": "cloud",
"developOptions": {
"hotReload": true
}
}

View File

@ -0,0 +1,6 @@
page{
width: 100vw;
height: auto;
overflow:hidden;
font-family: 华文楷体;
}

View File

@ -0,0 +1,29 @@
App({
onLaunch() {
my.getStorage({
key: 'userInfo',
success: (res) => {
const userInfo = res.data;
const currentTimestamp = new Date().getTime();
const lastLoginTimestamp = userInfo.timestamp; // 获取上次登录时间戳
// 计算时间差(单位:毫秒)
const timeDiff = currentTimestamp - lastLoginTimestamp;
const oneDay = 86400* 1000; // 24小时的毫秒数
// 如果时间差大于24小时则清除缓存
if (timeDiff > oneDay) {
console.log('超过24小时清除缓存');
my.removeStorage({
key: 'userInfo',
success: function () {
console.log('用户信息已删除');
},
fail: function (err) {
console.error('删除失败:', err);
}
});
}
},
});
},
})

View File

@ -0,0 +1,80 @@
{
"pages": [
"pages/shouye/shouye",
"pages/shangmenyuyue/shangmenyuyue",
"pages/daodianfuwu/daodianfuwu",
"pages/kehushangmenyuyueqiangdan/kehushangmenyuyueqiangdan",
"pages/wodeshoucang/wodeshoucang",
"pages/wodeyuyue/wodeyuyue",
"pages/zixunmeijiashi/zixunmeijiashi",
"pages/shangjiaqiangdan/shangjiaqiangdan",
"pages/denglu/denglu",
"pages/zhifujiemian/zhifujiemian",
"pages/index/index",
"pages/wode/wode",
"pages/wodedingdan/wodedingdan",
"pages/wodepingjia/wodepingjia",
"pages/shangpinjiemian/shangpinjiemian",
"pages/shangjiaruzhu/shangjiaruzhu",
"pages/gouwuche/gouwuche",
"pages/dianpuzhuye/dianpuzhuye",
"pages/index",
"pages/test/test",
"pages/meijiashirenzheng/meijiashirenzheng",
"pages/pingjia/pingjia",
"pages/test1/test1",
"pages/denglutest/denglutest",
"pages/yuyuezhifu/yuyuezhifu",
"pages/shnagmendianpu/shnagmendianpu",
"pages/yuyuezhifusm/yuyuezhifusm",
"pages/yuyuejiemian/yuyuejiemian",
"pages/message/message",
"pages/pay/pay",
"pages/dingdanxiangqing/dingdanxiangqing",
"pages/zhoubianshop/zhoubianshop",
"pages/kechengxiangqing/kechengxiangqing",
"pages/kehcnegbaoming/kehcnegbaoming"
],
"window": {
"defaultTitle": "甲情甲意",
"titleBarColor": "#eec2c7"
},
"behavior": {
"requestReferrerStrategy": "page",
"requestReferrerStyle": "full",
"requestDefaultEnableCookie": true,
"connectSocketDefaultMultiple": true
},
"tabBar": {
"textColor": "#000",
"selectedColor": "#FFC0CB",
"backgroundColor": "#fff",
"items": [
{
"pagePath": "pages/shouye/shouye",
"name": "首页",
"icon": "pages/image/shouyedianjiqian.png",
"activeIcon": "pages/image/shouyedianjihou.png"
},
{
"pagePath": "pages/gouwuche/gouwuche",
"name": "购物车",
"icon": "pages/image/gouwuchedianjiqian.png",
"activeIcon": "pages/image/gouwuchedianjihou.png"
},
{
"pagePath": "pages/zhoubianshop/zhoubianshop",
"name": "周边商城",
"icon": "pages/image/gouwuchedianjiqian.png",
"activeIcon": "pages/image/gouwuchedianjihou.png"
},
{
"pagePath": "pages/wode/wode",
"name": "我的",
"icon": "pages/image/wodedianjiqian.png",
"activeIcon": "pages/image/wodedianjihou.png"
}
]
},
"useDynamicPlugins": false
}

View File

@ -0,0 +1,59 @@
{
"name": "alipay-ykf-xj",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"node_modules/@mini-types/alipay": {
"version": "3.0.14",
"resolved": "https://registry.npmmirror.com/@mini-types/alipay/-/alipay-3.0.14.tgz",
"integrity": "sha512-FakzSsKvybtWlEIVTIRlr89kuQFn+XY86Ho9VUFFaKLplhW6Wx8FUxTDE7IzV7B9rT8DP/Icy637vUHlXPsw1g==",
"dependencies": {
"@mini-types/global": "3.0.14",
"@mini-types/my": "3.0.14"
}
},
"node_modules/@mini-types/global": {
"version": "3.0.14",
"resolved": "https://registry.npmmirror.com/@mini-types/global/-/global-3.0.14.tgz",
"integrity": "sha512-St2ucFRfKRskposOqV/9iNJTKn1MbyqDypQiy/0DaVJjEm2MFi82RJjX9sBz1uWhQIqzu741PgTjGSy7L/Qj9g=="
},
"node_modules/@mini-types/my": {
"version": "3.0.14",
"resolved": "https://registry.npmmirror.com/@mini-types/my/-/my-3.0.14.tgz",
"integrity": "sha512-aEgmM+rbEvEzTvqltCFRAg/h6KKs14M1y+FrOkz+hn2EyNpOVPesUzTjbRhSiFFsE3WdfBh54lHNYBahAmHq7w=="
},
"node_modules/antd-mini": {
"version": "2.36.8",
"resolved": "https://registry.npmmirror.com/antd-mini/-/antd-mini-2.36.8.tgz",
"integrity": "sha512-9eiCyeux4cMcRC9BeXzqE7p6Cua9YBMTaiU6nOiiuAzIDSI5NAoO9LIn0Vfo2N2UqhVgloBYyIWOE1M/iZLCCw==",
"dependencies": {
"@mini-types/alipay": "^3.0.5",
"async-validator": "^4.0.7",
"dayjs": "^1.11.3",
"fast-deep-equal": "3.1.3",
"tslib": "2.5.0"
}
},
"node_modules/async-validator": {
"version": "4.2.5",
"resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz",
"integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg=="
},
"node_modules/dayjs": {
"version": "1.11.13",
"resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.13.tgz",
"integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg=="
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"node_modules/tslib": {
"version": "2.5.0",
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.5.0.tgz",
"integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
}
}
}

View File

@ -0,0 +1,21 @@
MIT LICENSE
Copyright (c) 2018-present Alipay.com, https://www.alipay.com/
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

View File

@ -0,0 +1,30 @@
{
"name": "@mini-types/alipay",
"version": "3.0.14",
"description": "TypeScript declarations for Alipay's mini program.",
"scripts": {},
"miniprogram": "./",
"repository": {
"type": "git",
"url": "git@github.com:ant-mini-program/api-typings.git"
},
"keywords": [
"tinyapp",
"miniprogram",
"types"
],
"license": "MIT",
"types": "./types/index.d.ts",
"files": [
"types"
],
"publishConfig": {
"registry": "https://registry.npmjs.org/",
"access": "public"
},
"dependencies": {
"@mini-types/global": "3.0.14",
"@mini-types/my": "3.0.14"
},
"gitHead": "f923cf356c26bf6c80ca640951683ba777d968f8"
}

View File

@ -0,0 +1,4 @@
///<reference types='@mini-types/my' />
///<reference types='@mini-types/global' />
export * from '@mini-types/global/types/lib.global';

View File

@ -0,0 +1,21 @@
MIT LICENSE
Copyright (c) 2018-present Alipay.com, https://www.alipay.com/
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

View File

@ -0,0 +1,26 @@
{
"name": "@mini-types/global",
"version": "3.0.14",
"description": "TypeScript declarations for Alipay's mini program.",
"scripts": {},
"miniprogram": "./",
"repository": {
"type": "git",
"url": "git@github.com:ant-mini-program/api-typings.git"
},
"keywords": [
"tinyapp",
"miniprogram",
"types"
],
"license": "MIT",
"types": "./types/index.d.ts",
"files": [
"types"
],
"publishConfig": {
"registry": "https://registry.npmjs.org/",
"access": "public"
},
"gitHead": "f923cf356c26bf6c80ca640951683ba777d968f8"
}

View File

@ -0,0 +1,68 @@
/// <reference path="./lib.app.d.ts" />
/// <reference path="./lib.page.d.ts" />
/// <reference path="./lib.component.d.ts" />
/// <reference path="./lib.mixin.d.ts" />
/// <reference path="./lib.shared.d.ts" />
/// <reference path="./lib.global.d.ts" />
declare namespace MiniProgram {
type UnknownRecord = Record<string, unknown>;
/**
* Get union key of two types
*/
type UnionKeys<T, U> = keyof T | keyof U;
/**
* Get unique keys of left type.
*/
type UniqueLeftKeys<T, U> = Exclude<UnionKeys<T, U>, keyof U>;
/**
* Extract left-only types.
*/
type UniqueLeft<T, U> = {
[P in UniqueLeftKeys<T, U>]: T[P];
};
// 获取 mixins 数组的每一个元素的类型
type TExtractValuesOfTuple<T extends any[]> = T[keyof T & number];
// 获取 methods、props、data 类型(主要就是这个三个)
type TGetMixinMethods<T> = T extends { methods?: infer M } ? M : never;
type TGetMixinData<T> = T extends { data?: infer D } ? D : never;
type TGetMixinProps<T> = T extends { props?: infer P } ? P : never;
// 整合一下类型
type UnionToIntersection<T> = (
T extends any ? (x: T) => any : never
) extends (x: infer R) => any
? R
: never;
/**
* Recursively map a type and make all properties optional.
*/
type RecursivePartial<T> = {
[P in keyof T]?: T[P] extends Array<infer U>
? Array<RecursivePartial<U>>
: T[P] extends object
? RecursivePartial<T[P]>
: T[P];
};
/**
* Recursively map a type and make all properties optional & dynamic.
*/
type RecursivePartialAndDynamic<T> = T extends object
? {
[P in keyof T]?: T[P] extends Array<infer U>
? Array<RecursivePartialAndDynamic<U>>
: T[P] extends Function
? T[P]
: T[P] extends object
? RecursivePartialAndDynamic<T[P]>
: T[P];
}
: T;
}

View File

@ -0,0 +1,141 @@
declare namespace MiniProgram.App {
interface ReferrerInfo {
/**
* 来源小程序
*/
appId: string;
/**
* 来源插件,当处于插件运行模式时可见
*/
sourceServiceId: string;
/**
* 来源小程序传过来的数据
*/
extraData: Record<string, any>;
}
interface LaunchOptions<
Query extends Record<string, string> = Record<string, string>
> {
/**
* 当前小程序的 query从启动参数的 query 字段解析而来
*/
query: Query;
/**
* 启动小程序的 场景值
* @see https://opendocs.alipay.com/mini/framework/scene
*/
scene: number;
/**
* 当前小程序的页面地址,从启动参数 page 字段解析而来page 忽略时默认为首页
*/
path: string;
/**
* 来源信息
*/
referrerInfo: ReferrerInfo;
}
interface UnhandledRejectionRes {
/**
* reject 的原因
*/
reason: string;
/**
* 被 reject 的 Promise 对象
*/
promise: Promise<unknown>;
}
/**
* app.js App(options) 中 options 的内部类型
* ref: https://opendocs.alipay.com/mini/framework/app-detail
*/
interface Options<ExtraOptions extends UnknownRecord> {
/**
* 生命周期回调:监听小程序初始化
* 当小程序初始化完成时触发,全局只触发一次
*/
onLaunch(options: LaunchOptions): void;
/**
* 生命周期回调:监听小程序显示
* 当小程序启动,或从后台进入前台显示时触发
*/
onShow(options: LaunchOptions): void;
/**
* 生命周期回调:监听小程序隐藏
* 当当前页面被隐藏时触发,例如跳转、按下设备 Home 键离开
*/
onHide(): void;
/**
* 监听小程序错误
* 当小程序发生 js 错误时触发
*/
onError(error: string): void;
/**
* 全局分享配置
*/
onShareAppMessage(): Page.IShareAppMessage;
/**
* 监听 unhandledrejection 事件
* 当 Promise 被 reject 且没有 reject 处理器时,会触发 onUnhandledRejection 事件
*/
onUnhandledRejection(res: UnhandledRejectionRes): void;
/**
* 全局数据
*/
globalData: object;
}
/**
* Additional properties in App instance, for module augmentation
*/
interface IInstanceAdditionalProperties<ExtraOptions extends UnknownRecord> {}
/**
* App 的类型
*/
interface IApp<ExtraThis, ExtraOptions extends UnknownRecord> {
(opts: UserAppOptions<ExtraThis, ExtraOptions>): any;
}
type IAppInstance<ExtraThis, ExtraOptions extends UnknownRecord> = Omit<
ExtraOptions,
keyof Options<ExtraOptions>
> &
ExtraThis &
IInstanceAdditionalProperties<ExtraOptions>;
/**
* 用户可配置的 App Options
*/
type UserAppOptions<ExtraThis, ExtraOptions extends UnknownRecord> = Partial<
Options<ExtraOptions>
> &
Partial<
UniqueLeft<UniqueLeft<ExtraThis, ExtraOptions>, Options<ExtraOptions>>
> & {
[P in keyof ExtraOptions]: P extends keyof Options<ExtraOptions>
? unknown
: ExtraOptions[P];
} & ThisType<IAppInstance<ExtraThis, ExtraOptions>>;
interface Constructor {
<ExtraThis = {}, ExtraOptions extends Record<string, unknown> = {}>(
opts: UserAppOptions<
ExtraThis & IGlobalMiniProgramExtraThis4App,
ExtraOptions
>
): void;
}
interface GetApp {
<
ExtraThis = {},
ExtraOptions extends Record<string, unknown> = {}
>(): IAppInstance<
ExtraThis & IGlobalMiniProgramExtraThis4App,
ExtraOptions
>;
}
}

View File

@ -0,0 +1,312 @@
declare namespace MiniProgram.Component {
/**
* Additional properties in Component instance, for module augmentation
*/
interface IComponentInstanceAdditionalProperties<
ExtraOptions extends UnknownRecord
> {}
interface ILifetimes {
/**
* 在组件实例刚刚被创建时执行
*/
created(): void;
/**
* 在组件实例进入页面节点树时执行
*/
attached(): void;
/**
* 在组件在视图层布局完成后执行
*/
ready(): void;
/**
* 在组件实例被移动到节点树另一个位置时执行
*/
moved(): void;
/**
* 在组件实例被从页面节点树移除时执行
*/
detached(): void;
}
interface IRelationOption {
/**
* 与目标组件的相对关系
*/
type: 'parent' | 'child' | 'ancestor' | 'descendant';
/**
* 关系生命周期函数,目标组件建立时触发,触发时机在组件 attached 生命周期之后。
*/
linked?(target: BaseInstance): void;
/**
* 关系生命周期函数,目标组件移动时触发,触发时机在组件 moved 生命周期之后。
*/
linkChanged?(target: BaseInstance): void;
/**
* 关系生命周期函数,目标组件销毁时触发,触发时机在组件 detached 生命周期之后
*/
unlinked?(target: BaseInstance): void;
/**
* 根据组件使用的 Mixin 来建立关系
* 如果这一项被设置则它表示关联的目标节点所应具有的Mixin实例所有拥有这一Mixin实例的组件节点都会被关联
*/
target?: string;
}
/**
* component\/*\/index.js Component(options) 中 options 的内部类型
* ref: https://opendocs.alipay.com/mini/framework/component_object
*/
interface IOptions<
Data,
Props,
Methods,
ExtraOptions extends UnknownRecord,
Mixins extends Array<Mixin.IMixin4Legacy | ReturnType<Mixin.Constructor>>
> {
/**
* 组件内部状态
*/
data: Data | ((this: void) => Data);
/**
* 为外部传入的数据设置默认值
*/
props: Props;
/**
* 组件生命周期函数,组件创建时触发
* @version 1.14.0+
*/
onInit(): void;
/**
* 组件生命周期函数,组件创建时和更新前触发
* @version 1.14.0+
*/
deriveDataFromProps(nextProps: Partial<Props>): void;
/**
* 组件生命周期函数,组件创建完毕时触发
*/
didMount(): void;
/**
* 组件生命周期函数,组件更新完毕时触发
*/
didUpdate(prevProps: Partial<Props>, prevData: Partial<Data>): void;
/**
* 组件生命周期函数,组件删除时触发
*/
didUnmount(): void;
/**
* 组件间代码复用机制
*/
mixins: Mixins;
/**
* 组件的方法,可以是事件响应函数或任意的自定义方法
* Object of Functions
*/
methods: Methods;
/**
* 指定组件被ref引用时的返回值
* @version 1.18.0+
*/
ref(): void;
/**
* 监听所属页面除onShareAppMessage外的页面的生命周期函数以及页面事件处理函数。
* @version 2.8.5
*/
pageEvents: Partial<Page.Events>;
/**
* 开启某些功能项
*/
options: Partial<{
/**
* 开启虚拟化自定义组件节点,默认值为 true
* @version 2.8.0
*/
virtualHost: boolean;
/**
* 开启 observers 数据变化观测器
* @version 2.8.1
*/
observers: boolean;
/**
* 开启 lifetimes 节点树维度生命周期
* @version 2.8.5
*/
lifetimes: boolean;
/**
* 开启 relations 组件间关系
* @version 2.8.5
*/
relations: boolean;
/**
* 开启 externalClasses 外部样式类
* @version 2.8.5
*/
externalClasses: boolean;
}>;
/**
* 数据变化观测器,观测和响应任何属性和数据字段的变化
* @version 2.8.1
*/
observers: Record<string, (...args: any[]) => void>;
/**
* 节点树维度生命周期
* @version 2.8.5
*/
lifetimes: Partial<ILifetimes>;
/**
* 组件间关系
* @version 2.8.5
*/
relations: Record<string, IRelationOption>;
/**
* 组件接受的外部样式类
* @version 2.8.5
*/
externalClasses: string[];
}
interface IInstanceProperties {
/**
* 组件路径
*/
readonly is: string;
/**
* 组件 id可直接在组件 axml 中渲染值
*/
readonly $id: number;
/**
* 组件所属页面实例
*/
readonly $page: Record<string, any>;
/**
* 自定义组件路由对象
* @description 可获得当前自定义组件的路由对象,路由方法与全局路由方法功能相同,唯一区别在于调用时,相对路径是相对于该自定义组件
* @version 2.7.22
*/
readonly router: Shared.IRouter;
/**
* 自定义组件所在页面路由对象
* @description 可获得当前自定义组件所在页面的路由对象,路由方法与全局路由方法功能相同,唯一区别在于调用时,相对路径是相对于所在页面
* @version 2.7.22
*/
readonly pageRouter: Shared.IRouter;
}
interface IInstanceMethods<Data> {
/**
* 将数据从逻辑层发送到视图层
* @param data
* @param callback
*/
setData(
data: RecursivePartialAndDynamic<Data> & Record<string, unknown>,
callback?: () => void
): void;
/**
* $spliceData 同样用于将数据从逻辑层发送到视图层,但是相比于 setData在处理长列表的时候其具有更高的性能。
* @param data
* @param callback
* @version 1.7.2+ 可以使用 my.canIUse('page.$spliceData') 做兼容性处理
*/
$spliceData(
data: RecursivePartialAndDynamic<Data> & Record<string, unknown>,
callback?: () => void
): void;
/**
* 选取当前组件的创建者(即 AXML 中定义了此组件的组件),返回它的组件实例对象(会被 `ref` 影响)。
*
* @version 2.7.22
* @returns undefined | null | 页面 | 自定义组件 | 用户 ref 的 Object
*/
selectOwnerComponent(): BaseInstance;
/**
* 选取当前组件在事件冒泡路径上的父组件,返回它的组件实例对象(会被 `ref` 影响)。
*
* @version 2.7.22
* @returns undefined | null | 页面 | 自定义组件 | 用户 ref 的 Object
*/
selectComposedParentComponent(): BaseInstance;
/**
* 检查组件是否具有 mixin(须是通过Mixin()创建的mixin实例)。
* @description 若自定义组件注册时传入了ref以指定组件返回值则可通过hasMixin('ref')检查到
* @version 2.8.2
* @return boolean
* @see https://opendocs.alipay.com/mini/framework/component_object#%E7%BB%84%E4%BB%B6%E5%AE%9E%E4%BE%8B%E6%96%B9%E6%B3%95
*/
hasMixin(mixin: Mixin.IMixinIdentifier): boolean;
/**
* 获取这个关系所对应的所有关联节点,参见 组件间关系
* @version 2.8.5
*/
getRelationNodes(relationKey: string): BaseInstance[];
}
/**
* Public instance
*/
type IInstance<
Data,
Props,
Methods,
ExtraThis,
ExtraOptions extends UnknownRecord,
Mixins extends Array<Mixin.IMixin4Legacy | ReturnType<Mixin.Constructor>>
> = {
data: Data &
UnionToIntersection<TGetMixinData<TExtractValuesOfTuple<Mixins>>>;
props: Readonly<
Props & UnionToIntersection<TGetMixinProps<TExtractValuesOfTuple<Mixins>>>
>;
} & Methods &
UnionToIntersection<TGetMixinMethods<TExtractValuesOfTuple<Mixins>>> &
ExtraThis &
Omit<
ExtraOptions,
keyof IOptions<Data, Props, Methods, ExtraOptions, Mixins>
> &
IComponentInstanceAdditionalProperties<ExtraOptions> &
IInstanceProperties &
IInstanceMethods<Data> &
Shared.IInstanceSharedMethods<Data>;
type BaseInstance = IInstance<
UnknownRecord,
UnknownRecord,
UnknownRecord,
UnknownRecord,
UnknownRecord,
[]
>;
interface Constructor {
<
Data = UnknownRecord,
Props = UnknownRecord,
Methods = UnknownRecord,
ExtraThis = UnknownRecord,
ExtraOptions extends Record<string, unknown> = UnknownRecord,
Mixins extends Array<
Mixin.IMixin4Legacy | ReturnType<Mixin.Constructor>
> = any[]
>(
opts: {
[P in keyof ExtraOptions]: P extends keyof IOptions<
Data,
Props,
Methods,
ExtraOptions,
Mixins
>
? unknown
: ExtraOptions[P];
} & Partial<IOptions<Data, Props, Methods, ExtraOptions, Mixins>> &
ThisType<
IInstance<
Data,
Props,
Methods,
ExtraThis & IGlobalMiniProgramExtraThis4Component,
ExtraOptions,
Mixins
>
>
): void;
}
}

View File

@ -0,0 +1,98 @@
export type IAppOnLaunchOptions<Query extends Record<string, string>> =
MiniProgram.App.LaunchOptions<Query>;
export interface IRequirePluginAsync<
Target extends Record<string, any> = Record<string, any>
> {
<K extends keyof Target>(pluginName: K): Promise<Target[K]>;
<Result extends any>(pluginName: string): Promise<Result>;
}
export interface IRequirePlugin<
Target extends Record<string, any> = Record<string, any>
> {
<K extends keyof Target>(pluginName: K): Target[K];
<Result extends any>(pluginName: string): Result;
async: IRequirePluginAsync;
}
export type IMixin4Legacy<
Data,
Props,
Methods,
ExtraThis = MiniProgram.UnknownRecord,
ExtraOptions extends MiniProgram.UnknownRecord = MiniProgram.UnknownRecord
> = MiniProgram.Mixin.IMixin4Legacy<
Data,
Props,
Methods,
ExtraThis,
ExtraOptions
>;
export interface Require {
<T extends any>(path: string): T;
<T extends any>(path: string, cb?: (o: T) => void): void;
async<T extends any>(path: string): Promise<T>;
}
declare global {
/**
* Extra `this` for Component instance.
*/
interface IGlobalMiniProgramExtraThis4Component {}
/**
* Extra `this` for Page instance.
*/
interface IGlobalMiniProgramExtraThis4Page {}
/**
* Extra `this` for App instance.
*/
interface IGlobalMiniProgramExtraThis4App {}
/**
* 使用插件提供的 JS 接口,函数返回值为 \`插件\` 通过 \`main\` 字段暴露的 JS 接口。
*/
const requirePlugin: IRequirePlugin;
const require: Require;
/**
* App's constructor
* @link https://opendocs.alipay.com/mini/framework/app-detail
*/
const App: MiniProgram.App.Constructor;
/**
* Get App.
* @link https://opendocs.alipay.com/mini/framework/get-app
*/
const getApp: MiniProgram.App.GetApp;
/**
* Get Current Pages
* @link https://opendocs.alipay.com/mini/framework/getcurrentpages
*/
const getCurrentPages: MiniProgram.Page.GetCurrentPages;
/**
* Page's constructor
* @link https://opendocs.alipay.com/mini/framework/page-detail
*/
const Page: MiniProgram.Page.Constructor;
/**
* Component's constructor
* @link https://opendocs.alipay.com/mini/framework/component_object
*/
const Component: MiniProgram.Component.Constructor;
/**
* 注册一个 `mixin`,接受一个 `Object` 类型的参数。
* @version 2.8.2
* @link https://opendocs.alipay.com/mini/05bchn
*/
const Mixin: MiniProgram.Mixin.Constructor;
}

View File

@ -0,0 +1,104 @@
declare namespace MiniProgram.Mixin {
/**
* 传统的组件间代码复用仅Component的mixins参数支持传入Mixin参数mixins 则只支持传入Mixin()的返回值
*/
type IMixin4Legacy<
Data extends UnknownRecord,
Props extends UnknownRecord,
Methods extends UnknownRecord,
ExtraThis extends UnknownRecord = UnknownRecord,
ExtraOptions extends UnknownRecord = UnknownRecord
> = Partial<
MiniProgram.Component.IOptions<Data, Props, Methods, ExtraOptions, []>
> &
ThisType<
MiniProgram.Component.IInstance<
Data,
Props,
Methods,
ExtraThis & IGlobalMiniProgramExtraThis4Component,
ExtraOptions,
[]
>
>;
/**
* Mixin() 返回值
*/
type IMixinIdentifier = string;
type IMixinDefinitionFilter = <
T extends
| Component.IOptions<any, any, any, any, any>
| IMixinOptions<any, any, any, any, any, any>
| Page.IOptions<any, any>
>(
/** 使用该 mixin 的 component/mixin 的定义对象 */
defFields: T,
/** 该 mixin 所使用的 mixin 的 definitionFilter 函数列表 */
definitionFilterArr?: IMixinDefinitionFilter[] | void
) => void;
/**
* Mixin构造器参数
*/
type IMixinOptions<
Data,
Props,
Methods,
ExtraThis,
ExtraOptions extends UnknownRecord,
Mixins extends Array<ReturnType<Constructor>>
> = {
[P in keyof ExtraOptions]: P extends
| keyof Component.IOptions<Data, Props, Methods, ExtraOptions, Mixins>
| 'definitionFilter'
| 'mixins'
? unknown
: ExtraOptions[P];
} & Omit<
Partial<
Component.IOptions<Data, Props, Methods, ExtraOptions, IMixinIdentifier[]>
>,
'ref' | 'options' | 'externalClasses'
> &
Partial<{
/**
* 定义段过滤器,用于自定义组件扩展
*/
definitionFilter: IMixinDefinitionFilter;
/**
* 组件间代码复用用于Mixin()的mixins 只支持传入Mixin()注册生成的返回值。不支持传入 js Object
*/
mixins: Mixins;
}> &
ThisType<
Component.IInstance<
Data,
Props,
Methods,
ExtraThis,
ExtraOptions,
IMixinIdentifier[]
>
>;
interface Constructor {
<
Data = UnknownRecord,
Props = UnknownRecord,
Methods = UnknownRecord,
ExtraThis = UnknownRecord,
ExtraOptions extends UnknownRecord = UnknownRecord,
Mixins extends IMixinIdentifier[] = []
>(
options: IMixinOptions<
Data,
Props,
Methods,
ExtraThis & IGlobalMiniProgramExtraThis4Component,
ExtraOptions,
Mixins
>
): IMixinIdentifier;
}
}

View File

@ -0,0 +1,406 @@
declare namespace MiniProgram.Page {
interface IOnResizeEvent {
/**
* 窗口尺寸
*/
size: {
/**
* 窗口宽度
*/
windowWidth: number;
/**
* 窗口高度
*/
windowHeight: number;
};
}
interface IKeyboardHeightEvent {
/**
* 键盘高度
*/
height: number;
}
interface ITabItemTapEvent {
/**
* 点击来源。
*/
from: string;
/**
* 被点击 tabItem 的页面路径。
*/
pagePath: string;
/**
* 被点击 tabItem 的按钮文字。
*/
text: string;
/**
* 被点击 tabItem 的序号,从 0 开始。
*/
index: number;
}
interface ISelectedTabItemTapEvent {
/**
* 被点击 tabItem 的页面路径。
*/
pagePath: string;
/**
* 被点击 tabItem 的按钮文字。
*/
text: string;
/**
* 被点击 tabItem 的序号,从 0 开始。
*/
index: number;
}
interface IPageScrollEvent {
/**
* 页面滚动距离。
*/
scrollTop: number;
/**
* 页面内容高度。
*/
scrollHeight: number;
}
interface IPullDownRefreshEvent {
/**
* 触发原
* @description
* - manual: 下拉事件通过 my.startPullDownRefresh 触发
* - code: 下拉事件用通过户下拉触发
*/
from: 'manual' | 'code';
}
interface IShareAppMessageEvent {
/**
* 触发来源
* @description
* - button 页面分享按钮触发
* - menu 右上角分享按钮触
* - code 执行 my.showSharePanel 触发
* @version 1.10.0
*/
from: 'button' | 'menu' | 'code';
/**
* 如果 from 值为 button则 target 为触发这次分享的 button否则为 undefined。
* @version 1.10.0
*/
target: object;
/**
* 页面中包含 web-view 组件时,返回当前 web-view 的 URL。
* @version 1.6.0
*/
webViewUrl: string;
}
interface IShareAppMessage {
title: string;
desc: string;
path: string;
}
/**
* 页面事件处理对象
*/
interface Events {
/**
* 页面加载时触发
* @param query 打开当前页面路径中的参数
* @see https://opendocs.alipay.com/mini/03durs
*/
onLoad(query: unknown): void;
/**
* 页面显示时/切入前台时触发
*/
onShow(): void;
/**
* 页面初次渲染完成时触发
*/
onReady(): void;
/**
* 页面隐藏时/切入后台时触发
*/
onHide(): void;
/**
* 页面卸载时触发
* @version 2.8.5
*/
onUnload(): void;
/**
* 点击标题触发
*/
onTitleClick(): void;
/**
* 点击导航栏额外图标触发
* @see 设置额外图标: https://opendocs.alipay.com/mini/api/optionmenu
*/
onOptionMenuClick(): void;
/**
* 页面下拉时触发
* @description 需要先在 app.json 的 window 选项中开启 pullRefresh 。当处理完数据刷新后my.stopPullDownRefresh 可以停止当前页面的下拉刷新。
* @param event 页面下拉事件
* @see https://opendocs.alipay.com/mini/framework/page-detail#onPullDownRefresh(%7Bfrom%3A%20manual%7Ccode%7D)
*/
onPullDownRefresh(event: IPullDownRefreshEvent): void;
/**
* 点击 tabItem非当前 时触发
* @param event 点击 tabItem非当前事件
*/
onTabItemTap: (event: ITabItemTapEvent) => void;
/**
* 页面滚动时触发。
* @param event 页面滚动事件
*/
onPageScroll: (event: IPageScrollEvent) => void;
/**
* 页面被拉到底部时触发
* @description
* - onReachBottom() 上拉触底时才会触发,如果页面已经在页面底部继续上拉是不会再次触发。
* - 可配合 my.pageScrollTo 向上滚动一点位置或者在底部增加数据等方式让页面不处在底部位置达到可以连续上拉触发 onReachBottom()的效果。
* - 可在应用配置app.json通过 onReachBottomDistance 配置项 自定义 页面上拉触底时触发时距离页面底部的距离,单位为 px。
*/
onReachBottom(): void;
/**
* 点击非当前 tabItem 前触发
*/
beforeTabItemTap(): void;
/**
* 键盘高度变化时触发
* @param event 键盘高度变化事件
*/
onKeyboardHeight(event: IKeyboardHeightEvent): void;
/**
* 导航栏左侧返回按钮(以及 Android 系统返回键)被点击时触发
*/
onBack: () => void;
/**
* window尺寸改变时触发
* @version 1.16.0
*/
onResize(event: IOnResizeEvent): void;
/**
* 点击当前 tabItem 后触发。
* @param event 点击当前 tabItem 事件
* @version 2.7.2
*/
onSelectedTabItemTap: (event: ISelectedTabItemTapEvent) => void;
}
/**
* pages\/*\/index.js Page(options) 中 options 的内部类型
* ref: https://opendocs.alipay.com/mini/framework/app-detail
*/
interface IOptions<Data, ExtraOptions extends UnknownRecord> {
/**
* 初始数据或返回初始化数据的函数
*/
data: Data | ((this: void) => Data);
/**
* 页面加载时触发
* @param query 打开当前页面路径中的参数
* @see https://opendocs.alipay.com/mini/03durs
*/
onLoad(query: unknown): void;
/**
* 页面显示时/切入前台时触发
*/
onShow(): void;
/**
* 页面初次渲染完成时触发
*/
onReady(): void;
/**
* 页面隐藏时/切入后台时触发
*/
onHide(): void;
/**
* 页面卸载时触发
*/
onUnload(): void;
/**
* 在 Page 中定义 onShareAppMessage 函数,设置该页面的分享信息。
* @description
* 开发者可通过传入参数自定义小程序分享内容例如标题、描述、图片用户通过点击或者复制分享的内容可以快速打开小程序进入指定页面。目前支持的分享渠道有支付宝朋友动态、支付宝好友、钉钉、新浪微博、微信、QQ。
* - 每个 Page 页面的右上角菜单中默认有 分享 按钮。
* - 用户点击分享按钮的时候会调用。
* - 要求返回一个对象Object类型用于自定义该页面的分享信息如果未定义该回调会使用默认分享信息不影响分享功能
* - 若定义该回调但未返回对象Object类型会导致默认分享不可用。
* - 分享图片中的二维码的有效期为 60 天,若需要长期有效的二维码,请登录 开放平台控制台 > 我的应用 > 进入小程序应用详情页 > 小程序码 中生成。
* - 小程序在 1.1.0 版本中开始支持 open-type 为 share 的按钮触发分享。
* - 从基础库 1.24.13、2.6.7 版本开始支持 async 写法,可通过 my.canIUse('page.onShareAppMessage.async') 检测是否支持。
* @see https://opendocs.alipay.com/mini/framework/page-detail#onShareAppMessage(options%3A%20Object)
*/
onShareAppMessage(
event: IShareAppMessageEvent
): IShareAppMessage | Promise<IShareAppMessage>;
/**
* 点击标题触发
*/
onTitleClick(): void;
/**
* 点击导航栏额外图标触发
* @see 设置额外图标: https://opendocs.alipay.com/mini/api/optionmenu
* @version 1.3.0
*/
onOptionMenuClick: () => void;
/**
* 页面下拉时触发
* @description 需要先在 app.json 的 window 选项中开启 pullRefresh 。当处理完数据刷新后my.stopPullDownRefresh 可以停止当前页面的下拉刷新。
* @param event 页面下拉事件
* @see https://opendocs.alipay.com/mini/framework/page-detail#onPullDownRefresh(%7Bfrom%3A%20manual%7Ccode%7D)
*/
onPullDownRefresh(event: IPullDownRefreshEvent): void;
/**
* 点击 tabItem非当前 时触发
* @param event 点击 tabItem非当前事件
* @version 1.11.0
*/
onTabItemTap: (event: ITabItemTapEvent) => void;
/**
* 页面滚动时触发。
* @param event 页面滚动事件
*/
onPageScroll: (event: IPageScrollEvent) => void;
/**
* 页面被拉到底部时触发
* @description
* - onReachBottom() 上拉触底时才会触发,如果页面已经在页面底部继续上拉是不会再次触发。
* - 可配合 my.pageScrollTo 向上滚动一点位置或者在底部增加数据等方式让页面不处在底部位置达到可以连续上拉触发 onReachBottom()的效果。
* - 可在应用配置app.json通过 onReachBottomDistance 配置项 自定义 页面上拉触底时触发时距离页面底部的距离,单位为 px。
*/
onReachBottom(): void;
/**
* 事件处理函数对象
* @version 1.13.7
*/
events: Partial<Events>;
/**
* 开启某些功能项
*/
options: {
/**
* 开启 observers 数据变化观测器
*/
observers: boolean;
};
/**
* 数据变化观测器,观测和响应任何数据字段的变化。
* @version 2.8.1
*/
observers: Record<string, (...args: any[]) => void>;
/**
* 组件间代码复用机制,只支持传入 Mixin() 实例。
* @version 2.8.5
*/
mixins: Mixin.IMixinIdentifier[];
}
/**
* Additional properties in Page instance, for module augmentation
*/
interface IInstanceAdditionalProperties<ExtraOptions> {}
interface IInstanceProperties {
/**
* Page 路径,对应 app.json 中配置的路径值,类型为 String。这是一个只读属性。
* @readonly
*/
readonly route: string;
/**
* 页面路由对象
* @description 可获得当前页面的路由对象,路由方法与全局路由方法功能相同,唯一区别在于调用时,相对路径是相对于该页面
* @version 2.7.22
*/
readonly router: Shared.IRouter;
/**
* 页面路由对象
* @description 同 router, 可获得当前页面的路由对象,路由方法与全局路由方法功能相同,唯一区别在于调用时,相对路径是相对于该页面
* @version 2.7.22
*/
readonly pageRouter: Shared.IRouter;
}
type IInstanceSharedMethods<Data> = Shared.IInstanceSharedMethods<Data>;
interface IInstanceMethods<Data> {
/**
* 将数据从逻辑层发送到视图层
* @param data
* @param callback
*/
setData(
data: RecursivePartialAndDynamic<Data>,
callback?: () => void
): void;
/**
* $spliceData 同样用于将数据从逻辑层发送到视图层,但是相比于 setData在处理长列表的时候其具有更高的性能。
* @param data
* @param callback
* @version 1.7.2+ 可以使用 my.canIUse('page.$spliceData') 做兼容性处理
*/
$spliceData(
data: RecursivePartialAndDynamic<Data>,
callback?: () => void
): void;
/**
* 批量更新数据。
* @param callback
* @version 1.14.0+ 可以使用 my.canIUse('page.$batchedUpdates') 做兼容性处理
*/
$batchedUpdates(callback: () => void): void;
/**
* 获取 通信通道 EventChannel
* @description
* - 如果一个页面由另一个页面通过 my.navigateTo 打开,这两个页面间将建立一条通信通道:
* - 被打开的页面可以通过 this.getOpenerEventChannel() 方法来获得一个 EventChannel 对象。
* - my.navigateTo 的 success 回调中也包含一个 EventChannel 对象。
* - 这两个 EventChannel 对象间可以使用 emit 和 on 方法相互发送、监听事件。
* @version 2.7.7
* @see https://opendocs.alipay.com/mini/api/eventchannel
*/
getOpenerEventChannel(): Shared.EventChannel;
/**
* 检查组件是否具有 mixin(须是通过Mixin()创建的mixin实例)。
* @version 2.8.5
* @return boolean
* @see https://opendocs.alipay.com/mini/framework/page-detail#hasMixin
*/
hasMixin(mixin: Mixin.IMixinIdentifier): boolean;
}
/**
* `this` type of life cycle hooks in App.
*/
type IInstance<Data, ExtraThis, ExtraOptions extends UnknownRecord> = {
data: Data & UnknownRecord;
} & ExtraThis &
Omit<ExtraOptions, keyof IOptions<Data, ExtraOptions>> &
IInstanceProperties &
IInstanceSharedMethods<Data> &
IInstanceMethods<Data> &
IInstanceAdditionalProperties<ExtraOptions>;
interface Constructor {
<
Data = {},
ExtraThis = {},
ExtraOptions extends Record<string, unknown> = {}
>(
options: Partial<
UniqueLeft<
UniqueLeft<ExtraThis, ExtraOptions>,
IOptions<Data, ExtraOptions>
>
> & {
[P in keyof ExtraOptions]: P extends keyof IOptions<Data, ExtraOptions>
? unknown
: ExtraOptions[P];
} & Partial<IOptions<Data, ExtraOptions>> &
ThisType<IInstance<Data, ExtraThis, ExtraOptions>>
): void;
}
interface GetCurrentPages {
(): Array<IInstance<object, {}, {}>>;
}
}

View File

@ -0,0 +1,309 @@
declare namespace MiniProgram.Shared {
interface SetUpdatePerformanceListenerOption<WithDataPath extends boolean> {
/**
* 是否返回变更的 data 字段信息
*/
withDataPaths?: WithDataPath;
}
interface UpdatePerformanceListener<WithDataPath extends boolean> {
(res: ISetUpdatePerformanceListenerResult<WithDataPath>): void;
}
interface ISingleSetDataPerformanceInfo<WithDataPath extends boolean> {
/** setData ID */
id: number;
/** 加入到队列的时间 */
pendingStartTimestamp: number;
/** 本次更新的 data所包含的 key 值 */
dataPaths?: WithDataPath extends true ? string[] : undefined;
}
interface ISetUpdatePerformanceListenerResult<WithDataPath extends boolean> {
/** 其他组件更新,而导致的更新 */
isMergedUpdate: boolean;
/** 更新批次 ID */
updateProcessId: number;
/** 父更新批次 ID */
parentUpdateProcessId?: number;
/**
* 本批次合并之后的 data所包含的 key 值
*/
dataPaths?: WithDataPath extends true ? string[] : undefined;
/** 组件第一条数据,加入到队列的时间 */
pendingStartTimestamp?: number;
/** render 侧接收到data 数据的时间 */
updateStartTimestamp?: number;
/** render 侧完成 UI 更新的时间 */
updateEndTimestamp?: number;
/**
* 本批次所有 setData 的数据信息
*/
dataList: ISingleSetDataPerformanceInfo<WithDataPath>[];
}
interface IMediaQueryObserver {
/**
* 开始监听页面 media query 变化情况
* @param descriptor media query 描述符
* @param callback 监听 media query 状态变化的回调函数
* @see https://opendocs.alipay.com/mini/05awpq
*/
observe: (
descriptor: IMediaQueryObserveDescriptor,
callback: IMediaQueryObserveCallback
) => void;
/**
* 停止监听。回调函数将不再触发
* @see https://opendocs.alipay.com/mini/05bb9o
*/
disconnect: () => void;
}
type IMediaQueryObserveCallback = (
payload: IMediaQueryObserveCallbackResponse
) => void;
interface IMediaQueryObserveCallbackResponse {
/**
* 页面的当前状态是否满足所指定的 media query
*/
matches: boolean;
}
interface IMediaQueryObserveDescriptor {
/**
* 页面最小宽度( px 为单位)
*/
minWidth?: number;
/**
* 页面最大宽度( px 为单位)
*/
maxWidth?: number;
/**
* 页面宽度( px 为单位)
*/
width?: number;
/**
* 页面最小高度( px 为单位)
*/
minHeight?: number;
/**
* 页面最大高度( px 为单位)
*/
maxHeight?: number;
/**
* 页面高度( px 为单位)
*/
height?: number;
/**
* 屏幕方向( landscape 或 portrait
* - landscape viewport 处于横向,即宽度大于高度。
* - portrait viewport 处于纵向,即高度大于等于宽度。
*/
orientation?: 'landscape' | 'portrait';
}
interface IRouter {
navigateTo: (object: {
/**
* 需要跳转的目标页面路径
* @description 路径后可以带参数, 目标路径必须为应用内非 tabbar 的,路径与参数之间使用 ?分隔,参数键与参数值用=相连,不同参数必须用&分隔
*/
url: string;
/**
* 页面间通信接口,用于监听被打开页面发送到当前页面的数据
*/
events?: IMyNavigateToEvents;
/**
* 接口调用成功的回调函数
*/
success?(data: {
/**
* 和被打开页面进行通信
*/
eventChannel: EventChannel;
}): void;
/**
* 接口调用失败的回调函数
*/
fail?(err: { error?: number; errorMessage?: string }): void;
/**
* 接口调用结束的回调函数(调用成功、失败都会执行)
*/
complete?(
arg:
| {
/**
* 和被打开页面进行通信
*/
eventChannel: EventChannel;
}
| {
error?: number;
errorMessage?: string;
}
): void;
}) => Promise<{
/**
* 和被打开页面进行通信
*/
eventChannel: EventChannel;
}>;
redirectTo: (object: {
/**
* 需要跳转的目标页面路径
* 路径后可以带参数, 目标路径必须为应用内非 tabbar 的,路径与参数之间使用 ?分隔,参数键与参数值用=相连,不同参数必须用&分隔
*/
url: string;
/**
* 接口调用成功的回调函数
*/
success?(data: {}): void;
/**
* 接口调用失败的回调函数
*/
fail?(err: { error?: number; errorMessage?: string }): void;
/**
* 接口调用结束的回调函数(调用成功、失败都会执行)
*/
complete?(arg: { error?: number; errorMessage?: string }): void;
}) => Promise<void>;
navigateBack: (object?: {
/**
* 返回的页面数
* @description 如果 delta 大于现有打开的页面数,则返回到首页
* @default 1
*/
delta?: number | string;
/**
* 接口调用成功的回调函数
*/
success?(data: {}): void;
/**
* 接口调用失败的回调函数
*/
fail?(err: { error?: number; errorMessage?: string }): void;
/**
* 接口调用结束的回调函数(调用成功、失败都会执行)
*/
complete?(arg: { error?: number; errorMessage?: string }): void;
}) => Promise<void>;
switchTab: (object: {
/**
* 跳转的特定 tab 的路径
* @description 目标路径必须为应用内 tabbar 的,且路径后不能带参数
*/
url: string;
/**
* 接口调用成功的回调函数
*/
success?(data: {}): void;
/**
* 接口调用失败的回调函数
*/
fail?(err: { error?: number; errorMessage?: string }): void;
/**
* 接口调用结束的回调函数(调用成功、失败都会执行)
*/
complete?(arg: { error?: number; errorMessage?: string }): void;
}) => Promise<void>;
reLaunch: (object: {
/**
* 需要跳转的目标页面路径
* @description
* 目标路径如果是 Tab 路径后不可以带参数
* 目标路径如果是非 Tab 页,可以携带参数,路径与参数之间使用 `?` 分隔,参数键与参数值用 `=` 相连,不同参数必须用 `&` 分隔
*/
url: string;
/**
* 接口调用成功的回调函数
*/
success?(data: {}): void;
/**
* 接口调用失败的回调函数
*/
fail?(err: { error?: number; errorMessage?: string }): void;
/**
* 接口调用结束的回调函数(调用成功、失败都会执行)
*/
complete?(arg: { error?: number; errorMessage?: string }): void;
}) => Promise<void>;
}
interface IMyNavigateToEvents {
/**
* 特定事件名监听回调
*/
[eventName: string]: (...args: unknown[]) => void;
}
interface EventChannel {
/**
* 在页面间通信中触发一个事件
* @see https://opendocs.alipay.com/mini/api/eventchannel.emit
*/
emit(eventName: string, args?: unknown): void;
/**
* 在页面间通信中停止监听一个事件
* @see https://opendocs.alipay.com/mini/api/eventchannel.off
*/
off(eventName: string, callback: (...args: unknown[]) => void): void;
/**
* 在页面间通信中持续监听一个事件
* @see https://opendocs.alipay.com/mini/api/eventchannel.on
*/
on(eventName: string, callback: (...args: unknown[]) => void): void;
/**
* 在页面间通信中监听一个事件仅一次
* @description 事件触发后失效
* @see https://opendocs.alipay.com/mini/api/eventchannel.once
*/
once(eventName: string, callback: (...args: unknown[]) => void): void;
}
interface IInstanceSharedMethods<Data> {
/**
* 创建 SelectorQuery 对象实例。
* @version 2.7.4
*/
createSelectorQuery(): any;
/**
* 创建 IntersectionObserver 对象实例。
* @version 2.7.4
*/
createIntersectionObserver(): any;
/**
* 创建 MediaQueryObserver 对象实例,用于监听页面 media query 状态的变化。
* @version 2.8.2
* @see https://opendocs.alipay.com/mini/framework/component_object#createMediaQueryObserver
*/
createMediaQueryObserver(): IMediaQueryObserver;
/**
* 获取自定义 tabBar 实例,可以通过判断 `this.getTabBar` 是否为一个函数做兼容性处理
* @version 2.7.20
* @see https://opendocs.alipay.com/mini/framework/page-detail#Page.getTabBar
*/
getTabBar<T extends any = Component.BaseInstance>(): T | undefined;
/**
* 查询子组件
* @description 根据传入的 selector 匹配器查询,返回匹配到的第一个组件实例(会被 ref 影响)
* @version 2.8.0
* @see https://opendocs.alipay.com/mini/framework/component_object#%24selectComponent%2F%24selectAllComponents
*/
$selectComponent(selector: string): Component.BaseInstance | void;
/**
* 查询子组件
* @description 根据传入的 selector 匹配器查询,返回匹配到的所有组件实例(会被 ref 影响)
* @version 2.8.0
* @see https://opendocs.alipay.com/mini/framework/component_object#%24selectComponent%2F%24selectAllComponents
*/
$selectAllComponents(selector: string): Component.BaseInstance[];
/**
* 监听 setData 引发界面更新的开销,参见 获取更新性能统计信息
* @version 2.8.5
* @see https://opendocs.alipay.com/mini/069xfk
*/
setUpdatePerformanceListener<WithDataPath extends boolean = false>(
option: SetUpdatePerformanceListenerOption<WithDataPath>,
callback?: UpdatePerformanceListener<WithDataPath>
): void;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
MIT LICENSE
Copyright (c) 2018-present Alipay.com, https://www.alipay.com/
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

View File

@ -0,0 +1,26 @@
{
"name": "@mini-types/my",
"version": "3.0.14",
"description": "TypeScript declarations for Alipay's mini program.",
"scripts": {},
"miniprogram": "./",
"repository": {
"type": "git",
"url": "git@github.com:ant-mini-program/api-typings.git"
},
"keywords": [
"tinyapp",
"miniprogram",
"types"
],
"license": "MIT",
"types": "./types/index.d.ts",
"files": [
"types"
],
"publishConfig": {
"registry": "https://registry.npmjs.org/",
"access": "public"
},
"gitHead": "f923cf356c26bf6c80ca640951683ba777d968f8"
}

View File

@ -0,0 +1,2 @@
///<reference path='./lib.my.d.ts' />
///<reference path='./lib.my.extra.d.ts' />

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,46 @@
declare namespace my {
/**
* @description 通用形式
* @param name JSAPI 名称
* @param opt JSAPI 入参
* @param callback 回调
*/
export function call(
name: string,
opt: any,
callback: (resp: any) => void
): void;
/**
* @description 无入参形式
* @param name JSAPI 名称
* @param callback 回调
*/
export function call(name: string, callback: (resp: any) => void): void;
/**
* @description 无回调返回 Promise 形式
* @param name JSAPI 名称
* @param opt JSAPI 入参
*/
export function call(name: string, opt?: any): Promise<any>;
/**
* @param eventName 需要监听的事件名
* @param callback 事件被触发后的回调函数
*/
export function on(
eventName: string,
callback: (...args: any) => any
): {
/**
* @description 调用该方法后,可移除刚才监听的事件
*/
remove: () => void;
};
/**
* @param eventName 需要监听的事件名
* @param callback 事件被触发后的回调函数
*/
export function off(eventName: string, callback: (...args: any) => any): void;
export function canIUse(name: string): boolean;
}

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Ant Design Team
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.

View File

@ -0,0 +1,21 @@
<img src="https://gw.alipayobjects.com/zos/bmw-prod/0350261f-bac2-443d-9580-d25f3365a26e.svg" alt="logo" width="100%" />
![npm (tag)](https://img.shields.io/npm/v/antd-mini)
&nbsp;
![npm](https://img.shields.io/npm/dw/antd-mini)
&nbsp;
![GitHub](https://img.shields.io/github/license/ant-design/ant-design-mini)
```bash
$ npm i antd-mini -S
```
antd-mini 是支付宝小程序 UI 组件库,遵循 Ant Design 规范。你可以扫描下方的支付宝二维码体验,或者访问[官网](https://mini.ant.design/)以获取更多信息。
<img src="https://mdn.alipayobjects.com/huamei_jlgevq/afts/img/A*2ZAZR7NQQJ4AAAAAAAAAAAAADtSSAQ/original" alt="logo" width="220" />
如果你发现了 bug 或者是希望 antd-mini 增加一些特性,可以[提交 issue](https://github.com/ant-design/ant-design-mini/issues)。也欢迎参与共建,这里有一份[贡献指南](/docs/guide/contribute.md)。
如果你想深入参与讨论可以加入我们的社区钉钉群62730003177
<img src="https://mdn.alipayobjects.com/huamei_trbi3h/afts/img/A*UMWdT5yaPqsAAAAAAAAAAAAADpDJAQ/original" width="220" alt="dingding" />

View File

@ -0,0 +1,14 @@
import { Component, triggerEventOnly, triggerEventValues } from '../_util/simply';
import { ActionSheetDefaultProps } from './props';
Component(ActionSheetDefaultProps, {
onAction: function (e) {
var _a = e.currentTarget.dataset, item = _a.item, index = _a.index;
if (item === null || item === void 0 ? void 0 : item.disabled)
return;
triggerEventOnly(this, 'close', e);
triggerEventValues(this, 'action', [item, index], e);
},
onClose: function (e) {
triggerEventOnly(this, 'close', e);
}
});

View File

@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"ant-popup": "../Popup/index"
}
}

View File

@ -0,0 +1,45 @@
---
nav:
path: /components
group:
title: 反馈
order: 12
toc: 'content'
---
# ActionSheet 动作面板
<code src="../../docs/components/compatibility.tsx" inline="true"></code>
从底部弹出的动作菜单面板。
## 何时使用
由用户操作触发,提供一组与操作相关的两个或多个选项,让用户在不离场的情况下完成操作。相比于对话框,动作面板的位置更适合于在大屏幕时代单手操作的场景。
## 代码示例
<code src='pages/ActionSheet/index'></code>
## API
| 属性 | 说明 | 类型 | 默认值 |
| ---------- | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
| actions | 面板选项列表 | `[ActionSheetItem](#actionshetitem)`[] | [] |
| cancelText | 取消按钮文字 | string | 取消 |
| className | 类名 | string | - |
| style | 样式 | string | - |
| title | 标题 | string | - |
| visible | 是否展开 | boolean | false |
| zIndex | 弹窗层级 | number | 998 |
| onClose | 关闭时触发 | `(event: [Event](https://opendocs.alipay.com/mini/framework/event-object))` => void | - |
| onAction | 点击选项时触发,禁用状态下不会触发 | `(item: [ActionSheetItem](#actionsheetitem), index: number, event: [Event](https://opendocs.alipay.com/mini/framework/event-object))` => void | - |
### ActionSheetItem
| 属性 | 说明 | 类型 | 默认值 |
| ----------- | ------------ | ------- | ------ |
| icon | 图标 | - | - |
| danger | 是否危险模式 | boolean | false |
| description | 描述 | string | - |
| disabled | 是否禁用 | boolean | false |

View File

@ -0,0 +1,57 @@
<wxs
src="./index.wxs"
module="helper"
></wxs>
<ant-popup
className="ant-actionsheet-popup"
visible="{{visible}}"
position="bottom"
zIndex="{{zIndex}}"
bind:close="onClose"
>
<view
style="{{style}}"
class="ant-actionsheet {{className ? className : ''}} {{helper.isIconMode(actions) ? 'ant-actionsheet-icon' : ''}}"
>
<view
wx:if="{{title}}"
class="ant-actionsheet-title-wrap"
>
<view class="ant-actionsheet-title-content">{{title}}</view>
</view>
<view class="ant-actionsheet-list">
<block
wx:for="{{actions}}"
wx:for-index="index"
wx:for-item="item"
key="{{index}}"
>
<view
class="ant-actionsheet-list-item {{item.disabled ? 'ant-actionsheet-list-item-disabled' : ''}}"
hoverClass="{{item.disabled ? '' : 'ant-actionsheet-list-item-active'}}"
bind:tap="onAction"
data-index="{{index}}"
data-item="{{item}}"
>
<view
wx:if="{{helper.isIconMode(actions)}}"
class="ant-actionsheet-list-item-icon"
style="background-image: url('{{item.icon}}')"
></view>
<view class="ant-actionsheet-list-item-content">
<view class="ant-actionsheet-list-item-title {{item.danger ? 'ant-actionsheet-list-item-title-danger' : ''}}">{{item.text}}</view>
<view
wx:if="{{item.description}}"
class="ant-actionsheet-list-item-description"
>{{item.description}}</view>
</view>
</view>
</block>
</view>
<view class="ant-actionsheet-cancel-gap"></view>
<view
class="ant-actionsheet-cancel"
bind:tap="onClose"
>{{cancelText}}</view>
</view>
</ant-popup>

View File

@ -0,0 +1,8 @@
function isIconMode(actions) {
return actions.some(function (action) {
return !!action.icon;
});
}
module.exports = {
isIconMode: isIconMode
};

View File

@ -0,0 +1,105 @@
.ant-actionsheet {
padding-left: 12px;
padding-right: 12px;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
.ant-actionsheet-title-wrap {
text-align: center;
position: relative;
margin: 0 -12px;
}
.ant-actionsheet-title-content {
display: inline-block;
text-align: left;
padding: 18px 15px;
font-size: 15px;
color: #999999;
}
.ant-actionsheet-title-content::after {
content: '';
position: absolute;
background-color: #eeeeee;
display: block;
top: auto;
right: 0;
bottom: 0;
left: 0;
height: 1px;
transform: scaleY(0.5);
}
.ant-actionsheet-list {
margin: 0 -12px;
}
.ant-actionsheet-list-item {
color: #333333;
padding: 16px 15px;
text-align: center;
position: relative;
font-size: 18px;
}
.ant-actionsheet-list-item::after {
content: '';
position: absolute;
background-color: #eeeeee;
display: block;
top: auto;
right: 0;
bottom: 0;
left: 0;
height: 1px;
transform: scaleY(0.5);
}
.ant-actionsheet-list-item-title-danger {
color: #ff3141;
font-weight: bold;
}
.ant-actionsheet-list-item-description {
color: #999999;
font-size: 14px;
line-height: 20px;
margin-top: 4px;
}
.ant-actionsheet-list-item-active {
background-color: #eeeeee;
}
.ant-actionsheet-list-item:last-child.ant-actionsheet-list-item:last-child:after {
display: none;
}
.ant-actionsheet-list-item-disabled .ant-actionsheet-list-item-icon,
.ant-actionsheet-list-item-disabled .ant-actionsheet-list-item-content {
opacity: 0.4;
}
.ant-actionsheet-cancel-gap {
height: 8px;
background: #f5f5f5;
margin: 0 -12px;
}
.ant-actionsheet-cancel {
color: #333333;
padding: 16px 15px;
font-size: 18px;
text-align: center;
margin: 0 -12px;
}
.ant-actionsheet-cancel:active {
background-color: #eeeeee;
}
.ant-actionsheet-icon .ant-actionsheet-title-wrap {
text-align: left;
}
.ant-actionsheet-icon .ant-actionsheet-list-item {
display: flex;
align-items: center;
}
.ant-actionsheet-icon .ant-actionsheet-list-item-icon {
height: 24px;
flex: 0 0 24px;
margin-right: 12px;
background-size: contain;
background-position: center center;
background-repeat: no-repeat;
}
.ant-actionsheet-icon .ant-actionsheet-list-item-content {
text-align: left;
}

View File

@ -0,0 +1,8 @@
export var ActionSheetDefaultProps = {
title: '',
actions: [],
cancelText: '取消',
visible: false,
// 弹窗层级
zIndex: 998,
};

View File

@ -0,0 +1,4 @@
import '../_util/assert-component2';
import { Component } from '../_util/simply';
import { AvatarDefaultProps } from './props';
Component(AvatarDefaultProps);

View File

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

View File

@ -0,0 +1,31 @@
---
nav:
path: /components
group:
title: 信息展示
order: 8
toc: content
---
# Avatar 头像
<code src="../../docs/components/compatibility.tsx" inline="true"></code>
用来代表用户或事物。
## 何时使用
需要更加直观地展现人物或事物特征时。
## 代码示例
<code src='pages/Avatar/index'></code>
## API
| 属性 | 说明 | 类型 | 默认值 |
|---------|----------|------|-----------|
| className | 类名 | string | - |
| size | 大小,可选 `x-small``small``medium``large` | string | `medium` |
| src | 头像地址 | string | 灰色的内置图片 |
| style | 样式 | string | - |

View File

@ -0,0 +1,13 @@
<wxs
src="./index.wxs"
module="utils"
></wxs>
<view
class="ant-avatar {{className ? className : ''}}"
style="{{style}}"
>
<image
class="ant-avatar-image {{utils.getClass(size)}}"
src="{{src || utils.defaultSrc}}"
></image>
</view>

View File

@ -0,0 +1,12 @@
function getClass(size) {
var list = ['x-small', 'small', 'medium', 'large'];
if (list.indexOf(size) >= 0) {
return "ant-avatar-image-".concat(size);
}
return 'ant-avatar-image-medium';
}
var defaultSrc = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMTIwcHgiIGhlaWdodD0iMTIwcHgiIHZpZXdCb3g9IjAgMCAxMjAgMTIwIiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgogICAgPHRpdGxlPuS/oeaBr+Wxleekujo0MC/lpLTlg49BdmF0YXIv5Y2V5Zu+OjEv5bC65a+4OuWkpzwvdGl0bGU+CiAgICA8ZGVmcz4KICAgICAgICA8cGF0aCBkPSJNOCwwIEwxMTIsMCBDMTE2LjQxODI3OCwtOC4xMTYyNDUwMWUtMTYgMTIwLDMuNTgxNzIyIDEyMCw4IEwxMjAsMTEyIEMxMjAsMTE2LjQxODI3OCAxMTYuNDE4Mjc4LDEyMCAxMTIsMTIwIEw4LDEyMCBDMy41ODE3MjIsMTIwIDUuNDEwODMwMDFlLTE2LDExNi40MTgyNzggMCwxMTIgTDAsOCBDLTUuNDEwODMwMDFlLTE2LDMuNTgxNzIyIDMuNTgxNzIyLDguMTE2MjQ1MDFlLTE2IDgsMCBaIiBpZD0icGF0aC0xIj48L3BhdGg+CiAgICA8L2RlZnM+CiAgICA8ZyBpZD0iUGFnZS0xIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgICAgICA8ZyBpZD0i5aS05YOPIj4KICAgICAgICAgICAgPG1hc2sgaWQ9Im1hc2stMiIgZmlsbD0id2hpdGUiPgogICAgICAgICAgICAgICAgPHVzZSB4bGluazpocmVmPSIjcGF0aC0xIj48L3VzZT4KICAgICAgICAgICAgPC9tYXNrPgogICAgICAgICAgICA8dXNlIGlkPSJNYXNrIiBmaWxsPSIjRUVFRUVFIiBmaWxsLXJ1bGU9Im5vbnplcm8iIHhsaW5rOmhyZWY9IiNwYXRoLTEiPjwvdXNlPgogICAgICAgICAgICA8cGF0aCBkPSJNNjAuNzc4Mjk5MywyMS44MTgxODE4IEw1OS4yMjE2NTIzLDIxLjgxODE4MTggTDU4LjU3ODQzNTksMjEuODI5OTY0MSBMNTguNTc4NDM1NywyMS44Mjk5NjQxIEM0OS44MDIxNTI3LDIyLjE3NDgzNiA0Mi44NjQ3OTEzLDI5LjQxMDY0NyA0Mi44NjUyMDQzLDM4LjIxOTE2MzMgTDQyLjg2NTIwNDMsNDcuNDI0MDc1MSBMNDIuODg1NzYzNyw0OC4yMzQxMDc0IEw0Mi44ODU3NjI3LDQ4LjIzNDA4NTYgQzQzLjA5MDQ4MjMsNTIuNTUwMjgwNCA0NC45MjExODc0LDU2LjYyNzYzNTUgNDguMDA3OTc5LDU5LjY0MjI3OTQgTDUyLjExMTA1ODEsNjMuNjUxMjA1MiBMNTIuMzc1MzkzNiw2My45NDI4MTY3IEM1Mi44NzQ2OTQ0LDY0LjU1MjU0OTcgNTMuMTQ3ODQxMSw2NS4zMTgzOTg0IDUzLjE0Nzg0MTEsNjYuMTEzNzA2NiBMNTMuMTQ3ODQxMSw2Ni42NzMzNjQ1IEw1My4xMjE0MDc2LDY3LjA3NjkwODEgTDUzLjEyMTQwNzYsNjcuMDc2OTA3OSBDNTIuOTg3ODc0NSw2OC4xNTYyNzIxIDUyLjMzMDE4ODEsNjkuMDk5MzI3MyA1MS4zNjUwNDk2LDY5LjU5NTM3MDUgTDI1LjU1MTE3Myw4Mi44MzI3NjM1IEwyNS4xMDQ3MzkzLDgzLjA4MzEzNjUgTDI1LjEwNDczOTUsODMuMDgzMTM2NCBDMjMuMDY0NzcxNSw4NC4zMjk4MTQgMjEuODE5NDYyMiw4Ni41NTIwMDEgMjEuODE4MTgxOCw4OC45NDc3ODUyIEwyMS44MTgxODE4LDkwLjA5NjU1NzcgTDIxLjgzNTgwNDIsOTAuNTM4MzkzMiBDMjIuMDU5MDIwNCw5My4yODk1NTEzIDI0LjM1NTgwMjcsOTUuNDU0NTQ1NSAyNy4xNTc3NTksOTUuNDU0NTQ1NSBMOTIuODQyMjQxLDk1LjQ1NDU0NTUgTDkyLjg0MjI0MSw5NS40NTQ1NDU1IEM5NS43OTAwNjM3LDk1LjQ1NDU0NTUgOTguMTgwMTkzNiw5My4wNTg4MDI3IDk4LjE4MTgxODIsOTAuMTAyNDM5NiBMOTguMTgxODE4Miw4OC45NTM2NjcyIEM5OC4xODE4MTgyLDg2LjM3MDQwNjYgOTYuNzQyNjYyOCw4NC4wMDUxMDkxIDk0LjQ0ODgwODgsODIuODMyNzY3NSBMNjguNjM0OTMyMyw2OS41OTUzNzQ1IEw2OC42MzQ5MzIsNjkuNTk1Mzc0NCBDNjcuNTM5NzExNSw2OS4wMzM5NjU3IDY2Ljg1MDk3MDIsNjcuOTAzOTcyNyA2Ni44NTIxNDA0LDY2LjY3MDQyMyBMNjYuODUyMTQwNCw2Ni4xMTA3NjUxIEM2Ni44NTIxNDA0LDY1LjE4NTg1NTYgNjcuMjI4MDg0Nyw2NC4yOTkyMzk0IDY3Ljg4ODkyMzUsNjMuNjUxMjE4NSBMNzEuOTkyMDAyNSw1OS42NDIyOTI3IEw3MS45OTIwMDI5LDU5LjY0MjI5MjQgQzc1LjI3ODYwMTksNTYuNDMxNjgwNiA3Ny4xMzIxODU3LDUyLjAyNTQyMDQgNzcuMTMxODU1Myw0Ny40MjQwNjIyIEw3Ny4xMzE4NTUzLDM4LjIxOTE1MDQgTDc3LjEzMTg1NTMsMzguMjE5MTUxIEM3Ny4xMzE4NTUzLDI5LjE2MTE2MzMgNjkuODEwMTE5OCwyMS44MTgxODE4IDYwLjc3ODI5ODcsMjEuODE4MTgxOCBMNjAuNzc4Mjk5MywyMS44MTgxODE4IFoiIGlkPSLlvaLnirYiIGZpbGw9IiNDQ0NDQ0MiIGZpbGwtcnVsZT0ibm9uemVybyIgbWFzaz0idXJsKCNtYXNrLTIpIj48L3BhdGg+CiAgICAgICAgPC9nPgogICAgPC9nPgo8L3N2Zz4=';
module.exports = {
getClass: getClass,
defaultSrc: defaultSrc
};

View File

@ -0,0 +1,28 @@
.ant-avatar {
display: inline-flex;
align-items: center;
}
.ant-avatar-image {
width: 52px;
height: 52px;
border-radius: 4px;
}
.ant-avatar-image-x-small {
width: 40px;
height: 40px;
}
.ant-avatar-image-small {
width: 44px;
height: 44px;
}
.ant-avatar-image-medium {
width: 52px;
height: 52px;
}
.ant-avatar-image-large {
width: 60px;
height: 60px;
}
.ant-avatar-circle {
border-radius: 100vh;
}

View File

@ -0,0 +1,4 @@
export var AvatarDefaultProps = {
size: 'medium',
src: '',
};

View File

@ -0,0 +1,3 @@
import { Component } from '../_util/simply';
import { BadgeFunctionalProps } from './props';
Component(BadgeFunctionalProps);

View File

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

View File

@ -0,0 +1,34 @@
---
nav:
path: /components
group:
title: 引导提示
order: 14
toc: 'content'
---
# Badge 徽标
<code src="../../docs/components/compatibility.tsx" inline="true"></code>
徽标,显示红点、数字或文字。用于提醒用户,有待处理的事项或者新的更新数量。
## 何时使用
当需要在右上角展示数字、文字或小红点时使用。适合于提示产品化的新消息、功能或服务等内容,通过显眼的视觉形式吸引用户注意,并促使其进行相关操作。
## 代码示例
<code src="pages/Badge/index"></code>
## API
| 属性 | 说明 | 类型 | 默认值 |
| --------- | ------------------------------------ | -------------------- | ------------ |
| bgColor | 自定义背景色CSS 色值 | string | - |
| className | 组件根节点的类名 | string | - |
| offsetX | 水平方向偏移量 | string | '-50%' |
| offsetY | 垂直方向的偏移量 | string | '-50%' |
| position | 徽标相对于容器的位置,选项包括:`top-left``top-right``top-center``left``right``bottom-left``bottom-center``bottom-right` | string | `top-right` |
| stroke | 徽标是否带有描边 | boolean | false |
| style | 自定义样式 | object | - |
| text | 徽标内容,为空代表仅展示红点;可以是数字或文字;若是数字且超过 99则显示为 `...` | string \| number \| slot | - |
| type | 徽标类型,选项包括:`dot`(红点)、`number`(数字类型,超过 99 会自动转换)、`text`(文字气泡)和 `bubble`(气泡形态,带有箭头) | string | `dot` |

View File

@ -0,0 +1,54 @@
<wxs
src="./index.wxs"
module="_sjs"
></wxs>
<view
class="ant-badge {{className || ''}}"
style="{{style}}"
>
<view class="ant-badge-body">
<slot></slot>
</view>
<view
wx:if="{{type === 'dot'}}"
class="ant-badge-content"
style="{{_sjs.setPositionStyle(position, offsetX, offsetY)}}"
>
<view
class="ant-badge-dot {{stroke ? 'ant-badge-dot-stroke' : ''}}"
style="{{bgColor ? 'background-color: ' + bgColor + ';' : ''}}"
></view>
</view>
<view
wx:else
class="ant-badge-content ant-badge-content-not-dot {{type === 'bubble' ? 'ant-badge-content-' + position + '-bubble' : ''}} {{stroke ? 'ant-badge-content-stroke' : ''}}"
style="{{bgColor ? 'background-color: ' + bgColor + ';' : ''}} {{_sjs.setBubbleStyle(type, position)}};{{_sjs.setPositionStyle(position, offsetX, offsetY)}}"
>
<view class="ant-badge-icon-container"></view>
<view class="ant-badge-content-text">
<slot
name="text"
wx:if="{{!text}}"
></slot>
<block wx:if="{{text}}">
<view
wx:if="{{type === 'number'}}"
class="ant-badge-number"
>
<!--display: inline-->
<text wx:if="{{_sjs.getOverCount(text)}}">99+</text>
<!--display: inline-->
<text wx:else>{{text}}</text>
</view>
<view
wx:if="{{type === 'text'}}"
class="ant-badge-text"
>{{text}}</view>
<view
wx:if="{{type === 'bubble'}}"
class="ant-badge-bubble"
>{{text}}</view>
</block>
</view>
</view>
</view>

View File

@ -0,0 +1,54 @@
function setPositionStyle(position) {
var offsetX = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '-50%';
var offsetY = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '-50%';
var transformStyle = "transform: translate(calc(".concat(offsetX, "), calc(").concat(offsetY, "));");
switch (position) {
case 'top-left':
return "top: 0; left: 0; ".concat(transformStyle);
case 'top-center':
return "top: 0; left: 50%; ".concat(transformStyle);
case 'top-right':
return "top: 0; left: 100%; ".concat(transformStyle);
case 'left':
return "top: 50%; left: 0; ".concat(transformStyle);
case 'right':
return "top: 50%; left: 100%; ".concat(transformStyle);
case 'bottom-left':
return "top: 100%; left: 0; ".concat(transformStyle);
case 'bottom-center':
return "top: 100%; left: 50%; ".concat(transformStyle);
case 'bottom-right':
return "top: 100%; left: 100%; ".concat(transformStyle);
default:
return "top: 0; left: 0; ".concat(transformStyle);
}
}
function setBubbleStyle(type, position) {
if (type !== 'bubble') return '';
switch (position) {
case 'top-left':
return 'border-bottom-right-radius: 0;';
case 'top-right':
return 'border-bottom-left-radius: 0;';
case 'bottom-left':
return 'border-top-right-radius: 0;';
case 'bottom-right':
return 'border-top-left-radius: 0;';
default:
return '';
}
}
function getOverCount(text) {
var overCount = false;
if (typeof text === 'number') {
if (text >= 100) {
overCount = true;
}
}
return overCount;
}
module.exports = {
setPositionStyle: setPositionStyle,
setBubbleStyle: setBubbleStyle,
getOverCount: getOverCount
};

View File

@ -0,0 +1,53 @@
.ant-badge {
display: inline-block;
position: relative;
}
.ant-badge-content {
position: absolute;
display: flex;
height: 14px;
align-self: center;
align-items: center;
font-size: 9px;
padding: 2px 4px;
box-sizing: border-box;
word-break: keep-all;
justify-content: center;
top: 0;
left: 100%;
transform: translate(-50%, -50%);
}
.ant-badge-content-stroke {
border: 1px solid #ffffff;
}
.ant-badge-content-text {
padding-left: 2px;
}
.ant-badge-content-text:empty {
display: none;
}
.ant-badge-content .ant-icon {
font-size: 9px;
color: #ffffff;
}
.ant-badge-content-not-dot {
min-width: 14px;
height: 14px;
border-radius: 14px;
display: flex;
background-color: #ff3141;
}
.ant-badge-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background-color: #ff3141;
}
.ant-badge-dot-stroke {
border: 1px solid #ffffff;
}
.ant-badge-number,
.ant-badge-text,
.ant-badge-bubble {
color: #ffffff;
}

View File

@ -0,0 +1,15 @@
export var BadgeDefaultProps = {
position: 'top-right',
stroke: false,
type: 'dot',
bgColor: '',
};
export var BadgeFunctionalProps = {
type: 'dot',
text: null,
position: 'top-right',
offsetX: null,
offsetY: null,
stroke: false,
bgColor: '',
};

View File

@ -0,0 +1,74 @@
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
/* eslint-disable @typescript-eslint/ban-ts-comment */
import { ButtonDefaultProps } from './props';
Component({
properties: {
className: String,
style: String,
disabled: Boolean,
activeClassName: String,
subText: String,
inline: Boolean,
size: {
type: String,
value: 'medium',
},
icon: String,
loading: Boolean,
danger: Boolean,
formType: {
type: String,
value: 'button',
},
publicId: String,
openType: String,
scope: String,
type: {
type: String,
value: 'default',
},
},
options: {
styleIsolation: 'shared',
},
props: ButtonDefaultProps,
methods: __assign({
onGetUserInfo: function (event) {
this.triggerEvent('getuserinfo', event.detail);
},
onContact: function (event) {
this.triggerEvent('contact', event.detail);
},
onGetPhoneNumber: function (event) {
this.triggerEvent('getphonenumber', event.detail);
},
onGetRealTimePhoneNumber: function (event) {
this.triggerEvent('getrealtimephonenumber', event.detail);
},
onError: function (event) {
this.triggerEvent('error', event.detail);
},
onLaunchApp: function (event) {
this.triggerEvent('launchapp', event.detail);
},
onOpenSetting: function (event) {
this.triggerEvent('opensetting', event.detail);
},
onAgreePrivacyAuthorization: function (event) {
this.triggerEvent('agreeprivacyauthorization', event.detail);
},
onChooseAvatar: function (event) {
this.triggerEvent('chooseavatar', event.detail);
},
}),
});

View File

@ -0,0 +1,7 @@
{
"component": true,
"usingComponents": {
"loading": "../Loading/index",
"ant-icon": "../Icon/index"
}
}

View File

@ -0,0 +1,77 @@
---
nav:
path: /components
group:
title: 通用
order: 2
toc: 'content'
---
# Button 按钮
<code src="../../docs/components/compatibility.tsx" inline="true"></code>
用于开始一个即时操作。
## 何时使用
标记了一个(或封装一组)操作命令,响应用户点击行为,触发相应的业务逻辑。
## 代码示例
### 基本使用
<code src='pages/Button/index'></code>
### Inline
<code src='pages/ButtonInline/index'></code>
### Icon
<code src='pages/ButtonIcon/index'></code>
### 更多自定义
<code src='pages/ButtonCustom/index'></code>
## API
### Button
以下表格介绍了 Button 组件的 API 属性:
| 属性 | 说明 | 类型 | 默认值 |
| --------------- | --------------------------------------------------------------- | ----------------------------------------------------------------------------- | --------- |
| type | 按钮类型,可选 `primary``default``text` | string | `default` |
| danger | 是否为危险按钮 | boolean | false |
| disabled | 是否为失效按钮 | boolean | false |
| activeClassName | 按下时的类名 | string | - |
| className | 类名 | string | - |
| style | 样式 | string | - |
| inline | 是否为内联按钮 | boolean | false |
| icon | 按钮左侧图标 | string | - |
| loading | 是否加载中,加载中时不可点击 | boolean | - |
| size | 按钮大小。仅在 `inline` 下生效,可选 `small``medium``large` | string | `medium` |
| subText | 辅助文字,显示在第二行。`inline` 下不生效 | string | - |
| catchTap | 点击按钮,触发此回调,非冒泡 | (e: [Event](https://opendocs.alipay.com/mini/framework/event-object)) => void | - |
| onTap | 点击按钮,触发此回调 | (e: [Event](https://opendocs.alipay.com/mini/framework/event-object)) => void | - |
| onDisabledTap | 禁用时点击出发回调(微信不支持) | (e: [Event](https://opendocs.alipay.com/mini/framework/event-object)) => void | - |
### 更多属性
以下是 Button 组件支持的其他属性:
- `public-id`
- `open-type`
- `scope`
- `form-type`
- `onGetAuthorize`
- `onFollowLifestyle`
- `onError`
- `onGetUserInfo`
- `onGetPhoneNumber`
具体的属性说明,请参考支付宝小程序的官方文档。
[Button 组件属性说明](https://opendocs.alipay.com/mini/component/button#%E5%B1%9E%E6%80%A7%E8%AF%B4%E6%98%8E)

View File

@ -0,0 +1,46 @@
<wxs
src="./index.wxs"
module="utils"
></wxs>
<button
formType="{{formType}}"
hoverClass="{{utils.getHoverClass(loading, type, activeClassName)}}"
scope="{{scope}}"
bindgetuserinfo="onGetUserInfo"
bindcontact="onContact"
bindgetphonenumber="onGetPhoneNumber"
bindgetrealtimephonenumber="onGetRealTimePhoneNumber"
binderror="onError"
bindlaunchapp="onLaunchApp"
bindopensetting="onOpenSetting"
bindagreeprivacyauthorization="onAgreePrivacyAuthorization"
bindchooseavatar="onChooseAvatar"
publicId="{{publicId}}"
openType="{{openType}}"
class="ant-button {{inline ? 'ant-button-inline ' + utils.getClass(size) : ''}} {{'ant-button-' + type + (danger ? '-danger' : '')}} {{disabled || loading ? 'ant-button-disabled' : ''}} {{className ? className : ''}}"
style="{{style}}"
>
<view class="ant-button-wrap">
<ant-icon
wx:if="{{!!icon}}"
type="{{icon}}"
></ant-icon>
<view class="ant-button-content-text {{icon ? 'ant-button-content-text-margin' : ''}}">
<slot></slot>
<view
wx:if="{{!inline && subText}}"
class="ant-button-content-subtext"
>{{subText}}</view>
</view>
<view
wx:if="{{loading}}"
class="ant-button-content-loading-container"
>
<loading
type="mini"
color="currentColor"
className="ant-button-content-loading"
></loading>
</view>
</view>
</button>

View File

@ -0,0 +1,24 @@
function getClass(size) {
var list = ['small', 'medium', 'large'];
if (list.indexOf(size) >= 0) {
return "ant-button-".concat(size);
}
return 'ant-button-medium';
}
function getHoverClass(loading, type, activeClassName) {
if (loading) {
return '';
}
var className = 'ant-button-active';
if (type === 'text') {
className += ' ant-button-text-active';
}
if (activeClassName) {
className += ' ' + activeClassName;
}
return className;
}
module.exports = {
getClass: getClass,
getHoverClass: getHoverClass
};

View File

@ -0,0 +1,112 @@
.ant-button {
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: auto;
line-height: normal;
padding: 12px;
border-radius: 4px;
border: 0 none;
box-sizing: border-box;
font-size: 18px;
z-index: 2;
}
.ant-button-large {
font-size: 18px;
padding: 12px 12px 12px 12px;
}
.ant-button-medium {
font-size: 17px;
padding: 8px 12px 8px 12px;
}
.ant-button-small {
font-size: 15px;
padding: 4px 12px 4px 12px;
}
.ant-button-primary {
color: #ffffff;
background-color: #1677ff;
box-shadow: inset 0 0 0 1px #1677ff;
}
.ant-button-default {
color: #1677ff;
background-color: #ffffff;
box-shadow: inset 0 0 0 1px #1677ff;
}
.ant-button-text {
color: #1677ff;
background-color: transparent;
box-shadow: none;
}
.ant-button-primary-danger {
color: #ffffff;
background-color: #ff3141;
box-shadow: inset 0 0 0 1px #ff3141;
}
.ant-button-default-danger {
color: #ff3141;
background-color: #ffffff;
box-shadow: inset 0 0 0 1px #ff3141;
}
.ant-button-text-danger {
color: #ff3141;
background-color: transparent;
box-shadow: none;
}
.ant-button-text-active {
background-color: rgba(255, 255, 255, 0.92);
}
.ant-button-active {
filter: brightness(0.92);
}
.ant-button-disabled {
opacity: 0.4;
}
.ant-button-wrap {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.ant-button-content-text-margin {
margin-left: 8px;
}
.ant-button-content-text:empty {
margin-left: 0;
width: 0;
opacity: 0;
}
.ant-button-content-text:empty::after {
content: '\00a0';
}
.ant-button-content-subtext {
font-size: 12px;
opacity: 0.6;
}
.ant-button-content-loading-container {
display: flex;
justify-content: center;
align-items: center;
width: 33px;
height: 16px;
margin-left: 8px;
}
.ant-button-content-loading {
position: relative;
}
.ant-button-inline {
display: inline-block;
border-radius: 4px;
}
.ant-button-inline .ant-button-content-loading-container {
width: 16px;
height: 16px;
}
.ant-button-inline .ant-button-content-loading {
transform: scale(0.5);
}
.ant-button::after {
border-width: 0;
}

View File

@ -0,0 +1,5 @@
export var ButtonDefaultProps = {
type: 'default',
formType: 'button',
size: 'medium',
};

View File

@ -0,0 +1,28 @@
/* size | 按钮内间距 */
/* corner-radius| 按钮圆角 */
/* font-size | 副标题字号 */
/* color | 按钮边框宽度 */
/* opacity | disable状态不透明度 */
/* color | 默认按钮文字色 */
/* color | 默认按钮背景色 */
/* color | 默认按钮边框色 */
/* color |primary按钮背景色 */
/* color |primary按钮边框色 */
/* color |primary按钮文字色 */
/* color |ghost按钮边框色 */
/* color |ghost按钮文字色 */
/* color |danger按钮背景色 */
/* color |danger按钮边框色 */
/* color |danger按钮文字色 */
/* color |danger-ghost按钮边框色 */
/* color |danger-ghost按钮文字色 */
/* color |light按钮背景色 */
/* color |light按钮边框色 */
/* color |light按钮文字色 */
/* size | 胶囊按钮圆角 */
/* size | 胶囊按钮水平内间距 */
/* size | 胶囊按钮垂直内间距 */
/* font-size | 胶囊按钮大字号 */
/* font-size | 胶囊按钮中字号 */
/* font-size | 胶囊按钮小字号 */
/* 图标尺寸 */

View File

@ -0,0 +1,84 @@
function keys(obj) {
return JSON.stringify(obj).replace(getRegExp('{|}|"', 'g'), '').split(',').map(function (item) {
return item.split(':')[0];
});
}
function getClassName(value, index, showSelectableDatesOnly) {
var isSelected = value.isSelected,
isSelectedBegin = value.isSelectedBegin,
isSelectedEnd = value.isSelectedEnd,
isRowBegin = value.isRowBegin,
isRowEnd = value.isRowEnd,
inThisMonth = value.inThisMonth,
isToday = value.isToday,
disabled = value.disabled,
className = value.className,
isRange = value.isRange;
var classNames = {
disabled: disabled,
today: inThisMonth && isToday,
selected: inThisMonth && isSelected,
'selected-begin': inThisMonth && isSelectedBegin,
'selected-end': inThisMonth && isSelectedEnd,
'selected-row-begin': inThisMonth && isRowBegin && isSelected,
'selected-row-end': inThisMonth && isRowEnd && isSelected,
hidden: !inThisMonth || showSelectableDatesOnly && !isRange,
'row-end': index % 7 === 6
};
var result = "ant-calendar-cell ".concat(className || '');
keys(classNames).forEach(function (key) {
if (classNames[key]) {
result += " ant-calendar-cell-".concat(key);
}
});
return result;
}
function getSpaceClassName(index, items) {
var isNotEnd = index % 7 !== 6;
var nextItem = items[index + 1];
var nextSelected = nextItem && nextItem.isSelected && nextItem.inThisMonth;
var isSelected = items[index].isSelected;
var classNames = {
active: isNotEnd && isSelected && nextSelected
};
var result = 'ant-calendar-cell-space';
keys(classNames).forEach(function (key) {
if (classNames[key]) {
result += " ant-calendar-cell-space-".concat(key);
}
});
return result;
}
function getMarkCellClassName(index, items) {
if (items[index].length - 1 === index) {
return "ant-calendar-mark-cell ant-calendar-mark-cell-last";
}
return 'ant-calendar-mark-cell';
}
function isDisplay(index, items) {
// 找到需要当前月需要展示的日期最大最小索引
var _items_reduce = items.reduce(function (res, item) {
// !item.inThisMonth 被隐藏掉的日期
// !item.isRange 不在传入范围内的日期
if (!(!item.inThisMonth || !item.isRange)) {
if (res.minIndex === null || res.maxIndex === null) {
res.minIndex = item.index;
res.maxIndex = item.index;
}
res.minIndex = Math.min(res.minIndex, item.index);
res.maxIndex = Math.max(res.maxIndex, item.index);
}
return res;
}, {
minIndex: null,
maxIndex: null
});
if (_items_reduce.maxIndex === null || _items_reduce.maxIndex === null) return true;
return index >= Math.floor(_items_reduce.minIndex / 7) * 7 && index < Math.ceil(_items_reduce.maxIndex / 7) * 7;
}
module.exports = {
getSpaceClassName: getSpaceClassName,
getClassName: getClassName,
getMarkCellClassName: getMarkCellClassName,
isDisplay: isDisplay
};

View File

@ -0,0 +1,300 @@
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
import dayjs from 'dayjs';
import equal from 'fast-deep-equal';
import { Component, triggerEvent, getValueFromProps } from '../_util/simply';
import { defaultLocaleText, CalendarDefaultProps, } from './props';
import { getMonthListFromRange, getSelectionModeFromValue, renderCells, getScrollIntoViewId, } from './utils';
import mixinValue from '../mixins/value';
import { getInstanceBoundingClientRect } from '../_util/jsapi/get-instance-bounding-client-rect';
Component(CalendarDefaultProps, {
getInstance: function () {
if (this.$id) {
return my;
}
return this;
},
getBoundingClientRect: function (query) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, getInstanceBoundingClientRect(this.getInstance(), query)];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
},
scrollIntoView: function (value) {
this.updateScrollIntoViewId(getScrollIntoViewId(value));
},
clickCell: function (e) {
var _a, _b;
var time = e.currentTarget.dataset.time;
var clickDate = dayjs(time.time);
if (time.disabled) {
return;
}
var value = this.getValue();
var selectionModeFromValue = getSelectionModeFromValue(value);
var selectionMode = (_b = (_a = getValueFromProps(this, 'selectionMode')) !== null && _a !== void 0 ? _a : selectionModeFromValue) !== null && _b !== void 0 ? _b : 'range';
if (selectionMode === 'range') {
if (Array.isArray(value)) {
if (value.length === 1) {
var current = value[0];
if (dayjs(clickDate.toDate().getTime()).isBefore(dayjs(current))) {
this.updateValue([clickDate.toDate().getTime()]);
}
else {
this.updateValue([value[0], clickDate.toDate().getTime()]);
}
}
else {
this.updateValue([clickDate.toDate().getTime()]);
}
}
else {
this.updateValue([clickDate.toDate().getTime()]);
}
}
else if (selectionMode === 'single') {
this.updateValue(clickDate.toDate().getTime());
}
},
setCurrentMonth: function (e) {
this.setData({ headerState: e.month });
},
measurement: function () {
var elementSize = this.data.elementSize;
// 组件如果内嵌在 slot 里, 一定会被渲染出来, 但是此时 cellHight 为 0
// 此时需要重新计算
if (!elementSize || elementSize.cellHight === 0) {
this.measurementFn();
}
},
measurementFn: function () {
var _this = this;
Promise.all([
this.getBoundingClientRect('.ant-calendar-body-container'),
this.getBoundingClientRect('.ant-calendar-cells'),
this.getBoundingClientRect('.ant-calendar-title-container'),
])
.then(function (_a) {
var bodyContainer = _a[0], cellContainer = _a[1], Title = _a[2];
// 滚动的时候 top 和 bottom 等尺寸会变
// 所以只能依赖 height 来计算
var paddingHeight = bodyContainer.height - cellContainer.height - Title.height;
var monthTitleHeight = Title.height + paddingHeight;
var cellHight = cellContainer.height / (_this.data.monthList[0].cells.length / 7);
_this.setData({
elementSize: {
monthTitleHeight: monthTitleHeight,
cellHight: cellHight,
paddingHeight: paddingHeight,
},
});
})
.catch(function () {
_this.setData({ elementSize: null });
});
},
// scroll 触发滚动之后需要重置 scrollIntoViewId
updateScrollIntoViewId: function (id) {
var _this = this;
this.setData({ scrollIntoViewId: id });
var timer = setTimeout(function () {
_this.setData({ scrollIntoViewId: '' });
clearTimeout(timer);
});
},
updateValue: function (newValue) {
triggerEvent(this, 'change', newValue);
if (!this.isControlled()) {
this.update(newValue);
}
},
updateData: function () {
var _a = getValueFromProps(this, [
'monthRange',
'localeText',
'weekStartsOn',
'onFormatter',
'onMonthFormatter',
]), monthRange = _a[0], plocaleText = _a[1], pweekStartsOn = _a[2], onFormatter = _a[3], onMonthFormatter = _a[4];
var localeText = Object.assign({}, defaultLocaleText, plocaleText);
var markItems = __spreadArray([], localeText.weekdayNames, true);
var weekStartsOn = pweekStartsOn;
if (weekStartsOn === 'Sunday') {
var item = markItems.pop();
if (item)
markItems.unshift(item);
}
var value = this.getValue();
var start = dayjs(monthRange === null || monthRange === void 0 ? void 0 : monthRange[0]).startOf('d');
var end = dayjs(monthRange === null || monthRange === void 0 ? void 0 : monthRange[1]).startOf('d');
var monthRangeList = getMonthListFromRange(start, end);
var monthList = monthRangeList.map(function (p) {
var cells = renderCells(p, weekStartsOn, value, localeText,
// 如果monthRange传入异常用内置的时间范围
start.isAfter(end) || start.isSame(end)
? [monthRangeList[0], dayjs(monthRangeList[1]).endOf('month')]
: [start, end]);
if (onFormatter && typeof onFormatter === 'function') {
cells = cells.map(function (o) {
var _a;
var time = o.time, top = o.top, bottom = o.bottom, disabled = o.disabled, isSelectedBegin = o.isSelectedBegin, isSelectedEnd = o.isSelectedEnd, isSelected = o.isSelected, className = o.className, isRange = o.isRange;
var newState = (_a = onFormatter({
time: time,
top: top ? __assign({}, top) : undefined,
bottom: bottom ? __assign({}, bottom) : undefined,
disabled: disabled,
isSelectedBegin: isSelectedBegin,
isSelectedEnd: isSelectedEnd,
isSelected: isSelected,
className: className,
isRange: isRange,
}, value)) !== null && _a !== void 0 ? _a : {};
var result = __assign({}, o);
if (typeof newState === 'object') {
// 只允许修改的字段字段
['top', 'bottom', 'disabled', 'className'].forEach(function (key) {
if (key in newState) {
result[key] = newState[key];
}
});
}
return result;
});
}
var month = {
title: p.format(localeText.title),
className: '',
cells: cells,
};
if (onMonthFormatter && typeof onMonthFormatter === 'function') {
month = __assign(__assign({}, month), onMonthFormatter(p));
}
return month;
});
this.setData({ markItems: markItems, monthList: monthList });
},
}, {
elementSize: null,
markItems: [],
monthList: [],
headerState: 0,
scrollIntoViewId: '',
}, [mixinValue()], {
didMount: function () {
this.updateData();
this.measurementFn();
// 初始化默认值时,滚动到选中位置
var _a = getValueFromProps(this, [
'value',
'defaultValue',
]), value = _a[0], defaultValue = _a[1];
if (this.isControlled()) {
this.updateScrollIntoViewId(getScrollIntoViewId(value));
}
else {
defaultValue &&
this.updateScrollIntoViewId(getScrollIntoViewId(defaultValue));
}
},
didUpdate: function (prevProps, prevData) {
if (!this.isEqualValue(prevData)) {
// 滚动到已选的位置
var changedScrollIntoView = getValueFromProps(this, 'changedScrollIntoView');
changedScrollIntoView &&
this.updateScrollIntoViewId(getScrollIntoViewId(this.getValue()));
}
if (!equal(prevProps, this.props) || !this.isEqualValue(prevData)) {
this.updateData();
}
},
attached: function () {
this.updateData();
this.measurementFn();
// 初始化默认值时,滚动到选中位置
var _a = getValueFromProps(this, [
'value',
'defaultValue',
]), value = _a[0], defaultValue = _a[1];
if (this.isControlled()) {
this.updateScrollIntoViewId(getScrollIntoViewId(value));
}
else {
defaultValue &&
this.updateScrollIntoViewId(getScrollIntoViewId(defaultValue));
}
this.triggerEvent('ref', this);
},
observers: {
'**': function (data) {
var prevData = this._prevData || this.data;
this._prevData = __assign({}, data);
if (!equal(prevData, data)) {
this.updateData();
}
},
'mixin.value': function () {
// 滚动到已选的位置
var changedScrollIntoView = getValueFromProps(this, 'changedScrollIntoView');
changedScrollIntoView &&
this.updateScrollIntoViewId(getScrollIntoViewId(this.getValue()));
},
},
});

View File

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

View File

@ -0,0 +1,175 @@
---
nav:
path: /components
group:
title: 信息展示
order: 8
toc: 'content'
---
# Calendar 日历
<code src="../../docs/components/compatibility.tsx" inline="true"></code>
日历组件
## 代码示例
<code src='pages/Calendar/index' ></code>
## API
以下为日历组件的属性及描述:
| 属性 | 说明 | 类型 | 默认值 |
| ----------------------- | ---------------------------------------------- | ----------------------------------------------------------- | ----------- |
| defaultValue | 初始值 | CalendarValue | 无 |
| value | 日历选择的日期,传入后即为受控模式 | CalendarValue | 无 |
| selectionMode | 设置选择模式,单选或者连续区间,默认为 `range` | `single` \| `range` | `range` |
| monthRange | 月份范围,默认为最近 3 个月 | `[number, number]` | 最近 3 个月 |
| weekStartsOn | 星期栏,以周几作为第一天显示。默认为 `Sunday` | `Sunday` \| `Monday` | `Sunday` |
| onChange | 日期变化回调 | (date: CalendarValue) => void | 无 |
| onFormatter | 用于设置单元格的自定义数据 | (cell: CellState, currentValue: CalendarValue) => CellState | 无 |
| onMonthFormatter | 用于设置月份的自定义数据 | (month: any) => CellState | 无 |
| localeText | 国际化文案 | Partial`<LocaleText>` | 无 |
| changedScrollIntoView | 选中值改变后是否滚动视图 | boolean | 无 |
| showSelectableDatesOnly | 只展示在可选范围内的日期 | boolean | false |
### 类型
**CalendarValue** : 日历的值类型,为数字或数字元组 `number | [number,number]`,表示单选或连续日期区间。单位为毫秒的时间戳。
**CellState** : 定义了日历单元格的各种状态。
```typescript
interface CellState {
/**
* 是否禁用
*/
disabled: boolean;
/**
* 日历单元格的顶部内容
*/
top?: { label: string; className?: string };
/**
* 日历单元格的底部内容
*/
bottom?: { label: string; className?: string };
/**
* 时间戳
*/
time: number;
/**
* 日期
*/
date: number;
/**
* 是否选中
*/
isSelected: boolean;
}
```
**LocaleText** : 提供国际化支持的文案结构。
```typescript
interface LocaleText {
/**
* 星期的名称,从周一至周日
* 默认为 ['一', '二', '三', '四', '五', '六', '日']
*/
weekdayNames: string[];
/**
* 月份标题的格式,默认为 'YYYY年MM月'
*/
title: string;
/**
* 今天的文案,默认为 '今日'
*/
today: string;
/**
* 开始的文案,默认为 '开始'
*/
start: string;
/**
* 结束的文案,默认为 '结束'
*/
end: string;
/**
* 开始与结束的文案,默认为 '开始/结束'
*/
startAndEnd: string;
}
```
## FAQ
### 如何设置默认的开始与结束时间?
通过 `defaultValue` 可以设置默认的时间。`defaultValue` 的类型是 `CalendarValue`
`CalendarValue` 的类型是 `number | [number, number]`,代表单选或者连续区间的日期。它是一个时间戳,单位是毫秒。
例如,如果我们想设置默认的开始时间为今天,结束时间为七天后,我们可以在 `defaultValue` 中传入以下代码:
```ts
[dayjs().startOf('date'), dayjs().add(7, 'days').startOf('date')];
```
### 通过 `onFormatter` 设置单元格的自定义数据
我们可以通过 `onFormatter` 方法设置单元格的自定义数据,`onFormatter` 的格式是 `(cell: CellState, currentValue: CalendarValue) => CellState`
这个函数会获取每个单元格的状态以及当前的值。通过返回新的单元格数据,我们可以自定义单元格的状态。
以下是一些常见的使用场景:
#### 如何让当天之前的时间不可选?
在支付宝小程序中,我们可以通过页面上的方法设置,需要在 axml 文件中传入一个方法名字符串。
axml 文件:
```xml
<calendar onFormatter="handleFormat" />
```
ts 文件:
```ts
import dayjs from 'dayjs';
Page({
handleFormat(cell: CellState) {
// 如果单元格代表的时间早于今天的开始时间,则禁止选择
return {
disabled: dayjs(cell.time).isBefore(dayjs().startOf('date')),
};
},
});
```
在微信小程序,我们也可以通过 data 中的函数来设置,此时在 wxml 文件中需要传入一个变量名。
wxml 文件:
```xml
<calendar onFormatter="{{ handleFormat }}" />
```
ts 文件:
```ts
import dayjs from 'dayjs';
Page({
data: {
handleFormat: (cell: CellState) => {
// 如果单元格代表的时间早于今天的开始时间,则禁止选择
return {
disabled: dayjs(cell.time).isBefore(dayjs().startOf('date')),
};
},
},
});
```

View File

@ -0,0 +1,99 @@
<wxs
src="./helper.wxs"
module="helper"
></wxs>
<wxs
src="./scroll.wxs"
module="scroll"
></wxs>
<view
class="ant-calendar {{className ? className : ''}}"
style="{{style}}"
>
<view class="ant-calendar-mark">
<block
wx:for="{{markItems}}"
wx:for-index="index"
wx:for-item="item"
>
<view class="{{helper.getMarkCellClassName(index, markItems)}}">
<!--display: inline-->
<text>{{item}}</text>
</view>
</block>
</view>
<view
wx:if="{{!!elementSize}}"
class="ant-calendar-sticky"
>
<view class="ant-calendar-sticky-title">
<view class="ant-calendar-title">{{monthList[headerState].title}}</view>
</view>
</view>
<scroll-view
scrollY="{{true}}"
class="ant-calendar-body"
data-elementsize="{{elementSize}}"
data-monthlist="{{monthList}}"
bind:scroll="{{scroll.handleScroll}}"
scrollIntoView="{{scrollIntoViewId}}"
scrollWithAnimation
scrollAnimationDuration="{{300}}"
disableLowerScroll="out-of-bounds"
disableUpperScroll="out-of-bounds"
bind:ref="handleRef"
>
<block
wx:for="{{monthList}}"
wx:for-index="index"
wx:for-item="currentMonth"
>
<view
class="ant-calendar-body-container {{currentMonth.className || ''}}"
style="{{currentMonth.style || ''}}"
>
<view class="ant-calendar-title-container">
<view class="ant-calendar-title">{{currentMonth.title}}</view>
</view>
<view class="ant-calendar-cells">
<block
wx:for="{{currentMonth.cells}}"
wx:for-index="index"
wx:for-item="item"
>
<block wx:if="{{helper.isDisplay(index, currentMonth.cells)}}">
<view
class="{{helper.getClassName(item, index, showSelectableDatesOnly)}}"
id="id_{{item.time}}"
data-time="{{item}}"
bind:tap="clickCell"
>
<view class="ant-calendar-cell-container">
<view class="ant-calendar-cell-top">
<!--display: inline-->
<text
wx:if="{{item.top}}"
class="ant-calendar-cell-top-text {{item.top.className ? item.top.className : ''}}"
>{{item.top.label}}</text>
</view>
<view class="ant-calendar-cell-center">{{item.date}}</view>
<view class="ant-calendar-cell-bottom">
<!--display: inline-->
<text
wx:if="{{item.bottom}}"
class="{{item.bottom.className}}"
>{{item.bottom.label}}</text>
</view>
</view>
</view>
<view
wx:if="{{index % 7 !== 6}}"
class="{{helper.getSpaceClassName(index, currentMonth.cells)}}"
></view>
</block>
</block>
</view>
</view>
</block>
</scroll-view>
</view>

View File

@ -0,0 +1,146 @@
.ant-calendar {
color: #333333;
position: relative;
display: flex;
flex-direction: column;
height: 100%;
}
.ant-calendar-body {
flex: 1;
overflow: hidden;
}
.ant-calendar-sticky {
position: absolute;
top: 0px;
left: 0px;
max-height: 41px;
width: 100%;
overflow: hidden;
top: 44px;
z-index: 1000;
}
.ant-calendar-mark {
height: 44px;
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
box-sizing: border-box;
font-size: 14px;
padding: 0 8px;
}
.ant-calendar-mark .ant-calendar-mark-cell {
flex: 1;
text-align: center;
width: calc((100% - 6 * 5px) / 7);
margin-right: 5px;
}
.ant-calendar-mark .ant-calendar-mark-cell-last {
margin-right: 0;
}
.ant-calendar-title {
color: #333333;
font-size: 18px;
height: 41px;
line-height: 41px;
padding-left: 20px;
margin-bottom: 4px;
background: #f8f8f8;
}
.ant-calendar-cells {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-start;
align-items: stretch;
padding: 0 8px;
}
.ant-calendar-cell-space {
width: 5px;
height: 55px;
}
.ant-calendar-cell-space-active {
background: rgba(22, 119, 255, 0.1);
}
.ant-calendar-cell {
box-sizing: border-box;
width: calc((100% - 6 * 5px) / 7);
height: 55px;
margin-bottom: 4px;
position: relative;
}
.ant-calendar-cell-container {
box-sizing: border-box;
padding-top: 3.5px;
height: 100%;
}
.ant-calendar-cell-top {
color: #999999;
text-align: center;
font-size: 9px;
height: 12.5px;
}
.ant-calendar-cell-top-text {
white-space: nowrap;
}
.ant-calendar-cell-center {
text-align: center;
height: 22.5px;
font-size: 16px;
}
.ant-calendar-cell-bottom {
color: #999999;
text-align: center;
font-size: 9px;
height: 12.5px;
}
.ant-calendar-cell-selected {
background: rgba(22, 119, 255, 0.1);
}
.ant-calendar-cell-selected-begin {
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
background: rgba(22, 119, 255, 0.1);
}
.ant-calendar-cell-selected-end {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
color: #ffffff;
}
.ant-calendar-cell-selected-row-end {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.ant-calendar-cell-selected-row-begin {
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
.ant-calendar-cell-selected-begin .ant-calendar-cell-container {
background: #1677ff;
border-radius: 4px;
color: #ffffff;
}
.ant-calendar-cell-selected-end .ant-calendar-cell-container {
background: #1677ff;
border-radius: 4px;
color: #ffffff;
}
.ant-calendar-cell-selected-end .ant-calendar-cell-top {
color: #ffffff;
}
.ant-calendar-cell-selected-begin .ant-calendar-cell-top {
color: #ffffff;
}
.ant-calendar-cell-selected-end .ant-calendar-cell-bottom {
color: #ffffff;
}
.ant-calendar-cell-selected-begin .ant-calendar-cell-bottom {
color: #ffffff;
}
.ant-calendar-cell-disabled {
opacity: 0.4;
}
.ant-calendar-cell-hidden {
opacity: 0;
pointer-events: none;
}

View File

@ -0,0 +1,21 @@
import { defaultMonthRange } from './utils';
export var defaultLocaleText = {
weekdayNames: ['一', '二', '三', '四', '五', '六', '日'],
title: 'YYYY年MM月',
today: '今日',
start: '开始',
end: '结束',
startAndEnd: '开始/结束',
};
export var CalendarDefaultProps = {
defaultValue: null,
value: null,
selectionMode: 'range',
monthRange: defaultMonthRange(),
weekStartsOn: 'Sunday',
localeText: defaultLocaleText,
onFormatter: null,
onMonthFormatter: null,
changedScrollIntoView: null,
showSelectableDatesOnly: false,
};

View File

@ -0,0 +1,45 @@
function handleScroll(event, ownerComponent) {
var currentScroll = event.detail.scrollTop;
var dataset = event.instance.getDataset();
var elementSize = dataset.elementsize,
monthList = dataset.monthlist;
if (!elementSize) {
return;
}
// 组件如果内嵌在 slot 里, 一定会被渲染出来, 但是此时 cellHight 为 0
if (elementSize.cellHight === 0) {
ownerComponent.callMethod('measurement');
return;
}
var instance = ownerComponent.selectComponent('.ant-calendar-sticky-title');
var sticky = ownerComponent.selectComponent('.ant-calendar-sticky');
if (sticky) {
sticky.setStyle({
display: currentScroll < 0 ? 'none' : 'block'
});
}
var monthHeight = elementSize.monthTitleHeight;
var paddingHeight = elementSize.paddingHeight;
var cellHeight = elementSize.cellHight;
var heightList = monthList.map(function (p) {
return monthHeight + cellHeight * p.cells.length / 7;
});
for (var i = 0; i < heightList.length; i++) {
if (currentScroll < heightList[i]) {
var topHeight = currentScroll - heightList[i] + monthHeight - paddingHeight;
topHeight = Math.max(topHeight, 0);
instance.setStyle({
transform: "translateY(-".concat(topHeight, "px)")
});
ownerComponent.callMethod('setCurrentMonth', {
month: topHeight > monthHeight * 0.8 ? i + 1 : i
});
break;
} else {
currentScroll = currentScroll - heightList[i];
}
}
}
module.exports = {
handleScroll: handleScroll
};

View File

@ -0,0 +1,157 @@
import dayjs from 'dayjs';
import { isoWeekday } from '../_util/dayjs/iso-weekday';
export function getMonthListFromRange(start, end) {
if (start.isAfter(end))
throw new Error("Start time can't be later than end time.");
var result = [];
var current = start.date(1);
while (!current.isAfter(end)) {
result.push(current.date(1));
current = current.add(1, 'month');
}
return result;
}
export function defaultMonthRange() {
var start = dayjs().startOf('date');
var end = dayjs().startOf('date').add(2, 'month');
return [start.toDate().getTime(), end.toDate().getTime()];
}
/**
*
* @param month 月份的某一天
* @param weekStartsOn 日历以星期几开始
* @returns 获取当月日历所有的日子
*/
export function getDate(month, weekStartsOn) {
var startOfMonth = month.date(1);
var cells = [];
var iterator = startOfMonth
.subtract(isoWeekday(startOfMonth) % 7, 'day')
.startOf('day');
if (weekStartsOn === 'Monday') {
iterator = iterator.add(1, 'day');
if (iterator.isSame(startOfMonth, 'month') &&
!iterator.isSame(startOfMonth.startOf('date'), 'date')) {
iterator = iterator.add(-7, 'days');
}
}
var diffDay = startOfMonth.date(1).add(1, 'month').diff(iterator, 'day');
var lintCount = Math.ceil(diffDay / 7);
while (cells.length < lintCount * 7) {
cells.push(iterator);
iterator = iterator.add(1, 'day');
}
return cells;
}
export function renderCells(cellsMonth, weekStartsOn, value, localeText, monthRangeList) {
var _a;
var rangeStartDate = monthRangeList[0], rangeEndDate = monthRangeList[1];
var rowBeginDay = 0;
var rowEndDay = 6;
if (weekStartsOn === 'Monday') {
rowBeginDay = 1;
rowEndDay = 0;
}
var dates = getDate(cellsMonth, weekStartsOn);
if (!value) {
return dates.map(function (d, index) {
var isToday = dayjs().isSame(d, 'day');
var isRowBegin = d.isSame(cellsMonth.startOf('month'), 'date') ||
d.day() === rowBeginDay;
var isRowEnd = d.isSame(cellsMonth.endOf('month'), 'date') || d.day() === rowEndDay;
var top;
if (isToday) {
top = {
label: localeText.today,
};
}
return {
index: index,
disabled: false,
time: d.toDate().getTime(),
date: d.get('date'),
isSelected: false,
isSelectedBegin: false,
top: top,
isSelectedEnd: false,
inThisMonth: d.month() === cellsMonth.month(),
isRowBegin: isRowBegin,
isRowEnd: isRowEnd,
isRange: (d.isSame(rangeStartDate) || d.isAfter(rangeStartDate)) &&
(d.isSame(rangeEndDate) || d.isBefore(rangeEndDate)),
};
});
}
var selectBegin;
var selectEnd;
if (Array.isArray(value)) {
selectBegin = dayjs(value[0]);
selectEnd = dayjs((_a = value[1]) !== null && _a !== void 0 ? _a : value[0]);
}
else {
selectBegin = dayjs(value);
selectEnd = dayjs(value);
}
return dates.map(function (d, index) {
var isToday = dayjs().isSame(d, 'day');
var isRowBegin = d.isSame(cellsMonth.startOf('month'), 'date') || d.day() === rowBeginDay;
var isRowEnd = d.isSame(cellsMonth.endOf('month'), 'date') || d.day() === rowEndDay;
var isSelectedBegin = selectBegin.isSame(d, 'day');
var isSelectedEnd = selectEnd.isSame(d, 'day');
var isSelected = (!!selectBegin.isBefore(d, 'day') && !!selectEnd.isAfter(d, 'day')) ||
isSelectedBegin ||
isSelectedEnd;
var inThisMonth = d.month() === cellsMonth.month();
var time = d.toDate().getTime();
var topLabel = isToday ? localeText.today : '';
if (Array.isArray(value)) {
if (isSelectedBegin) {
if (isSelectedEnd && value.length === 2) {
topLabel = localeText.startAndEnd;
}
else {
topLabel = localeText.start;
}
}
else {
if (isSelectedEnd) {
topLabel = localeText.end;
}
}
}
return {
index: index,
disabled: false,
time: time,
date: d.get('date'),
isSelected: isSelected,
isSelectedBegin: isSelectedBegin,
top: { label: topLabel },
isSelectedEnd: isSelectedEnd,
inThisMonth: inThisMonth,
isRowBegin: isRowBegin,
isRowEnd: isRowEnd,
isRange: (d.isSame(rangeStartDate) || d.isAfter(rangeStartDate)) &&
(d.isSame(rangeEndDate) || d.isBefore(rangeEndDate)),
};
});
}
export function getSelectionModeFromValue(value) {
if (Array.isArray(value)) {
return 'range';
}
if (typeof value === 'number') {
return 'single';
}
return null;
}
// 获取滚动视图的元素id
export function getScrollIntoViewId(value) {
// 已选中时间滚动到可视区域内微信不支持id为数字开头
return "id_".concat(value &&
dayjs(Array.isArray(value) ? value[0] : value)
.startOf('d')
.subtract(7, 'd') // 需要定位的地方往前推7天让已选中时间定位到中间位置
.toDate()
.getTime());
}

View File

@ -0,0 +1 @@
/* size | 按钮内间距 */

View File

@ -0,0 +1,44 @@
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
import { Component, triggerEvent, getValueFromProps } from '../../_util/simply';
import { CheckboxGroupDefaultProps } from './props';
import mixinValue from '../../mixins/value';
Component(CheckboxGroupDefaultProps, {
onChange: function (args, e) {
if (getValueFromProps(this, 'disabled')) {
return;
}
var event;
event = args;
var currentValue = this.getValue();
var index = event.currentTarget.dataset.index;
var selectValue = getValueFromProps(this, 'options')[index].value;
if (currentValue.indexOf(selectValue) > -1) {
currentValue = currentValue.filter(function (v) { return v !== selectValue; });
}
else {
currentValue = __spreadArray(__spreadArray([], currentValue, true), [selectValue], false);
}
if (!this.isControlled()) {
this.update(currentValue);
}
triggerEvent(this, 'change', currentValue, e);
},
}, null, [
mixinValue({
transformValue: function (val) {
var value = val || [];
return {
needUpdate: true,
value: value,
};
},
}),
]);

View File

@ -0,0 +1,8 @@
{
"component": true,
"usingComponents": {
"list": "../../List/index",
"list-item": "../../List/ListItem/index",
"ant-checkbox": "../index"
}
}

View File

@ -0,0 +1,54 @@
<wxs
src="../index.wxs"
module="componentUtils"
></wxs>
<list
className="ant-checkbox-group {{className ? className : ''}} ant-checkbox-group-{{position}}"
style="{{style}}"
>
<checkbox-group
name="{{name}}"
value="{{mixin.value}}"
>
<view class="ant-checkbox-group-body">
<block wx:if="{{position === 'vertical'}}">
<block
wx:for="{{options}}"
wx:for-index="index"
wx:for-item="item"
>
<list-item>
<ant-checkbox
color="{{color}}"
checked="{{componentUtils.getCheckboxChecked(item, mixin.value)}}"
data-index="{{index}}"
value="{{item.value}}"
disabled="{{disabled || item.disabled}}"
bind:change="onChange"
>
<view class="ant-checkbox-group-item-label-default">{{item.label}}</view>
</ant-checkbox>
</list-item>
</block>
</block>
<block wx:else>
<block
wx:for="{{options}}"
wx:for-index="index"
wx:for-item="item"
>
<ant-checkbox
color="{{color}}"
checked="{{componentUtils.getCheckboxChecked(item, mixin.value)}}"
data-index="{{index}}"
value="{{item.value}}"
disabled="{{disabled || item.disabled}}"
bind:change="onChange"
>
<view class="ant-checkbox-group-item-label-default">{{item.label}}</view>
</ant-checkbox>
</block>
</block>
</view>
</checkbox-group>
</list>

View File

@ -0,0 +1,34 @@
.ant-checkbox-group-horizontal .ant-checkbox-group-body {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
}
.ant-checkbox-group-horizontal .ant-checkbox-group-body .ant-list-item-line {
padding-right: 0;
}
.ant-checkbox-group-horizontal .ant-checkbox-group-body .ant-checkbox-item {
flex-flow: 0;
}
.ant-checkbox-group-horizontal .ant-checkbox-group-body .ant-list-item-line::after {
display: none;
}
.ant-checkbox-group-header:empty,
.ant-checkbox-group-footer:empty {
display: none;
}
.ant-checkbox-group-header,
.ant-checkbox-group-footer {
display: flex;
align-items: center;
padding: 8px 12px;
line-height: 1.4;
font-size: 15px;
color: #999999;
}
.ant-checkbox-group-body {
position: relative;
overflow: hidden;
}
.ant-checkbox-group-body .ant-checkbox-item-content .ant-checkbox-group-item-label-default:not(:nth-child(1)) {
display: none;
}

View File

@ -0,0 +1,8 @@
export var CheckboxGroupDefaultProps = {
value: null,
defaultValue: [],
disabled: false,
position: 'vertical',
color: '',
options: [],
};

View File

@ -0,0 +1,17 @@
import { CheckboxDefaultProps } from './props';
import { Component, triggerEvent } from '../_util/simply';
import mixinValue from '../mixins/value';
Component(CheckboxDefaultProps, {
onChange: function (e) {
var value = !this.getValue();
if (!this.isControlled()) {
this.update(value);
}
triggerEvent(this, 'change', value, e);
},
}, null, [
mixinValue({
valueKey: 'checked',
defaultValueKey: 'defaultChecked',
}),
]);

View File

@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"ant-icon": "../Icon/index"
}
}

View File

@ -0,0 +1,62 @@
---
nav:
path: /components
group:
title: 信息输入
order: 10
toc: 'content'
---
# Checkbox 复选框
<code src="../../docs/components/compatibility.tsx" inline="true"></code>
在一组可选项中进行多选。
## 何时使用
- 在一组可选项中进行多项选择时。
- 单独使用时可以表示两种状态之间的切换,与 switch 类似。区别在于,切换 switch 会直接触发状态改变,而 checkbox 一般用于状态标记,需要与提交操作配合。
## 代码示例
### 基本使用
<code src='pages/Checkbox/index'></code>
### CheckboxGroup
<code src='pages/CheckboxGroup/index'></code>
### Checkbox 自定义分组
<code src='pages/CheckboxCustomGroup/index'></code>
## API
#### Checkbox
| 属性 | 说明 | 类型 | 默认值 |
| -------------- | ----------------------- | ------------------------------------------------------------------------------------------------- | ------ |
| checked | 是否选中 | boolean | - |
| className | 类名 | string | - |
| color | 选中的颜色,同 CSS 色值 | string | - |
| defaultChecked | 默认是否选中 | boolean | - |
| disabled | 是否禁用 | boolean | false |
| style | 样式 | string | - |
| onChange | 选中状态改变时触发回调 | (checked: boolean, event: `Event`(https://opendocs.alipay.com/mini/framework/event-object)) => void | - |
#### CheckboxGroup
| 属性 | 说明 | 类型 | 默认值 |
| ------------ | ------------------------------------------------------------ | ----------------------------------------------------------------------------------------------- | ----------- |
| className | 类名 | string | - |
| color | 选中的颜色,同 CSS 色值 | string | - |
| defaultValue | 默认选中的值 | `string[]` | - |
| disabled | 是否禁用 | boolean | false |
| label | label 区插槽,接收 value当前项可选项 item、index索引 | slot | - |
| options | 指定可选项 | `{label: string; value: string; disabled: boolean}[]` | - |
| position | 布局,可选 `horizontal``vertical` | string | `vertical` |
| style | 样式 | string | - |
| value | CheckboxGroup 的值,决定子元素是否勾选 | `string[]` | - |
| onChange | 勾选状态变化时触发此函数 | (value: `string[]`, event: `Event`(https://opendocs.alipay.com/mini/framework/event-object)) => void | - |

View File

@ -0,0 +1,36 @@
<wxs
src="./index.wxs"
module="componentUtils"
></wxs>
<label
class="ant-checkbox-item {{className || ''}}"
style="{{style || ''}}"
>
<view class="ant-checkbox-item-container">
<view class="ant-checkbox-item-wrap">
<checkbox-group bindchange="onChange">
<checkbox
class="ant-checkbox-item-base"
value="{{value}}"
checked="{{mixin.value}}"
disabled="{{disabled}}"
></checkbox>
</checkbox-group>
<view class="ant-checkbox-item-fake">
<view
class="ant-checkbox-item-fake-{{componentUtils.getClassName(mixin.value, disabled)}}"
style="{{mixin.value && !disabled && color ? 'background:' + color : ''}}"
>
<ant-icon
wx:if="{{mixin.value}}"
type="CheckOutline"
className="ant-checkbox-item-fake-{{componentUtils.getClassName(mixin.value, disabled)}}-icon"
></ant-icon>
</view>
</view>
</view>
<view class="ant-checkbox-item-content {{disabled ? 'ant-checkbox-item-disabled' : ''}}">
<slot></slot>
</view>
</view>
</label>

View File

@ -0,0 +1,21 @@
function getClassName(checked, disabled) {
if (!checked && !disabled) {
return 'icon';
}
if (checked && !disabled) {
return 'checkedIcon';
}
if (!checked && disabled) {
return 'disbaledIcon';
}
if (checked && disabled) {
return 'disabledCheckedIcon';
}
}
function getCheckboxChecked(item, value) {
return (value || []).indexOf(item.value) > -1;
}
module.exports = {
getClassName: getClassName,
getCheckboxChecked: getCheckboxChecked
};

View File

@ -0,0 +1,88 @@
.ant-checkbox-item {
color: #333333;
margin-right: 8px;
height: 29.8px;
line-height: 29.8px;
display: inline-block;
}
.ant-checkbox-item-container {
display: flex;
align-items: center;
}
.ant-checkbox-item-content {
padding-left: 5px;
text-align: left;
}
.ant-checkbox-item-wrap {
position: relative;
width: 22px;
height: 22px;
flex: 0 0 22px;
}
.ant-checkbox-item-base {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
}
.ant-checkbox-item-fake {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
pointer-events: none;
display: flex;
justify-content: center;
align-items: center;
}
.ant-checkbox-item-fake-icon {
background-color: #ffffff;
border: 1px solid #cccccc;
border-radius: 50vh;
width: 100%;
height: 100%;
box-sizing: border-box;
}
.ant-checkbox-item-fake-checkedIcon {
border-radius: 50vh;
background-color: #1677ff;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.ant-checkbox-item-fake-checkedIcon-icon {
color: #ffffff;
font-size: 14px;
}
.ant-checkbox-item-fake-disbaledIcon {
box-sizing: border-box;
border: 1px solid #cccccc;
border-radius: 50vh;
width: 100%;
height: 100%;
background-color: #f5f5f5;
}
.ant-checkbox-item-fake-disabledCheckedIcon {
box-sizing: border-box;
border: 1px solid #cccccc;
background-color: #f5f5f5;
border-radius: 50vh;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.ant-checkbox-item-fake-disabledCheckedIcon-icon {
color: #cccccc;
font-size: 14px;
}
.ant-checkbox-item-disabled {
opacity: 0.4;
}

View File

@ -0,0 +1,7 @@
export var CheckboxDefaultProps = {
value: null,
checked: null,
defaultChecked: null,
disabled: false,
color: '',
};

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