bug fix and performance improvements

This commit is contained in:
quantulr
2023-08-18 17:32:18 +08:00
parent 3c6ab550cf
commit e750b9be9c
923 changed files with 46650 additions and 9 deletions

View File

@ -0,0 +1,7 @@
export default class Bus {
listeners: Map<string, any>;
emitted: Set<string>;
constructor();
on(evtName: string, listener: any): void;
emit(evtName: string): void;
}

View File

@ -0,0 +1,22 @@
export default class Bus {
constructor() {
this.listeners = new Map();
this.emitted = new Set();
}
on(evtName, listener) {
if (this.emitted.has(evtName)) {
listener();
return;
}
const target = this.listeners.get(evtName) || [];
target.push(listener);
this.listeners.set(evtName, target);
}
emit(evtName) {
const listeners = this.listeners.get(evtName);
if (listeners) {
listeners.forEach((func) => func());
}
this.emitted.add(evtName);
}
}

View File

@ -0,0 +1,35 @@
export declare type Classes = Array<string>;
export interface Styles {
[css: string]: string | number;
}
export declare type OptionData = {
label?: string;
value?: string | number;
} & {
[key: string]: any;
};
export declare type TreeOptionData = {
children?: Array<TreeOptionData>;
} & OptionData;
export declare type SizeEnum = 'small' | 'medium' | 'large';
export declare type HorizontalAlignEnum = 'left' | 'center' | 'right';
export declare type VerticalAlignEnum = 'top' | 'middle' | 'bottom';
export declare type ClassName = {
[className: string]: any;
} | ClassName[] | string;
export declare type CSSSelector = string;
export interface KeysType {
value?: string;
label?: string;
}
export interface HTMLElementAttributes {
[css: string]: string;
}
export interface InfinityScroll {
bufferSize?: number;
isFixedRowHeight?: boolean;
rowHeight?: number;
threshold?: number;
type: 'lazy' | 'virtual';
}
export declare type TScroll = InfinityScroll;

View File

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

View File

@ -0,0 +1,3 @@
/// <reference types="miniprogram-api-typings" />
declare const TComponent: typeof Component;
export default TComponent;

View File

@ -0,0 +1,5 @@
const TComponent = (options) => {
options.options = Object.assign({ multipleSlots: true, addGlobalClass: true }, options.options);
return Component(options);
};
export default TComponent;

View File

@ -0,0 +1,5 @@
declare const _default: {
prefix: string;
};
export default _default;
export declare const prefix = "t";

View File

@ -0,0 +1,4 @@
export default {
prefix: "t",
};
export const prefix = "t";

View File

@ -0,0 +1,27 @@
.t-float-left {
float: left;
}
.t-float-right {
float: right;
}
@keyframes tdesign-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.hotspot-expanded.relative {
position: relative;
}
.hotspot-expanded::after {
content: '';
display: block;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
transform: scale(1.5);
}

View File

@ -0,0 +1,19 @@
import type { TDate, TCalendarType, TCalendarValue } from './type';
export default class TCalendar {
firstDayOfWeek: number;
value: TCalendarValue | TCalendarValue[];
type: TCalendarType;
minDate: Date;
maxDate: Date;
format: (day: TDate) => TDate;
constructor(options?: {});
getTrimValue(): Date | Date[];
getDays(): any[];
getMonths(): any[];
select({ cellType, year, month, date }: {
cellType: any;
year: any;
month: any;
date: any;
}): Date | TCalendarValue[];
}

View File

@ -0,0 +1,128 @@
import { getDateRect, isSameDate, getMonthDateRect, isValidDate, getDate } from '../date';
export default class TCalendar {
constructor(options = {}) {
this.type = 'single';
Object.assign(this, options);
if (!this.minDate)
this.minDate = getDate();
if (!this.maxDate)
this.maxDate = getDate(6);
}
getTrimValue() {
const { value, type } = this;
const format = (val) => {
if (val instanceof Date)
return val;
if (typeof val === 'number')
return new Date(val);
return new Date();
};
if (type === 'single' && isValidDate(value))
return format(value);
if (type === 'multiple' || type === 'range') {
if (Array.isArray(value)) {
const isValid = value.every((item) => isValidDate(item));
return isValid ? value.map((item) => format(item)) : [];
}
return [];
}
}
getDays() {
const raw = '日一二三四五六';
const ans = [];
let i = this.firstDayOfWeek % 7;
while (ans.length < 7) {
ans.push(raw[i]);
i = (i + 1) % 7;
}
return ans;
}
getMonths() {
const ans = [];
const selectedDate = this.getTrimValue();
const { minDate, maxDate, type, format } = this;
let { year: minYear, month: minMonth, time: minTime } = getDateRect(minDate);
const { year: maxYear, month: maxMonth, time: maxTime } = getDateRect(maxDate);
const calcType = (year, month, date) => {
const curDate = new Date(year, month, date, 23, 59, 59);
if (type === 'single' && selectedDate) {
if (isSameDate({ year, month, date }, selectedDate))
return 'selected';
}
if (type === 'multiple' && selectedDate) {
const hit = selectedDate.some((item) => isSameDate({ year, month, date }, item));
if (hit) {
return 'selected';
}
}
if (type === 'range' && selectedDate) {
if (Array.isArray(selectedDate)) {
const [startDate, endDate] = selectedDate;
if (startDate && isSameDate({ year, month, date }, startDate))
return 'start';
if (endDate && isSameDate({ year, month, date }, endDate))
return 'end';
if (startDate && endDate && curDate.getTime() > startDate.getTime() && curDate.getTime() < endDate.getTime())
return 'centre';
}
}
const minCurDate = new Date(year, month, date, 0, 0, 0);
if (curDate.getTime() < minTime || minCurDate.getTime() > maxTime) {
return 'disabled';
}
return '';
};
while (minYear < maxYear || (minYear === maxYear && minMonth <= maxMonth)) {
const target = getMonthDateRect(new Date(minYear, minMonth, 1));
const months = [];
for (let i = 1; i <= 31; i++) {
if (i > target.lastDate)
break;
const dateObj = {
date: new Date(minYear, minMonth, i),
day: i,
type: calcType(minYear, minMonth, i),
};
months.push(format ? format(dateObj) : dateObj);
}
ans.push({
year: minYear,
month: minMonth,
months,
weekdayOfFirstDay: target.weekdayOfFirstDay,
});
const curDate = getDateRect(new Date(minYear, minMonth + 1, 1));
minYear = curDate.year;
minMonth = curDate.month;
}
return ans;
}
select({ cellType, year, month, date }) {
const { type } = this;
const selectedDate = this.getTrimValue();
if (cellType === 'disabled')
return;
const selected = new Date(year, month, date);
this.value = selected;
if (type === 'range' && Array.isArray(selectedDate)) {
if (selectedDate.length === 1 && selected > selectedDate[0]) {
this.value = [selectedDate[0], selected];
}
else {
this.value = [selected];
}
}
else if (type === 'multiple' && Array.isArray(selectedDate)) {
const newVal = [...selectedDate];
const index = selectedDate.findIndex((item) => isSameDate(item, selected));
if (index > -1) {
newVal.splice(index, 1);
}
else {
newVal.push(selected);
}
this.value = newVal;
}
return this.value;
}
}

View File

@ -0,0 +1,11 @@
export interface TDate {
date: Date;
day: number;
type: TDateType;
className?: string;
prefix?: string;
suffix?: string;
}
export declare type TCalendarValue = number | Date;
export declare type TDateType = 'selected' | 'disabled' | 'start' | 'centre' | 'end' | '';
export declare type TCalendarType = 'single' | 'multiple' | 'range';

View File

@ -0,0 +1,21 @@
export declare type CompareDate = Date | number | {
year: number;
month: number;
date: number;
};
export declare const getDateRect: (date: Date | number) => {
year: number;
month: number;
date: number;
day: number;
time: number;
};
export declare const isSameDate: (date1: CompareDate, date2: CompareDate) => boolean;
export declare const getMonthDateRect: (date: Date | number) => {
year: number;
month: number;
weekdayOfFirstDay: number;
lastDate: number;
};
export declare const isValidDate: (val: any) => boolean;
export declare const getDate: (...args: any[]) => any;

View File

@ -0,0 +1,41 @@
export const getDateRect = (date) => {
const _date = new Date(date);
return {
year: _date.getFullYear(),
month: _date.getMonth(),
date: _date.getDate(),
day: _date.getDay(),
time: _date.getTime(),
};
};
export const isSameDate = (date1, date2) => {
if (date1 instanceof Date || typeof date1 === 'number')
date1 = getDateRect(date1);
if (date2 instanceof Date || typeof date2 === 'number')
date2 = getDateRect(date2);
const keys = ['year', 'month', 'date'];
return keys.every((key) => date1[key] === date2[key]);
};
export const getMonthDateRect = (date) => {
const { year, month } = getDateRect(date);
const firstDay = new Date(year, month, 1);
const weekdayOfFirstDay = firstDay.getDay();
const lastDate = new Date(+new Date(year, month + 1, 1) - 24 * 3600 * 1000).getDate();
return {
year,
month,
weekdayOfFirstDay,
lastDate,
};
};
export const isValidDate = (val) => typeof val === 'number' || val instanceof Date;
export const getDate = (...args) => {
const now = new Date();
if (args.length === 0)
return now;
if (args.length === 1 && args[0] <= 1000) {
const { year, month, date } = getDateRect(now);
return new Date(year, month + args[0], date);
}
return Date.apply(null, args);
};

View File

@ -0,0 +1,15 @@
declare type ControlInstance = {
controlled: boolean;
initValue: any;
set(newVal: any, extObj?: Object, fn?: any): void;
get(): any;
change(newVal: any, customChangeData?: any, customUpdateFn?: any): void;
};
declare type ControlOption = {
valueKey?: string;
defaultValueKey?: string;
changeEventName?: string;
strict?: boolean;
};
declare function useControl(this: any, option?: ControlOption): ControlInstance;
export { ControlOption, ControlInstance, useControl };

View File

@ -0,0 +1,40 @@
const defaultOption = {
valueKey: 'value',
defaultValueKey: 'defaultValue',
changeEventName: 'change',
strict: true,
};
function useControl(option = {}) {
const { valueKey, defaultValueKey, changeEventName, strict } = Object.assign(Object.assign({}, defaultOption), option);
const props = this.properties || {};
const value = props[valueKey];
const defaultValue = props[strict ? defaultValueKey : valueKey];
let controlled = false;
if (strict && typeof value !== 'undefined' && value !== null) {
controlled = true;
}
const set = (newVal, extObj, fn) => {
this.setData(Object.assign({ [`_${valueKey}`]: newVal }, extObj), fn);
};
return {
controlled,
initValue: controlled ? value : defaultValue,
set,
get: () => {
return this.data[`_${valueKey}`];
},
change: (newVal, customChangeData, customUpdateFn) => {
this.triggerEvent(changeEventName, typeof customChangeData !== 'undefined' ? customChangeData : newVal);
if (controlled) {
return;
}
if (typeof customUpdateFn === 'function') {
customUpdateFn();
}
else {
set(newVal);
}
},
};
}
export { useControl };

View File

@ -0,0 +1,15 @@
export declare const getPrototypeOf: (obj: any) => any;
export declare const isObject: (something: any) => boolean;
export declare const iterateInheritedPrototype: (callback: (proto: Record<string, any>) => boolean | void, fromCtor: any, toCtor: any, includeToCtor?: boolean) => void;
export interface ClassInstanceToObjectOptions {
bindTo?: any;
excludes?: string[];
till?: any;
enumerable?: 0 | boolean;
configurable?: 0 | boolean;
writable?: 0 | boolean;
}
export declare const toObject: (something: any, options?: ClassInstanceToObjectOptions) => {
[key: string]: any;
};
export declare const isPlainObject: (something: any) => boolean;

View File

@ -0,0 +1,57 @@
export const getPrototypeOf = function (obj) {
return Object.getPrototypeOf ? Object.getPrototypeOf(obj) : obj.__proto__;
};
export const isObject = function isObject(something) {
const type = typeof something;
return something !== null && (type === 'function' || type === 'object');
};
export const iterateInheritedPrototype = function iterateInheritedPrototype(callback, fromCtor, toCtor, includeToCtor = true) {
let proto = fromCtor.prototype || fromCtor;
const toProto = toCtor.prototype || toCtor;
while (proto) {
if (!includeToCtor && proto === toProto)
break;
if (callback(proto) === false)
break;
if (proto === toProto)
break;
proto = getPrototypeOf(proto);
}
};
export const toObject = function toObject(something, options = {}) {
const obj = {};
if (!isObject(something))
return obj;
const excludes = options.excludes || ['constructor'];
const { enumerable = true, configurable = 0, writable = 0 } = options;
const defaultDesc = {};
if (enumerable !== 0)
defaultDesc.enumerable = enumerable;
if (configurable !== 0)
defaultDesc.configurable = configurable;
if (writable !== 0)
defaultDesc.writable = writable;
iterateInheritedPrototype((proto) => {
Object.getOwnPropertyNames(proto).forEach((key) => {
if (excludes.indexOf(key) >= 0)
return;
if (Object.prototype.hasOwnProperty.call(obj, key))
return;
const desc = Object.getOwnPropertyDescriptor(proto, key);
const fnKeys = ['get', 'set', 'value'];
fnKeys.forEach((k) => {
if (typeof desc[k] === 'function') {
const oldFn = desc[k];
desc[k] = function (...args) {
return oldFn.apply(Object.prototype.hasOwnProperty.call(options, 'bindTo') ? options.bindTo : this, args);
};
}
});
Object.defineProperty(obj, key, Object.assign(Object.assign({}, desc), defaultDesc));
});
}, something, options.till || Object, false);
return obj;
};
export const isPlainObject = function isPlainObject(something) {
return Object.prototype.toString.call(something) === '[object Object]';
};

View File

@ -0,0 +1,4 @@
export * from './superComponent';
export * from './flatTool';
export * from './instantiationDecorator';
export * from './control';

View File

@ -0,0 +1,4 @@
export * from './superComponent';
export * from './flatTool';
export * from './instantiationDecorator';
export * from './control';

View File

@ -0,0 +1,3 @@
import { SuperComponent } from './superComponent';
export declare const toComponent: (options: Record<string, any>) => Record<string, any>;
export declare const wxComponent: () => (constructor: new () => SuperComponent) => void;

View File

@ -0,0 +1,142 @@
import { isPlainObject, toObject } from './flatTool';
import { canUseVirtualHost } from '../version';
const RawLifeCycles = ['Created', 'Attached', 'Ready', 'Moved', 'Detached', 'Error'];
const NativeLifeCycles = RawLifeCycles.map((k) => k.toLowerCase());
const ComponentNativeProps = [
'properties',
'data',
'observers',
'methods',
'behaviors',
...NativeLifeCycles,
'relations',
'externalClasses',
'options',
'lifetimes',
'pageLifeTimes',
'definitionFilter',
];
export const toComponent = function toComponent(options) {
const { relations, behaviors = [], externalClasses = [] } = options;
if (options.properties) {
Object.keys(options.properties).forEach((k) => {
let opt = options.properties[k];
if (!isPlainObject(opt)) {
opt = { type: opt };
}
options.properties[k] = opt;
});
const ariaProps = [
{ key: 'ariaHidden', type: Boolean },
{ key: 'ariaRole', type: String },
{ key: 'ariaLabel', type: String },
{ key: 'ariaLabelledby', type: String },
{ key: 'ariaDescribedby', type: String },
{ key: 'ariaBusy', type: Boolean },
];
ariaProps.forEach(({ key, type }) => {
options.properties[key] = {
type,
};
});
options.properties.style = { type: String, value: '' };
options.properties.customStyle = { type: String, value: '' };
}
if (!options.methods)
options.methods = {};
if (!options.lifetimes)
options.lifetimes = {};
const inits = {};
if (relations) {
const getRelations = (relation, path) => Behavior({
created() {
Object.defineProperty(this, `$${relation}`, {
get: () => {
const nodes = this.getRelationNodes(path) || [];
return relation === 'parent' ? nodes[0] : nodes;
},
});
},
});
const map = {};
Object.keys(relations).forEach((path) => {
const comp = relations[path];
const relation = ['parent', 'ancestor'].includes(comp.type) ? 'parent' : 'children';
const mixin = getRelations(relation, path);
map[relation] = mixin;
});
behaviors.push(...Object.keys(map).map((key) => map[key]));
}
options.behaviors = [...behaviors];
options.externalClasses = ['class', ...externalClasses];
Object.getOwnPropertyNames(options).forEach((k) => {
const desc = Object.getOwnPropertyDescriptor(options, k);
if (!desc)
return;
if (NativeLifeCycles.indexOf(k) < 0 && typeof desc.value === 'function') {
Object.defineProperty(options.methods, k, desc);
delete options[k];
}
else if (ComponentNativeProps.indexOf(k) < 0) {
inits[k] = desc;
}
else if (NativeLifeCycles.indexOf(k) >= 0) {
options.lifetimes[k] = options[k];
}
});
if (Object.keys(inits).length) {
const oldCreated = options.lifetimes.created;
const oldAttached = options.lifetimes.attached;
const { controlledProps = [] } = options;
options.lifetimes.created = function (...args) {
Object.defineProperties(this, inits);
if (oldCreated)
oldCreated.apply(this, args);
};
options.lifetimes.attached = function (...args) {
if (oldAttached)
oldAttached.apply(this, args);
controlledProps.forEach(({ key }) => {
const defaultKey = `default${key.replace(/^(\w)/, (m, m1) => m1.toUpperCase())}`;
const props = this.properties;
if (props[key] == null) {
this._selfControlled = true;
}
if (props[key] == null && props[defaultKey] != null) {
this.setData({
[key]: props[defaultKey],
});
}
});
};
options.methods._trigger = function (evtName, detail, opts) {
const target = controlledProps.find((item) => item.event == evtName);
if (target) {
const { key } = target;
if (this._selfControlled) {
this.setData({
[key]: detail[key],
});
}
}
this.triggerEvent(evtName, detail, opts);
};
}
return options;
};
export const wxComponent = function wxComponent() {
return function (constructor) {
class WxComponent extends constructor {
}
const current = new WxComponent();
current.options = current.options || {};
if (current.options.addGlobalClass === undefined) {
current.options.addGlobalClass = true;
}
if (canUseVirtualHost()) {
current.options.virtualHost = true;
}
const obj = toComponent(toObject(current));
Component(obj);
};
};

View File

@ -0,0 +1,19 @@
/// <reference types="miniprogram-api-typings" />
export interface ComponentsOptionsType extends WechatMiniprogram.Component.ComponentOptions {
styleIsolation?: 'isolated' | 'apply-shared' | 'shared' | 'page-isolated' | 'page-apply-shared' | 'page-shared';
}
export interface RelationsOptions {
[componentName: string]: WechatMiniprogram.Component.RelationOption;
}
export interface SuperComponent<D = {}, P = {}, M = {}> extends WechatMiniprogram.Component.Lifetimes, WechatMiniprogram.Component.OtherOption, WechatMiniprogram.Component.InstanceMethods<D> {
properties: P;
data: D;
options: ComponentsOptionsType;
methods: M | Record<string, (...args: any[]) => any>;
$global: Function;
[x: string]: any;
}
export declare class SuperComponent<D = {}, P = {}, M = {}> {
readonly app: any;
constructor();
}

View File

@ -0,0 +1,5 @@
export class SuperComponent {
constructor() {
this.app = getApp();
}
}

View File

@ -0,0 +1,27 @@
.t-float-left {
float: left;
}
.t-float-right {
float: right;
}
@keyframes tdesign-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.hotspot-expanded.relative {
position: relative;
}
.hotspot-expanded::after {
content: '';
display: block;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
transform: scale(1.5);
}

View File

@ -0,0 +1,8 @@
@keyframes tdesign-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}

View File

@ -0,0 +1,6 @@
.t-float-left {
float: left;
}
.t-float-right {
float: right;
}

View File

@ -0,0 +1,27 @@
.t-float-left {
float: left;
}
.t-float-right {
float: right;
}
@keyframes tdesign-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.hotspot-expanded.relative {
position: relative;
}
.hotspot-expanded::after {
content: '';
display: block;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
transform: scale(1.5);
}

View File

@ -0,0 +1,16 @@
<template name="badge">
<t-badge
color="{{color || ''}}"
content="{{content || ''}}"
count="{{count || 0}}"
dot="{{dot || false}}"
max-count="{{maxCount || 99}}"
offset="{{offset || []}}"
shape="{{shape || 'circle'}}"
show-zero="{{showZero || false}}"
size="{{size || 'medium'}}"
t-class="{{class}} {{tClass}}"
t-class-content="{{tClassContent}}"
t-class-count="{{tClassCount}}"
/>
</template>

View File

@ -0,0 +1,38 @@
<template name="button">
<t-button
block="{{block || false}}"
class="{{class || ''}}"
t-class="{{externalClass}}"
disabled="{{disabled || false}}"
data-type="{{type}}"
data-extra="{{extra}}"
icon="{{icon || ''}}"
loading="{{loading || false}}"
theme="{{theme || 'default'}}"
ghost="{{ghost || false}}"
shape="{{shape || 'rectangle'}}"
size="{{size || 'medium'}}"
variant="{{variant || 'base'}}"
open-type="{{openType || ''}}"
hover-class="{{hoverClass || ''}}"
hover-stop-propagation="{{hoverStopPropagation || false}}"
hover-start-time="{{hoverStartTime || 20}}"
hover-stay-time="{{hoverStayTime || 70}}"
lang="{{lang || 'en'}}"
session-from="{{sessionFrom || ''}}"
send-message-title="{{sendMessageTitle || ''}}"
send-message-path="{{sendMessagePath || ''}}"
send-message-img="{{sendMessageImg || ''}}"
app-parameter="{{appParameter || ''}}"
show-message-card="{{showMessageCard || false}}"
bind:tap="onTplButtonTap"
bind:getuserinfo="onTplButtonTap"
bind:contact="onTplButtonTap"
bind:getphonenumber="onTplButtonTap"
bind:error="onTplButtonTap"
bind:opensetting="onTplButtonTap"
bind:launchapp="onTplButtonTap"
aria-label="{{ariaLabel || ''}}"
>{{content}}</t-button
>
</template>

View File

@ -0,0 +1,15 @@
<template name="icon">
<t-icon
style="{{style || ''}}"
class="{{class}}"
t-class="{{tClass}}"
prefix="{{prefix || ''}}"
name="{{name || ''}}"
size="{{size || ''}}"
color="{{color || ''}}"
aria-hidden="{{ariaHidden || '' }}"
aria-label="{{ariaLabel || ''}}"
aria-role="{{ariaRole || ''}}"
bind:click="{{bindclick || ''}}"
/>
</template>

View File

@ -0,0 +1,22 @@
<template name="image">
<t-image
class="{{class}}"
t-class="{{tClass}}"
t-class-load="{{tClassLoad}}"
style="{{style || ''}}"
customStyle="{{customStyle || ''}}"
height="{{height || ''}}"
width="{{width || ''}}"
error="{{error || 'default'}}"
lazy="{{lazy || false}}"
loading="{{count || 'default'}}"
shape="{{shape || 'square'}}"
src="{{src || ''}}"
mode="{{mode || 'scaleToFill'}}"
webp="{{webp || false}}"
showMenuByLongpress="{{showMenuByLongpress || false}}"
data-custom="{{dataset || null}}"
bind:error="{{binderror}}"
bind:load="{{bindload}}"
/>
</template>

View File

@ -0,0 +1,30 @@
/// <reference types="miniprogram-api-typings" />
/// <reference types="miniprogram-api-typings" />
declare type Context = WechatMiniprogram.Page.TrivialInstance | WechatMiniprogram.Component.TrivialInstance;
export declare const debounce: (func: any, wait?: number) => (...rest: any[]) => void;
export declare const throttle: (func: any, wait?: number, options?: any) => (...args: any[]) => void;
export declare const classNames: (...args: any[]) => string;
export declare const styles: (styleObj: any) => string;
export declare const getAnimationFrame: (context: any, cb: Function) => WechatMiniprogram.NodesRef;
export declare const getRect: (context: any, selector: string, needAll?: boolean) => Promise<any>;
export declare const isNumber: (value: any) => boolean;
export declare const addUnit: (value?: string | number) => string | undefined;
export declare const getCharacterLength: (type: string, str: string, max?: number) => {
length: number;
characters: string;
};
export declare const chunk: (arr: any[], size: number) => any[][];
export declare const getInstance: (context?: Context, selector?: string) => WechatMiniprogram.Component.TrivialInstance;
export declare const unitConvert: (value: number | string) => number;
export declare const setIcon: (iconName: any, icon: any, defaultIcon: any) => {
[x: string]: any;
};
export declare const isBool: (val: any) => boolean;
export declare const isObject: (val: any) => boolean;
export declare const isString: (val: any) => boolean;
export declare const toCamel: (str: any) => any;
export declare const getCurrentPage: <T>() => T & WechatMiniprogram.OptionalInterface<WechatMiniprogram.Page.ILifetime> & WechatMiniprogram.Page.InstanceProperties & WechatMiniprogram.Page.InstanceMethods<WechatMiniprogram.IAnyObject> & WechatMiniprogram.Page.Data<WechatMiniprogram.IAnyObject> & WechatMiniprogram.IAnyObject;
export declare const uniqueFactory: (compName: any) => () => string;
export declare const calcIcon: (icon: string | Record<string, any>, defaultIcon?: string) => string | Record<string, any>;
export declare const isOverSize: (size: any, sizeLimit: any) => boolean;
export {};

View File

@ -0,0 +1,233 @@
import { prefix } from './config';
const systemInfo = wx.getSystemInfoSync();
export const debounce = function (func, wait = 500) {
let timerId;
return function (...rest) {
if (timerId) {
clearTimeout(timerId);
}
timerId = setTimeout(() => {
func.apply(this, rest);
}, wait);
};
};
export const throttle = (func, wait = 100, options = null) => {
let previous = 0;
let timerid = null;
if (!options) {
options = {
leading: true,
};
}
return function (...args) {
const now = Date.now();
if (!previous && !options.leading)
previous = now;
const remaining = wait - (now - previous);
const context = this;
if (remaining <= 0) {
if (timerid) {
clearTimeout(timerid);
timerid = null;
}
previous = now;
func.apply(context, args);
}
};
};
export const classNames = function (...args) {
const hasOwn = {}.hasOwnProperty;
const classes = [];
args.forEach((arg) => {
if (!arg)
return;
const argType = typeof arg;
if (argType === 'string' || argType === 'number') {
classes.push(arg);
}
else if (Array.isArray(arg) && arg.length) {
const inner = classNames(...arg);
if (inner) {
classes.push(inner);
}
}
else if (argType === 'object') {
for (const key in arg) {
if (hasOwn.call(arg, key) && arg[key]) {
classes.push(key);
}
}
}
});
return classes.join(' ');
};
export const styles = function (styleObj) {
return Object.keys(styleObj)
.map((styleKey) => `${styleKey}: ${styleObj[styleKey]}`)
.join('; ');
};
export const getAnimationFrame = function (context, cb) {
return wx
.createSelectorQuery()
.in(context)
.selectViewport()
.boundingClientRect()
.exec(() => {
cb();
});
};
export const getRect = function (context, selector, needAll = false) {
return new Promise((resolve, reject) => {
wx.createSelectorQuery()
.in(context)[needAll ? 'selectAll' : 'select'](selector)
.boundingClientRect((rect) => {
if (rect) {
resolve(rect);
}
else {
reject(rect);
}
})
.exec();
});
};
const isDef = function (value) {
return value !== undefined && value !== null;
};
export const isNumber = function (value) {
return /^\d+(\.\d+)?$/.test(value);
};
export const addUnit = function (value) {
if (!isDef(value)) {
return undefined;
}
value = String(value);
return isNumber(value) ? `${value}px` : value;
};
export const getCharacterLength = (type, str, max) => {
if (!str || str.length === 0) {
return {
length: 0,
characters: '',
};
}
if (type === 'maxcharacter') {
let len = 0;
for (let i = 0; i < str.length; i += 1) {
let currentStringLength = 0;
if (str.charCodeAt(i) > 127 || str.charCodeAt(i) === 94) {
currentStringLength = 2;
}
else {
currentStringLength = 1;
}
if (len + currentStringLength > max) {
return {
length: len,
characters: str.slice(0, i),
};
}
len += currentStringLength;
}
return {
length: len,
characters: str,
};
}
else if (type === 'maxlength') {
const length = str.length > max ? max : str.length;
return {
length,
characters: str.slice(0, length),
};
}
return {
length: str.length,
characters: str,
};
};
export const chunk = (arr, size) => Array.from({ length: Math.ceil(arr.length / size) }, (v, i) => arr.slice(i * size, i * size + size));
export const getInstance = function (context, selector) {
if (!context) {
const pages = getCurrentPages();
const page = pages[pages.length - 1];
context = page.$$basePage || page;
}
const instance = context ? context.selectComponent(selector) : null;
if (!instance) {
console.warn('未找到组件,请检查selector是否正确');
return null;
}
return instance;
};
export const unitConvert = (value) => {
var _a;
if (typeof value === 'string') {
if (value.includes('rpx')) {
return (parseInt(value, 10) * ((_a = systemInfo === null || systemInfo === void 0 ? void 0 : systemInfo.screenWidth) !== null && _a !== void 0 ? _a : 750)) / 750;
}
return parseInt(value, 10);
}
return value;
};
export const setIcon = (iconName, icon, defaultIcon) => {
if (icon) {
if (typeof icon === 'string') {
return {
[`${iconName}Name`]: icon,
[`${iconName}Data`]: {},
};
}
else if (typeof icon === 'object') {
return {
[`${iconName}Name`]: '',
[`${iconName}Data`]: icon,
};
}
else {
return {
[`${iconName}Name`]: defaultIcon,
[`${iconName}Data`]: {},
};
}
}
return {
[`${iconName}Name`]: '',
[`${iconName}Data`]: {},
};
};
export const isBool = (val) => typeof val === 'boolean';
export const isObject = (val) => typeof val === 'object' && val != null;
export const isString = (val) => typeof val === 'string';
export const toCamel = (str) => str.replace(/-(\w)/g, (match, m1) => m1.toUpperCase());
export const getCurrentPage = function () {
const pages = getCurrentPages();
return pages[pages.length - 1];
};
export const uniqueFactory = (compName) => {
let number = 0;
return () => `${prefix}_${compName}_${number++}`;
};
export const calcIcon = (icon, defaultIcon) => {
if ((isBool(icon) && icon && defaultIcon) || isString(icon)) {
return { name: isBool(icon) ? defaultIcon : icon };
}
if (isObject(icon)) {
return icon;
}
return null;
};
export const isOverSize = (size, sizeLimit) => {
var _a;
if (!sizeLimit)
return false;
const base = 1000;
const unitMap = {
B: 1,
KB: base,
MB: base * base,
GB: base * base * base,
};
const computedSize = typeof sizeLimit === 'number' ? sizeLimit * base : (sizeLimit === null || sizeLimit === void 0 ? void 0 : sizeLimit.size) * unitMap[(_a = sizeLimit === null || sizeLimit === void 0 ? void 0 : sizeLimit.unit) !== null && _a !== void 0 ? _a : 'KB'];
return size > computedSize;
};

View File

@ -0,0 +1,137 @@
/* utils */
/**
* addUnit */
// 为 css 添加单位
function addUnit(value) {
var REGEXP = getRegExp('^-?\d+(.\d+)?$');
if (value == null) {
return undefined;
}
return REGEXP.test('' + value) ? value + 'px' : value;
}
function isString(string) {
return string && string.constructor === 'String';
}
function isArray(array) {
return array && array.constructor === 'Array';
}
function isObject(obj) {
return obj && obj.constructor === 'Object';
}
var isNoEmptyObj = function (obj) {
return isObject(obj) && JSON.stringify(obj) !== '{}';
};
function includes(arr, value) {
if (!arr || !isArray(arr)) return false;
var i = 0;
var len = arr.length;
for (; i < len; i++) {
if (arr[i] === value) return true;
}
return false;
}
function cls(base, arr) {
var res = [base];
var i = 0;
for (var size = arr.length; i < size; i++) {
var item = arr[i];
if (item && item.constructor === 'Array') {
var key = arr[i][0];
var value = arr[i][1];
if (value) {
res.push(base + '--' + key);
}
} else if (typeof item === 'string' || typeof item === 'number') {
if (item) {
res.push(base + '--' + item);
}
}
}
return res.join(' ');
}
function getBadgeAriaLabel(options) {
var maxCount = options.maxCount || 99;
if (options.dot) {
return '有新的消息';
}
if (options.count === '...') {
return '有很多消息';
}
if (isNaN(options.count)) {
return options.count;
}
var str1 = '有' + maxCount + '+条消息';
var str2 = '有' + options.count + '条消息';
return Number(options.count) > maxCount ? str1 : str2;
}
function endsWith(str, endStr) {
return str.slice(-endStr.length) === endStr ? str : str + endStr;
}
function keys(obj) {
return JSON.stringify(obj)
.replace(getRegExp('{|}|"', 'g'), '')
.split(',')
.map(function (item) {
return item.split(':')[0];
});
}
function kebabCase(str) {
return str
.replace(getRegExp('[A-Z]', 'g'), function (ele) {
return '-' + ele;
})
.toLowerCase();
}
function _style(styles) {
if (isArray(styles)) {
return styles
.filter(function (item) {
return item != null && item !== '';
})
.map(function (item) {
return isArray(item) ? _style(item) : endsWith(item, ';');
})
.join(' ');
}
if (isObject(styles)) {
return keys(styles)
.filter(function (key) {
return styles[key] != null && styles[key] !== '';
})
.map(function (key) {
return [kebabCase(key), [styles[key]]].join(':');
})
.join(';');
}
return styles;
}
module.exports = {
addUnit: addUnit,
isString: isString,
isArray: isArray,
isObject: isObject,
isNoEmptyObj: isNoEmptyObj,
includes: includes,
cls: cls,
getBadgeAriaLabel: getBadgeAriaLabel,
_style: _style,
};

View File

@ -0,0 +1,2 @@
export declare function canIUseFormFieldButton(): boolean;
export declare function canUseVirtualHost(): boolean;

View File

@ -0,0 +1,40 @@
let systemInfo;
function getSystemInfo() {
if (systemInfo == null) {
systemInfo = wx.getSystemInfoSync();
}
return systemInfo;
}
function compareVersion(v1, v2) {
v1 = v1.split('.');
v2 = v2.split('.');
const len = Math.max(v1.length, v2.length);
while (v1.length < len) {
v1.push('0');
}
while (v2.length < len) {
v2.push('0');
}
for (let i = 0; i < len; i++) {
const num1 = parseInt(v1[i]);
const num2 = parseInt(v2[i]);
if (num1 > num2) {
return 1;
}
else if (num1 < num2) {
return -1;
}
}
return 0;
}
function judgeByVersion(version) {
const currentSDKVersion = getSystemInfo().SDKVersion;
return compareVersion(currentSDKVersion, version) >= 0;
}
export function canIUseFormFieldButton() {
const version = '2.10.3';
return judgeByVersion(version);
}
export function canUseVirtualHost() {
return judgeByVersion('2.19.2');
}

View File

@ -0,0 +1 @@
export declare const getObserver: (context: any, selector: string) => Promise<unknown>;

View File

@ -0,0 +1,9 @@
export const getObserver = (context, selector) => {
return new Promise((resolve, reject) => {
wx.createIntersectionObserver(context)
.relativeToViewport()
.observe(selector, (res) => {
resolve(res);
});
});
};