cxy 1 month ago
parent 2a21352354
commit 69639d5a5e

@ -0,0 +1,31 @@
/*
* Eslint config file
* Documentation: https://eslint.org/docs/user-guide/configuring/
* Install the Eslint extension before using this feature.
*/
module.exports = {
env: {
es6: true,
browser: true,
node: true,
},
ecmaFeatures: {
modules: true,
},
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
},
globals: {
wx: true,
App: true,
Page: true,
getCurrentPages: true,
getApp: true,
Component: true,
requirePlugin: true,
requireMiniProgram: true,
},
// extends: 'eslint:recommended',
rules: {},
}

@ -0,0 +1,3 @@
需要安装两个npm依赖
npm install mina-request
npm i mobx-miniprogram mobx-miniprogram-bindings

@ -0,0 +1,40 @@
// app.js
import { setStorage, getStorage, removeStorage, clearStorage} from './utils/storage'
// import { asyncSetStorage, asyncGetStorage, asyncRemoveStorage, asyncClearStorage} from './utils/storage'
// import { toast} from './utils/extendApi'
App({
async onShow(){
//测试封装函数
// toast({toast:'o( ̄▽ ̄)',icon:'error'})
// setStorage('id',1)
// setStorage('identify',1)
// const name = getStorage('name')
// console.log(name)
// removeStorage('name')
// clearStorage()
// asyncSetStorage('name','Jerry').then((res) =>{
// console.log(res)
// })
// asyncSetStorage('age','28').then((res) =>{
// console.log(res)
// })
// asyncGetStorage('name').then((res) =>{
// console.log(res)
// })
// asyncRemoveStorage('name').then((res) =>{
// console.log(res)
// })
// asyncClearStorage().then((res) =>{
// console.log(res)
// })
},
globalData: {
userInfo: null
}
})

@ -0,0 +1,57 @@
{
"pages": [
"pages/login/login",
"pages/upteach/upteach",
"pages/addlesson/addlesson",
"pages/home/home",
"pages/rank/rank",
"pages/attend/attend",
"pages/teacherinfo/teacherinfo",
"pages/identify/identify",
"pages/index/index",
"pages/logs/logs",
"pages/mine/mine"
],
"window": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "classRoll",
"navigationBarBackgroundColor": "#ffffff"
},
"style": "v2",
"enablePullDownRefresh":true,
"componentFramework": "glass-easel",
"sitemapLocation": "sitemap.json",
"lazyCodeLoading": "requiredComponents",
"tabBar": {
"borderStyle":"white",
"list": [
{
"pagePath": "pages/home/home",
"text": "课程",
"color": "#7A7E83",
"iconPath": "/images/icon/class.png",
"selectedIconPath": "/images/icon/class_selected.png",
"selectedColor": "#3cc51f"
},
{
"pagePath": "pages/rank/rank",
"text": "排行榜",
"color": "#7A7E83",
"iconPath": "/images/icon/rank.png",
"selectedIconPath": "/images/icon/rank_selected.png",
"selectedColor": "#3cc51f"
},
{
"pagePath": "pages/mine/mine",
"text": "我的",
"color": "#7A7E83",
"iconPath": "/images/icon/user_01.png",
"selectedIconPath": "/images/icon/user_01_selected.png",
"selectedColor": "#3cc51f"
}
]
}
}

@ -0,0 +1,10 @@
/**app.wxss**/
.container {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
padding: 200rpx 0;
box-sizing: border-box;
}

@ -0,0 +1,59 @@
module.exports = (function() {
var __MODS__ = {};
var __DEFINE__ = function(modId, func, req) { var m = { exports: {}, _tempexports: {} }; __MODS__[modId] = { status: 0, func: func, req: req, m: m }; };
var __REQUIRE__ = function(modId, source) { if(!__MODS__[modId]) return require(source); if(!__MODS__[modId].status) { var m = __MODS__[modId].m; m._exports = m._tempexports; var desp = Object.getOwnPropertyDescriptor(m, "exports"); if (desp && desp.configurable) Object.defineProperty(m, "exports", { set: function (val) { if(typeof val === "object" && val !== m._exports) { m._exports.__proto__ = val.__proto__; Object.keys(val).forEach(function (k) { m._exports[k] = val[k]; }); } m._tempexports = val }, get: function () { return m._tempexports; } }); __MODS__[modId].status = 1; __MODS__[modId].func(__MODS__[modId].req, m, m.exports); } return __MODS__[modId].m.exports; };
var __REQUIRE_WILDCARD__ = function(obj) { if(obj && obj.__esModule) { return obj; } else { var newObj = {}; if(obj != null) { for(var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) newObj[k] = obj[k]; } } newObj.default = obj; return newObj; } };
var __REQUIRE_DEFAULT__ = function(obj) { return obj && obj.__esModule ? obj.default : obj; };
__DEFINE__(1728655564987, function(require, module, exports) {
// do not edit .js files directly - edit src/index.jst
module.exports = function equal(a, b) {
if (a === b) return true;
if (a && b && typeof a == 'object' && typeof b == 'object') {
if (a.constructor !== b.constructor) return false;
var length, i, keys;
if (Array.isArray(a)) {
length = a.length;
if (length != b.length) return false;
for (i = length; i-- !== 0;)
if (!equal(a[i], b[i])) return false;
return true;
}
if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
keys = Object.keys(a);
length = keys.length;
if (length !== Object.keys(b).length) return false;
for (i = length; i-- !== 0;)
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
for (i = length; i-- !== 0;) {
var key = keys[i];
if (!equal(a[key], b[key])) return false;
}
return true;
}
// true if both NaN, false otherwise
return a!==a && b!==b;
};
}, function(modId) {var map = {}; return __REQUIRE__(map[modId], modId); })
return __REQUIRE__(1728655564987);
})()
//miniprogram-npm-outsideDeps=[]
//# sourceMappingURL=index.js.map

@ -0,0 +1 @@
{"version":3,"sources":["index.js"],"names":[],"mappings":";;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"index.js","sourcesContent":["\n\n// do not edit .js files directly - edit src/index.jst\n\n\n\nmodule.exports = function equal(a, b) {\n if (a === b) return true;\n\n if (a && b && typeof a == 'object' && typeof b == 'object') {\n if (a.constructor !== b.constructor) return false;\n\n var length, i, keys;\n if (Array.isArray(a)) {\n length = a.length;\n if (length != b.length) return false;\n for (i = length; i-- !== 0;)\n if (!equal(a[i], b[i])) return false;\n return true;\n }\n\n\n\n if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;\n if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();\n if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();\n\n keys = Object.keys(a);\n length = keys.length;\n if (length !== Object.keys(b).length) return false;\n\n for (i = length; i-- !== 0;)\n if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;\n\n for (i = length; i-- !== 0;) {\n var key = keys[i];\n\n if (!equal(a[key], b[key])) return false;\n }\n\n return true;\n }\n\n // true if both NaN, false otherwise\n return a!==a && b!==b;\n};\n"]}

@ -0,0 +1,212 @@
class WxRequest {
// 定义实例属性,用来设置默认请求参数
defaults = {
baseURL: '', // 请求基准地址
url: '', // 接口的请求路径
data: null, // 请求参数
method: 'GET', // 默认的请求方法
// 请求头
header: {
'Content-type': 'application/json' // 设置数据的交互格式
},
timeout: 60000, // 默认的超时时长,小程序默认的超时时长是 1 分钟
isLoading: true // 控制是否使用默认的 loading默认值是 true 表示使用默认的 loading
}
// 定义拦截器对象
interceptors = {
// 请求拦截器
request: (config) => config,
// 响应拦截器
response: (response) => response
}
// 定义数组队列,用来存储请求队列、存储请求标识
queue = []
// constructor 用于创建和初始化类的属性以及方法
constructor(params = {}) {
// 注意:需要传入的参数,覆盖默认的参数,因此传入的参数需要放到最后
this.defaults = Object.assign({}, this.defaults, params)
}
/**
* @description request 实例方法发送网络请求接收一个对象类型的参数
* @param {*} options 属性值和 wx.request() 方法调用时传递的参数保持一致
* @returns Promise
*/
request(options) {
// 如果有新的请求,就清除上一次的定时器
this.timerId && clearTimeout(this.timerId)
// 合并完整的请求地址
options.url = this.defaults.baseURL + options.url
// 合并请求参数:调用实例方法时传入的覆盖默认的以及实例配置的
options = { ...this.defaults, ...options }
// 控制 loading 的显示与隐藏
if (options.isLoading && options.method !== 'UPLOAD') {
this.queue.length === 0 && wx.showLoading()
this.queue.push('request')
}
// 在请求发送之前,调用请求拦截器,新增和修改请求参数
// 请求拦截器内部,会将新增和修改以后的参数返回
options = this.interceptors.request(options)
// 需要使用 Promise 封装 wx.request处理异步请求
return new Promise((resolve, reject) => {
// 如果 method 等于 UPLOAD 说明需要调用 wx.uploadFile() 方法
// 否则调用的是 wx.request() 方法
if (options.method === 'UPLOAD') {
wx.uploadFile({
...options,
success: (res) => {
// 需要将服务器返回的 JSON 字符串 通过 JSON.parse 转成对象
res.data = JSON.parse(res.data)
// 合并参数
const mergeRes = Object.assign({}, res, {
config: options,
isSuccess: true
})
resolve(this.interceptors.response(mergeRes))
},
fail: (err) => {
// 合并参数
const mergeErr = Object.assign({}, err, {
config: options,
isSuccess: false
})
reject(this.interceptors.response(mergeErr))
}
})
} else {
wx.request({
...options,
// 当接口调用成功时会触发 success 回调函数
success: (res) => {
// 合并请求参数,方便进行代码调试
// 追加 isSuccess 属性,是为了标识响应拦截器是 success 调用还是 fail 调用
const mergeRes = Object.assign({}, res, {
config: options,
isSuccess: true
})
resolve(this.interceptors.response(mergeRes))
},
// 当接口调用失败时会触发 fail 回调函数
fail: (err) => {
// 合并请求参数,方便进行代码调试
// 追加 isSuccess 属性,是为了标识响应拦截器是 success 调用还是 fail 调用
const mergeErr = Object.assign({}, err, {
config: options,
isSuccess: false
})
reject(this.interceptors.response(mergeErr))
},
// 接口调用结束的回调函数(调用成功、失败都会执行)
complete: () => {
// 如果需要显示 loading ,那么就需要控制 loading 的隐藏
if (options.isLoading) {
// 在每一个请求结束以后,都会执行 complete 回调函数
// 每次从 queue 队列中删除一个标识
this.queue.pop()
// 解决并发请求loading 闪烁问题
this.queue.length === 0 && this.queue.push('request')
//解决并发请求loading 闪烁问题
this.timerId = setTimeout(() => {
this.queue.pop()
this.queue.length === 0 && wx.hideLoading()
clearTimeout(this.timerId)
}, 1)
}
}
})
}
})
}
/**
* @description 封装 GET 实例方法
* @param {*} url 请求地址
* @param {*} data 请求参数
* @param {*} config 其他请求配置项
* @returns Promise
*/
get(url, data = {}, config = {}) {
// 需要调用 request 请求方法发送请求,只需要组织好参数,传递给 request 请求方法即可
// 当调用 get 方法时,需要将 request 方法的返回值 return 出去
return this.request(Object.assign({ url, data, method: 'GET' }, config))
}
/**
* @description 封装 DELETE 实例方法
* @param {*} url 请求地址
* @param {*} data 请求参数
* @param {*} config 其他请求配置项
* @returns Promise
*/
delete(url, data = {}, config = {}) {
return this.request(Object.assign({ url, data, method: 'DELETE' }, config))
}
/**
* @description 封装 POST 实例方法
* @param {*} url 请求地址
* @param {*} data 请求参数
* @param {*} config 其他请求配置项
* @returns Promise
*/
post(url, data = {}, config = {}) {
return this.request(Object.assign({ url, data, method: 'POST' }, config))
}
/**
* @description 封封装 PUT 实例方法
* @param {*} url 请求地址
* @param {*} data 请求参数
* @param {*} config 其他请求配置项
* @returns Promise
*/
put(url, data = {}, config = {}) {
return this.request(Object.assign({ url, data, method: 'PUT' }, config))
}
/**
* @description 处理并发请求
* @param {...promise} promise 传入的每一项需要是 Promise
* @returns Promise
*/
all(...promise) {
// 那么展开运算符会将传入的参数转成数组
return Promise.all(promise)
}
/**
* @description upload 实例方法用来对 wx.uploadFile 进行封装
* @param {*} url 文件的上传地址接口地址
* @param {*} filePath 要上传的文件资源路径
* @param {*} name 文件对应的 key
* @param {*} config 其他配置项
*/
upload(url, filePath, name = 'file', config = {}) {
return this.request(
Object.assign({ url, filePath, name, method: 'UPLOAD' }, config)
)
}
}
export default WxRequest

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,211 @@
module.exports = (function() {
var __MODS__ = {};
var __DEFINE__ = function(modId, func, req) { var m = { exports: {}, _tempexports: {} }; __MODS__[modId] = { status: 0, func: func, req: req, m: m }; };
var __REQUIRE__ = function(modId, source) { if(!__MODS__[modId]) return require(source); if(!__MODS__[modId].status) { var m = __MODS__[modId].m; m._exports = m._tempexports; var desp = Object.getOwnPropertyDescriptor(m, "exports"); if (desp && desp.configurable) Object.defineProperty(m, "exports", { set: function (val) { if(typeof val === "object" && val !== m._exports) { m._exports.__proto__ = val.__proto__; Object.keys(val).forEach(function (k) { m._exports[k] = val[k]; }); } m._tempexports = val }, get: function () { return m._tempexports; } }); __MODS__[modId].status = 1; __MODS__[modId].func(__MODS__[modId].req, m, m.exports); } return __MODS__[modId].m.exports; };
var __REQUIRE_WILDCARD__ = function(obj) { if(obj && obj.__esModule) { return obj; } else { var newObj = {}; if(obj != null) { for(var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) newObj[k] = obj[k]; } } newObj.default = obj; return newObj; } };
var __REQUIRE_DEFAULT__ = function(obj) { return obj && obj.__esModule ? obj.default : obj; };
__DEFINE__(1728655564989, function(require, module, exports) {
module.exports = rfdc
function copyBuffer (cur) {
if (cur instanceof Buffer) {
return Buffer.from(cur)
}
return new cur.constructor(cur.buffer.slice(), cur.byteOffset, cur.length)
}
function rfdc (opts) {
opts = opts || {}
if (opts.circles) return rfdcCircles(opts)
const constructorHandlers = new Map()
constructorHandlers.set(Date, (o) => new Date(o))
constructorHandlers.set(Map, (o, fn) => new Map(cloneArray(Array.from(o), fn)))
constructorHandlers.set(Set, (o, fn) => new Set(cloneArray(Array.from(o), fn)))
if (opts.constructorHandlers) {
for (const handler of opts.constructorHandlers) {
constructorHandlers.set(handler[0], handler[1])
}
}
let handler = null
return opts.proto ? cloneProto : clone
function cloneArray (a, fn) {
const keys = Object.keys(a)
const a2 = new Array(keys.length)
for (let i = 0; i < keys.length; i++) {
const k = keys[i]
const cur = a[k]
if (typeof cur !== 'object' || cur === null) {
a2[k] = cur
} else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
a2[k] = handler(cur, fn)
} else if (ArrayBuffer.isView(cur)) {
a2[k] = copyBuffer(cur)
} else {
a2[k] = fn(cur)
}
}
return a2
}
function clone (o) {
if (typeof o !== 'object' || o === null) return o
if (Array.isArray(o)) return cloneArray(o, clone)
if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {
return handler(o, clone)
}
const o2 = {}
for (const k in o) {
if (Object.hasOwnProperty.call(o, k) === false) continue
const cur = o[k]
if (typeof cur !== 'object' || cur === null) {
o2[k] = cur
} else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
o2[k] = handler(cur, clone)
} else if (ArrayBuffer.isView(cur)) {
o2[k] = copyBuffer(cur)
} else {
o2[k] = clone(cur)
}
}
return o2
}
function cloneProto (o) {
if (typeof o !== 'object' || o === null) return o
if (Array.isArray(o)) return cloneArray(o, cloneProto)
if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {
return handler(o, cloneProto)
}
const o2 = {}
for (const k in o) {
const cur = o[k]
if (typeof cur !== 'object' || cur === null) {
o2[k] = cur
} else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
o2[k] = handler(cur, cloneProto)
} else if (ArrayBuffer.isView(cur)) {
o2[k] = copyBuffer(cur)
} else {
o2[k] = cloneProto(cur)
}
}
return o2
}
}
function rfdcCircles (opts) {
const refs = []
const refsNew = []
const constructorHandlers = new Map()
constructorHandlers.set(Date, (o) => new Date(o))
constructorHandlers.set(Map, (o, fn) => new Map(cloneArray(Array.from(o), fn)))
constructorHandlers.set(Set, (o, fn) => new Set(cloneArray(Array.from(o), fn)))
if (opts.constructorHandlers) {
for (const handler of opts.constructorHandlers) {
constructorHandlers.set(handler[0], handler[1])
}
}
let handler = null
return opts.proto ? cloneProto : clone
function cloneArray (a, fn) {
const keys = Object.keys(a)
const a2 = new Array(keys.length)
for (let i = 0; i < keys.length; i++) {
const k = keys[i]
const cur = a[k]
if (typeof cur !== 'object' || cur === null) {
a2[k] = cur
} else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
a2[k] = handler(cur, fn)
} else if (ArrayBuffer.isView(cur)) {
a2[k] = copyBuffer(cur)
} else {
const index = refs.indexOf(cur)
if (index !== -1) {
a2[k] = refsNew[index]
} else {
a2[k] = fn(cur)
}
}
}
return a2
}
function clone (o) {
if (typeof o !== 'object' || o === null) return o
if (Array.isArray(o)) return cloneArray(o, clone)
if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {
return handler(o, clone)
}
const o2 = {}
refs.push(o)
refsNew.push(o2)
for (const k in o) {
if (Object.hasOwnProperty.call(o, k) === false) continue
const cur = o[k]
if (typeof cur !== 'object' || cur === null) {
o2[k] = cur
} else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
o2[k] = handler(cur, clone)
} else if (ArrayBuffer.isView(cur)) {
o2[k] = copyBuffer(cur)
} else {
const i = refs.indexOf(cur)
if (i !== -1) {
o2[k] = refsNew[i]
} else {
o2[k] = clone(cur)
}
}
}
refs.pop()
refsNew.pop()
return o2
}
function cloneProto (o) {
if (typeof o !== 'object' || o === null) return o
if (Array.isArray(o)) return cloneArray(o, cloneProto)
if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {
return handler(o, cloneProto)
}
const o2 = {}
refs.push(o)
refsNew.push(o2)
for (const k in o) {
const cur = o[k]
if (typeof cur !== 'object' || cur === null) {
o2[k] = cur
} else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
o2[k] = handler(cur, cloneProto)
} else if (ArrayBuffer.isView(cur)) {
o2[k] = copyBuffer(cur)
} else {
const i = refs.indexOf(cur)
if (i !== -1) {
o2[k] = refsNew[i]
} else {
o2[k] = cloneProto(cur)
}
}
}
refs.pop()
refsNew.pop()
return o2
}
}
}, function(modId) {var map = {}; return __REQUIRE__(map[modId], modId); })
return __REQUIRE__(1728655564989);
})()
//miniprogram-npm-outsideDeps=[]
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

@ -0,0 +1,54 @@
{
"name": "classRoll",
"lockfileVersion": 3,
"requires": true,
"packages": {
"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/mina-request": {
"version": "1.0.8",
"resolved": "https://registry.npmmirror.com/mina-request/-/mina-request-1.0.8.tgz",
"integrity": "sha512-IzsnzZEAJOyQnYMKhut7+m6EygiiZOd5yvspNplVlVT026ucaaJrie92k0K0Umw0jkASvJn1WXjSq+FntYj/GQ=="
},
"node_modules/miniprogram-api-typings": {
"version": "3.12.3",
"resolved": "https://registry.npmmirror.com/miniprogram-api-typings/-/miniprogram-api-typings-3.12.3.tgz",
"integrity": "sha512-o7bOfrU28MEMCBWo83nXv0ROQSBFxJcfCl4f2wTYqah64ipC5RGqLJfvWJTWhlQt2ECVwspSzM8LgvnfMo7TEQ=="
},
"node_modules/miniprogram-computed": {
"version": "5.1.0",
"resolved": "https://registry.npmmirror.com/miniprogram-computed/-/miniprogram-computed-5.1.0.tgz",
"integrity": "sha512-sA2Kx9N8xYnZtOlZogSzCUdy+e6wTztnnAzbY2yRksdXL5Zo2Zs2BGzHMTLvn1JlDyyS5K9QD0L4ksohfxNOYg==",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"miniprogram-api-typings": "^3.12.2",
"rfdc": "^1.3.1"
}
},
"node_modules/mobx-miniprogram": {
"version": "6.12.3",
"resolved": "https://registry.npmmirror.com/mobx-miniprogram/-/mobx-miniprogram-6.12.3.tgz",
"integrity": "sha512-GEq1EG7jZPnrHYV43oppa6jY9lgbNRuGPiXyOFRoluHjd5LIGBf3a+zXMjzO1AVwrFOWvVRazxtzfiRXMUUqZw==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mobx"
}
},
"node_modules/mobx-miniprogram-bindings": {
"version": "4.0.1",
"resolved": "https://registry.npmmirror.com/mobx-miniprogram-bindings/-/mobx-miniprogram-bindings-4.0.1.tgz",
"integrity": "sha512-K2abvA+tGdEj70SD0hPEGCwTUgMLCZhdgHxO17B18TN5GhGNlUnj09BwXauqdWONwq4OuODYCrZwjAIadPQXFw==",
"peerDependencies": {
"mobx-miniprogram": "^6.0.0"
}
},
"node_modules/rfdc": {
"version": "1.4.1",
"resolved": "https://registry.npmmirror.com/rfdc/-/rfdc-1.4.1.tgz",
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="
}
}
}

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Evgeny Poberezkin
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.

@ -0,0 +1,96 @@
# fast-deep-equal
The fastest deep equal with ES6 Map, Set and Typed arrays support.
[![Build Status](https://travis-ci.org/epoberezkin/fast-deep-equal.svg?branch=master)](https://travis-ci.org/epoberezkin/fast-deep-equal)
[![npm](https://img.shields.io/npm/v/fast-deep-equal.svg)](https://www.npmjs.com/package/fast-deep-equal)
[![Coverage Status](https://coveralls.io/repos/github/epoberezkin/fast-deep-equal/badge.svg?branch=master)](https://coveralls.io/github/epoberezkin/fast-deep-equal?branch=master)
## Install
```bash
npm install fast-deep-equal
```
## Features
- ES5 compatible
- works in node.js (8+) and browsers (IE9+)
- checks equality of Date and RegExp objects by value.
ES6 equal (`require('fast-deep-equal/es6')`) also supports:
- Maps
- Sets
- Typed arrays
## Usage
```javascript
var equal = require('fast-deep-equal');
console.log(equal({foo: 'bar'}, {foo: 'bar'})); // true
```
To support ES6 Maps, Sets and Typed arrays equality use:
```javascript
var equal = require('fast-deep-equal/es6');
console.log(equal(Int16Array([1, 2]), Int16Array([1, 2]))); // true
```
To use with React (avoiding the traversal of React elements' _owner
property that contains circular references and is not needed when
comparing the elements - borrowed from [react-fast-compare](https://github.com/FormidableLabs/react-fast-compare)):
```javascript
var equal = require('fast-deep-equal/react');
var equal = require('fast-deep-equal/es6/react');
```
## Performance benchmark
Node.js v12.6.0:
```
fast-deep-equal x 261,950 ops/sec ±0.52% (89 runs sampled)
fast-deep-equal/es6 x 212,991 ops/sec ±0.34% (92 runs sampled)
fast-equals x 230,957 ops/sec ±0.83% (85 runs sampled)
nano-equal x 187,995 ops/sec ±0.53% (88 runs sampled)
shallow-equal-fuzzy x 138,302 ops/sec ±0.49% (90 runs sampled)
underscore.isEqual x 74,423 ops/sec ±0.38% (89 runs sampled)
lodash.isEqual x 36,637 ops/sec ±0.72% (90 runs sampled)
deep-equal x 2,310 ops/sec ±0.37% (90 runs sampled)
deep-eql x 35,312 ops/sec ±0.67% (91 runs sampled)
ramda.equals x 12,054 ops/sec ±0.40% (91 runs sampled)
util.isDeepStrictEqual x 46,440 ops/sec ±0.43% (90 runs sampled)
assert.deepStrictEqual x 456 ops/sec ±0.71% (88 runs sampled)
The fastest is fast-deep-equal
```
To run benchmark (requires node.js 6+):
```bash
npm run benchmark
```
__Please note__: this benchmark runs against the available test cases. To choose the most performant library for your application, it is recommended to benchmark against your data and to NOT expect this benchmark to reflect the performance difference in your application.
## Enterprise support
fast-deep-equal package is a part of [Tidelift enterprise subscription](https://tidelift.com/subscription/pkg/npm-fast-deep-equal?utm_source=npm-fast-deep-equal&utm_medium=referral&utm_campaign=enterprise&utm_term=repo) - it provides a centralised commercial support to open-source software users, in addition to the support provided by software maintainers.
## Security contact
To report a security vulnerability, please use the
[Tidelift security contact](https://tidelift.com/security).
Tidelift will coordinate the fix and disclosure. Please do NOT report security vulnerability via GitHub issues.
## License
[MIT](https://github.com/epoberezkin/fast-deep-equal/blob/master/LICENSE)

@ -0,0 +1,2 @@
declare const equal: (a: any, b: any) => boolean;
export = equal;

@ -0,0 +1,72 @@
'use strict';
// do not edit .js files directly - edit src/index.jst
var envHasBigInt64Array = typeof BigInt64Array !== 'undefined';
module.exports = function equal(a, b) {
if (a === b) return true;
if (a && b && typeof a == 'object' && typeof b == 'object') {
if (a.constructor !== b.constructor) return false;
var length, i, keys;
if (Array.isArray(a)) {
length = a.length;
if (length != b.length) return false;
for (i = length; i-- !== 0;)
if (!equal(a[i], b[i])) return false;
return true;
}
if ((a instanceof Map) && (b instanceof Map)) {
if (a.size !== b.size) return false;
for (i of a.entries())
if (!b.has(i[0])) return false;
for (i of a.entries())
if (!equal(i[1], b.get(i[0]))) return false;
return true;
}
if ((a instanceof Set) && (b instanceof Set)) {
if (a.size !== b.size) return false;
for (i of a.entries())
if (!b.has(i[0])) return false;
return true;
}
if (ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {
length = a.length;
if (length != b.length) return false;
for (i = length; i-- !== 0;)
if (a[i] !== b[i]) return false;
return true;
}
if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
keys = Object.keys(a);
length = keys.length;
if (length !== Object.keys(b).length) return false;
for (i = length; i-- !== 0;)
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
for (i = length; i-- !== 0;) {
var key = keys[i];
if (!equal(a[key], b[key])) return false;
}
return true;
}
// true if both NaN, false otherwise
return a!==a && b!==b;
};

@ -0,0 +1,2 @@
declare const equal: (a: any, b: any) => boolean;
export = equal;

@ -0,0 +1,79 @@
'use strict';
// do not edit .js files directly - edit src/index.jst
var envHasBigInt64Array = typeof BigInt64Array !== 'undefined';
module.exports = function equal(a, b) {
if (a === b) return true;
if (a && b && typeof a == 'object' && typeof b == 'object') {
if (a.constructor !== b.constructor) return false;
var length, i, keys;
if (Array.isArray(a)) {
length = a.length;
if (length != b.length) return false;
for (i = length; i-- !== 0;)
if (!equal(a[i], b[i])) return false;
return true;
}
if ((a instanceof Map) && (b instanceof Map)) {
if (a.size !== b.size) return false;
for (i of a.entries())
if (!b.has(i[0])) return false;
for (i of a.entries())
if (!equal(i[1], b.get(i[0]))) return false;
return true;
}
if ((a instanceof Set) && (b instanceof Set)) {
if (a.size !== b.size) return false;
for (i of a.entries())
if (!b.has(i[0])) return false;
return true;
}
if (ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {
length = a.length;
if (length != b.length) return false;
for (i = length; i-- !== 0;)
if (a[i] !== b[i]) return false;
return true;
}
if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
keys = Object.keys(a);
length = keys.length;
if (length !== Object.keys(b).length) return false;
for (i = length; i-- !== 0;)
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
for (i = length; i-- !== 0;) {
var key = keys[i];
if (key === '_owner' && a.$$typeof) {
// React-specific: avoid traversing React elements' _owner.
// _owner contains circular references
// and is not needed when comparing the actual elements (and not their owners)
continue;
}
if (!equal(a[key], b[key])) return false;
}
return true;
}
// true if both NaN, false otherwise
return a!==a && b!==b;
};

@ -0,0 +1,4 @@
declare module 'fast-deep-equal' {
const equal: (a: any, b: any) => boolean;
export = equal;
}

@ -0,0 +1,46 @@
'use strict';
// do not edit .js files directly - edit src/index.jst
module.exports = function equal(a, b) {
if (a === b) return true;
if (a && b && typeof a == 'object' && typeof b == 'object') {
if (a.constructor !== b.constructor) return false;
var length, i, keys;
if (Array.isArray(a)) {
length = a.length;
if (length != b.length) return false;
for (i = length; i-- !== 0;)
if (!equal(a[i], b[i])) return false;
return true;
}
if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
keys = Object.keys(a);
length = keys.length;
if (length !== Object.keys(b).length) return false;
for (i = length; i-- !== 0;)
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
for (i = length; i-- !== 0;) {
var key = keys[i];
if (!equal(a[key], b[key])) return false;
}
return true;
}
// true if both NaN, false otherwise
return a!==a && b!==b;
};

@ -0,0 +1,61 @@
{
"name": "fast-deep-equal",
"version": "3.1.3",
"description": "Fast deep equal",
"main": "index.js",
"scripts": {
"eslint": "eslint *.js benchmark/*.js spec/*.js",
"build": "node build",
"benchmark": "npm i && npm run build && cd ./benchmark && npm i && node ./",
"test-spec": "mocha spec/*.spec.js -R spec",
"test-cov": "nyc npm run test-spec",
"test-ts": "tsc --target ES5 --noImplicitAny index.d.ts",
"test": "npm run build && npm run eslint && npm run test-ts && npm run test-cov",
"prepublish": "npm run build"
},
"repository": {
"type": "git",
"url": "git+https://github.com/epoberezkin/fast-deep-equal.git"
},
"keywords": [
"fast",
"equal",
"deep-equal"
],
"author": "Evgeny Poberezkin",
"license": "MIT",
"bugs": {
"url": "https://github.com/epoberezkin/fast-deep-equal/issues"
},
"homepage": "https://github.com/epoberezkin/fast-deep-equal#readme",
"devDependencies": {
"coveralls": "^3.1.0",
"dot": "^1.1.2",
"eslint": "^7.2.0",
"mocha": "^7.2.0",
"nyc": "^15.1.0",
"pre-commit": "^1.2.2",
"react": "^16.12.0",
"react-test-renderer": "^16.12.0",
"sinon": "^9.0.2",
"typescript": "^3.9.5"
},
"nyc": {
"exclude": [
"**/spec/**",
"node_modules"
],
"reporter": [
"lcov",
"text-summary"
]
},
"files": [
"index.js",
"index.d.ts",
"react.js",
"react.d.ts",
"es6/"
],
"types": "index.d.ts"
}

@ -0,0 +1,2 @@
declare const equal: (a: any, b: any) => boolean;
export = equal;

@ -0,0 +1,53 @@
'use strict';
// do not edit .js files directly - edit src/index.jst
module.exports = function equal(a, b) {
if (a === b) return true;
if (a && b && typeof a == 'object' && typeof b == 'object') {
if (a.constructor !== b.constructor) return false;
var length, i, keys;
if (Array.isArray(a)) {
length = a.length;
if (length != b.length) return false;
for (i = length; i-- !== 0;)
if (!equal(a[i], b[i])) return false;
return true;
}
if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
keys = Object.keys(a);
length = keys.length;
if (length !== Object.keys(b).length) return false;
for (i = length; i-- !== 0;)
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
for (i = length; i-- !== 0;) {
var key = keys[i];
if (key === '_owner' && a.$$typeof) {
// React-specific: avoid traversing React elements' _owner.
// _owner contains circular references
// and is not needed when comparing the actual elements (and not their owners)
continue;
}
if (!equal(a[key], b[key])) return false;
}
return true;
}
// true if both NaN, false otherwise
return a!==a && b!==b;
};

@ -0,0 +1,387 @@
### 介绍
<br />
微信小程序网络请求工具,包含以下功能:
1. 请求拦截器
2. 响应拦截器
3. 并发请求
4. 本地资源上传等
5. 其他...
<br />
### 安装
<br />
```shell
npm install mina-request
```
> 📌 构建 npm
>
> 安装包后,需要在微信开发者工具中进行 npm 构建,点击 `工具` ➡️ `构建 npm`
<br />
### 实例
<br />
#### 创建实例
<br />
您可以使用自定义配置新建一个实例
<br />
```js
import WxRequest from 'mina-request'
// 对 WxRequest 进行实例化
const instance = new WxRequest({
baseURL: 'https://some-domain.com/api', // 使用时请换成真实接口
timeout: 1000, // 超时时长
isLoading: false // 是否使用默认的 loading 效果
})
```
<br />
#### 实例方法
<br />
以下是可用的实例方法。指定的配置将与实例的配置合并。
> 📌config 对象属性值和 wx.request() 方法调用时传递的参数保持一致
<br />
```js
instance.request(config)
instance.get(url, data, config)
instance.delete(url, data, config)
instance.post(url, data, config)
instance.put(url, data, config)
instance.all(...promise) // 传入一个个 Promise 即可
instance.upload(url, filePath, name, config) // 将本地资源上传到服务器
```
<br />
#### 代码示例
<br />
```js
// request 实例方法
instance.request({
url: '/path',
method: 'POST'
})
// get 实例方法
// 不需要请求参数,也不需要自定义请求配置
instance.get('/path')
// 不需要自定义请求配置
instance.get('/path', { id: 123 })
// 需要请求参数,也需要自定义请求配置
instance.get('/path', { id: 123 }, { timeout: 15000 })
// 不需要请求参数,但需要自定义请求配置
instance.get('/path', null, { timeout: 15000 })
// delete、post、put 方法同上
```
<br />
### 请求配置
<br />
这些是创建请求时可以用的配置选项。如果没有指定 `method`,请求将默认使用 `GET` 方法。
<br />
```js
{
baseURL: '', // 请求基准路径,方便进行接口的统一管理
url: '', // 是用于请求的服务器 URL
method: 'GET', // method是创建请求时使用的方法默认值是 GET
headers: {}, // 请求头
data: {}, // 请求参数
timeout: 60000, // 默认的超时时长,小程序默认的超时时长是 1 分钟
isLoading: true // 控制是否使用默认的 loading默认值是 true 表示使用默认的 loading
// ... 📌 其他属性值和 wx.request() 方法调用时传递的参数保持一致
}
```
<br />
### 默认配置
<br />
您可以指定默认配置,它将作用于每个请求。
<br />
#### 全局默认值
<br />
```js
instance.defaults.baseURL = 'https://some-domain.com/api/'
instance.defaults.header['token'] = token
instance.defaults.isLoading = fasle
```
<br />
#### 自定义实例默认值
<br />
```js
// 创建实例时配置默认值
const instance = new WxRequest({
baseURL: 'https://some-domain.com/api/'
})
// 创建实例后修改默认值
instance.defaults.header['token'] = token
```
<br />
#### 配置的优先级
<br />
实例方法配置(2) > 创建实例时配置项(1) > 默认配置(0)
<br />
```js
// 默认配置,优先级 0
{
timeout: 60000 // 默认的超时时长,小程序默认的超时时长是 1 分钟
}
// 创建实例时配置项,优先级 1
const instance = new WxRequest({
timeout = 2500
})
// 调用实例方法,优先级 2
instance.get('/path', null, {
timeout: 5000
})
```
<br />
### 拦截器
<br />
在请求之前新增、修改参数,在响应以后进行逻辑判断、处理
<br />
```js
// 添加请求拦截器
instance.interceptors.request = (config) => {
// 在发送请求之前做些什么
return config
}
// 添加响应拦截器
instance.interceptors.response = (response) => {
// response.isSuccess = true代码执行了 wx.request 的 success 回调函数
// response.isSuccess = false代码执行了 wx.request 的 fail 回调函数
// response.statusCode // http 响应状态码
// response.config // 网络请求请求参数
// response.data 服务器响应的真正数据
// 对响应数据做点什么
return response
}
```
<br />
### 本地资源上传
<br />
将本地资源上传到服务器.
<br />
```js
/**
* @description upload 实例方法,用来对 wx.uploadFile 进行封装
* @param {*} url 文件的上传地址、接口地址
* @param {*} filePath 要上传的文件资源路径
* @param {*} name 文件对应的 key
* @param {*} config 其他配置项
*/
upload(url, filePath, name = 'file', config = {}) {
return this.request(
Object.assign({ url, filePath, name, method: 'UPLOAD' }, config)
)
}
// 使用示例
await instance.upload('/path', filePath, name, { ... })
```
<br />
### 并发请求
<br />
```js
/**
* @description 处理并发请求
* @param {...promise} promise 传入的每一项需要是 Promise
* @returns Promise
*/
all(...promise) {
// 那么展开运算符会将传入的参数转成数组
return Promise.all(promise)
}
// 使用示例
await instance.all(promise1, promise2, promise3)
```
<br />
### 完整示例
<br />
导入 `mina-request` ,进行网络请求统一配置:
```js
import WxRequest from 'mina-request'
// 对 WxRequest 进行实例化
const instance = new WxRequest({
baseURL: 'https://some-domain.com/api/',
timeout: 15000,
isLoading: false // 不使用默认 loading
})
// 添加请求拦截器
instance.interceptors.request = (config) => {
// 在请求发送之前做点什么……
// 新增请求头
const token = wx.getStorageSync('token')
if (token) {
config.header['token'] = token
}
return config
}
// 添加响应拦截器
instance.interceptors.response = (response) => {
// 对响应数据做点什么
// 从 response 中解构 isSuccess
const { isSuccess, data } = response
// 如果 isSuccess 为 false说明执行了 fail 回调函数
// 这时候就说明网络异常,需要给用户提示网络异常
if (!isSuccess) {
wx.showToast({
title: '网络异常,请稍后重试 !'
})
return response
}
// 对业务状态码进行
// ...
// 将服务器响应的数据返回
return data
}
export default instance
```
导入实例,使用实例提供的方法:
```js
// 导入封装的 网络请求模块实例
import instance from '../utils/instance'
/**
* @description 用来获取首页轮播图数据
*/
export const reqSwiperData = () => instance.get('/index/findBanner')
```

@ -0,0 +1,212 @@
class WxRequest {
// 定义实例属性,用来设置默认请求参数
defaults = {
baseURL: '', // 请求基准地址
url: '', // 接口的请求路径
data: null, // 请求参数
method: 'GET', // 默认的请求方法
// 请求头
header: {
'Content-type': 'application/json' // 设置数据的交互格式
},
timeout: 60000, // 默认的超时时长,小程序默认的超时时长是 1 分钟
isLoading: true // 控制是否使用默认的 loading默认值是 true 表示使用默认的 loading
}
// 定义拦截器对象
interceptors = {
// 请求拦截器
request: (config) => config,
// 响应拦截器
response: (response) => response
}
// 定义数组队列,用来存储请求队列、存储请求标识
queue = []
// constructor 用于创建和初始化类的属性以及方法
constructor(params = {}) {
// 注意:需要传入的参数,覆盖默认的参数,因此传入的参数需要放到最后
this.defaults = Object.assign({}, this.defaults, params)
}
/**
* @description request 实例方法发送网络请求接收一个对象类型的参数
* @param {*} options 属性值和 wx.request() 方法调用时传递的参数保持一致
* @returns Promise
*/
request(options) {
// 如果有新的请求,就清除上一次的定时器
this.timerId && clearTimeout(this.timerId)
// 合并完整的请求地址
options.url = this.defaults.baseURL + options.url
// 合并请求参数:调用实例方法时传入的覆盖默认的以及实例配置的
options = { ...this.defaults, ...options }
// 控制 loading 的显示与隐藏
if (options.isLoading && options.method !== 'UPLOAD') {
this.queue.length === 0 && wx.showLoading()
this.queue.push('request')
}
// 在请求发送之前,调用请求拦截器,新增和修改请求参数
// 请求拦截器内部,会将新增和修改以后的参数返回
options = this.interceptors.request(options)
// 需要使用 Promise 封装 wx.request处理异步请求
return new Promise((resolve, reject) => {
// 如果 method 等于 UPLOAD 说明需要调用 wx.uploadFile() 方法
// 否则调用的是 wx.request() 方法
if (options.method === 'UPLOAD') {
wx.uploadFile({
...options,
success: (res) => {
// 需要将服务器返回的 JSON 字符串 通过 JSON.parse 转成对象
res.data = JSON.parse(res.data)
// 合并参数
const mergeRes = Object.assign({}, res, {
config: options,
isSuccess: true
})
resolve(this.interceptors.response(mergeRes))
},
fail: (err) => {
// 合并参数
const mergeErr = Object.assign({}, err, {
config: options,
isSuccess: false
})
reject(this.interceptors.response(mergeErr))
}
})
} else {
wx.request({
...options,
// 当接口调用成功时会触发 success 回调函数
success: (res) => {
// 合并请求参数,方便进行代码调试
// 追加 isSuccess 属性,是为了标识响应拦截器是 success 调用还是 fail 调用
const mergeRes = Object.assign({}, res, {
config: options,
isSuccess: true
})
resolve(this.interceptors.response(mergeRes))
},
// 当接口调用失败时会触发 fail 回调函数
fail: (err) => {
// 合并请求参数,方便进行代码调试
// 追加 isSuccess 属性,是为了标识响应拦截器是 success 调用还是 fail 调用
const mergeErr = Object.assign({}, err, {
config: options,
isSuccess: false
})
reject(this.interceptors.response(mergeErr))
},
// 接口调用结束的回调函数(调用成功、失败都会执行)
complete: () => {
// 如果需要显示 loading ,那么就需要控制 loading 的隐藏
if (options.isLoading) {
// 在每一个请求结束以后,都会执行 complete 回调函数
// 每次从 queue 队列中删除一个标识
this.queue.pop()
// 解决并发请求loading 闪烁问题
this.queue.length === 0 && this.queue.push('request')
//解决并发请求loading 闪烁问题
this.timerId = setTimeout(() => {
this.queue.pop()
this.queue.length === 0 && wx.hideLoading()
clearTimeout(this.timerId)
}, 1)
}
}
})
}
})
}
/**
* @description 封装 GET 实例方法
* @param {*} url 请求地址
* @param {*} data 请求参数
* @param {*} config 其他请求配置项
* @returns Promise
*/
get(url, data = {}, config = {}) {
// 需要调用 request 请求方法发送请求,只需要组织好参数,传递给 request 请求方法即可
// 当调用 get 方法时,需要将 request 方法的返回值 return 出去
return this.request(Object.assign({ url, data, method: 'GET' }, config))
}
/**
* @description 封装 DELETE 实例方法
* @param {*} url 请求地址
* @param {*} data 请求参数
* @param {*} config 其他请求配置项
* @returns Promise
*/
delete(url, data = {}, config = {}) {
return this.request(Object.assign({ url, data, method: 'DELETE' }, config))
}
/**
* @description 封装 POST 实例方法
* @param {*} url 请求地址
* @param {*} data 请求参数
* @param {*} config 其他请求配置项
* @returns Promise
*/
post(url, data = {}, config = {}) {
return this.request(Object.assign({ url, data, method: 'POST' }, config))
}
/**
* @description 封封装 PUT 实例方法
* @param {*} url 请求地址
* @param {*} data 请求参数
* @param {*} config 其他请求配置项
* @returns Promise
*/
put(url, data = {}, config = {}) {
return this.request(Object.assign({ url, data, method: 'PUT' }, config))
}
/**
* @description 处理并发请求
* @param {...promise} promise 传入的每一项需要是 Promise
* @returns Promise
*/
all(...promise) {
// 那么展开运算符会将传入的参数转成数组
return Promise.all(promise)
}
/**
* @description upload 实例方法用来对 wx.uploadFile 进行封装
* @param {*} url 文件的上传地址接口地址
* @param {*} filePath 要上传的文件资源路径
* @param {*} name 文件对应的 key
* @param {*} config 其他配置项
*/
upload(url, filePath, name = 'file', config = {}) {
return this.request(
Object.assign({ url, filePath, name, method: 'UPLOAD' }, config)
)
}
}
export default WxRequest

@ -0,0 +1,13 @@
{
"name": "mina-request",
"version": "1.0.8",
"description": "小程序网络请求工具,包含:请求拦截器、响应拦截器、并发请求、文件上传 API 封装等功能",
"main": "index.js",
"miniprogram": "miniprogram_dist",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": ["wx.request", "wx.uploadFile", "request", "小程序网络请求", "小程序请求"],
"author": "zdkhero",
"license": "ISC"
}

@ -0,0 +1,258 @@
## 2024-08-08 v3.12.3
- 更新 API 定义到 3.5.2
- 修复 [#235](https://github.com/wechat-miniprogram/api-typings/issues/235), [#302](https://github.com/wechat-miniprogram/api-typings/issues/302), [#303](https://github.com/wechat-miniprogram/api-typings/issues/303), [#304](https://github.com/wechat-miniprogram/api-typings/issues/304) by [@Yang Mingshan](https://github.com/yangmingshan)
## 2023-12-01 v3.12.2
- 更新 API 定义到 3.2.3
## 2023-10-17 v3.12.1
- 更新 API 定义到 3.1.2
- 补齐自定义组件实例的 `getPassiveEvent`, `setPassiveEvent` 方法
## 2023-08-24 v3.12.0
- `App` 生命周期 `onLaunch`, `onShow` 参数中的 `referrerInfo` 字段类型对齐 API 定义中的 `ReferrerInfo`。这是一个 **破坏性改动**,其中 `extraData` 的类型从 `any` 收窄到了 `Record<string, any>`
- 根据实际实现,修改了 `LaunchOptions``query` 字段的类型。这是一个 **破坏性改动**,该类型从 `Record<string, any>` 收窄到了 `Record<string, string>`
## 2023-08-24 v3.11.1
- 更新 API 定义到 3.0.1
## 2023-08-04 v3.11.0
- 更新 API 定义到 3.0.0
- 暂未支持 [glass-easel](https://github.com/wechat-miniprogram/glass-easel) [Chaining API](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/glass-easel/chaining-api.html) 的类型定义
- 补齐 `WXWebAssembly` 定义
## 2023-06-09 v3.10.0
- 更新 API 定义到 2.32.1
- 新增 CanvasRenderingContext 类型定义 [#111](https://github.com/wechat-miniprogram/api-typings/issues/111)
## 2023-04-10 v3.9.1
- 更新 API 定义到 2.30.4
- 修复页面 `onShareAppMessage` 异步形式的定义错误
## 2023-01-12 v3.9.0
- 更新 API 定义到 2.29.1
- 将 xr-frame 的命名空间由 `WechatXrFrame` 改为 `XrFrame`。这是一个 **破坏性改动**
## 2022-09-09 v3.6.0
- 更新 API 定义到 2.26.0
- 更改了部分监听方法及其参数的命名
## 2022-06-24 v3.5.0
- 更新 API 定义到 2.24.6
## 2022-04-01 v3.4.6
- 更新 API 定义到 2.23.2
## 2022-01-20 v3.4.5
- 更新 API 定义到 2.21.3
## 2021-08-24 v3.4.4
- 更新 API 定义到 2.20.1
## 2021-08-24 v3.4.3
- 更新 API 定义到 2.19.2
- 补充自定义组件获取更新性能接口定义
## 2021-08-02 v3.4.2
- 更新 API 定义到 2.19.0
- 重新整理了注释,包括:
- 加入插件支持情况、版本和说明
- 将支持和废弃情况挪到前面,使其更不容易因为接口说明太长而被忽略
- 移除文首、文末和多余(连续超过两个)的空行
- 修复几个链接
## 2021-07-07 v3.4.1
- 移除一个意外加入的非预期字符
## 2021-07-07 v3.4.0
- 更新 API 定义到 2.18.0
- 更新来自文档代码示例的测试用例
- 更新 npm 依赖以解决安全问题
- 修复 [#202](https://github.com/wechat-miniprogram/api-typings/issues/202), [#204](https://github.com/wechat-miniprogram/api-typings/issues/204)
## 2021-04-21 v3.3.2
- 更新 API 定义到 2.16.1
## 2021-04-09 v3.3.1
- 更新 API 定义到 2.16.0
## 2021-03-02 v3.3.0
- 更新部分新接口定义
- 支持泛型([#177](https://github.com/wechat-miniprogram/api-typings/issues/177)
- 支持索引签名,以支持 `wx.requestSubscribeMessage`[#175](https://github.com/wechat-miniprogram/api-typings/issues/175)
## 2021-02-22 v3.2.3
- 更新 API 定义到 2.15.0
- 修复 `Component.triggerEvent``detail` 类型
- 修复几个接口的定义([#193](https://github.com/wechat-miniprogram/api-typings/issues/193), [#185](https://github.com/wechat-miniprogram/api-typings/issues/185), [#180](https://github.com/wechat-miniprogram/api-typings/issues/180)
- 修改 `MethodOption` 以解决 [#161](https://github.com/wechat-miniprogram/api-typings/issues/161)(鸣谢:[@Lienviws](https://github.com/Lienviws)
## 2021-01-14 v3.2.2
- 修复几个接口未 Promise 化的问题
## 2021-01-06 v3.2.1
- 更新 API 定义到 2.14.1
- 补齐 `virtualHost` ([#174](https://github.com/wechat-miniprogram/api-typings/issues/174))
## 2020-11-13 v3.2.0
- 更新 API 定义到 2.14.0
- 补齐 NFC 接口的错误码
## 2020-11-04 v3.1.6
- 补齐 `requirePlugin``requireMiniProgram`
## 2020-10-29 v3.1.5
- 更新 API 定义
- 修复代码格式问题(`no-unnecessary-qualifier`
## 2020-10-28 v3.1.4
- 更新 API 定义到 2.13.2
- 为被废弃的接口增加了 `@deprecated` 标识
## 2020-10-14 v3.1.3
- 修复 `ICustomTimelineContent``query` 的类型
## 2020-09-30 v3.1.2
- 更新 API 定义到 2.13.1
## 2020-09-24 v3.1.1
- 更新 API 定义到 2.13.0
- 改变了嵌套命名空间的写法
- 支持 `Component` 的第五个泛型参数,用于将自定义组件作为页面根组件使用的情况
## 2020-09-22 v3.1.0
- 将代码风格检查从 tslint 迁移到 eslint
## 2020-08-19 v3.0.2
- 更新 API 定义
- 合并 PR [#151](https://github.com/wechat-miniprogram/api-typings/pull/151), [#152](https://github.com/wechat-miniprogram/api-typings/pull/152),补齐事件类型,补齐 `onShareTimeline`
## 2020-08-19 v3.0.2
- 更新 API 定义
- 合并 PR [#124](https://github.com/wechat-miniprogram/api-typings/pull/124), [#145](https://github.com/wechat-miniprogram/api-typings/pull/145),修复两个动画接口的问题
## 2020-08-03 v3.0.1
- 更新 API 定义
- 修复某些取消监听的接口(`off`)的参数不为可选值的问题
## 2020-07-30 v3.0.0
- 由于基础库接口基本向前兼容,不再与基础库保持版本同步
- 更新 API 定义到 2.12.0
## 2020-06-15 v2.11.0-1
- 该版本继续合并了一部分完全相同的 interface / callback是一个 **破坏性改动**,原本字面上引用了这些 interface / callback 的代码可能会报错。
- 为 `Component` 构造器增加第四个泛型,以允许在自定义组件上挂载自定义的字段 ([#133](https://github.com/wechat-miniprogram/api-typings/issues/133))
- 修复一些接口错误 ([#134](https://github.com/wechat-miniprogram/api-typings/issues/134))
- 补齐 `App``onThemeChange` ([#135](https://github.com/wechat-miniprogram/api-typings/issues/135))
- 补齐 `Page``onAddToFavorites` ([#136](https://github.com/wechat-miniprogram/api-typings/issues/136))
## 2020-05-20 v2.11.0
- 同步 API 定义到基础库 2.11.0
- 该版本继续合并了一部分完全相同的 interface / callback是一个 **破坏性改动**,原本字面上引用了这些 interface / callback 的代码可能会报错。
- 修复接口错误 ([#126](https://github.com/wechat-miniprogram/api-typings/issues/126))
## 2020-04-20 v2.10.4
- 同步 API 定义到基础库 2.10.4
- 在之前的版本中,分属于不同接口的两个 interface / callback 即使完全相同,也会拥有不同的名字。在这次更新中,他们将合并为同一个(如 `FileSystemManagerGetFileInfoCompleteCallback``WxGetFileInfoCompleteCallback` 都变成了 `GetFileInfoCompleteCallback`)。这是一个 **破坏性改动**,原本字面上引用了这些 interface / callback 的代码可能会报错。
- 修复了一些取消监听接口off callback的参数错误 ([#120](https://github.com/wechat-miniprogram/api-typings/issues/120))
## 2020-04-03 v2.10.3-1
- 补齐 `Component``getOpenerEventChannel` ([#112](https://github.com/wechat-miniprogram/api-typings/issues/113) by [@baranwang](https://github.com/baranwang))
- 加入了部分事件的定义 ([#115](https://github.com/wechat-miniprogram/api-typings/issues/115) by [@zenml](https://github.com/zenml))
- 更新了小程序·云开发的 API 定义 ([#92](https://github.com/wechat-miniprogram/api-typings/issues/92))
## 2020-03-26 v2.10.3
- 同步 API 定义到基础库 2.10.3
## 2020-03-18 v2.10.2-1
- 支持 API Promise 化调用 ([#105](https://github.com/wechat-miniprogram/api-typings/issues/105))
## 2020-03-06 v2.10.2
- 同步 API 定义到基础库 2.10.2
## 2020-02-10 v2.10.1-1
- 允许重写部分全局变量 (由 `const` 改为 `let`) ([#102](https://github.com/wechat-miniprogram/api-typings/issues/102))
- 补齐 `Page` 上的 `options` 字段 ([#101](https://github.com/wechat-miniprogram/api-typings/issues/101) by [@baranwang](https://github.com/baranwang))
## 2020-01-19 v2.10.1
- 同步 API 定义到基础库 2.10.1
- 补齐 `Component` `selectOwnerComponent`, `animate`, `clearAnimation` ([#96](https://github.com/wechat-miniprogram/api-typings/issues/96))
- 补齐 `App` `onUnhandledRejection` ([#99](https://github.com/wechat-miniprogram/api-typings/issues/99))
## 2020-01-07 v2.10.0-1
- 修复接口错误 ([#95](https://github.com/wechat-miniprogram/api-typings/issues/95))
## 2020-01-07 v2.10.0
- 同步 API 定义到基础库 2.10.0
## 2019-12-20 v2.9.4
- 同步 API 定义到基础库 2.9.4
- 修正一些接口错误 ([#88](https://github.com/wechat-miniprogram/api-typings/issues/88)[#89](https://github.com/wechat-miniprogram/api-typings/issues/89)[#91](https://github.com/wechat-miniprogram/api-typings/issues/91))
## 2019-12-06 v2.9.3
- 同步 API 定义到基础库 2.9.3
- 补齐 `Component` 纯数据字段 (`pureDataPattern`)
- 支持 `Component` 的属性监听器使用 `string` 类型
## 2019-11-14 v2.9.2
- 同步 API 定义到基础库 2.9.2
- 补齐 `Behaviors` 中缺少的一些选项
## 2019-11-06 v2.9.1
- 同步 API 定义到基础库 2.9.1
## 2019-10-23 v2.9.0
- 同步 API 定义到基础库 2.9.0
## 2019-10-10 v2.8.3-1
- 修复注释文档中不可用的链接
- 组件实例类型支持 `Partial` 的自定义方法 ([用例](https://github.com/wechat-miniprogram/api-typings/blob/master/test/issue.test.ts#L170-L185))
## 2019-09-19 v2.8.3
- 同步 API 定义到基础库 2.8.3
- `getApp` 支持范型 ([#77](https://github.com/wechat-miniprogram/api-typings/issues/77))
- 修正一些接口错误 ([#73](https://github.com/wechat-miniprogram/api-typings/issues/73), [#75](https://github.com/wechat-miniprogram/api-typings/issues/75), [#79](https://github.com/wechat-miniprogram/api-typings/issues/79))
- 补齐 `require`, `exports`, `module.exports` 定义,以支持在没有 `@types/node` 下编译
## 2019-09-10 v2.8.2
- 同步 API 定义到基础库 2.8.2
- 加强了参数为可选值的方法参数类型定义和注释 (如 `FileSystemManager.appendFileSync``encoding`)
## 2019-08-30 v2.8.1
- 同步 API 定义到基础库 2.8.1
- 修复了部分最低基础库显示为 `[object Object]` 的问题
## 2019-08-20 v2.8.0-2
- 将 `object` 改为 `Record<string, any>`,以允许任意属性和方法
- 自定义组件属性构造器为 `ObjectConstructor` 时,类型推导为 `Record<string, any>` 而不是 `object`
- 修正 `component` 参数的类型为页面或自定义组件实例
- 补齐 `console: WechatMiniprogram.Console` 全局变量
- 修正一些其他的接口类型错误
## 2019-08-14 v2.8.0-1
- 补齐 `styleIsolation``ComponentOption`
## 2019-08-14 v2.8.0
- 同步 API 定义到基础库 2.8.0
- 不再向全局暴露 `IAnyObject`,收回到命名空间 `WechatMiniprogram`
- 对齐代码规范,使用 4 空格缩进,不再使用分号等
- 小幅改动 behavior, component 和 page 的定义,使其对 data 和 properties 等的类型推断更准确
- 修复了一些其他问题 ([#60](https://github.com/wechat-miniprogram/api-typings/issues/60), [#59](https://github.com/wechat-miniprogram/api-typings/issues/59), [#48](https://github.com/wechat-miniprogram/api-typings/issues/48), [#47](https://github.com/wechat-miniprogram/api-typings/issues/47), [#45](https://github.com/wechat-miniprogram/api-typings/issues/45), [#33](https://github.com/wechat-miniprogram/api-typings/issues/33), [#13](https://github.com/wechat-miniprogram/api-typings/issues/13))
## 2019-08-08 v2.7.7-2
- 补齐了部分接口 fail 回调的错误码 ([#51](https://github.com/wechat-miniprogram/api-typings/issues/51))
## 2019-08-06 v2.7.7-1
- 重写了 page, component 和 behavior 的定义,替换原来不完整的定义,使其更全面,更准确 ([#46](https://github.com/wechat-miniprogram/api-typings/issues/46), [#40](https://github.com/wechat-miniprogram/api-typings/issues/40), [#30](https://github.com/wechat-miniprogram/api-typings/issues/30), [#28](https://github.com/wechat-miniprogram/api-typings/issues/28), [#27](https://github.com/wechat-miniprogram/api-typings/issues/27))
## 2019-07-31 v2.7.7
- 同步 API 定义到基础库 2.7.7
- 将命名空间从 `Wx` 更改为更正式的 `WechatMiniprogram`,这是一个 **破坏性改动**,原本字面上引用了 `Wx` 命名空间的代码可能失效
- 修复了云开发的定义无法使用的问题 ([#25](https://github.com/wechat-miniprogram/api-typings/issues/25), [#32](https://github.com/wechat-miniprogram/api-typings/issues/32), [#42](https://github.com/wechat-miniprogram/api-typings/issues/42))
- 修复了一些其它问题 ([#11](https://github.com/wechat-miniprogram/api-typings/issues/11), [#35](https://github.com/wechat-miniprogram/api-typings/issues/35), [#43](https://github.com/wechat-miniprogram/api-typings/issues/43))

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

@ -0,0 +1,68 @@
# Wechat Mini Program API Typings
> [中文版本](./README.md)
[![Published on DefinitelyTyped](https://img.shields.io/npm/v/@types/wechat-miniprogram?label=%40types)](https://www.npmjs.com/package/@types/wechat-miniprogram)
[![Published on NPM](https://img.shields.io/npm/v/miniprogram-api-typings.svg?style=flat)](https://www.npmjs.com/package/miniprogram-api-typings)
[![MIT License](https://img.shields.io/github/license/wechat-miniprogram/api-typings.svg)](https://github.com/wechat-miniprogram/api-typings)
[![GitHub Actions Test Status](https://github.com/wechat-miniprogram/api-typings/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/wechat-miniprogram/api-typings/actions/workflows/test.yml)
Type definitions for APIs of Wechat Mini Program in TypeScript
## Install
### By standalone npm package
```bash
npm install miniprogram-api-typings
```
Manually import it after installed:
- `import 'miniprogram-api-typings';`
Or specify types in typescript config:
- Specify `types: ["miniprogram-api-typings"]` in `tsconfig.json`
Or reference by [Triple-Slash Directives](https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html):
- `/// <reference path="node_modules/miniprogram-api-typings/index.d.ts" />`
or:
### By DefinitelyTyped
```bash
npm install @types/wechat-miniprogram
```
## Changelog
See [CHANGELOG.md](https://github.com/wechat-miniprogram/api-typings/blob/master/CHANGELOG.md) (Chinese only)
## Contribution
Definitions of Wechat APIs (`lib.wx.api.d.ts`) are auto-generated together with our [documentations](https://developers.weixin.qq.com/miniprogram/en/dev/api/), therefore PRs including that file will __not__ be merged. If you found some APIs defined wrongly, create an issue instead.
Both PR and issue are welcomed for definitions of pages (`Page`), custom components (`Component`) and other else, since they are written manually. Help us improve this definition if you have any bug reports or suggestions! Thanks for contributing!
### Contributors
- [Baran](https://github.com/baranwang)
- [MinLiang Zeng](https://github.com/zenml/)
- [Garfield Lee](https://github.com/Garfield550)
- [Mr.Hope](https://github.com/Mister-Hope)
- [chs97](https://github.com/chs97)
- [Jelf](https://github.com/okxiaoliang4)
- [xieyuhang](https://github.com/haiya6)
- [苏杰豪](https://github.com/Megasu)
- [Yang Mingshan](https://github.com/yangmingshan)
### Automated tests
We use [`tsd`](https://github.com/SamVerschueren/tsd) to check if this definition is working properly. All test cases are under folder `test`.
To perform an automated test, clone this repo, `npm install --save-dev` and `npm test`.
If you have test case that fails the test, an issue or PR will be great. Strong test case that passes are also welcomed.

@ -0,0 +1,68 @@
# 微信小程序定义文件
> [English version](./README-en.md)
[![已在 DefinitelyTyped 发布](https://img.shields.io/npm/v/@types/wechat-miniprogram?label=%40types)](https://www.npmjs.com/package/@types/wechat-miniprogram)
[![已在 NPM 发布](https://img.shields.io/npm/v/miniprogram-api-typings.svg?style=flat)](https://www.npmjs.com/package/miniprogram-api-typings)
[![MIT 协议](https://img.shields.io/github/license/wechat-miniprogram/api-typings.svg)](https://github.com/wechat-miniprogram/api-typings)
[![GitHub Actions 测试状况](https://github.com/wechat-miniprogram/api-typings/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/wechat-miniprogram/api-typings/actions/workflows/test.yml)
微信小程序 API 的 TypeScript 类型定义文件
## 安装
### 通过独立 npm 包
```bash
npm install miniprogram-api-typings
```
安装后手动导入:
- `import 'miniprogram-api-typings';`
或者在 ts 配置中指定:
- 在 `tsconfig.json` 中指定 `types: ["miniprogram-api-typings"]`
或者通过 [三斜杠指令](https://www.tslang.cn/docs/handbook/triple-slash-directives.html) 引用:
- `/// <reference path="node_modules/miniprogram-api-typings/index.d.ts" />`
或:
### 通过 DefinitelyTyped
```bash
npm install @types/wechat-miniprogram
```
## 更新日志
参考 [CHANGELOG.md](https://github.com/wechat-miniprogram/api-typings/blob/master/CHANGELOG.md)
## 贡献
API 的定义文件(`lib.wx.api.d.ts`)是随 [文档](https://developers.weixin.qq.com/miniprogram/dev/api/) 一起自动生成的,如果发现了 API 接口的定义错误,请提一个 issue 给我们,关于 API 的 PR 将 __不会__ 被接受。
如果有针对页面(`Page`)、自定义组件(`Component`)等接口的 bug 和建议,欢迎 PR 或提一个 issue 给我们。非常感谢!
### 贡献者
- [Baran](https://github.com/baranwang)
- [MinLiang Zeng](https://github.com/zenml/)
- [Garfield Lee](https://github.com/Garfield550)
- [Mr.Hope](https://github.com/Mister-Hope)
- [chs97](https://github.com/chs97)
- [Jelf](https://github.com/okxiaoliang4)
- [xieyuhang](https://github.com/haiya6)
- [苏杰豪](https://github.com/Megasu)
- [Yang Mingshan](https://github.com/yangmingshan)
### 测试
本定义文件使用 [`tsd`](https://github.com/SamVerschueren/tsd) 进行测试,所有的测试样例放在 `test` 目录下。
想执行测试的话,克隆本项目并完成 `npm install --save-dev` 后执行 `npm test` 即可。
如果您发现了不能通过自动化测试的测试样例,可以提交 PR 或者提一个 issue。当然能通过自动化测试的强有力的测试样例也是欢迎的。

@ -0,0 +1 @@
/// <reference path="./types/index.d.ts" />

@ -0,0 +1,41 @@
{
"name": "miniprogram-api-typings",
"version": "3.12.3",
"description": "Type definitions for APIs of Wechat Mini Program in TypeScript",
"main": "./index.d.ts",
"types": "./index.d.ts",
"scripts": {
"test": "npm run tsd && npm run eslint",
"tsd": "tsd",
"eslint": "eslint --config .eslintrc.js types/**/*.ts"
},
"repository": {
"type": "git",
"url": "git+https://github.com/wechat-miniprogram/api-typings.git"
},
"author": "Wechat Miniprogram <wx-miniprogram@qq.com>",
"license": "MIT",
"bugs": {
"url": "https://github.com/wechat-miniprogram/api-typings/issues"
},
"homepage": "https://github.com/wechat-miniprogram/api-typings#readme",
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.46.0",
"@typescript-eslint/parser": "^5.46.0",
"eslint": "^8.29.0",
"tsd": "^0.25.0",
"typescript": "^4.9.4"
},
"tsd": {
"directory": "test"
},
"files": [
"LICENSE",
"CHANGELOG.md",
"README.md",
"README-en.md",
"index.d.ts",
"typings.json",
"types/"
]
}

@ -0,0 +1 @@
/// <reference path="./wx/index.d.ts" />

@ -0,0 +1,163 @@
/*! *****************************************************************************
Copyright (c) 2024 Tencent, Inc. All rights reserved.
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.
***************************************************************************** */
/// <reference path="./lib.wx.app.d.ts" />
/// <reference path="./lib.wx.page.d.ts" />
/// <reference path="./lib.wx.api.d.ts" />
/// <reference path="./lib.wx.cloud.d.ts" />
/// <reference path="./lib.wx.canvas.d.ts" />
/// <reference path="./lib.wx.component.d.ts" />
/// <reference path="./lib.wx.behavior.d.ts" />
/// <reference path="./lib.wx.event.d.ts" />
/// <reference path="./lib.wx.wasm.d.ts" />
declare namespace WechatMiniprogram {
type IAnyObject = Record<string, any>
type Optional<F> = F extends (arg: infer P) => infer R ? (arg?: P) => R : F
type OptionalInterface<T> = { [K in keyof T]: Optional<T[K]> }
interface AsyncMethodOptionLike {
success?: (...args: any[]) => void
}
type PromisifySuccessResult<
P,
T extends AsyncMethodOptionLike
> = P extends {
success: any
}
? void
: P extends { fail: any }
? void
: P extends { complete: any }
? void
: Promise<Parameters<Exclude<T['success'], undefined>>[0]>
// TODO: Extract real definition from `lib.dom.d.ts` to replace this
type IIRFilterNode = any
type WaveShaperNode = any
type ConstantSourceNode = any
type OscillatorNode = any
type GainNode = any
type BiquadFilterNode = any
type PeriodicWaveNode = any
type AudioNode = any
type ChannelSplitterNode = any
type ChannelMergerNode = any
type DelayNode = any
type DynamicsCompressorNode = any
type ScriptProcessorNode = any
type PannerNode = any
type AnalyserNode = any
type WebGLTexture = any
type WebGLRenderingContext = any
// TODO: fill worklet type
type WorkletFunction = (...args: any) => any
type AnimationObject = any
type SharedValue<T = any> = T
type DerivedValue<T = any> = T
}
declare let console: WechatMiniprogram.Console
declare let wx: WechatMiniprogram.Wx
/** 引入模块。返回模块通过 `module.exports` 或 `exports` 暴露的接口。 */
interface Require {
(
/** 需要引入模块文件相对于当前文件的相对路径,或 npm 模块名,或 npm 模块路径。不支持绝对路径 */
module: string,
/** 用于异步获取其他分包中的模块的引用结果,详见 [分包异步化]((subpackages/async)) */
callback?: (moduleExport: any) => void,
/** 异步获取分包失败时的回调,详见 [分包异步化]((subpackages/async)) */
errorCallback?: (err: any) => void
): any
/** 以 Promise 形式异步引入模块。返回模块通过 `module.exports` 或 `exports` 暴露的接口。 */
async(
/** 需要引入模块文件相对于当前文件的相对路径,或 npm 模块名,或 npm 模块路径。不支持绝对路径 */
module: string
): Promise<any>
}
declare const require: Require
/** 引入插件。返回插件通过 `main` 暴露的接口。 */
interface RequirePlugin {
(
/** 需要引入的插件的 alias */
module: string,
/** 用于异步获取其他分包中的插件的引用结果,详见 [分包异步化]((subpackages/async)) */
callback?: (pluginExport: any) => void
): any
/** 以 Promise 形式异步引入插件。返回插件通过 `main` 暴露的接口。 */
async(
/** 需要引入的插件的 alias */
module: string
): Promise<any>
}
declare const requirePlugin: RequirePlugin
/** 插件引入当前使用者小程序。返回使用者小程序通过 [插件配置中 `export` 暴露的接口](https://developers.weixin.qq.com/miniprogram/dev/framework/plugin/using.html#%E5%AF%BC%E5%87%BA%E5%88%B0%E6%8F%92%E4%BB%B6)
*
*
*
* `2.11.1` */
declare function requireMiniProgram(): any
/** 当前模块对象 */
declare let module: {
/** 模块向外暴露的对象,使用 `require` 引用该模块时可以获取 */
exports: any
}
/** `module.exports` 的引用 */
declare let exports: any
/** [clearInterval(number intervalID)](https://developers.weixin.qq.com/miniprogram/dev/api/base/timer/clearInterval.html)
*
* setInterval */
declare function clearInterval(
/** 要取消的定时器的 ID */
intervalID: number
): void
/** [clearTimeout(number timeoutID)](https://developers.weixin.qq.com/miniprogram/dev/api/base/timer/clearTimeout.html)
*
* setTimeout */
declare function clearTimeout(
/** 要取消的定时器的 ID */
timeoutID: number
): void
/** [number setInterval(function callback, number delay, any rest)](https://developers.weixin.qq.com/miniprogram/dev/api/base/timer/setInterval.html)
*
* */
declare function setInterval(
/** 回调函数 */
callback: (...args: any[]) => any,
/** 执行回调函数之间的时间间隔,单位 ms。 */
delay?: number,
/** param1, param2, ..., paramN 等附加参数,它们会作为参数传递给回调函数。 */
rest?: any
): number
/** [number setTimeout(function callback, number delay, any rest)](https://developers.weixin.qq.com/miniprogram/dev/api/base/timer/setTimeout.html)
*
* */
declare function setTimeout(
/** 回调函数 */
callback: (...args: any[]) => any,
/** 延迟的时间,函数的调用会在该延迟之后发生,单位 ms。 */
delay?: number,
/** param1, param2, ..., paramN 等附加参数,它们会作为参数传递给回调函数。 */
rest?: any
): number

File diff suppressed because it is too large Load Diff

@ -0,0 +1,424 @@
/*! *****************************************************************************
Copyright (c) 2024 Tencent, Inc. All rights reserved.
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.
***************************************************************************** */
declare namespace WechatMiniprogram.App {
type SceneValues =
| 1000
| 1001
| 1005
| 1006
| 1007
| 1008
| 1010
| 1011
| 1012
| 1013
| 1014
| 1017
| 1019
| 1020
| 1022
| 1023
| 1024
| 1025
| 1026
| 1027
| 1028
| 1029
| 1030
| 1031
| 1032
| 1034
| 1035
| 1036
| 1037
| 1038
| 1039
| 1042
| 1043
| 1044
| 1045
| 1046
| 1047
| 1048
| 1049
| 1052
| 1053
| 1054
| 1056
| 1057
| 1058
| 1059
| 1060
| 1064
| 1065
| 1067
| 1068
| 1069
| 1071
| 1072
| 1073
| 1074
| 1077
| 1078
| 1079
| 1081
| 1082
| 1084
| 1088
| 1089
| 1090
| 1091
| 1092
| 1095
| 1096
| 1097
| 1099
| 1100
| 1101
| 1102
| 1103
| 1104
| 1106
| 1107
| 1113
| 1114
| 1119
| 1120
| 1121
| 1124
| 1125
| 1126
| 1129
| 1131
| 1133
| 1135
| 1144
| 1145
| 1146
| 1148
| 1150
| 1151
| 1152
| 1153
| 1154
| 1155
| 1157
| 1158
| 1160
| 1167
| 1168
| 1169
| 1171
| 1173
| 1175
| 1176
| 1177
| 1178
| 1179
| 1181
| 1183
| 1184
| 1185
| 1186
| 1187
| 1189
| 1191
| 1192
| 1193
| 1194
| 1195
| 1196
| 1197
| 1198
| 1200
| 1201
| 1202
| 1203
| 1206
| 1207
| 1208
| 1212
| 1215
| 1216
| 1223
| 1228
| 1231
interface LaunchShowOption {
/** 打开小程序的路径 */
path: string
/** 打开小程序的query */
query: IAnyObject
/**
* - 1000
* - 1001使 2.2.4
* - 1005
* - 1006
* - 1007
* - 1008
* - 1010
* - 1011
* - 1012
* - 1013
* - 1014 1107
* - 1017
* - 1019 7.0.0
* - 1020 profile
* - 1022 6.6.1
* - 1023
* - 1024 profile
* - 1025
* - 1026
* - 1027使
* - 1028
* - 1029
* - 1030
* - 1031
* - 1032
* - 1034
* - 1035
* - 1036App
* - 1037
* - 1038
* - 1039
* - 1042
* - 1043
* - 1044 shareTicket [](https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/share.html)
* - 1045广
* - 1046广
* - 1047
* - 1048
* - 1049
* - 1052
* - 1053
* - 1054 6.7.4
* - 1056
* - 1057
* - 1058
* - 1059
* - 1060 1034
* - 1064 Wi-Fi
* - 1065URL scheme [](https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/url-scheme.html)
* - 1067广
* - 1068广
* - 1069 openSDK
* - 1071
* - 1072
* - 1073
* - 1074
* - 1077
* - 1078 Wi-Fi
* - 1079
* - 1081
* - 1082
* - 1084广
* - 1088
* - 1089使 2.2.4
* - 1090使
* - 1091
* - 1092
* - 1095广
* - 1096
* - 1097
* - 1099
* - 1100
* - 1101 -> ->
* - 1102 profile
* - 1103 2.2.4
* - 1104 2.2.4
* - 1106
* - 1107
* - 1113
* - 1114
* - 1119
* - 1120
* - 1121
* - 1124
* - 1125
* - 1126
* - 1129访 [](https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/sitemap.html)
* - 11318.0
* - 1133 [](https://developers.weixin.qq.com/doc/oplatform/Miniprogram_Frame/)
* - 1135 profile
* - 1144 -
* - 1145 -
* - 1146
* - 1148-
* - 1150
* - 1151 -
* - 1152
* - 1153
* - 1154
* - 1155
* - 1157
* - 1158
* - 1160
* - 1167H5 [](https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_Open_Tag.html)
* - 1168
* - 1169
* - 1171
* - 1173 [](https://developers.weixin.qq.com/miniprogram/dev/framework/material/support_material.html)
* - 1175
* - 1176
* - 1177
* - 1178
* - 1179#
* - 1181 PC
* - 1183PC - - -
* - 1184
* - 1185
* - 1186 -
* - 11878.0
* - 1189广
* - 1191
* - 1192 profile
* - 1193
* - 1194URL Link [](https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/url-link.html)
* - 1195 tab
* - 1196
* - 1197
* - 1198
* - 1200广
* - 1201广
* - 1202
* - 1203
* - 1206
* - 1207
* - 1208
* - 1212
* - 1215广
* - 1216
* - 1223 Widget
* - 1228广
* - 1231
*/
scene: SceneValues
/** shareTicket详见 [获取更多转发信息]((转发#获取更多转发信息)) */
shareTicket: string
/** 当场景为由从另一个小程序或公众号或App打开时返回此字段 */
referrerInfo?: ReferrerInfo
/** 打开的文件信息数组只有从聊天素材场景打开scene为1173才会携带该参数 */
forwardMaterials: ForwardMaterials[]
/** /chatType /
*
*
* - 1: ;
* - 2: ;
* - 3: ;
* - 4: ; */
chatType?: 1 | 2 | 3 | 4
/** `2.20.0`
*
* API
*
*
* - 'default': ;
* - 'nativeFunctionalized': ;
* - 'browseOnly': ;
* - 'embedded': ; */
apiCategory:
| 'default'
| 'nativeFunctionalized'
| 'browseOnly'
| 'embedded'
}
interface PageNotFoundOption {
/** 不存在页面的路径 */
path: string
/** 打开不存在页面的 query */
query: IAnyObject
/** 是否本次启动的首个页面(例如从分享等入口进来,首个页面是开发者配置的分享页面) */
isEntryPage: boolean
}
interface Option {
/**
*
*
*/
onLaunch(options: LaunchShowOption): void
/**
*
*
*/
onShow(options: LaunchShowOption): void
/**
*
*
*/
onHide(): void
/**
*
* api
*/
onError(/** 错误信息,包含堆栈 */ error: string): void
/**
*
*
*
* ****
* 1. `onPageNotFound`
* 2. `onPageNotFound` `onPageNotFound`
*
* 1.9.90
*/
onPageNotFound(options: PageNotFoundOption): void
/**
* Promise 使 [wx.onUnhandledRejection](https://developers.weixin.qq.com/miniprogram/dev/api/base/app/app-event/wx.onUnhandledRejection.html) 绑定监听。注意事项请参考 [wx.onUnhandledRejection](https://developers.weixin.qq.com/miniprogram/dev/api/base/app/app-event/wx.onUnhandledRejection.html)。
* **** [wx.onUnhandledRejection](https://developers.weixin.qq.com/miniprogram/dev/api/base/app/app-event/wx.onUnhandledRejection.html) 一致
*/
onUnhandledRejection: OnUnhandledRejectionCallback
/**
* 使 wx.onThemeChange
*
* 2.11.0
*/
onThemeChange: OnThemeChangeCallback
}
type Instance<T extends IAnyObject> = Option & T
type Options<T extends IAnyObject> = Partial<Option> &
T &
ThisType<Instance<T>>
type TrivialInstance = Instance<IAnyObject>
interface Constructor {
<T extends IAnyObject>(options: Options<T>): void
}
interface GetAppOption {
/** `App` AppApp
*
* 2.2.4
*/
allowDefault?: boolean
}
interface GetApp {
<T extends IAnyObject = IAnyObject>(opts?: GetAppOption): Instance<T>
}
}
declare let App: WechatMiniprogram.App.Constructor
declare let getApp: WechatMiniprogram.App.GetApp

@ -0,0 +1,68 @@
/*! *****************************************************************************
Copyright (c) 2024 Tencent, Inc. All rights reserved.
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.
***************************************************************************** */
declare namespace WechatMiniprogram.Behavior {
type BehaviorIdentifier = string
type Instance<
TData extends DataOption,
TProperty extends PropertyOption,
TMethod extends MethodOption,
TCustomInstanceProperty extends IAnyObject = Record<string, never>
> = Component.Instance<TData, TProperty, TMethod, TCustomInstanceProperty>
type TrivialInstance = Instance<IAnyObject, IAnyObject, IAnyObject>
type TrivialOption = Options<IAnyObject, IAnyObject, IAnyObject>
type Options<
TData extends DataOption,
TProperty extends PropertyOption,
TMethod extends MethodOption,
TCustomInstanceProperty extends IAnyObject = Record<string, never>
> = Partial<Data<TData>> &
Partial<Property<TProperty>> &
Partial<Method<TMethod>> &
Partial<OtherOption> &
Partial<Lifetimes> &
ThisType<Instance<TData, TProperty, TMethod, TCustomInstanceProperty>>
interface Constructor {
<
TData extends DataOption,
TProperty extends PropertyOption,
TMethod extends MethodOption,
TCustomInstanceProperty extends IAnyObject = Record<string, never>
>(
options: Options<TData, TProperty, TMethod, TCustomInstanceProperty>
): BehaviorIdentifier
}
type DataOption = Component.DataOption
type PropertyOption = Component.PropertyOption
type MethodOption = Component.MethodOption
type Data<D extends DataOption> = Component.Data<D>
type Property<P extends PropertyOption> = Component.Property<P>
type Method<M extends MethodOption> = Component.Method<M>
type DefinitionFilter = Component.DefinitionFilter
type Lifetimes = Component.Lifetimes
type OtherOption = Omit<Component.OtherOption, 'options'>
}
/** 注册一个 `behavior`,接受一个 `Object` 类型的参数。*/
declare let Behavior: WechatMiniprogram.Behavior.Constructor

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,744 @@
/*! *****************************************************************************
Copyright (c) 2024 Tencent, Inc. All rights reserved.
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.
***************************************************************************** */
declare namespace WechatMiniprogram.Component {
type Instance<
TData extends DataOption,
TProperty extends PropertyOption,
TMethod extends Partial<MethodOption>,
TCustomInstanceProperty extends IAnyObject = {},
TIsPage extends boolean = false
> = InstanceProperties &
InstanceMethods<TData> &
TMethod &
(TIsPage extends true ? Page.ILifetime : {}) &
TCustomInstanceProperty & {
/** 组件数据,**包括内部数据和属性值** */
data: TData & PropertyOptionToData<TProperty>
/** 组件数据,**包括内部数据和属性值**(与 `data` 一致) */
properties: TData & PropertyOptionToData<TProperty>
}
type TrivialInstance = Instance<
IAnyObject,
IAnyObject,
IAnyObject,
IAnyObject
>
type TrivialOption = Options<IAnyObject, IAnyObject, IAnyObject, IAnyObject>
type Options<
TData extends DataOption,
TProperty extends PropertyOption,
TMethod extends MethodOption,
TCustomInstanceProperty extends IAnyObject = {},
TIsPage extends boolean = false
> = Partial<Data<TData>> &
Partial<Property<TProperty>> &
Partial<Method<TMethod, TIsPage>> &
Partial<OtherOption> &
Partial<Lifetimes> &
ThisType<
Instance<
TData,
TProperty,
TMethod,
TCustomInstanceProperty,
TIsPage
>
>
interface Constructor {
<
TData extends DataOption,
TProperty extends PropertyOption,
TMethod extends MethodOption,
TCustomInstanceProperty extends IAnyObject = {},
TIsPage extends boolean = false
>(
options: Options<
TData,
TProperty,
TMethod,
TCustomInstanceProperty,
TIsPage
>
): string
}
type DataOption = Record<string, any>
type PropertyOption = Record<string, AllProperty>
type MethodOption = Record<string, Function>
interface Data<D extends DataOption> {
/** 组件的内部数据,和 `properties` 一同用于组件的模板渲染 */
data?: D
}
interface Property<P extends PropertyOption> {
/** 组件的对外属性,是属性名到属性设置的映射表 */
properties: P
}
interface Method<M extends MethodOption, TIsPage extends boolean = false> {
/** 组件的方法,包括事件响应函数和任意的自定义方法,关于事件响应函数的使用,参见 [组件间通信与事件](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/events.html) */
methods: M & (TIsPage extends true ? Partial<Page.ILifetime> : {})
}
type PropertyType =
| StringConstructor
| NumberConstructor
| BooleanConstructor
| ArrayConstructor
| ObjectConstructor
| null
type ValueType<T extends PropertyType> = T extends null
? any
: T extends StringConstructor
? string
: T extends NumberConstructor
? number
: T extends BooleanConstructor
? boolean
: T extends ArrayConstructor
? any[]
: T extends ObjectConstructor
? IAnyObject
: never
type FullProperty<T extends PropertyType> = {
/** 属性类型 */
type: T
/** 属性初始值 */
value?: ValueType<T>
/** 属性值被更改时的响应函数 */
observer?:
| string
| ((
newVal: ValueType<T>,
oldVal: ValueType<T>,
changedPath: Array<string | number>
) => void)
/** 属性的类型(可以指定多个) */
optionalTypes?: ShortProperty[]
}
type AllFullProperty =
| FullProperty<StringConstructor>
| FullProperty<NumberConstructor>
| FullProperty<BooleanConstructor>
| FullProperty<ArrayConstructor>
| FullProperty<ObjectConstructor>
| FullProperty<null>
type ShortProperty =
| StringConstructor
| NumberConstructor
| BooleanConstructor
| ArrayConstructor
| ObjectConstructor
| null
type AllProperty = AllFullProperty | ShortProperty
type PropertyToData<T extends AllProperty> = T extends ShortProperty
? ValueType<T>
: FullPropertyToData<Exclude<T, ShortProperty>>
type FullPropertyToData<T extends AllFullProperty> = ValueType<T['type']>
// type FullPropertyToData<T extends AllFullProperty> = unknown extends T['value'] ? ValueType<T['type']> : T['value']
type PropertyOptionToData<P extends PropertyOption> = {
[name in keyof P]: PropertyToData<P[name]>
}
interface Router {
switchTab: Wx['switchTab']
reLaunch: Wx['reLaunch']
redirectTo: Wx['redirectTo']
navigateTo: Wx['navigateTo']
navigateBack: Wx['navigateBack']
}
interface InstanceProperties {
/** 组件的文件路径 */
is: string
/** 节点id */
id: string
/** 节点dataset */
dataset: Record<string, string>
/** 上一次退出前 onSaveExitState 保存的数据 */
exitState: any
/** 相对于当前自定义组件的 Router 对象 */
router: Router
/** 相对于当前自定义组件所在页面的 Router 对象 */
pageRouter: Router
/** 渲染当前组件的渲染后端 */
renderer: 'webview' | 'skyline'
}
interface InstanceMethods<D extends DataOption> {
/** `setData`
* `this.data`
*
* ****
*
* 1. ** this.data this.setData **
* 1. JSON
* 1. 1024kB
* 1. data value `undefined`
*/
setData(
/**
*
* `key: value` `this.data` `key` `value`
*
* `key` `array[2].message``a.b.c.d` this.data
*/
data: Partial<D> & IAnyObject,
/** setData引起的界面更新渲染完毕后的回调函数最低基础库 `1.5.0` */
callback?: () => void
): void
/** 检查组件是否具有 `behavior` 检查时会递归检查被直接或间接引入的所有behavior */
hasBehavior(behavior: Behavior.BehaviorIdentifier): void
/** 触发事件,参见组件事件 */
triggerEvent<DetailType = any>(
name: string,
detail?: DetailType,
options?: TriggerEventOption
): void
/** 创建一个 SelectorQuery 对象,选择器选取范围为这个组件实例内 */
createSelectorQuery(): SelectorQuery
/** 创建一个 IntersectionObserver 对象,选择器选取范围为这个组件实例内 */
createIntersectionObserver(
options: CreateIntersectionObserverOption
): IntersectionObserver
/** 创建一个 MediaQueryObserver 对象 */
createMediaQueryObserver(): MediaQueryObserver
/** 使用选择器选择组件实例节点,返回匹配到的第一个组件实例对象(会被 `wx://component-export` 影响) */
selectComponent(selector: string): TrivialInstance
/** 使用选择器选择组件实例节点,返回匹配到的全部组件实例对象组成的数组 */
selectAllComponents(selector: string): TrivialInstance[]
/**
* `wx://component-export`
*
* [`2.8.2`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
**/
selectOwnerComponent(): TrivialInstance
/** 获取这个关系所对应的所有关联节点,参见 组件间关系 */
getRelationNodes(relationKey: string): TrivialInstance[]
/**
* callback setData setData
*
* [`2.4.0`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
**/
groupSetData(callback?: () => void): void
/**
* custom-tab-bar
*
* [`2.6.2`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
**/
getTabBar(): TrivialInstance
/**
*
*
* [`2.7.1`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
**/
getPageId(): string
/**
* [](https://developers.weixin.qq.com/miniprogram/dev/framework/view/animation.html)
*
* [`2.9.0`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
**/
animate(
selector: string,
keyFrames: KeyFrame[],
duration: number,
callback?: () => void
): void
/**
* [](https://developers.weixin.qq.com/miniprogram/dev/framework/view/animation.html)
*
* [`2.9.0`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
**/
animate(
selector: string,
keyFrames: ScrollTimelineKeyframe[],
duration: number,
scrollTimeline: ScrollTimelineOption
): void
/**
* [](https://developers.weixin.qq.com/miniprogram/dev/framework/view/animation.html)
*
* [`2.9.0`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
**/
clearAnimation(selector: string, callback: () => void): void
/**
* [](https://developers.weixin.qq.com/miniprogram/dev/framework/view/animation.html)
*
* [`2.9.0`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
**/
clearAnimation(
selector: string,
options?: ClearAnimationOptions,
callback?: () => void
): void
/**
* [wx.navigateTo]((wx.navigateTo))
*
* [`2.7.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
*/
getOpenerEventChannel(): EventChannel
/**
* worklet [worklet ](https://developers.weixin.qq.com/miniprogram/dev/framework/runtime/skyline/worklet.html)
*
* [`2.29.0`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
*/
applyAnimatedStyle(
selector: string,
updater: () => Record<string, string>,
userConfig?: { immediate: boolean, flush: 'sync' | 'async' },
callback?: (res: { styleId: number }) => void
): void
/**
* worklet
*
* [`2.30.1`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
*/
clearAnimatedStyle(
selector: string,
styleIds: number[],
callback?: () => void
): void
/**
* []((custom-component/update-perf-stat))
*
*
* [`2.12.0`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
*/
setUpdatePerformanceListener<WithDataPath extends boolean = false>(
options: SetUpdatePerformanceListenerOption<WithDataPath>,
callback?: UpdatePerformanceListener<WithDataPath>
): void
/**
* `touch` passive [enablePassiveEvent]((configuration/app#enablePassiveEvent))
*
* [`2.25.1`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
*/
getPassiveEvent(callback: (config: PassiveConfig) => void): void
/**
* `touch` passive [enablePassiveEvent]((configuration/app#enablePassiveEvent))
*
* [`2.25.1`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
*/
setPassiveEvent(config: PassiveConfig): void
}
interface ComponentOptions {
/**
* [slot](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/wxml-wxss.html#组件wxml的slot)
*/
multipleSlots?: boolean
/**
* [](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/wxml-wxss.html#组件样式隔离)
*/
addGlobalClass?: boolean
/**
* [](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/wxml-wxss.html#组件样式隔离)
*/
styleIsolation?:
| 'isolated'
| 'apply-shared'
| 'shared'
| 'page-isolated'
| 'page-apply-shared'
| 'page-shared'
/**
* [](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/pure-data.html) 是一些不用于界面渲染的 data 字段,可以用于提升页面更新性能。从小程序基础库版本 2.8.2 开始支持。
*/
pureDataPattern?: RegExp
/**
* [](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/wxml-wxss.html#%E8%99%9A%E6%8B%9F%E5%8C%96%E7%BB%84%E4%BB%B6%E8%8A%82%E7%82%B9) 使自定义组件内部的第一层节点由自定义组件本身完全决定。从小程序基础库版本 [`2.11.2`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html) 开始支持 */
virtualHost?: boolean
}
interface TriggerEventOption {
/**
*
* `false`
*/
bubbles?: boolean
/** 穿false
*
* `false`
*/
composed?: boolean
/**
*
* `false`
*/
capturePhase?: boolean
}
interface RelationOption {
/** 目标组件的相对关系 */
type: 'parent' | 'child' | 'ancestor' | 'descendant'
/** 关系生命周期函数当关系被建立在页面节点树中时触发触发时机在组件attached生命周期之后 */
linked?(target: TrivialInstance): void
/** 关系生命周期函数当关系在页面节点树中发生改变时触发触发时机在组件moved生命周期之后 */
linkChanged?(target: TrivialInstance): void
/** 关系生命周期函数当关系脱离页面节点树时触发触发时机在组件detached生命周期之后 */
unlinked?(target: TrivialInstance): void
/** 如果这一项被设置则它表示关联的目标节点所应具有的behavior所有拥有这一behavior的组件节点都会被关联 */
target?: string
}
interface PageLifetimes {
/**
*
* /
*/
show(): void
/**
*
* / `navigateTo` `tab`
*/
hide(): void
/**
*
*
*/
resize(size: Page.IResizeOption): void
/**
*
*
*/
routeDone(): void
}
type DefinitionFilter = <T extends TrivialOption>(
/** 使用该 behavior 的 component/behavior 的定义对象 */
defFields: T,
/** 该 behavior 所使用的 behavior 的 definitionFilter 函数列表 */
definitionFilterArr?: DefinitionFilter[]
) => void
interface Lifetimes {
/** `created``attached``ready``moved``detached` `lifetimes` `lifetimes`
*
* `2.2.3` */
lifetimes: Partial<{
/**
* `setData`
*
* [`1.6.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
*/
created(): void
/**
*
*
* [`1.6.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
*/
attached(): void
/**
*
*
* [`1.6.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
*/
ready(): void
/**
*
*
* [`1.6.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
*/
moved(): void
/**
*
*
* [`1.6.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
*/
detached(): void
/**
*
*
* [`2.4.1`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
*/
error(err: Error): void
}>
/**
* @deprecated `2.2.3` lifetimes
*
*
*
* [`1.6.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
*/
created(): void
/**
* @deprecated `2.2.3` lifetimes
*
*
*
* [`1.6.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
*/
attached(): void
/**
* @deprecated `2.2.3` lifetimes
*
*
*
* [`1.6.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
*/
ready(): void
/**
* @deprecated `2.2.3` lifetimes
*
*
*
* [`1.6.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
*/
moved(): void
/**
* @deprecated `2.2.3` lifetimes
*
*
*
* [`1.6.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
*/
detached(): void
/**
* @deprecated `2.2.3` lifetimes
*
*
*
* [`2.4.1`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
*/
error(err: Error): void
}
interface OtherOption {
/** 类似于mixins和traits的组件间代码复用机制参见 [behaviors](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/behaviors.html) */
behaviors: Behavior.BehaviorIdentifier[]
/**
* properties data [](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/observer.html)
*
* [`2.6.1`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html)
*/
observers: Record<string, (...args: any[]) => any>
/** 组件间关系定义,参见 [组件间关系](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/lifetimes.html) */
relations: {
[componentName: string]: RelationOption
}
/** 组件接受的外部样式类,参见 [外部样式类](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/wxml-wxss.html) */
externalClasses?: string[]
/** 组件所在页面的生命周期声明对象,参见 [组件生命周期](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/lifetimes.html)
*
* [`2.2.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html) */
pageLifetimes?: Partial<PageLifetimes>
/** 一些选项(文档中介绍相关特性时会涉及具体的选项设置,这里暂不列举) */
options: ComponentOptions
/** 定义段过滤器,用于自定义组件扩展,参见 [自定义组件扩展](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/extend.html)
*
* [`2.2.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html) */
definitionFilter?: DefinitionFilter
/**
* 使 `behavior: wx://component-export` selectComponent [](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/events.html)
* [`2.2.3`](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html) */
export: () => IAnyObject
}
interface KeyFrame {
/** 关键帧的偏移,范围[0-1] */
offset?: number
/** 动画缓动函数 */
ease?: string
/** 基点位置,即 CSS transform-origin */
transformOrigin?: string
/** 背景颜色,即 CSS background-color */
backgroundColor?: string
/** 底边位置,即 CSS bottom */
bottom?: number | string
/** 高度,即 CSS height */
height?: number | string
/** 左边位置,即 CSS left */
left?: number | string
/** 宽度,即 CSS width */
width?: number | string
/** 不透明度,即 CSS opacity */
opacity?: number | string
/** 右边位置,即 CSS right */
right?: number | string
/** 顶边位置,即 CSS top */
top?: number | string
/** 变换矩阵,即 CSS transform matrix */
matrix?: number[]
/** 三维变换矩阵,即 CSS transform matrix3d */
matrix3d?: number[]
/** 旋转,即 CSS transform rotate */
rotate?: number
/** 三维旋转,即 CSS transform rotate3d */
rotate3d?: number[]
/** X 方向旋转,即 CSS transform rotateX */
rotateX?: number
/** Y 方向旋转,即 CSS transform rotateY */
rotateY?: number
/** Z 方向旋转,即 CSS transform rotateZ */
rotateZ?: number
/** 缩放,即 CSS transform scale */
scale?: number[]
/** 三维缩放,即 CSS transform scale3d */
scale3d?: number[]
/** X 方向缩放,即 CSS transform scaleX */
scaleX?: number
/** Y 方向缩放,即 CSS transform scaleY */
scaleY?: number
/** Z 方向缩放,即 CSS transform scaleZ */
scaleZ?: number
/** 倾斜,即 CSS transform skew */
skew?: number[]
/** X 方向倾斜,即 CSS transform skewX */
skewX?: number
/** Y 方向倾斜,即 CSS transform skewY */
skewY?: number
/** 位移,即 CSS transform translate */
translate?: Array<number | string>
/** 三维位移,即 CSS transform translate3d */
translate3d?: Array<number | string>
/** X 方向位移,即 CSS transform translateX */
translateX?: number | string
/** Y 方向位移,即 CSS transform translateY */
translateY?: number | string
/** Z 方向位移,即 CSS transform translateZ */
translateZ?: number | string
}
interface ClearAnimationOptions {
/** 基点位置,即 CSS transform-origin */
transformOrigin?: boolean
/** 背景颜色,即 CSS background-color */
backgroundColor?: boolean
/** 底边位置,即 CSS bottom */
bottom?: boolean
/** 高度,即 CSS height */
height?: boolean
/** 左边位置,即 CSS left */
left?: boolean
/** 宽度,即 CSS width */
width?: boolean
/** 不透明度,即 CSS opacity */
opacity?: boolean
/** 右边位置,即 CSS right */
right?: boolean
/** 顶边位置,即 CSS top */
top?: boolean
/** 变换矩阵,即 CSS transform matrix */
matrix?: boolean
/** 三维变换矩阵,即 CSS transform matrix3d */
matrix3d?: boolean
/** 旋转,即 CSS transform rotate */
rotate?: boolean
/** 三维旋转,即 CSS transform rotate3d */
rotate3d?: boolean
/** X 方向旋转,即 CSS transform rotateX */
rotateX?: boolean
/** Y 方向旋转,即 CSS transform rotateY */
rotateY?: boolean
/** Z 方向旋转,即 CSS transform rotateZ */
rotateZ?: boolean
/** 缩放,即 CSS transform scale */
scale?: boolean
/** 三维缩放,即 CSS transform scale3d */
scale3d?: boolean
/** X 方向缩放,即 CSS transform scaleX */
scaleX?: boolean
/** Y 方向缩放,即 CSS transform scaleY */
scaleY?: boolean
/** Z 方向缩放,即 CSS transform scaleZ */
scaleZ?: boolean
/** 倾斜,即 CSS transform skew */
skew?: boolean
/** X 方向倾斜,即 CSS transform skewX */
skewX?: boolean
/** Y 方向倾斜,即 CSS transform skewY */
skewY?: boolean
/** 位移,即 CSS transform translate */
translate?: boolean
/** 三维位移,即 CSS transform translate3d */
translate3d?: boolean
/** X 方向位移,即 CSS transform translateX */
translateX?: boolean
/** Y 方向位移,即 CSS transform translateY */
translateY?: boolean
/** Z 方向位移,即 CSS transform translateZ */
translateZ?: boolean
}
interface ScrollTimelineKeyframe {
composite?: 'replace' | 'add' | 'accumulate' | 'auto'
easing?: string
offset?: number | null
[property: string]: string | number | null | undefined
}
interface ScrollTimelineOption {
/** 指定滚动元素的选择器(只支持 scroll-view该元素滚动时会驱动动画的进度 */
scrollSource: string
/** 指定滚动的方向。有效值为 horizontal 或 vertical */
orientation?: string
/** 指定开始驱动动画进度的滚动偏移量,单位 px */
startScrollOffset: number
/** 指定停止驱动动画进度的滚动偏移量,单位 px */
endScrollOffset: number
/** 起始和结束的滚动范围映射的时间长度,该时间可用于与关键帧动画里的时间 (duration) 相匹配,单位 ms */
timeRange: number
}
interface SetUpdatePerformanceListenerOption<WithDataPath> {
/** 是否返回变更的 data 字段信息 */
withDataPaths?: WithDataPath
}
interface UpdatePerformanceListener<WithDataPath> {
(res: UpdatePerformance<WithDataPath>): void
}
interface UpdatePerformance<WithDataPath> {
/** 此次更新过程的 ID */
updateProcessId: number
/** 对于子更新,返回它所属的更新过程 ID */
parentUpdateProcessId?: number
/** 是否是被合并更新,如果是,则 updateProcessId 表示被合并到的更新过程 ID */
isMergedUpdate: boolean
/** 此次更新的 data 字段信息,只有 withDataPaths 设为 true 时才会返回 */
dataPaths: WithDataPath extends true ? string[] : undefined
/** 此次更新进入等待队列时的时间戳 */
pendingStartTimestamp: number
/** 更新运算开始时的时间戳 */
updateStartTimestamp: number
/** 更新运算结束时的时间戳 */
updateEndTimestamp: number
}
type PassiveConfig =
| {
/** 是否设置 touchmove 事件为 passive默认为 `false` */
touchmove?: boolean
/** 是否设置 touchstart 事件为 passive默认为 `false` */
touchstart?: boolean
/** 是否设置 wheel 事件为 passive默认为 `false` */
wheel?: boolean
}
| boolean
}
/** ComponentComponent
*
* * 使 `this.data` 使 `setData`
* * `this` 访
* * data `dataXyz` WXML `data-xyz=""` dataset
* * 使 data
* * `2.0.9` data
* * `bug` : type Object Array `this.setData` observer observer `newVal` `oldVal` `changedPath`
*/
declare let Component: WechatMiniprogram.Component.Constructor

File diff suppressed because it is too large Load Diff

@ -0,0 +1,299 @@
/*! *****************************************************************************
Copyright (c) 2024 Tencent, Inc. All rights reserved.
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.
***************************************************************************** */
declare namespace WechatMiniprogram.Page {
type Instance<
TData extends DataOption,
TCustom extends CustomOption
> = OptionalInterface<ILifetime> &
InstanceProperties &
InstanceMethods<TData> &
Data<TData> &
TCustom
type Options<
TData extends DataOption,
TCustom extends CustomOption
> = (TCustom &
Partial<Data<TData>> &
Partial<ILifetime> & {
options?: Component.ComponentOptions
}) &
ThisType<Instance<TData, TCustom>>
type TrivialInstance = Instance<IAnyObject, IAnyObject>
interface Constructor {
<TData extends DataOption, TCustom extends CustomOption>(
options: Options<TData, TCustom>
): void
}
interface ILifetime {
/**
*
* onLoad
*/
onLoad(
/** 打开当前页面路径中的参数 */
query: Record<string, string | undefined>
): void | Promise<void>
/**
*
* /
*/
onShow(): void | Promise<void>
/**
*
*
*
* API `wx.setNavigationBarTitle``onReady`
*/
onReady(): void | Promise<void>
/**
*
* / `navigateTo` `tab`
*/
onHide(): void | Promise<void>
/**
*
* `redirectTo``navigateBack`
*/
onUnload(): void | Promise<void>
/**
*
* wx.navigateTo wx.navigateBack
*/
onRouteDone(): void | Promise<void>
/**
*
*
* - `app.json``window``enablePullDownRefresh`
* - `wx.startPullDownRefresh`
* - `wx.stopPullDownRefresh`
*/
onPullDownRefresh(): void | Promise<void>
/**
*
*
* - `app.json``window``onReachBottomDistance`
* -
*/
onReachBottom(): void | Promise<void>
/**
*
* `<button>` `open-type="share"`
*
* ****
*
* return Object
*/
onShareAppMessage(
/** 分享发起来源参数 */
options: IShareAppMessageOption
):
| ICustomShareContent
| IAsyncCustomShareContent
| Promise<ICustomShareContent>
| void
| Promise<void>
/**
*
*
* Beta Android [ (Beta)](https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/share-timeline.html)
*
* 2.11.3
*/
onShareTimeline(): ICustomTimelineContent | void
/**
*
*
*/
onPageScroll(
/** 页面滚动参数 */
options: IPageScrollOption
): void | Promise<void>
/** 当前是 tab 页时,点击 tab 时触发,最低基础库: `1.9.0` */
onTabItemTap(
/** tab 点击参数 */
options: ITabItemTapOption
): void | Promise<void>
/** 窗口尺寸改变时触发,最低基础库:`2.4.0` */
onResize(
/** 窗口尺寸参数 */
options: IResizeOption
): void | Promise<void>
/**
*
* 2.10.3 7.0.15 iOS
*/
onAddToFavorites(options: IAddToFavoritesOption): IAddToFavoritesContent
/** 每当小程序可能被销毁之前会被调用,可以进行退出状态的保存。最低基础库: `2.7.4` */
onSaveExitState(): ISaveExitState
}
interface InstanceProperties {
/** 页面的文件路径 */
is: string
/** 到当前页面的路径 */
route: string
/** 打开当前页面路径中的参数 */
options: Record<string, string | undefined>
/** 上一次退出前 onSaveExitState 保存的数据 */
exitState: any
/** 相对于当前页面的 Router 对象 */
router: Component.Router
/** 相对于当前页面的 Router 对象 */
pageRouter: Component.Router
/** 渲染当前页面的渲染后端 */
renderer: 'webview' | 'skyline'
}
type DataOption = Record<string, any>
type CustomOption = Record<string, any>
type InstanceMethods<D extends DataOption> = Component.InstanceMethods<D>
interface Data<D extends DataOption> {
/**
*
* `data` 使****
*
* `data` `JSON``data``JSON`
*
* `WXML`
*/
data: D
}
interface ICustomShareContent {
/** 转发标题。默认值:当前小程序名称 */
title?: string
/** 转发路径,必须是以 / 开头的完整路径。默认值:当前页面 path */
path?: string
/** 自定义图片路径可以是本地文件路径、代码包文件路径或者网络图片路径。支持PNG及JPG。显示图片长宽比是 5:4最低基础库 `1.5.0`。默认值:使用默认截图 */
imageUrl?: string
}
interface IAsyncCustomShareContent extends ICustomShareContent {
promise: Promise<ICustomShareContent>
}
interface ICustomTimelineContent {
/** 自定义标题,即朋友圈列表页上显示的标题。默认值:当前小程序名称 */
title?: string
/** 自定义页面路径中携带的参数,如 `path?a=1&b=2` 的 “?” 后面部分 默认值:当前页面路径携带的参数 */
query?: string
/** 自定义图片路径,可以是本地文件路径、代码包文件路径或者网络图片路径。支持 PNG 及 JPG。显示图片长宽比是 1:1。默认值默认使用小程序 Logo*/
imageUrl?: string
}
interface IPageScrollOption {
/** 页面在垂直方向已滚动的距离单位px */
scrollTop: number
}
interface IShareAppMessageOption {
/**
*
*
* - `button`
* - `menu`
*
* `1.2.4`
*/
from: 'button' | 'menu'
/** `from` `button` `target` `button` `undefined`
*
* `1.2.4` */
target: any
/** `<web-view>``<web-view>`url
*
* `1.6.4`
*/
webViewUrl?: string
}
interface ITabItemTapOption {
/** 被点击tabItem的序号从0开始最低基础库 `1.9.0` */
index: string
/** 被点击tabItem的页面路径最低基础库 `1.9.0` */
pagePath: string
/** 被点击tabItem的按钮文字最低基础库 `1.9.0` */
text: string
}
interface IResizeOption {
size: {
/** 变化后的窗口宽度,单位 px */
windowWidth: number
/** 变化后的窗口高度,单位 px */
windowHeight: number
}
}
interface IAddToFavoritesOption {
/** 页面中包含web-view组件时返回当前web-view的url */
webviewUrl?: string
}
interface IAddToFavoritesContent {
/** 自定义标题,默认值:页面标题或账号名称 */
title?: string
/** 自定义图片,显示图片长宽比为 11默认值页面截图 */
imageUrl?: string
/** 自定义query字段默认值当前页面的query */
query?: string
}
interface ISaveExitState {
/** 需要保存的数据(只能是 JSON 兼容的数据) */
data: any
/** 超时时刻,在这个时刻后,保存的数据保证一定被丢弃,默认为 (当前时刻 + 1 天) */
expireTimeStamp?: number
}
interface GetCurrentPages {
(): Array<Instance<IAnyObject, IAnyObject>>
}
}
/**
* `Object`
*/
declare let Page: WechatMiniprogram.Page.Constructor
/**
*
* ____
* - ____
* - `App.onLaunch` `getCurrentPages()` `page`
*/
declare let getCurrentPages: WechatMiniprogram.Page.GetCurrentPages

@ -0,0 +1,409 @@
/*! *****************************************************************************
Copyright (c) 2024 Tencent, Inc. All rights reserved.
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.
***************************************************************************** */
declare namespace phys3D {
// pvd调试配置
export interface PhysicsDebugConfig {
isNetwork: boolean // 采用网络的方式
ip?: string // 如果isNetwork为true调试信息会通过tcp转发的方式转发到打开了pvd调试软件的电脑需要注意的是防火墙要对pvd打开
port?: 5425 // pvd默认接口
timeout?: 1000 // 默认耗时
path?: string // 如果isNetwork为false调试信息会通过写本地文件的方式落地文件名建议为xxx.pxd2导入pvd调试即可
}
export enum QueryTriggerInteraction {
UseGlobal = 0,
Ignore = 1,
Collide = 2
}
export class PhysSystem {
constructor(config?: PhysicsDebugConfig)
gravity: RawVec3f
bounceThreshold: number
defaultMaxAngularSpeed: number
defaultSolverIterations: number
defaultSolverVelocityIterations: number
sleepThreshold: number
defaultContactOffset: number
destroyScene: () => void
createScene: () => number
Simulate: (step: number) => void
SyncFromTransforms: (() => void) | undefined // added in 2021.06
SetCollisionMask: (mask: ArrayBuffer) => void
Raycast: (
origin: RawVec3f,
unitDir: RawVec3f,
distance: number,
hit: RaycastHit,
layerMask?: number,
queryTriggerInteraction?: QueryTriggerInteraction
) => boolean
RaycastAll: (
origin: RawVec3f,
unitDir: RawVec3f,
distance: number,
layerMask?: number,
queryTriggerInteraction?: QueryTriggerInteraction
) => RaycastHit[]
CapsuleCast(
p1: RawVec3f,
p2: RawVec3f,
radius: number,
direction: RawVec3f,
hit: RaycastHit,
maxDistance: number,
layerMask?: number,
queryTriggerInteraction?: QueryTriggerInteraction
): void
CapsuleCastAll: (
p1: RawVec3f,
p2: RawVec3f,
radius: number,
direction: RawVec3f,
maxDistance: number,
layerMask?: number,
queryTriggerInteraction?: QueryTriggerInteraction
) => RaycastHit[]
BoxCast(
center: RawVec3f,
halfExt: RawVec3f,
direction: RawVec3f,
hit: RaycastHit,
orientation: RawQuaternion,
maxDistance: number,
layerMask?: number,
queryTriggerInteraction?: QueryTriggerInteraction
): void
BoxCastAll: (
center: RawVec3f,
halfExt: RawVec3f,
direction: RawVec3f,
orientation: RawQuaternion,
maxDistance: number,
layerMask?: number,
queryTriggerInteraction?: QueryTriggerInteraction
) => RaycastHit[]
OverlapBox: (
center: RawVec3f,
halfExt: RawVec3f,
orientation: RawQuaternion,
layermask?: number,
queryTriggerInteraction?: QueryTriggerInteraction
) => Collider[]
OverlapCapsule: (
p1: RawVec3f,
p2: RawVec3f,
radius: number,
layermask?: number,
queryTriggerInteraction?: QueryTriggerInteraction
) => Collider[]
}
export class Rigidbody {
constructor(system: PhysSystem)
enabled?: boolean // since 2021.06
position: RawVec3f
rotation: RawQuaternion
AttachToEntity: (pollObj: any, id: number) => void
Remove(): void
Detach(): void
IsAttached(): boolean
}
export enum CollisionDetectionMode {
Discrete = 0,
Continuous = 1,
ContinuousDynamic = 2,
ContinuousSpeculative = 3
}
export enum RigidbodyConstraints {
None = 0,
FreezePositionX = 1 << 0,
FreezePositionY = 1 << 1,
FreezePositionZ = 1 << 2,
FreezeRotationX = 1 << 3,
FreezeRotationY = 1 << 4,
FreezeRotationZ = 1 << 5,
FreezePosition = FreezePositionX | FreezePositionY | FreezePositionZ,
FreezeRotation = FreezeRotationX | FreezeRotationY | FreezeRotationZ,
FreezeAll = FreezePosition | FreezeRotation
}
export enum ForceMode {
kForceModeForce = 0,
kForceModeImpulse = 1 << 0,
kForceModeVelocityChange = 1 << 1,
kForceModeAcceleration = 1 << 2
}
export enum CombineMode {
eAverage = 0,
eMin,
eMultiply,
eMax
}
export enum CookingFlag {
None = 0,
CookForFasterSimulation = 1 << 0,
EnableMeshCleaning = 1 << 1,
WeldColocatedVertices = 1 << 2
}
export enum CollisionFlags {
None = 0,
Sides = 1 << 0,
Above = 1 << 1,
Below = 1 << 2
}
export class RawVec3f {
constructor()
constructor(x: number, y: number, z: number)
x: number
y: number
z: number
}
export class RawQuaternion {
constructor()
constructor(x: number, y: number, z: number, w: number)
x: number
y: number
z: number
w: number
}
export class Collider {
attachedRigidbody: Rigidbody
bounds: Bounds
name: string
contactOffset: number
enabled: boolean
isTrigger: boolean
scale: RawVec3f
material?: Material
sharedMateiral?: Material
ClosestPoint: (raw: RawVec3f) => RawVec3f
ClosestPointOnBounds: (raw: RawVec3f) => RawVec3f
onCollisionEnter?: (collision: Collision) => void
onCollisionExit?: (collision: Collision) => void
onCollisionStay?: (collision: Collision) => void
onTriggerEnter?: (collision: Collision) => void
onTriggerExit?: (collision: Collision) => void
onTriggerStay?: (collision: Collision) => void
dettachRigidbody?: () => void
userData?: unknown
layer: number
}
export class BoxCollider extends Collider {
constructor(system: PhysSystem, center: RawVec3f, size: RawVec3f)
center: RawVec3f
size: RawVec3f
}
export class SphereCollider extends Collider {
constructor(system: PhysSystem, center: RawVec3f, radius: number)
center: RawVec3f
radius: number
}
export class CapsuleCollider extends Collider {
constructor(
system: PhysSystem,
center: RawVec3f,
height: number,
radius: number
)
center: RawVec3f
height: number
radius: number
}
export class MeshCollider extends Collider {
constructor(
system: PhysSystem,
convex: boolean,
cookingOptions: number,
sharedMesh: PhysMesh
)
cookingOptions: number
sharedMesh: PhysMesh | null
convex: boolean
}
export class CharacterController extends Collider {
constructor(system: PhysSystem)
position: RawVec3f
center: RawVec3f
collisionFlags: CollisionFlags
detectCollisions: boolean
enableOverlapRecovery: boolean
height: number
isGrounded: boolean
minMoveDistance: number
radius: number
skinWidth: number
slopeLimit: number
stepOffset: number
velocity: RawVec3f
Move: (movement: RawVec3f) => CollisionFlags
SimpleMove: (speed: RawVec3f) => boolean
AttachToEntity: (pollObj: any, id: number) => void
OnControllerColliderHit?: (hit: ControllerColliderHit) => void
}
export interface ContactPoint {
normal: RawVec3f
this_collider: Collider
other_collider: Collider
point: RawVec3f
separation: number
}
export interface Collision {
collider: Collider
contacts: ContactPoint[]
impulse: RawVec3f
relative_velocity: RawVec3f
}
export interface ControllerColliderHit {
collider: Collider
controller: CharacterController
moveDirection: RawVec3f
normal: RawVec3f
moveLength: number
point: RawVec3f
}
export class Bounds {
constructor(center: RawVec3f, size: RawVec3f)
center: RawVec3f
extents: RawVec3f
max: RawVec3f
min: RawVec3f
size: RawVec3f
ClosestPoint: (point: RawVec3f) => RawVec3f
Contains: (point: RawVec3f) => boolean
Expand: (amount: number) => void
Intersects: (bounds: Bounds) => boolean
SetMinMax: (min: RawVec3f, max: RawVec3f) => void
SqrDistance: (point: RawVec3f) => number
}
export class Material {
constructor(system: PhysSystem)
dynamicFriction: number
staticFriction: number
bounciness: number
frictionCombine: CombineMode
bounceCombine: CombineMode
id: number
}
export class DynamicRigidbody extends Rigidbody {
mass: number
angularDamping: number
angularVelocity: RawVec3f
centerOfMass: RawVec3f
collisionDetectionMode: CollisionDetectionMode
constraints: number
detectCollisions: boolean
linearDamping: number
freezeRotation: boolean
inertiaTensor: number
// inertiaTensorRotation
// interpolation
isKinematic: boolean
maxAngularVelocity: number
maxDepenetrationVelocity: number
sleepThreshold: number
solverIterations: number
solverVelocityIterations: number
useGravity: boolean
velocity: RawVec3f
userData?: unknown
GetWorldCenterOfMass: () => RawVec3f
AddForce: (force: RawVec3f, mode: ForceMode) => void
AddTorque: (torque: RawVec3f, mode: ForceMode) => void
IsSleeping: () => boolean
Sleep: () => void
WakeUp: () => void
AddExplosionForce: (
explosionForce: number,
explosionPosition: RawVec3f,
explosionRadius: number,
upwardsModifier: number,
mode: ForceMode
) => void
AddForceAtPosition: (
force: RawVec3f,
position: RawVec3f,
mode: ForceMode
) => void
AddRelativeForce: (force: RawVec3f, mode: ForceMode) => void
AddRelativeTorque: (torque: RawVec3f, mode: ForceMode) => void
ClosestPointOnBounds: (position: RawVec3f) => RawVec3f
GetPointVelocity: (worldPoint: RawVec3f) => RawVec3f
GetRelativePointVelocity: (relativePoint: RawVec3f) => RawVec3f
MovePosition: (position: RawVec3f) => void
MoveRotation: (rotation: RawQuaternion) => void
ResetCenterOfMass: () => void
ResetInertiaTensor: () => void
SetDensity: (density: number) => void
// SweepTest: () => void;
// SweepTestAll: () => void;
}
export class PhysMesh {
constructor(system: PhysSystem)
// set vertices
SetVertices: (buffer: Float32Array, count: number) => void
// set indices
SetTriangles: (
buffer: Uint16Array | Uint32Array,
count: number,
useUint16: boolean
) => void
}
export class RaycastHit {
constructor()
collider: Collider
distance: number
normal: RawVec3f
point: RawVec3f
rigidbody: Rigidbody
}
}

@ -0,0 +1,152 @@
/*! *****************************************************************************
Copyright (c) 2024 Tencent, Inc. All rights reserved.
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.
***************************************************************************** */
/** [WXWebAssembly](https://developers.weixin.qq.com/miniprogram/dev/framework/performance/wasm.html)
*
* WXWebAssembly */
declare namespace WXWebAssembly {
type BufferSource = ArrayBufferView | ArrayBuffer
type CompileError = Error
const CompileError: {
prototype: CompileError
new (message?: string): CompileError
(message?: string): CompileError
}
/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Instance) */
interface Instance {
/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Instance/exports) */
readonly exports: Exports
}
const Instance: {
prototype: Instance
new (module: Module, importObject?: Imports): Instance
}
type LinkError = Error
const LinkError: {
prototype: LinkError
new (message?: string): LinkError
(message?: string): LinkError
}
/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory) */
interface Memory {
/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory/buffer) */
readonly buffer: ArrayBuffer
/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory/grow) */
grow(delta: number): number
}
const Memory: {
prototype: Memory
new (descriptor: MemoryDescriptor): Memory
}
/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Module) */
interface Module {}
const Module: {
prototype: Module
new (bytes: BufferSource): Module
/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Module/customSections) */
customSections(moduleObject: Module, sectionName: string): ArrayBuffer[]
/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Module/exports) */
exports(moduleObject: Module): ModuleExportDescriptor[]
/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Module/imports) */
imports(moduleObject: Module): ModuleImportDescriptor[]
}
interface RuntimeError extends Error {}
const RuntimeError: {
prototype: RuntimeError
new (message?: string): RuntimeError
(message?: string): RuntimeError
}
/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table) */
interface Table {
/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table/length) */
readonly length: number
/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table/get) */
get(index: number): any
/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table/grow) */
grow(delta: number, value?: any): number
/** [MDN Reference](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table/set) */
set(index: number, value?: any): void
}
const Table: {
prototype: Table
new (descriptor: TableDescriptor, value?: any): Table
}
interface MemoryDescriptor {
initial: number
maximum?: number
shared?: boolean
}
interface ModuleExportDescriptor {
kind: ImportExportKind
name: string
}
interface ModuleImportDescriptor {
kind: ImportExportKind
module: string
name: string
}
interface TableDescriptor {
element: TableKind
initial: number
maximum?: number
}
type ImportExportKind = 'function' | 'global' | 'memory' | 'table'
type TableKind = 'anyfunc' | 'externref'
type ValueType =
| 'anyfunc'
| 'externref'
| 'f32'
| 'f64'
| 'i32'
| 'i64'
| 'v128'
// eslint-disable-next-line @typescript-eslint/ban-types
type ExportValue = Function | Memory | Table
type Exports = Record<string, ExportValue>
type ImportValue = ExportValue | number
type Imports = Record<string, ModuleImports>
type ModuleImports = Record<string, ImportValue>
/** [WXWebAssembly](https://developers.weixin.qq.com/miniprogram/dev/framework/performance/wasm.html) */
function instantiate(
path: string,
importObject?: Imports
): Promise<Instance>
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,4 @@
{
"name": "miniprogram-api-typings",
"main": "index.d.ts"
}

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018-2024 wechat-miniprogram
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.

@ -0,0 +1,238 @@
# computed
小程序自定义组件扩展 behavior计算属性 `computed` 和监听器 `watch` 的实现。在 data 或者 properties 改变时,会重新计算 `computed` 字段并触发 `watch` 监听器。
> 此 behavior 依赖开发者工具的 npm 构建。具体详情可查阅[官方 npm 文档](https://developers.weixin.qq.com/miniprogram/dev/devtools/npm.html)。
注意: 4.0.0 大版本变更了最基本的接口名,从低版本升级到 4.0.0 以上时请注意 [#60](https://github.com/wechat-miniprogram/computed/issues/60) 的问题。
## 使用方法
### 方式一 代码片段
需要小程序基础库版本 >= 2.11.0 的环境。
可以直接体验一下这个代码片段,它包含了基本用法示例:[https://developers.weixin.qq.com/s/4KYn6TmJ7osP](https://developers.weixin.qq.com/s/4KYn6TmJ7osP)
体验该代码片段前,需要先安装并构建相对应的 npm 包。
```shell
npm install --save miniprogram-computed
```
### 方式二 本地构建
将本仓库 clone 到本地,进入根目录安装 npm 依赖。
```shell
npm install
```
安装完成后执行
```shell
npm run dev // 构建 dev 版本
```
构建完毕后,根目录下的 `demo` 即为小程序代码根目录,可以将此 demo 导入开发者工具中进行体验。
### computed 基本用法
```js
// component.js
const computedBehavior = require('miniprogram-computed').behavior
const behaviorTest = require('./behavior-test') // 引入自定义 behavior
Component({
behaviors: [behaviorTest, computedBehavior],
data: {
a: 1,
b: 1,
},
computed: {
sum(data) {
// 注意: computed 函数中不能访问 this ,只有 data 对象可供访问
// 这个函数的返回值会被设置到 this.data.sum 字段中
return data.a + data.b + data.c // data.c 为自定义 behavior 数据段
},
},
methods: {
onTap() {
this.setData({
a: this.data.b,
b: this.data.a + this.data.b,
})
},
},
})
```
```js
//behavior-test.js
module.exports = Behavior({
data: {
c: 2,
},
})
```
```xml
<view>A = {{a}}</view>
<view>B = {{b}}</view>
<view>SUM = {{sum}}</view>
<button bindtap="onTap">click</button>
```
### watch 基本用法
```js
const computedBehavior = require('miniprogram-computed').behavior
Component({
behaviors: [computedBehavior],
data: {
a: 1,
b: 1,
sum: 2,
},
watch: {
'a, b': function (a, b) {
this.setData({
sum: a + b,
})
},
},
methods: {
onTap() {
this.setData({
a: this.data.b,
b: this.data.a + this.data.b,
})
},
},
})
```
```xml
<view>A = {{a}}</view>
<view>B = {{b}}</view>
<view>SUM = {{sum}}</view>
<button bindtap="onTap">click</button>
```
### glass-easel Chaining API 支持
使用 glass-easel Chaining API 时,可以用更友好的 `computed` `watch` 函数。
```js
import { computed, watch } from 'miniprogram-computed'
Component()
.data(() => ({
a: 1,
b: 2,
}))
.init((ctx) => {
const data = computed(ctx, {
c: (data) => data.a + data.b,
d: (data) => data.a * 2,
}, {
e: (data) => data.c + data.d,
})
watch(ctx, 'a, b', (a: number, b: number) => {
// ...
})
})
.register()
```
### 非 chaining API 的 TypeScript 支持
由于通过 behavior 的方式引入不能获得类型支持, 因此为了获得类型的支持, 可以使用一个辅助组件构造器:
```ts
import { ComponentWithComputed } from 'miniprogram-computed'
ComponentWithComputed({
data: {
a: 1,
b: 1,
sum: 2,
},
watch: {
'a, b': function (a, b) {
this.setData({
sum: a + b,
})
},
},
computed: {
sum(data) {
// 注意: computed 函数中不能访问 this ,只有 data 对象可供访问
// 这个函数的返回值会被设置到 this.data.sum 字段中
return data.a + data.b + data.sum // data.c 为自定义 behavior 数据段
},
},
})
```
当使用该构造器的时候, 编译器可以给 `computed``watch` 提供自动提示和类型支持。
**注意: 当使用该构造器的时候, 无需手动加入 `computedBehavior` , 该构造器会自动引入该 behavior 。**
(类似地,也有 `BehaviorWithComputed` 构造器对应于 `Bahavior` 。)
**关于 TS 兼容问题**
若在小程序中用 `TypeScript` 进行开发并使用到了 `Component` 构造器。这时定义 `computed``watch` 字段会出现类型报错。
针对此问题,推荐使用 `ComponentWithComputed` 构造器代替 `Component` 构造器。
## 常见问题说明
### 我应该使用 computed 还是 watch
从原理上说, `watch` 的性能比 `computed` 更好;但 `computed` 的用法更简洁干净。
此外, `computed` 字段状态只能依赖于 `data` 和其他 `computed` 字段,不能访问 `this` 。如果不可避免要访问 `this` ,则必须使用 `watch` 代替。
### watch 和小程序基础库本身的 observers 有什么区别?
- 无论字段是否真的改变, `observers` 都会被触发,而 `watch` 只在字段值改变了的时候触发,并且触发时带有参数。
### 关于 \*\* 通配符
`watch` 字段上可以使用 `**` 通配符,它能够监听这个字段下的子字段的变化(类似于小程序基础库本身的 observers )。
```js
const computedBehavior = require('miniprogram-computed').behavior
Component({
behaviors: [computedBehavior],
data: {
obj: {
a: 1,
b: 2,
},
},
watch: {
'obj.**': function (obj) {
this.setData({
sum: obj.a + obj.b,
})
},
},
methods: {
onTap() {
this.setData({
'obj.a': 10,
})
},
},
})
```
除此以外:
- 对于没有使用 `**` 通配符的字段,在 `watch` 检查值是否发生变化时,只会进行粗略的浅比较(使用 `===`
- 对于使用了 `**` 通配符的字段,则会进行深比较,来尝试精确检测对象是否真的发生了变化,这要求对象字段不能包含循环(类似于 `JSON.stringify` )。

@ -0,0 +1,44 @@
## 0.0.6
- 支持 properties。
## 0.0.7
- 修复 setData 设置 properties 会报 can't call setData in computed getter function! 问题
## 2.0.0
- 基于 observers 重构,开始支持 watch
## 2.1.0
- 支持 watch 的 `.**` 语法
## 3.0.0
- 修复 computed 中使用自定义 behavior 数据段时,初始化视图的 computed data 不渲染的问题。
- 支持 mobx-miniprogram 扩展库。
- 更新 computed 数据追踪方式。
## 4.0.0
- 使用 TypeScript 重构。
- 优化部分生命周期逻辑。
## 4.1.1
- 优化打包方式
- 优化 dev 开发流程
## 4.2.x
- 增加 polyfill
## 4.3.x
- 修复引用类型的部分问题
## 5.0.0
- 基于 glass-easel 重构
- 支持 chaining API

File diff suppressed because one or more lines are too long

@ -0,0 +1,83 @@
{
"name": "miniprogram-computed",
"version": "5.1.0",
"description": "Computed & watch - wechat miniprogram custom component extend behavior",
"main": "dist/index.js",
"types": "types/index.d.ts",
"scripts": {
"dev": "gulp dev",
"watch": "gulp dev-watch",
"build": "gulp",
"gen_dts": "gulp dts",
"test": "jest ./test/* --bail",
"coverage": "jest ./test/* --coverage --bail",
"lint": "eslint . --fix"
},
"miniprogram": "dist",
"repository": {
"type": "git",
"url": "https://github.com/wechat-miniprogram/computed.git"
},
"files": [
"src",
"dist",
"types",
"LICENSE",
"package.json",
"README.md",
"UPDATE.md"
],
"author": "wechat-miniprogram",
"license": "MIT",
"devDependencies": {
"@swc/cli": "^0.3.12",
"@swc/core": "^1.5.7",
"@types/jest": "^29.5.12",
"@types/rfdc": "^1.2.0",
"@typescript-eslint/eslint-plugin": "^7.11.0",
"@typescript-eslint/parser": "^7.11.0",
"codecov": "^3.8.3",
"colors": "^1.4.0",
"eslint": "^8.57.0",
"eslint-config-airbnb-base": "15.0.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-promise": "^6.2.0",
"glass-easel": "~0.10.0",
"glass-easel-miniprogram-adapter": "~0.10.0",
"glass-easel-template-compiler": "~0.10.0",
"gulp": "^5.0.0",
"gulp-clean": "^0.4.0",
"gulp-esbuild": "^0.12.0",
"gulp-swc": "^2.1.0",
"gulp-typescript": "6.0.0-alpha.1",
"gulp-watch": "^5.0.1",
"husky": "^9.0.11",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"prettier": "^3.2.5",
"proxy-polyfill": "^0.3.2",
"ts-jest": "^29.1.4",
"ts-node": "^10.9.2",
"typescript": "^5.4.5"
},
"dependencies": {
"fast-deep-equal": "^3.1.3",
"miniprogram-api-typings": "^3.12.2",
"rfdc": "^1.3.1"
},
"husky": {
"hooks": {
"pre-commit": "npm run lint"
}
},
"pnpm": {
"overrides": {
"ansi-regex@>2.1.1 <5.0.1": ">=5.0.1",
"braces@<2.3.1": ">=2.3.1",
"glob-parent@<5.1.2": ">=5.1.2"
}
}
}

@ -0,0 +1,487 @@
import rfdc from 'rfdc'
import deepEqual from 'fast-deep-equal'
import * as dataPath from './data-path'
import * as dataTracer from './data-tracer'
import type { DataPathWithOptions } from './data-path'
import type * as adapter from 'glass-easel-miniprogram-adapter'
const deepClone = rfdc({ proto: true })
interface BehaviorData {
_computedWatchInit: ComputedWatchInitStatus
[k: string]: any
}
interface BehaviorExtend {
// original
data: BehaviorData
setData(d: Record<string, any>): void
_computedWatchInfo: Record<string, ComputedWatchInfo>
}
interface ObserversItem {
fields: string
observer(): void
}
interface ComputedWatchInfo {
computedUpdaters: Array<(...args: unknown[]) => boolean>
computedRelatedPathValues: Array<Array<dataTracer.RelatedPathValue>>
watchCurVal: Array<unknown>
_triggerFromComputedAttached: Record<string, boolean>
}
enum ComputedWatchInitStatus {
CREATED,
ATTACHED,
}
let computedWatchDefIdInc = 0
function equal(a: unknown, b: unknown) {
if (a === b) {
return true
} else {
// When a = b = NaN
// NaN === NaN is false
return a !== a && b !== b
}
}
class ComputedBuilder {
observersItems: ObserversItem[] = []
private computedWatchDefId = computedWatchDefIdInc++
private computedList: Array<[string, (data: Record<string, unknown>) => unknown]> = []
private watchList: Array<DataPathWithOptions[]> = []
constructor() {
const computedWatchDefId = this.computedWatchDefId
const computedList = this.computedList
const watchList = this.watchList
this.observersItems.push({
fields: '_computedWatchInit',
observer(this: BehaviorExtend) {
const status = this.data._computedWatchInit
if (status === ComputedWatchInitStatus.CREATED) {
// init data fields
const computedWatchInfo = {
computedUpdaters: [],
computedRelatedPathValues: new Array(computedList.length),
watchCurVal: new Array(watchList.length),
_triggerFromComputedAttached: Object.create(null),
}
if (!this._computedWatchInfo) this._computedWatchInfo = {}
this._computedWatchInfo[computedWatchDefId] = computedWatchInfo
// handling watch
// 1. push to initFuncs
watchList.forEach((paths, index) => {
// record the original value of watch targets
const curVal = paths.map(({ path, options }) => {
const val = dataPath.getDataOnPath(this.data, path)
return options.deepCmp ? deepClone(val) : val
})
computedWatchInfo.watchCurVal[index] = curVal
})
} else if (status === ComputedWatchInitStatus.ATTACHED) {
// handling computed
// 1. push to initFuncs
// 2. push to computedUpdaters
const computedWatchInfo = this._computedWatchInfo[computedWatchDefId]
computedList.forEach(([targetField, updateMethod], index) => {
const relatedPathValuesOnDef = [] as Array<dataTracer.RelatedPathValue>
const val = updateMethod(dataTracer.create(this.data, relatedPathValuesOnDef))
// here we can do small setDatas
// because observer handlers will force grouping small setDatas together
this.setData({
[targetField]: dataTracer.unwrap(val),
})
computedWatchInfo._triggerFromComputedAttached[targetField] = true
computedWatchInfo.computedRelatedPathValues[index] = relatedPathValuesOnDef
// will be invoked when setData is called
const updateValueAndRelatedPaths = () => {
const oldPathValues = computedWatchInfo.computedRelatedPathValues[index]
let needUpdate = false
// check whether its dependency updated
for (let i = 0; i < oldPathValues.length; i++) {
const item = oldPathValues[i]
if (item.kind === 'keys') {
const { path, keys: oldKeys } = item
const curVal = dataPath.getDataOnPath(this.data, path)
const keys = Object.keys(curVal).sort()
if (keys.length !== oldKeys.length) {
needUpdate = true
break
}
for (let j = 0; j < keys.length; j += 1) {
if (keys[j] !== oldKeys[j]) {
needUpdate = true
break
}
}
} else {
const { path, value: oldVal } = item
const curVal = dataPath.getDataOnPath(this.data, path)
if (!equal(oldVal, curVal)) {
needUpdate = true
break
}
}
}
if (!needUpdate) return false
const relatedPathValues = [] as Array<dataTracer.RelatedPathValue>
const val = updateMethod(dataTracer.create(this.data, relatedPathValues))
this.setData({
[targetField]: dataTracer.unwrap(val),
})
computedWatchInfo.computedRelatedPathValues[index] = relatedPathValues
return true
}
computedWatchInfo.computedUpdaters.push(updateValueAndRelatedPaths)
})
}
},
})
}
addComputed(targetField: string, updateMethod: (data: Record<string, unknown>) => unknown) {
this.computedList.push([targetField, updateMethod])
if (this.computedList.length !== 1) return
const computedWatchDefId = this.computedWatchDefId
this.observersItems.push({
fields: '**',
observer(this: BehaviorExtend) {
if (!this._computedWatchInfo) return
const computedWatchInfo = this._computedWatchInfo[computedWatchDefId]
if (!computedWatchInfo) return
let changed: boolean
do {
try {
changed = computedWatchInfo.computedUpdaters.some((func) => func.call(this))
} catch (err) {
console.error(err.stack)
break
}
} while (changed)
},
})
}
addWatch(watchPath: string, listener: (args: any) => void) {
const paths = dataPath.parseMultiDataPaths(watchPath)
const index = this.watchList.length
this.watchList.push(paths)
const computedWatchDefId = this.computedWatchDefId
this.observersItems.push({
fields: watchPath,
observer(this: BehaviorExtend) {
if (!this._computedWatchInfo) return
const computedWatchInfo = this._computedWatchInfo[computedWatchDefId]
if (!computedWatchInfo) return
// (issue #58) ignore watch func when trigger by computed attached
if (Object.keys(computedWatchInfo._triggerFromComputedAttached).length) {
const pathsMap: Record<string, boolean> = {}
paths.forEach((path) => (pathsMap[path.path[0]] = true))
for (const computedVal in computedWatchInfo._triggerFromComputedAttached) {
if (computedWatchInfo._triggerFromComputedAttached[computedVal]) {
if (
pathsMap[computedVal] &&
computedWatchInfo._triggerFromComputedAttached[computedVal]
) {
computedWatchInfo._triggerFromComputedAttached[computedVal] = false
return
}
}
}
}
const oldVal = computedWatchInfo.watchCurVal[index]
// get new watching field value
const originalCurValWithOptions = paths.map(({ path, options }) => {
const val = dataPath.getDataOnPath(this.data, path)
return { val, options }
})
const curVal = originalCurValWithOptions.map(({ val, options }) =>
options.deepCmp ? deepClone(val) : val,
)
computedWatchInfo.watchCurVal[index] = curVal
// compare
let changed = false
for (let i = 0; i < curVal.length; i++) {
const options = paths[i].options
const deepCmp = options.deepCmp
if (deepCmp ? !deepEqual(oldVal[i], curVal[i]) : !equal(oldVal[i], curVal[i])) {
changed = true
break
}
}
// if changed, update
if (changed) {
listener.apply(
this,
originalCurValWithOptions.map(({ val }) => val),
)
}
},
})
}
}
export const behavior = Behavior({
lifetimes: {
attached(this: BehaviorExtend) {
this.setData({
_computedWatchInit: ComputedWatchInitStatus.ATTACHED,
})
},
created(this: BehaviorExtend) {
this.setData({
_computedWatchInit: ComputedWatchInitStatus.CREATED,
})
},
},
definitionFilter(defFields: any & BehaviorExtend) {
const computedDef = defFields.computed
const watchDef = defFields.watch
const builder = new ComputedBuilder()
if (computedDef) {
Object.keys(computedDef).forEach((targetField) => {
const updateMethod = computedDef[targetField]
builder.addComputed(targetField, updateMethod)
})
}
if (watchDef) {
Object.keys(watchDef).forEach((watchPath) => {
const listener = watchDef[watchPath]
builder.addWatch(watchPath, listener)
})
}
const observersItems = builder.observersItems
if (typeof defFields.observers !== 'object') {
defFields.observers = {}
}
if (Array.isArray(defFields.observers)) {
defFields.observers.push(...observersItems)
} else {
observersItems.forEach((item) => {
// defFields.observers[item.fields] = item.observer
const f = defFields.observers[item.fields]
if (!f) {
defFields.observers[item.fields] = item.observer
} else {
defFields.observers[item.fields] = function () {
item.observer.call(this)
f.call(this)
}
}
})
}
},
})
const tryInitInCtx = (
ctx: adapter.builder.BuilderContext<any, any, any> & { _computedWatchInit?: boolean },
) => {
if (ctx._computedWatchInit) return
ctx._computedWatchInit = true
const { lifetime, setData } = ctx
lifetime('attached', function () {
setData({
_computedWatchInit: ComputedWatchInitStatus.ATTACHED,
})
})
lifetime('created', function () {
setData({
_computedWatchInit: ComputedWatchInitStatus.CREATED,
})
})
}
export function computed<
TComputedDefinition1 extends {
[k: string]: (
data: adapter.glassEasel.typeUtils.DataWithPropertyValues<TPrevData, TProperty>,
) => any
},
TPrevData extends adapter.glassEasel.typeUtils.DataList,
TProperty extends adapter.glassEasel.typeUtils.PropertyList,
>(
ctx: adapter.builder.BuilderContext<TPrevData, TProperty, any>,
computedDefinition1: TComputedDefinition1,
): adapter.glassEasel.typeUtils.DataWithPropertyValues<
TPrevData & { [k in keyof TComputedDefinition1]: ReturnType<TComputedDefinition1[k]> },
TProperty
>
export function computed<
TComputedDefinition1 extends {
[k: string]: (
data: adapter.glassEasel.typeUtils.DataWithPropertyValues<TPrevData, TProperty>,
) => any
},
TComputedDefinition2 extends {
[k: string]: (
data: adapter.glassEasel.typeUtils.DataWithPropertyValues<
TPrevData & { [k in keyof TComputedDefinition1]: ReturnType<TComputedDefinition1[k]> },
TProperty
>,
) => any
},
TPrevData extends adapter.glassEasel.typeUtils.DataList,
TProperty extends adapter.glassEasel.typeUtils.PropertyList,
>(
ctx: adapter.builder.BuilderContext<TPrevData, TProperty, any>,
computedDefinition1: TComputedDefinition1,
computedDefinition2: TComputedDefinition2,
): adapter.glassEasel.typeUtils.DataWithPropertyValues<
TPrevData & { [k in keyof TComputedDefinition1]: ReturnType<TComputedDefinition1[k]> } & {
[k in keyof TComputedDefinition2]: ReturnType<TComputedDefinition2[k]>
},
TProperty
>
export function computed<
TComputedDefinition1 extends {
[k: string]: (
data: adapter.glassEasel.typeUtils.DataWithPropertyValues<TPrevData, TProperty>,
) => any
},
TComputedDefinition2 extends {
[k: string]: (
data: adapter.glassEasel.typeUtils.DataWithPropertyValues<
TPrevData & { [k in keyof TComputedDefinition1]: ReturnType<TComputedDefinition1[k]> },
TProperty
>,
) => any
},
TComputedDefinition3 extends {
[k: string]: (
data: adapter.glassEasel.typeUtils.DataWithPropertyValues<
TPrevData & { [k in keyof TComputedDefinition1]: ReturnType<TComputedDefinition1[k]> } & {
[k in keyof TComputedDefinition2]: ReturnType<TComputedDefinition2[k]>
},
TProperty
>,
) => any
},
TPrevData extends adapter.glassEasel.typeUtils.DataList,
TProperty extends adapter.glassEasel.typeUtils.PropertyList,
>(
ctx: adapter.builder.BuilderContext<TPrevData, TProperty, any>,
computedDefinition1: TComputedDefinition1,
computedDefinition2: TComputedDefinition2,
computedDefinition3: TComputedDefinition3,
): adapter.glassEasel.typeUtils.DataWithPropertyValues<
TPrevData & { [k in keyof TComputedDefinition1]: ReturnType<TComputedDefinition1[k]> } & {
[k in keyof TComputedDefinition2]: ReturnType<TComputedDefinition2[k]>
} & { [k in keyof TComputedDefinition3]: ReturnType<TComputedDefinition3[k]> },
TProperty
>
export function computed<
TComputedDefinition1 extends {
[k: string]: (
data: adapter.glassEasel.typeUtils.DataWithPropertyValues<TPrevData, TProperty>,
) => any
},
TComputedDefinition2 extends {
[k: string]: (
data: adapter.glassEasel.typeUtils.DataWithPropertyValues<
TPrevData & { [k in keyof TComputedDefinition1]: ReturnType<TComputedDefinition1[k]> },
TProperty
>,
) => any
},
TComputedDefinition3 extends {
[k: string]: (
data: adapter.glassEasel.typeUtils.DataWithPropertyValues<
TPrevData & { [k in keyof TComputedDefinition1]: ReturnType<TComputedDefinition1[k]> } & {
[k in keyof TComputedDefinition2]: ReturnType<TComputedDefinition2[k]>
},
TProperty
>,
) => any
},
TComputedDefinition4 extends {
[k: string]: (
data: adapter.glassEasel.typeUtils.DataWithPropertyValues<
TPrevData & { [k in keyof TComputedDefinition1]: ReturnType<TComputedDefinition1[k]> } & {
[k in keyof TComputedDefinition2]: ReturnType<TComputedDefinition2[k]>
} & { [k in keyof TComputedDefinition3]: ReturnType<TComputedDefinition3[k]> },
TProperty
>,
) => any
},
TPrevData extends adapter.glassEasel.typeUtils.DataList,
TProperty extends adapter.glassEasel.typeUtils.PropertyList,
>(
ctx: adapter.builder.BuilderContext<TPrevData, TProperty, any>,
computedDefinition1: TComputedDefinition1,
computedDefinition2: TComputedDefinition2,
computedDefinition3: TComputedDefinition3,
computedDefinition4: TComputedDefinition4,
): adapter.glassEasel.typeUtils.DataWithPropertyValues<
TPrevData & { [k in keyof TComputedDefinition1]: ReturnType<TComputedDefinition1[k]> } & {
[k in keyof TComputedDefinition2]: ReturnType<TComputedDefinition2[k]>
} & { [k in keyof TComputedDefinition3]: ReturnType<TComputedDefinition3[k]> } & {
[k in keyof TComputedDefinition4]: ReturnType<TComputedDefinition4[k]>
},
TProperty
>
export function computed<
TPrevData extends adapter.glassEasel.typeUtils.DataList,
TProperty extends adapter.glassEasel.typeUtils.PropertyList,
>(
ctx: adapter.builder.BuilderContext<TPrevData, TProperty, any>,
computedDefinition1: any,
computedDefinition2?: any,
computedDefinition3?: any,
computedDefinition4?: any,
): unknown {
tryInitInCtx(ctx)
const builder = new ComputedBuilder()
Object.keys(computedDefinition1).forEach((targetField) => {
const updateMethod = computedDefinition1[targetField]
builder.addComputed(targetField, updateMethod)
})
if (computedDefinition2) {
Object.keys(computedDefinition2).forEach((targetField) => {
const updateMethod = computedDefinition2[targetField]
builder.addComputed(targetField, updateMethod)
})
}
if (computedDefinition3) {
Object.keys(computedDefinition3).forEach((targetField) => {
const updateMethod = computedDefinition3[targetField]
builder.addComputed(targetField, updateMethod)
})
}
if (computedDefinition4) {
Object.keys(computedDefinition4).forEach((targetField) => {
const updateMethod = computedDefinition4[targetField]
builder.addComputed(targetField, updateMethod)
})
}
builder.observersItems.forEach(({ fields, observer }) => {
ctx.observer(fields as any, observer)
})
return ctx.data as any
}
export const watch = (
ctx: adapter.builder.BuilderContext<any, any, any>,
watchPath: string,
listener: (...args: any[]) => void,
) => {
tryInitInCtx(ctx)
const builder = new ComputedBuilder()
builder.addWatch(watchPath, listener)
builder.observersItems.forEach(({ fields, observer }) => {
ctx.observer(fields as any, observer)
})
}

@ -0,0 +1,132 @@
const WHITE_SPACE_CHAR_REGEXP = /^\s/
export type DataPathWithOptions = {
path: string[]
options: { deepCmp: boolean }
}
type ParserState = {
index: number
length: number
}
const throwParsingError = (path: string, index: number) => {
throw new Error(
'Parsing data path "' + path + '" failed at char "' + path[index] + '" (index ' + index + ')',
)
}
const parseArrIndex = (path: string, state: ParserState) => {
const startIndex = state.index
while (state.index < state.length) {
const ch = path[state.index]
if (/^[0-9]/.test(ch)) {
state.index++
continue
}
break
}
if (startIndex === state.index) {
throwParsingError(path, state.index)
}
return parseInt(path.slice(startIndex, state.index), 10)
}
const parseIdent = (path: string, state: ParserState) => {
const startIndex = state.index
const ch = path[startIndex]
if (/^[_a-zA-Z$]/.test(ch)) {
state.index++
while (state.index < state.length) {
const ch = path[state.index]
if (/^[_a-zA-Z0-9$]/.test(ch)) {
state.index++
continue
}
break
}
} else {
throwParsingError(path, state.index)
}
return path.slice(startIndex, state.index)
}
const parseSinglePath = (path: string, state: ParserState): DataPathWithOptions => {
const paths = [parseIdent(path, state)]
const options = {
deepCmp: false,
}
while (state.index < state.length) {
const ch = path[state.index]
if (ch === '[') {
state.index++
paths.push(`${parseArrIndex(path, state)}`)
const nextCh = path[state.index]
if (nextCh !== ']') throwParsingError(path, state.index)
state.index++
} else if (ch === '.') {
state.index++
const ch = path[state.index]
if (ch === '*') {
state.index++
const ch = path[state.index]
if (ch === '*') {
state.index++
options.deepCmp = true
break
}
throwParsingError(path, state.index)
}
paths.push(parseIdent(path, state))
} else {
break
}
}
return { path: paths, options }
}
const parseMultiPaths = (path: string, state: ParserState): DataPathWithOptions[] => {
while (WHITE_SPACE_CHAR_REGEXP.test(path[state.index])) {
state.index++
}
const ret = [parseSinglePath(path, state)]
let splitted = false
while (state.index < state.length) {
const ch = path[state.index]
if (WHITE_SPACE_CHAR_REGEXP.test(ch)) {
state.index++
} else if (ch === ',') {
splitted = true
state.index++
} else if (splitted) {
splitted = false
ret.push(parseSinglePath(path, state))
} else {
throwParsingError(path, state.index)
}
}
return ret
}
const parseEOF = (path: string, state: ParserState) => {
if (state.index < state.length) throwParsingError(path, state.index)
}
export const parseMultiDataPaths = (path: string): DataPathWithOptions[] => {
const state = {
length: path.length,
index: 0,
}
const ret = parseMultiPaths(path, state)
parseEOF(path, state)
return ret
}
export const getDataOnPath = (data: unknown, path: Array<string>) => {
let ret = data
path.forEach((s) => {
if (typeof ret !== 'object' || ret === null) ret = undefined
else ret = ret[s]
})
return ret
}

@ -0,0 +1,86 @@
import ProxyPolyfillBuilder from 'proxy-polyfill/src/proxy'
const ProxyPolyfill = ProxyPolyfillBuilder()
interface WrappedData {
__rawObject__: unknown
}
export type RelatedPathValue =
| {
kind: 'value'
path: Array<string>
value: unknown
}
| {
kind: 'keys'
path: Array<string>
keys: Array<string>
}
const wrapData = (
data: unknown,
relatedPathValues: Array<RelatedPathValue>,
basePath: Array<string>,
) => {
if (typeof data !== 'object' || data === null) return data
const handler = {
get(obj: unknown, key: string) {
if (key === '__rawObject__') return obj
let keyWrapper = null
const keyPath = basePath.concat(key)
const value = obj[key]
relatedPathValues.push({
kind: 'value',
path: keyPath,
value,
})
keyWrapper = wrapData(value, relatedPathValues, keyPath)
return keyWrapper
},
ownKeys(obj: unknown) {
const keyPath = basePath.slice()
const keys = Object.keys(obj).sort()
relatedPathValues.push({
kind: 'keys',
path: keyPath,
keys,
})
return keys
},
}
try {
return new Proxy(data, handler)
} catch (e) {
return new ProxyPolyfill(data, handler)
}
}
export function create(data: unknown, relatedPathValues: Array<RelatedPathValue>) {
return wrapData(data, relatedPathValues, [])
}
export function unwrap(wrapped: unknown) {
// #70
if (
wrapped !== null &&
typeof wrapped === 'object' &&
typeof (wrapped as WrappedData).__rawObject__ !== 'object'
) {
if (Array.isArray(wrapped)) {
return wrapped.map((i) => unwrap(i))
}
const ret = {}
Object.keys(wrapped).forEach((k) => {
ret[k] = unwrap(wrapped[k])
})
return ret
}
if (
typeof wrapped !== 'object' ||
wrapped === null ||
typeof (wrapped as WrappedData).__rawObject__ !== 'object'
) {
return wrapped
}
return (wrapped as WrappedData).__rawObject__
}

@ -0,0 +1,91 @@
import { behavior } from './behavior'
export { behavior, computed, watch } from './behavior'
type ComputedInstance<
D extends WechatMiniprogram.Component.DataOption,
P extends WechatMiniprogram.Component.PropertyOption,
M extends WechatMiniprogram.Component.MethodOption,
C extends Record<string, (data: D & { [K in keyof P]: any }) => any>,
TCustomProperty extends WechatMiniprogram.IAnyObject = Record<string, never>,
> = WechatMiniprogram.Component.Instance<D, P, M, TCustomProperty> & {
data: { [K in keyof C]: ReturnType<C[K]> } & { [K in keyof P]: any }
}
type ComputedOptions<
TData extends WechatMiniprogram.Component.DataOption,
TProperty extends WechatMiniprogram.Component.PropertyOption,
TMethod extends WechatMiniprogram.Component.MethodOption,
TWatch extends Record<string, (...args: any[]) => void>,
TComputed extends Record<
string,
(data: TData & WechatMiniprogram.Component.PropertyOptionToData<TProperty>) => any
>,
TCustomInstanceProperty extends WechatMiniprogram.IAnyObject = {},
> = (Partial<WechatMiniprogram.Component.Data<TData>> &
Partial<WechatMiniprogram.Component.Property<TProperty>> &
Partial<WechatMiniprogram.Component.Method<TMethod>> &
Partial<WechatMiniprogram.Component.OtherOption> &
Partial<WechatMiniprogram.Component.Lifetimes> & {
watch?: TWatch
computed?: TComputed
template?: string
}) &
ThisType<ComputedInstance<TData, TProperty, TMethod, TComputed, TCustomInstanceProperty>>
export function ComponentWithComputed<
TData extends WechatMiniprogram.Component.DataOption,
TProperty extends WechatMiniprogram.Component.PropertyOption,
TMethod extends WechatMiniprogram.Component.MethodOption,
TWatch extends Record<string, (...args: any[]) => void>,
TComputed extends Record<
string,
(data: TData & WechatMiniprogram.Component.PropertyOptionToData<TProperty>) => any
>,
TCustomInstanceProperty extends WechatMiniprogram.IAnyObject = {},
>(
options: ComputedOptions<TData, TProperty, TMethod, TWatch, TComputed, TCustomInstanceProperty>,
): string {
if (!Array.isArray(options.behaviors)) {
options.behaviors = []
}
options.behaviors.unshift(behavior)
return Component(options)
}
export function BehaviorWithComputed<
TData extends WechatMiniprogram.Behavior.DataOption,
TProperty extends WechatMiniprogram.Behavior.PropertyOption,
TMethod extends WechatMiniprogram.Behavior.MethodOption,
TWatch extends Record<string, (...args: any[]) => void>,
TComputed extends Record<
string,
(data: TData & WechatMiniprogram.Component.PropertyOptionToData<TProperty>) => any
>,
TCustomInstanceProperty extends WechatMiniprogram.IAnyObject = {},
>(
options: ComputedOptions<TData, TProperty, TMethod, TWatch, TComputed, TCustomInstanceProperty>,
): string {
if (!Array.isArray(options.behaviors)) {
options.behaviors = []
}
options.behaviors.unshift(behavior)
return Behavior(options)
}
// data tracer mode
export enum DataTracerMode {
Auto,
Proxy,
DefineProperty,
}
let currentDataTracerMode = DataTracerMode.Auto
export const getCurrentDataTracerMode = () => {
return currentDataTracerMode
}
export const setCurrentDataTracerMode = (mode: DataTracerMode) => {
currentDataTracerMode = mode
}

@ -0,0 +1,67 @@
import type * as adapter from 'glass-easel-miniprogram-adapter';
export declare const behavior: string;
export declare function computed<TComputedDefinition1 extends {
[k: string]: (data: adapter.glassEasel.typeUtils.DataWithPropertyValues<TPrevData, TProperty>) => any;
}, TPrevData extends adapter.glassEasel.typeUtils.DataList, TProperty extends adapter.glassEasel.typeUtils.PropertyList>(ctx: adapter.builder.BuilderContext<TPrevData, TProperty, any>, computedDefinition1: TComputedDefinition1): adapter.glassEasel.typeUtils.DataWithPropertyValues<TPrevData & {
[k in keyof TComputedDefinition1]: ReturnType<TComputedDefinition1[k]>;
}, TProperty>;
export declare function computed<TComputedDefinition1 extends {
[k: string]: (data: adapter.glassEasel.typeUtils.DataWithPropertyValues<TPrevData, TProperty>) => any;
}, TComputedDefinition2 extends {
[k: string]: (data: adapter.glassEasel.typeUtils.DataWithPropertyValues<TPrevData & {
[k in keyof TComputedDefinition1]: ReturnType<TComputedDefinition1[k]>;
}, TProperty>) => any;
}, TPrevData extends adapter.glassEasel.typeUtils.DataList, TProperty extends adapter.glassEasel.typeUtils.PropertyList>(ctx: adapter.builder.BuilderContext<TPrevData, TProperty, any>, computedDefinition1: TComputedDefinition1, computedDefinition2: TComputedDefinition2): adapter.glassEasel.typeUtils.DataWithPropertyValues<TPrevData & {
[k in keyof TComputedDefinition1]: ReturnType<TComputedDefinition1[k]>;
} & {
[k in keyof TComputedDefinition2]: ReturnType<TComputedDefinition2[k]>;
}, TProperty>;
export declare function computed<TComputedDefinition1 extends {
[k: string]: (data: adapter.glassEasel.typeUtils.DataWithPropertyValues<TPrevData, TProperty>) => any;
}, TComputedDefinition2 extends {
[k: string]: (data: adapter.glassEasel.typeUtils.DataWithPropertyValues<TPrevData & {
[k in keyof TComputedDefinition1]: ReturnType<TComputedDefinition1[k]>;
}, TProperty>) => any;
}, TComputedDefinition3 extends {
[k: string]: (data: adapter.glassEasel.typeUtils.DataWithPropertyValues<TPrevData & {
[k in keyof TComputedDefinition1]: ReturnType<TComputedDefinition1[k]>;
} & {
[k in keyof TComputedDefinition2]: ReturnType<TComputedDefinition2[k]>;
}, TProperty>) => any;
}, TPrevData extends adapter.glassEasel.typeUtils.DataList, TProperty extends adapter.glassEasel.typeUtils.PropertyList>(ctx: adapter.builder.BuilderContext<TPrevData, TProperty, any>, computedDefinition1: TComputedDefinition1, computedDefinition2: TComputedDefinition2, computedDefinition3: TComputedDefinition3): adapter.glassEasel.typeUtils.DataWithPropertyValues<TPrevData & {
[k in keyof TComputedDefinition1]: ReturnType<TComputedDefinition1[k]>;
} & {
[k in keyof TComputedDefinition2]: ReturnType<TComputedDefinition2[k]>;
} & {
[k in keyof TComputedDefinition3]: ReturnType<TComputedDefinition3[k]>;
}, TProperty>;
export declare function computed<TComputedDefinition1 extends {
[k: string]: (data: adapter.glassEasel.typeUtils.DataWithPropertyValues<TPrevData, TProperty>) => any;
}, TComputedDefinition2 extends {
[k: string]: (data: adapter.glassEasel.typeUtils.DataWithPropertyValues<TPrevData & {
[k in keyof TComputedDefinition1]: ReturnType<TComputedDefinition1[k]>;
}, TProperty>) => any;
}, TComputedDefinition3 extends {
[k: string]: (data: adapter.glassEasel.typeUtils.DataWithPropertyValues<TPrevData & {
[k in keyof TComputedDefinition1]: ReturnType<TComputedDefinition1[k]>;
} & {
[k in keyof TComputedDefinition2]: ReturnType<TComputedDefinition2[k]>;
}, TProperty>) => any;
}, TComputedDefinition4 extends {
[k: string]: (data: adapter.glassEasel.typeUtils.DataWithPropertyValues<TPrevData & {
[k in keyof TComputedDefinition1]: ReturnType<TComputedDefinition1[k]>;
} & {
[k in keyof TComputedDefinition2]: ReturnType<TComputedDefinition2[k]>;
} & {
[k in keyof TComputedDefinition3]: ReturnType<TComputedDefinition3[k]>;
}, TProperty>) => any;
}, TPrevData extends adapter.glassEasel.typeUtils.DataList, TProperty extends adapter.glassEasel.typeUtils.PropertyList>(ctx: adapter.builder.BuilderContext<TPrevData, TProperty, any>, computedDefinition1: TComputedDefinition1, computedDefinition2: TComputedDefinition2, computedDefinition3: TComputedDefinition3, computedDefinition4: TComputedDefinition4): adapter.glassEasel.typeUtils.DataWithPropertyValues<TPrevData & {
[k in keyof TComputedDefinition1]: ReturnType<TComputedDefinition1[k]>;
} & {
[k in keyof TComputedDefinition2]: ReturnType<TComputedDefinition2[k]>;
} & {
[k in keyof TComputedDefinition3]: ReturnType<TComputedDefinition3[k]>;
} & {
[k in keyof TComputedDefinition4]: ReturnType<TComputedDefinition4[k]>;
}, TProperty>;
export declare const watch: (ctx: adapter.builder.BuilderContext<any, any, any>, watchPath: string, listener: (...args: any[]) => void) => void;

@ -0,0 +1,8 @@
export type DataPathWithOptions = {
path: string[];
options: {
deepCmp: boolean;
};
};
export declare const parseMultiDataPaths: (path: string) => DataPathWithOptions[];
export declare const getDataOnPath: (data: unknown, path: Array<string>) => unknown;

@ -0,0 +1,11 @@
export type RelatedPathValue = {
kind: 'value';
path: Array<string>;
value: unknown;
} | {
kind: 'keys';
path: Array<string>;
keys: Array<string>;
};
export declare function create(data: unknown, relatedPathValues: Array<RelatedPathValue>): any;
export declare function unwrap(wrapped: unknown): any;

@ -0,0 +1,24 @@
export { behavior, computed, watch } from './behavior';
type ComputedInstance<D extends WechatMiniprogram.Component.DataOption, P extends WechatMiniprogram.Component.PropertyOption, M extends WechatMiniprogram.Component.MethodOption, C extends Record<string, (data: D & {
[K in keyof P]: any;
}) => any>, TCustomProperty extends WechatMiniprogram.IAnyObject = Record<string, never>> = WechatMiniprogram.Component.Instance<D, P, M, TCustomProperty> & {
data: {
[K in keyof C]: ReturnType<C[K]>;
} & {
[K in keyof P]: any;
};
};
type ComputedOptions<TData extends WechatMiniprogram.Component.DataOption, TProperty extends WechatMiniprogram.Component.PropertyOption, TMethod extends WechatMiniprogram.Component.MethodOption, TWatch extends Record<string, (...args: any[]) => void>, TComputed extends Record<string, (data: TData & WechatMiniprogram.Component.PropertyOptionToData<TProperty>) => any>, TCustomInstanceProperty extends WechatMiniprogram.IAnyObject = {}> = (Partial<WechatMiniprogram.Component.Data<TData>> & Partial<WechatMiniprogram.Component.Property<TProperty>> & Partial<WechatMiniprogram.Component.Method<TMethod>> & Partial<WechatMiniprogram.Component.OtherOption> & Partial<WechatMiniprogram.Component.Lifetimes> & {
watch?: TWatch;
computed?: TComputed;
template?: string;
}) & ThisType<ComputedInstance<TData, TProperty, TMethod, TComputed, TCustomInstanceProperty>>;
export declare function ComponentWithComputed<TData extends WechatMiniprogram.Component.DataOption, TProperty extends WechatMiniprogram.Component.PropertyOption, TMethod extends WechatMiniprogram.Component.MethodOption, TWatch extends Record<string, (...args: any[]) => void>, TComputed extends Record<string, (data: TData & WechatMiniprogram.Component.PropertyOptionToData<TProperty>) => any>, TCustomInstanceProperty extends WechatMiniprogram.IAnyObject = {}>(options: ComputedOptions<TData, TProperty, TMethod, TWatch, TComputed, TCustomInstanceProperty>): string;
export declare function BehaviorWithComputed<TData extends WechatMiniprogram.Behavior.DataOption, TProperty extends WechatMiniprogram.Behavior.PropertyOption, TMethod extends WechatMiniprogram.Behavior.MethodOption, TWatch extends Record<string, (...args: any[]) => void>, TComputed extends Record<string, (data: TData & WechatMiniprogram.Component.PropertyOptionToData<TProperty>) => any>, TCustomInstanceProperty extends WechatMiniprogram.IAnyObject = {}>(options: ComputedOptions<TData, TProperty, TMethod, TWatch, TComputed, TCustomInstanceProperty>): string;
export declare enum DataTracerMode {
Auto = 0,
Proxy = 1,
DefineProperty = 2
}
export declare const getCurrentDataTracerMode: () => DataTracerMode;
export declare const setCurrentDataTracerMode: (mode: DataTracerMode) => void;

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 wechat-miniprogram
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.

@ -0,0 +1,275 @@
# 小程序的 MobX 绑定辅助库
小程序的 MobX 绑定辅助库。
> 此 behavior 依赖开发者工具的 npm 构建。具体详情可查阅 [官方 npm 文档](https://developers.weixin.qq.com/miniprogram/dev/devtools/npm.html) 。
## 使用方法
需要小程序基础库版本 >= 2.11.0 的环境。
具体的示例完整代码,可以参考 [examples](./examples/) 。
1. 安装 `mobx-miniprogram``mobx-miniprogram-bindings`
```shell
npm install --save mobx-miniprogram mobx-miniprogram-bindings
```
2. 创建 MobX Store。
```js
// store.js
import { observable, action } from 'mobx-miniprogram'
// 创建 store 时可以采用任何 mobx 的接口风格
// 这里以传统的 observable 风格为例
export const store = observable({
// 数据字段
numA: 1,
numB: 2,
// 计算属性
get sum() {
return this.numA + this.numB
},
// actions
update: action(function () {
const sum = this.sum
this.numA = this.numB
this.numB = sum
}),
})
```
3. 在 Page 或 Component 构造器中使用:
```js
import { storeBindingsBehavior } from 'mobx-miniprogram-bindings'
import { store } from './store'
Component({
behaviors: [storeBindingsBehavior], // 添加这个 behavior
data: {
someData: '...',
},
storeBindings: {
store,
fields: {
numA: () => store.numA,
numB: (store) => store.numB,
sum: 'sum',
},
actions: {
buttonTap: 'update',
},
},
methods: {
myMethod() {
this.data.sum // 来自于 MobX store 的字段
},
},
})
```
## TypeScript 接口
在 TypeScript 下,可以使用 `ComponentWithStore` 接口。它会自动处理一些类型问题。注意:
* 使用这个接口时,不要在 behaviors 中额外引入 `storeBindingsBehavior`
* `fields``actions` 末尾需要加上 `as const` 以便更好的类型推导;
* `storeBindings` 如果是一个数组,也要在数组后加上 `as const`
```js
import { ComponentWithStore } from 'mobx-miniprogram-bindings'
ComponentWithStore({
data: {
someData: '...',
},
storeBindings: {
store,
fields: ['numA', 'numB', 'sum'] as const,
actions: {
buttonTap: 'update',
} as const,
},
})
```
`BehaviorWithStore` 接口类似。
```js
import { BehaviorWithStore } from 'mobx-miniprogram-bindings'
export const testBehavior = BehaviorWithStore({
storeBindings: {
store,
fields: ['numA', 'numB', 'sum'] as const,
actions: ['update'] as const,
},
})
```
## glass-easel Chaining API 接口
使用 glass-easel Chaining API 时,使用 `initStoreBindings` 更友好。
```js
import { initStoreBindings } from 'mobx-miniprogram-bindings'
Component()
.init((ctx) => {
const { listener } = ctx
initStoreBindings(ctx, {
store,
fields: ['numA', 'numB', 'sum'],
})
const buttonTap = listener(() => {
store.update()
})
return { buttonTap }
})
.register()
```
## 具体接口说明
将页面、自定义组件和 store 绑定有两种方式: **behavior 绑定****手工绑定** 。
### behavior 绑定
**behavior 绑定** 适用于 `Component` 构造器。做法:使用 `storeBindingsBehavior` 这个 behavior 和 `storeBindings` 定义段。
```js
import { storeBindingsBehavior } from 'mobx-miniprogram-bindings'
Component({
behaviors: [storeBindingsBehavior],
storeBindings: {
/* 绑定配置(见下文) */
},
})
```
也可以把 `storeBindings` 设置为一个数组,这样可以同时绑定多个 `store`
```js
import { storeBindingsBehavior } from 'mobx-miniprogram-bindings'
Component({
behaviors: [storeBindingsBehavior],
storeBindings: [
{
/* 绑定配置 1 */
},
{
/* 绑定配置 2 */
},
],
})
```
### 手工绑定
**手工绑定** 更加灵活,适用于 store 需要在 `onLoad` (自定义组件 attached )时才能确定的情况。
做法:使用 `createStoreBindings` 创建绑定,它会返回一个包含清理函数的对象用于取消绑定。
注意:在页面 onUnload (自定义组件 detached )时一定要调用清理函数,否则将导致内存泄漏!
```js
import { createStoreBindings } from 'mobx-miniprogram-bindings'
Page({
onLoad() {
this.storeBindings = createStoreBindings(this, {
/* 绑定配置(见下文) */
})
},
onUnload() {
this.storeBindings.destroyStoreBindings()
},
})
```
### 绑定配置
无论使用哪种绑定方式,都必须提供一个绑定配置对象。这个对象包含的字段如下:
| 字段名 | 类型 | 含义 |
| ------- | -------------------- | ---------------------------- |
| store | 一个 MobX observable | 默认的 MobX store |
| fields | 数组或者对象 | 用于指定需要绑定的 data 字段 |
| actions | 数组或者对象 | 用于指定需要映射的 actions |
#### `fields`
`fields` 有三种形式:
- 数组形式:指定 data 中哪些字段来源于 `store` 。例如 `['numA', 'numB', 'sum']`
- 映射形式:指定 data 中哪些字段来源于 `store` 以及它们在 `store` 中对应的名字。例如 `{ a: 'numA', b: 'numB' }` ,此时 `this.data.a === store.numA` `this.data.b === store.numB`
- 函数形式:指定 data 中每个字段的计算方法。例如 `{ a: () => store.numA, b: () => anotherStore.numB }` ,此时 `this.data.a === store.numA` `this.data.b === anotherStore.numB`
上述三种形式中,映射形式和函数形式可以在一个配置中同时使用。
如果仅使用了函数形式,那么 `store` 字段可以为空,否则 `store` 字段必填。
#### `actions`
`actions` 可以用于将 store 中的一些 actions 放入页面或自定义组件的 this 下,来方便触发一些 actions 。有两种形式:
- 数组形式:例如 `['update']` ,此时 `this.update === store.update`
- 映射形式:例如 `{ buttonTap: 'update' }` ,此时 `this.buttonTap === store.update`
只要 `actions` 不为空,则 `store` 字段必填。
## 注意事项
### 延迟更新与立刻更新
为了提升性能,在 store 中的字段被更新后,并不会立刻同步更新到 `this.data` 上,而是等到下个 `wx.nextTick` 调用时才更新。(这样可以显著减少 setData 的调用次数。)
如果需要立刻更新,可以调用:
- `this.updateStoreBindings()` (在 **behavior 绑定** 中)
- `this.storeBindings.updateStoreBindings()` (在 **手工绑定** 中)
### 与 miniprogram-computed 一起使用
与 [miniprogram-computed](https://github.com/wechat-miniprogram/computed) 时,在 behaviors 列表中 `computedBehavior` 必须在后面:
```js
Component({
behaviors: [storeBindingsBehavior, computedBehavior],
/* ... */
})
```
### 关于部分更新
如果只是更新对象中的一部分(子字段),是不会引发界面变化的!例如:
```js
Component({
behaviors: [storeBindingsBehavior],
storeBindings: {
store,
fields: ['someObject'],
},
})
```
如果尝试在 `store` 中:
```js
this.someObject.someField = 'xxx'
```
这样是不会触发界面更新的。请考虑改成:
```js
this.someObject = Object.assign({}, this.someObject, { someField: 'xxx' })
```

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,82 @@
{
"name": "mobx-miniprogram-bindings",
"version": "4.0.1",
"description": "Mobx binding utils for WeChat miniprogram",
"main": "dist/index.js",
"types": "types/src/index.d.ts",
"files": [
"src",
"types",
"dist",
"LICENSE",
"package.json",
"README.md"
],
"scripts": {
"build": "gulp",
"gen_dts": "gulp dts",
"test": "jest ./test/* --bail",
"coverage": "jest ./test/* --coverage --bail",
"lint": "eslint . --fix"
},
"miniprogram": "dist",
"repository": {
"type": "git",
"url": "git+https://github.com/wechat-miniprogram/mobx-miniprogram-bindings.git"
},
"keywords": [
"mobx",
"wechat",
"miniprogram"
],
"author": "wechat-miniprogram",
"license": "MIT",
"bugs": {
"url": "https://github.com/wechat-miniprogram/mobx-miniprogram-bindings/issues"
},
"homepage": "https://github.com/wechat-miniprogram/mobx-miniprogram-bindings#readme",
"devDependencies": {
"@babel/runtime": "^7.24.5",
"@swc/core": "^1.5.2",
"@types/jest": "^29.5.12",
"@types/node": "^20.12.8",
"@typescript-eslint/eslint-plugin": "^7.8.0",
"@typescript-eslint/parser": "^7.8.0",
"colors": "^1.4.0",
"esbuild": "^0.20.2",
"eslint": "^8.56.0",
"eslint-config-airbnb-base": "15.0.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-promise": "^6.1.1",
"glass-easel": "0.5.2",
"glass-easel-miniprogram-adapter": "0.5.2",
"glass-easel-template-compiler": "0.5.2",
"gulp": "^5.0.0",
"gulp-clean": "^0.4.0",
"gulp-esbuild": "^0.12.0",
"gulp-swc": "^2.1.0",
"gulp-typescript": "6.0.0-alpha.1",
"gulp-watch": "^5.0.1",
"husky": "^9.0.11",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"miniprogram-api-typings": "^3.12.2",
"miniprogram-computed": "^4.4.0",
"mobx-miniprogram": "^6.0.0",
"prettier": "3.2.5",
"ts-jest": "^29.1.2",
"ts-node": "^10.9.2",
"typescript": "^5.4.5"
},
"peerDependencies": {
"mobx-miniprogram": "^6.0.0"
},
"husky": {
"hooks": {
"pre-commit": "npm run lint"
}
}
}

@ -0,0 +1,83 @@
import 'miniprogram-api-typings'
import { IStoreBindings } from './index'
import { createActions, createDataFieldsReactions, StoreBindingsManager } from './core'
type TDefFields = WechatMiniprogram.Component.TrivialOption & {
storeBindings?: IStoreBindings<any> | Array<IStoreBindings<any>>
}
type UninitializedThis = {
updateStoreBindings: () => void
_mobxMiniprogramBindings: (() => IStoreBindings<any>) | StoreBindingsManager | StoreBindingsManager[] | null
}
type InitializedThis = {
updateStoreBindings: () => void
_mobxMiniprogramBindings: StoreBindingsManager | StoreBindingsManager[] | null
}
export const behavior = Behavior({
definitionFilter: (defFields: TDefFields) => {
defFields.methods = defFields.methods || {}
const { storeBindings } = defFields
defFields.methods._mobxMiniprogramBindings = () => {
return storeBindings
}
if (storeBindings) {
if (Array.isArray(storeBindings)) {
storeBindings.forEach((binding) => {
createActions(defFields.methods, binding)
})
} else {
createActions(defFields.methods, storeBindings)
}
}
},
lifetimes: {
attached() {
const self = this as unknown as UninitializedThis
if (typeof self._mobxMiniprogramBindings !== 'function') return
const storeBindings = self._mobxMiniprogramBindings()
if (!storeBindings) {
self._mobxMiniprogramBindings = null
return
}
if (Array.isArray(storeBindings)) {
self._mobxMiniprogramBindings = storeBindings.map((item) => {
const ret = createDataFieldsReactions(self, item)
ret.updateStoreBindings()
return ret
})
} else {
self._mobxMiniprogramBindings = createDataFieldsReactions(this, storeBindings)
self._mobxMiniprogramBindings.updateStoreBindings()
}
},
detached() {
const self = this as unknown as InitializedThis
if (self._mobxMiniprogramBindings) {
if (Array.isArray(self._mobxMiniprogramBindings)) {
self._mobxMiniprogramBindings.forEach((item) => {
item.destroyStoreBindings()
})
} else {
self._mobxMiniprogramBindings.destroyStoreBindings()
}
}
},
},
methods: {
updateStoreBindings() {
const self = this as unknown as UninitializedThis
if (self._mobxMiniprogramBindings && typeof self._mobxMiniprogramBindings !== 'function') {
if (Array.isArray(self._mobxMiniprogramBindings)) {
self._mobxMiniprogramBindings.forEach((item) => {
item.updateStoreBindings()
})
} else {
self._mobxMiniprogramBindings.updateStoreBindings()
}
}
},
},
})

@ -0,0 +1,152 @@
import { reaction, comparer, toJS } from 'mobx-miniprogram'
import { IStoreBindings } from './index'
export const createActions = <TStore extends Record<string, any>>(methods, options: IStoreBindings<TStore>) => {
const { store, actions } = options
if (!actions) return
// for array-typed fields definition
if (typeof store === 'undefined') {
throw new Error('[mobx-miniprogram] no store specified')
}
if (Array.isArray(actions)) {
actions.forEach((field) => {
if (methods[field]) {
throw new Error('[mobx-miniprogram] multiple action definition')
}
methods[field] = (...args) => {
return (store[field] as (...args: unknown[]) => unknown)(...args)
}
})
} else if (typeof actions === 'object') {
Object.keys(actions).forEach((field) => {
const def = actions[field]
if (typeof field !== 'string' && typeof field !== 'number') {
throw new Error('[mobx-miniprogram] unrecognized field definition')
}
methods[field] = (...args) => {
return (store[def] as (...args: unknown[]) => unknown)(...args)
}
})
}
}
export type StoreBindingsManager = {
updateStoreBindings: () => void
destroyStoreBindings: () => void
}
export const createDataFieldsReactions = <TStore extends Record<string, any>>(
target,
options: Omit<IStoreBindings<TStore>, 'actions'>,
): StoreBindingsManager => {
const { store, fields, structuralComparison } = options
// if use namespace
let namespace = options.namespace || ''
if (namespace && typeof namespace !== 'string') {
throw new Error('[mobx-miniprogram] namespace only expect string')
}
namespace = namespace.replace(new RegExp(' ', 'gm'), '')
let namespaceData = Object.assign({}, target[namespace])
const useNamespace = (): boolean => {
return namespace !== ''
}
// choose equal method
const equals = structuralComparison ? comparer.structural : undefined
// setData combination
let pendingSetData: Record<string, any> | null = null
const applySetData = () => {
if (pendingSetData === null) return
const data = pendingSetData
pendingSetData = null
target.setData(data)
}
const scheduleSetData = (field, value) => {
if (!pendingSetData) {
pendingSetData = {}
if (typeof wx !== 'undefined') wx.nextTick(applySetData)
else Promise.resolve().then(applySetData)
}
if (useNamespace()) {
namespaceData = {
...namespaceData,
[field]: toJS(value),
}
pendingSetData[namespace] = namespaceData
} else {
pendingSetData[field] = toJS(value)
}
}
// handling fields
let reactions: (() => void)[] = []
if (Array.isArray(fields)) {
// for array-typed fields definition
if (typeof store === 'undefined') {
throw new Error('[mobx-miniprogram] no store specified')
}
reactions = fields.map((field) => {
return reaction(
() => store[field],
(value) => {
scheduleSetData(field, value)
},
{
equals,
fireImmediately: true,
},
)
})
} else if (typeof fields === 'object' && fields) {
// for object-typed fields definition
reactions = Object.keys(fields).map((field) => {
const def = fields[field]
if (typeof def === 'function') {
return reaction(
() => def.call(target, store),
(value) => {
scheduleSetData(field, value)
},
{
equals,
fireImmediately: true,
},
)
}
if (typeof field !== 'string' && typeof field !== 'number') {
throw new Error('[mobx-miniprogram] unrecognized field definition')
}
if (typeof store === 'undefined') {
throw new Error('[mobx-miniprogram] no store specified')
}
return reaction(
() => store[def],
(value) => {
scheduleSetData(String(field), value)
},
{
equals,
fireImmediately: true,
},
)
})
}
const destroyStoreBindings = () => {
reactions.forEach((reaction) => reaction())
}
return {
updateStoreBindings: applySetData,
destroyStoreBindings,
}
}

@ -0,0 +1,183 @@
import 'miniprogram-api-typings'
import { behavior } from './behavior'
import { StoreBindingsManager, createActions, createDataFieldsReactions } from './core'
import type * as adapter from 'glass-easel-miniprogram-adapter'
type Action = string
export interface IStoreBindings<T extends Record<string, any>> {
namespace?: string
store: T
fields: (keyof T)[] | { [k: string]: (keyof T | ((...args: any) => any)) }
actions: (keyof T)[] | { [k: Action]: keyof T }
structuralComparison?: boolean
}
type StoreData<T extends IStoreBindings<any>> = T['fields'] extends string[]
? { [k in T['fields'][number]]: T['store'][k] }
: T['fields'] extends { [k: Action]: string | ((...args: any) => any) }
? { [k in keyof T['fields']]: (
T['fields'][k] extends (...args: any) => any
? ReturnType<T['fields'][k]>
: T['fields'][k] extends string
? T['store'][T['fields'][k]]
: unknown
)}
: unknown
type StoreAction<T extends IStoreBindings<any>> = T['actions'] extends string[]
? { [k in T['actions'][number]]: T['store'][k] }
: T['actions'] extends { [k: Action]: string }
? { [k in keyof T['actions']]: T['store'][T['actions'][k]] }
: unknown
type StoreOptions<
TStoreBindings extends IStoreBindings<any>,
TData extends WechatMiniprogram.Component.DataOption,
TProperty extends WechatMiniprogram.Component.PropertyOption,
TMethod extends WechatMiniprogram.Component.MethodOption,
TCustomInstanceProperty extends WechatMiniprogram.IAnyObject = {},
> = (Partial<WechatMiniprogram.Component.Data<TData>> &
Partial<WechatMiniprogram.Component.Property<TProperty>> &
Partial<WechatMiniprogram.Component.Method<TMethod>> &
Partial<WechatMiniprogram.Component.OtherOption> &
Partial<WechatMiniprogram.Component.Lifetimes> & {
storeBindings: TStoreBindings
}) &
ThisType<
WechatMiniprogram.Component.Instance<
TData & StoreData<TStoreBindings>,
TProperty,
TMethod & StoreAction<TStoreBindings>,
TCustomInstanceProperty
>
>
type StoreListOptions<
TStoreBindings extends IStoreBindings<any>[],
TData extends WechatMiniprogram.Component.DataOption,
TProperty extends WechatMiniprogram.Component.PropertyOption,
TMethod extends WechatMiniprogram.Component.MethodOption,
TCustomInstanceProperty extends WechatMiniprogram.IAnyObject = {},
> = (Partial<WechatMiniprogram.Component.Data<TData>> &
Partial<WechatMiniprogram.Component.Property<TProperty>> &
Partial<WechatMiniprogram.Component.Method<TMethod>> &
Partial<WechatMiniprogram.Component.OtherOption> &
Partial<WechatMiniprogram.Component.Lifetimes> & {
storeBindings: TStoreBindings
}) &
ThisType<
WechatMiniprogram.Component.Instance<
TData
& StoreData<TStoreBindings[0]>
& StoreData<TStoreBindings[1]>
& StoreData<TStoreBindings[2]>
& StoreData<TStoreBindings[3]>
& StoreData<TStoreBindings[4]>
& StoreData<TStoreBindings[5]>
& StoreData<TStoreBindings[6]>
& StoreData<TStoreBindings[7]>,
TProperty,
TMethod
& StoreAction<TStoreBindings[0]>
& StoreAction<TStoreBindings[1]>
& StoreAction<TStoreBindings[2]>
& StoreAction<TStoreBindings[3]>
& StoreAction<TStoreBindings[4]>
& StoreAction<TStoreBindings[5]>
& StoreAction<TStoreBindings[6]>
& StoreAction<TStoreBindings[7]>,
TCustomInstanceProperty
>
>
export function ComponentWithStore<
TStoreBindings extends IStoreBindings<any>,
TData extends WechatMiniprogram.Component.DataOption,
TProperty extends WechatMiniprogram.Component.PropertyOption,
TMethod extends WechatMiniprogram.Component.MethodOption,
TCustomInstanceProperty extends WechatMiniprogram.IAnyObject = {},
>(options: StoreOptions<TStoreBindings, TData, TProperty, TMethod, TCustomInstanceProperty>): string;
export function ComponentWithStore<
TStoreBindings extends IStoreBindings<any>[],
TData extends WechatMiniprogram.Component.DataOption,
TProperty extends WechatMiniprogram.Component.PropertyOption,
TMethod extends WechatMiniprogram.Component.MethodOption,
TCustomInstanceProperty extends WechatMiniprogram.IAnyObject = {},
>(options: StoreListOptions<TStoreBindings, TData, TProperty, TMethod, TCustomInstanceProperty>): string;
export function ComponentWithStore<
TStoreBindings extends any,
TData extends WechatMiniprogram.Component.DataOption,
TProperty extends WechatMiniprogram.Component.PropertyOption,
TMethod extends WechatMiniprogram.Component.MethodOption,
TCustomInstanceProperty extends WechatMiniprogram.IAnyObject = {},
>(options: StoreListOptions<any, TData, TProperty, TMethod, TCustomInstanceProperty>): string {
if (!Array.isArray(options.behaviors)) {
options.behaviors = []
}
options.behaviors.unshift(behavior)
return Component(options)
}
export function BehaviorWithStore<
TStoreBindings extends IStoreBindings<any>,
TData extends WechatMiniprogram.Component.DataOption,
TProperty extends WechatMiniprogram.Component.PropertyOption,
TMethod extends WechatMiniprogram.Component.MethodOption,
TCustomInstanceProperty extends WechatMiniprogram.IAnyObject = {},
>(options: StoreOptions<TStoreBindings, TData, TProperty, TMethod, TCustomInstanceProperty>): string;
export function BehaviorWithStore<
TStoreBindings extends IStoreBindings<any>[],
TData extends WechatMiniprogram.Component.DataOption,
TProperty extends WechatMiniprogram.Component.PropertyOption,
TMethod extends WechatMiniprogram.Component.MethodOption,
TCustomInstanceProperty extends WechatMiniprogram.IAnyObject = {},
>(options: StoreListOptions<TStoreBindings, TData, TProperty, TMethod, TCustomInstanceProperty>): string;
export function BehaviorWithStore<
TStoreBindings extends any,
TData extends WechatMiniprogram.Component.DataOption,
TProperty extends WechatMiniprogram.Component.PropertyOption,
TMethod extends WechatMiniprogram.Component.MethodOption,
TCustomInstanceProperty extends WechatMiniprogram.IAnyObject = {},
>(options: StoreOptions<any, TData, TProperty, TMethod, TCustomInstanceProperty>): string {
if (!Array.isArray(options.behaviors)) {
options.behaviors = []
}
options.behaviors.unshift(behavior)
return Behavior(options)
}
export const createStoreBindings = <TStore extends Record<string, any>>(target, options: IStoreBindings<TStore>): StoreBindingsManager => {
createActions(target, options)
return createDataFieldsReactions(target, options)
}
export const storeBindingsBehavior = behavior
export type InitializedStoreBindings = {
updateStoreBindings: () => void
}
export const initStoreBindings = <TStore extends Record<string, any>>(
ctx: adapter.builder.BuilderContext<any, any, any>,
options: Omit<IStoreBindings<TStore>, 'actions'>,
): InitializedStoreBindings => {
const { self, lifetime } = ctx
let storeBindings: StoreBindingsManager | undefined
lifetime('attached', () => {
storeBindings = createDataFieldsReactions(self, options)
storeBindings.updateStoreBindings()
})
lifetime('detached', () => {
storeBindings!.destroyStoreBindings()
})
return {
updateStoreBindings: () => {
if (storeBindings) {
storeBindings.updateStoreBindings()
}
},
}
}

@ -0,0 +1,2 @@
import 'miniprogram-api-typings';
export declare const behavior: string;

@ -0,0 +1,7 @@
import { IStoreBindings } from './index';
export declare const createActions: <TStore extends Record<string, any>>(methods: any, options: IStoreBindings<TStore>) => void;
export type StoreBindingsManager = {
updateStoreBindings: () => void;
destroyStoreBindings: () => void;
};
export declare const createDataFieldsReactions: <TStore extends Record<string, any>>(target: any, options: Omit<IStoreBindings<TStore>, "actions">) => StoreBindingsManager;

@ -0,0 +1,46 @@
import 'miniprogram-api-typings';
import { StoreBindingsManager } from './core';
import type * as adapter from 'glass-easel-miniprogram-adapter';
type Action = string;
export interface IStoreBindings<T extends Record<string, any>> {
namespace?: string;
store: T;
fields: (keyof T)[] | {
[k: string]: (keyof T | ((...args: any) => any));
};
actions: (keyof T)[] | {
[k: Action]: keyof T;
};
structuralComparison?: boolean;
}
type StoreData<T extends IStoreBindings<any>> = T['fields'] extends string[] ? {
[k in T['fields'][number]]: T['store'][k];
} : T['fields'] extends {
[k: Action]: string | ((...args: any) => any);
} ? {
[k in keyof T['fields']]: (T['fields'][k] extends (...args: any) => any ? ReturnType<T['fields'][k]> : T['fields'][k] extends string ? T['store'][T['fields'][k]] : unknown);
} : unknown;
type StoreAction<T extends IStoreBindings<any>> = T['actions'] extends string[] ? {
[k in T['actions'][number]]: T['store'][k];
} : T['actions'] extends {
[k: Action]: string;
} ? {
[k in keyof T['actions']]: T['store'][T['actions'][k]];
} : unknown;
type StoreOptions<TStoreBindings extends IStoreBindings<any>, TData extends WechatMiniprogram.Component.DataOption, TProperty extends WechatMiniprogram.Component.PropertyOption, TMethod extends WechatMiniprogram.Component.MethodOption, TCustomInstanceProperty extends WechatMiniprogram.IAnyObject = {}> = (Partial<WechatMiniprogram.Component.Data<TData>> & Partial<WechatMiniprogram.Component.Property<TProperty>> & Partial<WechatMiniprogram.Component.Method<TMethod>> & Partial<WechatMiniprogram.Component.OtherOption> & Partial<WechatMiniprogram.Component.Lifetimes> & {
storeBindings: TStoreBindings;
}) & ThisType<WechatMiniprogram.Component.Instance<TData & StoreData<TStoreBindings>, TProperty, TMethod & StoreAction<TStoreBindings>, TCustomInstanceProperty>>;
type StoreListOptions<TStoreBindings extends IStoreBindings<any>[], TData extends WechatMiniprogram.Component.DataOption, TProperty extends WechatMiniprogram.Component.PropertyOption, TMethod extends WechatMiniprogram.Component.MethodOption, TCustomInstanceProperty extends WechatMiniprogram.IAnyObject = {}> = (Partial<WechatMiniprogram.Component.Data<TData>> & Partial<WechatMiniprogram.Component.Property<TProperty>> & Partial<WechatMiniprogram.Component.Method<TMethod>> & Partial<WechatMiniprogram.Component.OtherOption> & Partial<WechatMiniprogram.Component.Lifetimes> & {
storeBindings: TStoreBindings;
}) & ThisType<WechatMiniprogram.Component.Instance<TData & StoreData<TStoreBindings[0]> & StoreData<TStoreBindings[1]> & StoreData<TStoreBindings[2]> & StoreData<TStoreBindings[3]> & StoreData<TStoreBindings[4]> & StoreData<TStoreBindings[5]> & StoreData<TStoreBindings[6]> & StoreData<TStoreBindings[7]>, TProperty, TMethod & StoreAction<TStoreBindings[0]> & StoreAction<TStoreBindings[1]> & StoreAction<TStoreBindings[2]> & StoreAction<TStoreBindings[3]> & StoreAction<TStoreBindings[4]> & StoreAction<TStoreBindings[5]> & StoreAction<TStoreBindings[6]> & StoreAction<TStoreBindings[7]>, TCustomInstanceProperty>>;
export declare function ComponentWithStore<TStoreBindings extends IStoreBindings<any>, TData extends WechatMiniprogram.Component.DataOption, TProperty extends WechatMiniprogram.Component.PropertyOption, TMethod extends WechatMiniprogram.Component.MethodOption, TCustomInstanceProperty extends WechatMiniprogram.IAnyObject = {}>(options: StoreOptions<TStoreBindings, TData, TProperty, TMethod, TCustomInstanceProperty>): string;
export declare function ComponentWithStore<TStoreBindings extends IStoreBindings<any>[], TData extends WechatMiniprogram.Component.DataOption, TProperty extends WechatMiniprogram.Component.PropertyOption, TMethod extends WechatMiniprogram.Component.MethodOption, TCustomInstanceProperty extends WechatMiniprogram.IAnyObject = {}>(options: StoreListOptions<TStoreBindings, TData, TProperty, TMethod, TCustomInstanceProperty>): string;
export declare function BehaviorWithStore<TStoreBindings extends IStoreBindings<any>, TData extends WechatMiniprogram.Component.DataOption, TProperty extends WechatMiniprogram.Component.PropertyOption, TMethod extends WechatMiniprogram.Component.MethodOption, TCustomInstanceProperty extends WechatMiniprogram.IAnyObject = {}>(options: StoreOptions<TStoreBindings, TData, TProperty, TMethod, TCustomInstanceProperty>): string;
export declare function BehaviorWithStore<TStoreBindings extends IStoreBindings<any>[], TData extends WechatMiniprogram.Component.DataOption, TProperty extends WechatMiniprogram.Component.PropertyOption, TMethod extends WechatMiniprogram.Component.MethodOption, TCustomInstanceProperty extends WechatMiniprogram.IAnyObject = {}>(options: StoreListOptions<TStoreBindings, TData, TProperty, TMethod, TCustomInstanceProperty>): string;
export declare const createStoreBindings: <TStore extends Record<string, any>>(target: any, options: IStoreBindings<TStore>) => StoreBindingsManager;
export declare const storeBindingsBehavior: string;
export type InitializedStoreBindings = {
updateStoreBindings: () => void;
};
export declare const initStoreBindings: <TStore extends Record<string, any>>(ctx: adapter.builder.BuilderContext<any, any, any>, options: Omit<IStoreBindings<TStore>, "actions">) => InitializedStoreBindings;
export {};

File diff suppressed because it is too large Load Diff

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Michel Weststrate
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.

@ -0,0 +1,185 @@
# WeChat MiniProgram compatible build of MobX
This is a special build of MobX that is compatible with WeChat MiniProgram.
<img src="https://mobx.js.org/assets/mobx.png" alt="logo" height="120" align="right" />
# MobX
_Simple, scalable state management._
[![npm version](https://badge.fury.io/js/mobx.svg)](https://badge.fury.io/js/mobx)
[![OpenCollective](https://opencollective.com/mobx/backers/badge.svg)](docs/backers-sponsors.md#backers)
[![OpenCollective](https://opencollective.com/mobx/sponsors/badge.svg)](docs/backers-sponsors.md#sponsors)
[![Discuss on Github](https://img.shields.io/badge/discuss%20on-GitHub-orange)](https://github.com/mobxjs/mobx/discussions)
[![Coverage Status](https://coveralls.io/repos/github/mobxjs/mobx/badge.svg?branch=main)](https://coveralls.io/github/mobxjs/mobx?branch=main)
[![View changelog](https://img.shields.io/badge/changelogs.xyz-Explore%20Changelog-brightgreen)](https://changelogs.xyz/mobx)
---
## Documentation
Documentation can be found at **[mobx.js.org](https://mobx.js.org/)**.
---
## Sponsors
MobX is made possible by the generosity of the sponsors below, and many other [individual backers](https://github.com/mobxjs/mobx/blob/main/docs/backers-sponsors.md#backers). Sponsoring directly impacts the longevity of this project.
**🥇 Gold sponsors (\$2500+ total contribution):**
<br/>
<a href="https://www.guilded.gg/"><img src="https://mobx.js.org/assets/guilded.jpg" align="center" width="100" title="Guilded" alt="Guilded" /></a>
<a href="https://www.getparallax.com/"><img src="https://mobx.js.org/assets/parallax.png" align="center" width="100" title="Parallax" alt="Parallax" /></a>
<a href="https://www.one-beyond.com"><img src="https://mobx.js.org/assets/dcsl.png" align="center" width="100" title="One Beyond" alt="One Beyond"/></a>
<a href="https://frontendmasters.com/"><img src="https://mobx.js.org/assets/frontendmasters.jpg" align="center" width="100" title="Frontend Masters" alt="Frontend Masters"></a>
<a href="http://auctionfrontier.com/"><img src="https://mobx.js.org/assets/auctionfrontier.jpeg" align="center" width="100" title="Auction Frontier" alt="Auction Frontier"></a>
<a href="https://www.codefirst.co.uk/"><img src="https://mobx.js.org/assets/codefirst.png" align="center" width="100" title="CodeFirst" alt="CodeFirst"/></a>
<a href="https://modulz.app/"><img src="https://mobx.js.org/assets/modulz.png" align="center" width="100" title="Modulz" alt="Modulz"/></a>
<a href="https://coinbase.com/"><img src="https://mobx.js.org/assets/coinbase.jpeg" align="center" width="100" title="Coinbase" alt="Coinbase" /></a>
<a href="https://curology.com/blog/tech"><img src="https://mobx.js.org/assets/curology.png" align="center" width="100" title="Curology" alt="Curology"/></a>
<a href="https://mendix.com/"><img src="https://mobx.js.org/assets/mendix-logo.png" align="center" width="100" title="Mendix" alt="Mendix" /></a>
<a href="https://www.canva.com/"><img src="https://mobx.js.org/assets/canva.svg" align="center" width="100" title="Canva" alt="Canva" /></a>
<a href="https://opensource.facebook.com/"><img src="https://mobx.js.org/assets/fbos.jpeg" align="center" width="100" title="Facebook Open Source" alt="Facebook Open Source" /></a>
<a href="https://casinosites.ltd.uk/?utm_source=sponsorship&utm_medium=mobx&utm_campaign=readme"><img src="https://mobx.js.org/assets/casino2.png" align="center" width="100" title="Casino Sites" alt="Casino Sites"/></a>
<a href="https://www.bugsnag.com/platforms/react-error-reporting?utm_source=MobX&utm_medium=Website&utm_content=open-source&utm_campaign=2019-community&utm_term=20190913"><img src="https://mobx.js.org/assets/bugsnag.jpg" align="center" width="100" title="Bugsnag" alt="Bugsnag"/></a>
**🥈 Silver sponsors (\$500+ total contributions):**<br/>
<a href="https://mantro.net/jobs/warlock"><img src="https://mobx.js.org/assets/mantro.png" align="center" width="100" title="mantro GmbH" alt="mantro GmbH"></a>
<a href="https://www.xh.com/"><img src="https://mobx.js.org/assets/xh.png" align="center" width="100" title="Extremely Heavy" alt="Extremely Heavy" /></a>
<a href="https://www.algolia.com/"><img src="https://mobx.js.org/assets/algolia.jpg" align="center" width="100" title="Algolia" alt="Algolia" /></a>
<a href="https://space307.com/?utm_source=sponsorship&utm_medium=mobx&utm_campaign=readme"><img src="https://mobx.js.org/assets/space307.png" align="center" width="100" title="Space307" alt="Space307"/></a>
<a href="https://blokt.com/"><img src="https://mobx.js.org/assets/blokt.jpg" align="center" width="100" title="Blokt" alt="Blokt"/></a>
<a href="https://upper.co/?utm_source=github_mobxjs_sponsorship&utm_medium=paid_acquisition&utm_campaign=sponsorship"><img src="https://mobx.js.org/assets/upper.png" align="center" width="100" title="UPPER" alt="UPPER"/></a>
<a href="https://careers.dazn.com/"><img src="https://mobx.js.org/assets/dazn.png" align="center" width="100" title="DAZN" alt="DAZN"></a>
<a href="https://talentplot.com/"><img src="https://mobx.js.org/assets/talentplot.png" align="center" width="100" title="talentplot" alt="talentplot"></a>
## <a href="https://www.easeus.com/?utm_source=github_mobxjs_sponsorship&utm_medium=readme&utm_campaign=sponsorship"><img src="https://mobx.js.org/assets/easeus.png" align="center" width="100" title="EaseUS" alt="EaseUS"/></a>
## Introduction
_Anything that can be derived from the application state, should be. Automatically._
MobX is a signal based, battle-tested library that makes state management simple and scalable by transparently applying functional reactive programming.
The philosophy behind MobX is simple:
<div class="benefits">
<div>
<div class="pic">😙</div>
<div>
<h4>Straightforward</h4>
<p>Write minimalistic, boilerplate-free code that captures your intent.
Trying to update a record field? Simply use a normal JavaScript assignment —
the reactivity system will detect all your changes and propagate them out to where they are being used.
No special tools are required when updating data in an asynchronous process.
</p>
</div>
</div>
<div>
<div class="pic">🚅</div>
<div>
<h4>Effortless optimal rendering</h4>
<p>
All changes to and uses of your data are tracked at runtime, building a dependency tree that captures all relations between state and output.
This guarantees that computations that depend on your state, like React components, run only when strictly needed.
There is no need to manually optimize components with error-prone and sub-optimal techniques like memoization and selectors.
</p>
</div>
</div>
<div>
<div class="pic">🤹🏻‍♂️</div>
<div>
<h4>Architectural freedom</h4>
<p>
MobX is unopinionated and allows you to manage your application state outside of any UI framework.
This makes your code decoupled, portable, and above all, easily testable.
</p>
</div>
</div>
</div>
---
## A quick example
So what does code that uses MobX look like?
```javascript
import React from "react"
import ReactDOM from "react-dom"
import { makeAutoObservable } from "mobx"
import { observer } from "mobx-react-lite"
// Model the application state.
function createTimer() {
return makeAutoObservable({
secondsPassed: 0,
increase() {
this.secondsPassed += 1
},
reset() {
this.secondsPassed = 0
}
})
}
const myTimer = createTimer()
// Build a "user interface" that uses the observable state.
const TimerView = observer(({ timer }) => (
<button onClick={() => timer.reset()}>Seconds passed: {timer.secondsPassed}</button>
))
ReactDOM.render(<TimerView timer={myTimer} />, document.body)
// Update the 'Seconds passed: X' text every second.
setInterval(() => {
myTimer.increase()
}, 1000)
```
The `observer` wrapper around the `TimerView` React component will automatically detect that rendering
depends on the `timer.secondsPassed` observable, even though this relationship is not explicitly defined. The reactivity system will take care of re-rendering the component when _precisely that_ field is updated in the future.
Every event (`onClick` / `setInterval`) invokes an _action_ (`myTimer.increase` / `myTimer.reset`) that updates _observable state_ (`myTimer.secondsPassed`).
Changes in the observable state are propagated precisely to all _computations_ and _side effects_ (`TimerView`) that depend on the changes being made.
<img alt="MobX unidirectional flow" src="https://mobx.js.org/assets/flow2.png" align="center" />
This conceptual picture can be applied to the above example, or any other application using MobX.
## Getting started
To learn about the core concepts of MobX using a larger example, check out **[The gist of MobX](https://mobx.js.org/the-gist-of-mobx.html)** page, or take the **[10 minute interactive introduction to MobX and React](https://mobx.js.org/getting-started)**.
The philosophy and benefits of the mental model provided by MobX are also described in great detail in the blog posts [UI as an afterthought](https://michel.codes/blogs/ui-as-an-afterthought) and [How to decouple state and UI (a.k.a. you dont need componentWillMount)](https://hackernoon.com/how-to-decouple-state-and-ui-a-k-a-you-dont-need-componentwillmount-cc90b787aa37).
## Further resources
- The [MobX cheat sheet](https://gum.co/fSocU) (£5) is both useful and sponsors the project
- [10 minute interactive introduction to MobX and React](https://mobx.js.org/getting-started)
- [Egghead.io course, based on MobX 3](https://egghead.io/courses/manage-complex-state-in-react-apps-with-mobx)
- The [MobX awesome list](https://github.com/mobxjs/awesome-mobx#awesome-mobx) a long list of MobX resources and example projects
### The MobX book
<a href="https://www.packtpub.com/product/mobx-quick-start-guide/9781789344837"><img src="https://mobx.js.org/assets/book.jpg" height="120px" /></a>
The **[MobX Quick Start Guide](https://www.packtpub.com/product/mobx-quick-start-guide/9781789344837)** ($24.99) by [Pavan Podila](https://twitter.com/pavanpodila) and [Michel Weststrate](https://twitter.com/mweststrate) is available as an [ebook](https://www.packtpub.com/product/mobx-quick-start-guide/9781789344837), [paperback](https://www.amazon.com/MobX-Quick-Start-Guide-Supercharge/dp/1789344832), and on the [O'Reilly platform](https://www.oreilly.com/library/view/mobx-quick-start/9781789344837/) (see [preview](https://books.google.com/books?id=ALFmDwAAQBAJ&printsec=frontcover#v=onepage&q&f=false)).
### Videos
- [Introduction to MobX & React in 2020](https://www.youtube.com/watch?v=pnhIJA64ByY) by Leigh Halliday, _17 min_.
- [ReactNext 2016: Real World MobX](https://www.youtube.com/watch?v=Aws40KOx90U) by Michel Weststrate, _40 min_, [slides](https://docs.google.com/presentation/d/1DrI6Hc2xIPTLBkfNH8YczOcPXQTOaCIcDESdyVfG_bE/edit?usp=sharing).
- [CityJS 2020: MobX, from mutable to immutable, to observable data](https://youtu.be/sP7dtZm_Wx0?t=27050) by Michel Weststrate, _30 min_.
- [OpenSourceNorth: Practical React with MobX (ES5)](https://www.youtube.com/watch?v=XGwuM_u7UeQ) by Matt Ruby, _42 min_.
- [HolyJS 2019: MobX and the unique symbiosis of predictability and speed](https://www.youtube.com/watch?v=NBYbBbjZeX4&list=PL8sJahqnzh8JJD7xahG5zXkjfM5GOgcPA&index=21&t=0s) by Michel Weststrate, _59 min_.
- [React Amsterdam 2016: State Management Is Easy](https://www.youtube.com/watch?v=ApmSsu3qnf0&feature=youtu.be) by Michel Weststrate, _20 min_, [slides](https://speakerdeck.com/mweststrate/state-management-is-easy-introduction-to-mobx).
- {🚀} [React Live 2019: Reinventing MobX](https://www.youtube.com/watch?v=P_WqKZxpX8g) by Max Gallo, _27 min_.
## Credits
MobX is inspired by reactive programming principles, which are for example used in spreadsheets. It is inspired by modelviewviewmodel frameworks like [MeteorJS's Tracker](https://docs.meteor.com/api/tracker.html), [Knockout](https://knockoutjs.com/) and [Vue.js](https://vuejs.org/), but MobX brings _transparent functional reactive programming_ (TFRP, a concept which is further explained in the [MobX book](https://www.packtpub.com/product/mobx-quick-start-guide/9781789344837)) to the next level and provides a standalone implementation. It implements TFRP in a glitch-free, synchronous, predictable and efficient manner.
A ton of credit goes to [Mendix](https://github.com/mendix), for providing the flexibility and support to maintain MobX and the chance to prove the philosophy of MobX in a real, complex, performance critical applications.

@ -0,0 +1,16 @@
import { Annotation } from "../internal";
import type { ClassFieldDecorator, ClassMethodDecorator } from "../types/decorator_fills";
export declare const ACTION = "action";
export declare const ACTION_BOUND = "action.bound";
export declare const AUTOACTION = "autoAction";
export declare const AUTOACTION_BOUND = "autoAction.bound";
export interface IActionFactory extends Annotation, PropertyDecorator, ClassMethodDecorator, ClassFieldDecorator {
<T extends Function | undefined | null>(fn: T): T;
<T extends Function | undefined | null>(name: string, fn: T): T;
(customName: string): PropertyDecorator & Annotation & ClassMethodDecorator & ClassFieldDecorator;
bound: Annotation & PropertyDecorator & ClassMethodDecorator & ClassFieldDecorator;
}
export declare const action: IActionFactory;
export declare const autoAction: IActionFactory;
export declare function runInAction<T>(fn: () => T): T;
export declare function isAction(thing: any): boolean;

@ -0,0 +1,19 @@
import { ObservableObjectAdministration } from "../internal";
export declare const enum MakeResult {
Cancel = 0,
Break = 1,
Continue = 2
}
export type Annotation = {
annotationType_: string;
make_(adm: ObservableObjectAdministration, key: PropertyKey, descriptor: PropertyDescriptor, source: object): MakeResult;
extend_(adm: ObservableObjectAdministration, key: PropertyKey, descriptor: PropertyDescriptor, proxyTrap: boolean): boolean | null;
decorate_20223_(value: any, context: DecoratorContext): any;
options_?: any;
};
export type AnnotationMapEntry = Annotation | true | false;
export type AnnotationsMap<T, AdditionalFields extends PropertyKey> = {
[P in Exclude<keyof T, "toString">]?: AnnotationMapEntry;
} & Record<AdditionalFields, AnnotationMapEntry>;
export declare function isAnnotation(thing: any): boolean;
export declare function isAnnotationMapEntry(thing: any): boolean;

@ -0,0 +1,25 @@
import { IEqualsComparer, IReactionDisposer, IReactionPublic, GenericAbortSignal } from "../internal";
export interface IAutorunOptions {
delay?: number;
name?: string;
/**
* Experimental.
* Warns if the view doesn't track observables
*/
requiresObservable?: boolean;
scheduler?: (callback: () => void) => any;
onError?: (error: any) => void;
signal?: GenericAbortSignal;
}
/**
* Creates a named reactive view and keeps it alive, so that the view is always
* updated if one of the dependencies changes, even when the view is not further used by something else.
* @param view The reactive view
* @returns disposer function, which can be used to stop the view from being updated in the future.
*/
export declare function autorun(view: (r: IReactionPublic) => any, opts?: IAutorunOptions): IReactionDisposer;
export type IReactionOptions<T, FireImmediately extends boolean> = IAutorunOptions & {
fireImmediately?: FireImmediately;
equals?: IEqualsComparer<T>;
};
export declare function reaction<T, FireImmediately extends boolean = false>(expression: (r: IReactionPublic) => T, effect: (arg: T, prev: FireImmediately extends true ? T | undefined : T, r: IReactionPublic) => void, opts?: IReactionOptions<T, FireImmediately>): IReactionDisposer;

@ -0,0 +1,5 @@
import { IComputedValue, IObservable, IObservableArray, Lambda, ObservableMap, ObservableSet, IObservableValue } from "../internal";
export declare function onBecomeObserved(value: IObservable | IComputedValue<any> | IObservableArray<any> | ObservableMap<any, any> | ObservableSet<any> | IObservableValue<any>, listener: Lambda): Lambda;
export declare function onBecomeObserved<K, V = any>(value: ObservableMap<K, V> | Object, property: K, listener: Lambda): Lambda;
export declare function onBecomeUnobserved(value: IObservable | IComputedValue<any> | IObservableArray<any> | ObservableMap<any, any> | ObservableSet<any> | IObservableValue<any>, listener: Lambda): Lambda;
export declare function onBecomeUnobserved<K, V = any>(value: ObservableMap<K, V> | Object, property: K, listener: Lambda): Lambda;

@ -0,0 +1,14 @@
import { IComputedValueOptions, Annotation, IComputedValue } from "../internal";
import type { ClassGetterDecorator } from "../types/decorator_fills";
export declare const COMPUTED = "computed";
export declare const COMPUTED_STRUCT = "computed.struct";
export interface IComputedFactory extends Annotation, PropertyDecorator, ClassGetterDecorator {
<T>(options: IComputedValueOptions<T>): Annotation & PropertyDecorator & ClassGetterDecorator;
<T>(func: () => T, options?: IComputedValueOptions<T>): IComputedValue<T>;
struct: Annotation & PropertyDecorator & ClassGetterDecorator;
}
/**
* Decorator for class properties: @computed get value() { return expr; }.
* For legacy purposes also invokable as ES5 observable created: `computed(() => expr)`;
*/
export declare const computed: IComputedFactory;

@ -0,0 +1,17 @@
export declare function configure(options: {
enforceActions?: "never" | "always" | "observed";
computedRequiresReaction?: boolean;
/**
* Warn if you try to create to derivation / reactive context without accessing any observable.
*/
reactionRequiresObservable?: boolean;
/**
* Warn if observables are accessed outside a reactive context
*/
observableRequiresReaction?: boolean;
isolateGlobalState?: boolean;
disableErrorBoundaries?: boolean;
safeDescriptors?: boolean;
reactionScheduler?: (f: () => void) => void;
useProxies?: "always" | "never" | "ifavailable";
}): void;

@ -0,0 +1,20 @@
import { Annotation, AnnotationsMap } from "../internal";
import type { Decorator } from "../types/decorator_fills";
export declare const storedAnnotationsSymbol: unique symbol;
/**
* Creates a function that acts as
* - decorator
* - annotation object
*/
export declare function createDecoratorAnnotation<D extends Decorator = Decorator>(annotation: Annotation): PropertyDecorator & Annotation & D;
/**
* Stores annotation to prototype,
* so it can be inspected later by `makeObservable` called from constructor
*/
export declare function storeAnnotation(prototype: any, key: PropertyKey, annotation: Annotation): void;
/**
* Collects annotations from prototypes and stores them on target (instance)
*/
export declare function collectStoredAnnotations(target: any): AnnotationsMap<any, any>;
export declare function is20223Decorator(context: any): context is DecoratorContext;
export declare function assert20223DecoratorType(context: DecoratorContext, types: DecoratorContext["kind"][]): void;

@ -0,0 +1,2 @@
import { CreateObservableOptions, AnnotationsMap } from "../internal";
export declare function extendObservable<A extends Object, B extends Object>(target: A, properties: B, annotations?: AnnotationsMap<B, never>, options?: CreateObservableOptions): A & B;

@ -0,0 +1,10 @@
export interface IDependencyTree {
name: string;
dependencies?: IDependencyTree[];
}
export interface IObserverTree {
name: string;
observers?: IObserverTree[];
}
export declare function getDependencyTree(thing: any, property?: string): IDependencyTree;
export declare function getObserverTree(thing: any, property?: string): IObserverTree;

@ -0,0 +1,19 @@
import { Annotation } from "../internal";
import type { ClassMethodDecorator } from "../types/decorator_fills";
export declare const FLOW = "flow";
export declare function FlowCancellationError(): void;
export declare namespace FlowCancellationError {
var prototype: any;
}
export declare function isFlowCancellationError(error: Error): boolean;
export type CancellablePromise<T> = Promise<T> & {
cancel(): void;
};
interface Flow extends Annotation, PropertyDecorator, ClassMethodDecorator {
<R, Args extends any[]>(generator: (...args: Args) => Generator<any, R, any> | AsyncGenerator<any, R, any>): (...args: Args) => CancellablePromise<R>;
bound: Annotation & PropertyDecorator & ClassMethodDecorator;
}
export declare const flow: Flow;
export declare function flowResult<T>(result: T): T extends Generator<any, infer R, any> ? CancellablePromise<R> : T extends CancellablePromise<any> ? T : never;
export declare function isFlow(fn: any): boolean;
export {};

@ -0,0 +1,8 @@
import { IObservableArray, IObservableValue, Lambda, ObservableMap, ObservableSet } from "../internal";
export type ReadInterceptor<T> = (value: any) => T;
/** Experimental feature right now, tested indirectly via Mobx-State-Tree */
export declare function interceptReads<T>(value: IObservableValue<T>, handler: ReadInterceptor<T>): Lambda;
export declare function interceptReads<T>(observableArray: IObservableArray<T>, handler: ReadInterceptor<T>): Lambda;
export declare function interceptReads<K, V>(observableMap: ObservableMap<K, V>, handler: ReadInterceptor<V>): Lambda;
export declare function interceptReads<V>(observableSet: ObservableSet<V>, handler: ReadInterceptor<V>): Lambda;
export declare function interceptReads(object: Object, property: string, handler: ReadInterceptor<any>): Lambda;

@ -0,0 +1,8 @@
import { IArrayWillChange, IArrayWillSplice, IInterceptor, IMapWillChange, IObjectWillChange, IObservableArray, IObservableValue, IValueWillChange, Lambda, ObservableMap, ObservableSet, ISetWillChange } from "../internal";
export declare function intercept<T>(value: IObservableValue<T>, handler: IInterceptor<IValueWillChange<T>>): Lambda;
export declare function intercept<T>(observableArray: IObservableArray<T> | Array<T>, handler: IInterceptor<IArrayWillChange<T> | IArrayWillSplice<T>>): Lambda;
export declare function intercept<K, V>(observableMap: ObservableMap<K, V> | Map<K, V>, handler: IInterceptor<IMapWillChange<K, V>>): Lambda;
export declare function intercept<V>(observableSet: ObservableSet<V> | Set<V>, handler: IInterceptor<ISetWillChange<V>>): Lambda;
export declare function intercept<K, V>(observableMap: ObservableMap<K, V> | Map<K, V>, property: K, handler: IInterceptor<IValueWillChange<V>>): Lambda;
export declare function intercept(object: object, handler: IInterceptor<IObjectWillChange>): Lambda;
export declare function intercept<T extends object, K extends keyof T>(object: T, property: K, handler: IInterceptor<IValueWillChange<T[K]>>): Lambda;

@ -0,0 +1,3 @@
export declare function _isComputed(value: any, property?: PropertyKey): boolean;
export declare function isComputed(value: any): boolean;
export declare function isComputedProp(value: any, propName: PropertyKey): boolean;

@ -0,0 +1,2 @@
export declare function isObservable(value: any): boolean;
export declare function isObservableProp(value: any, propName: PropertyKey): boolean;

@ -0,0 +1,6 @@
import { AnnotationsMap, CreateObservableOptions } from "../internal";
type NoInfer<T> = [T][T extends any ? 0 : never];
type MakeObservableOptions = Omit<CreateObservableOptions, "proxy">;
export declare function makeObservable<T extends object, AdditionalKeys extends PropertyKey = never>(target: T, annotations?: AnnotationsMap<T, NoInfer<AdditionalKeys>>, options?: MakeObservableOptions): T;
export declare function makeAutoObservable<T extends object, AdditionalKeys extends PropertyKey = never>(target: T, overrides?: AnnotationsMap<T, NoInfer<AdditionalKeys>>, options?: MakeObservableOptions): T;
export {};

@ -0,0 +1,36 @@
import { IObservableArray, ObservableMap, ObservableSet } from "../internal";
export declare function keys<K>(map: ObservableMap<K, any>): ReadonlyArray<K>;
export declare function keys<T>(ar: IObservableArray<T>): ReadonlyArray<number>;
export declare function keys<T>(set: ObservableSet<T>): ReadonlyArray<T>;
export declare function keys<T extends Object>(obj: T): ReadonlyArray<PropertyKey>;
export declare function values<K, T>(map: ObservableMap<K, T>): ReadonlyArray<T>;
export declare function values<T>(set: ObservableSet<T>): ReadonlyArray<T>;
export declare function values<T>(ar: IObservableArray<T>): ReadonlyArray<T>;
export declare function values<T = any>(obj: T): ReadonlyArray<T extends object ? T[keyof T] : any>;
export declare function entries<K, T>(map: ObservableMap<K, T>): ReadonlyArray<[K, T]>;
export declare function entries<T>(set: ObservableSet<T>): ReadonlyArray<[T, T]>;
export declare function entries<T>(ar: IObservableArray<T>): ReadonlyArray<[number, T]>;
export declare function entries<T = any>(obj: T): ReadonlyArray<[string, T extends object ? T[keyof T] : any]>;
export declare function set<V>(obj: ObservableMap<PropertyKey, V>, values: {
[key: string]: V;
}): any;
export declare function set<K, V>(obj: ObservableMap<K, V>, key: K, value: V): any;
export declare function set<T>(obj: ObservableSet<T>, value: T): any;
export declare function set<T>(obj: IObservableArray<T>, index: number, value: T): any;
export declare function set<T extends Object>(obj: T, values: {
[key: string]: any;
}): any;
export declare function set<T extends Object>(obj: T, key: PropertyKey, value: any): any;
export declare function remove<K, V>(obj: ObservableMap<K, V>, key: K): any;
export declare function remove<T>(obj: ObservableSet<T>, key: T): any;
export declare function remove<T>(obj: IObservableArray<T>, index: number): any;
export declare function remove<T extends Object>(obj: T, key: string): any;
export declare function has<K>(obj: ObservableMap<K, any>, key: K): boolean;
export declare function has<T>(obj: ObservableSet<T>, key: T): boolean;
export declare function has<T>(obj: IObservableArray<T>, index: number): boolean;
export declare function has<T extends Object>(obj: T, key: string): boolean;
export declare function get<K, V>(obj: ObservableMap<K, V>, key: K): V | undefined;
export declare function get<T>(obj: IObservableArray<T>, index: number): T | undefined;
export declare function get<T extends Object>(obj: T, key: string): any;
export declare function apiDefineProperty(obj: Object, key: PropertyKey, descriptor: PropertyDescriptor): boolean | null;
export declare function apiOwnKeys(obj: Object): (string | symbol)[];

@ -0,0 +1,45 @@
import { IEnhancer, IEqualsComparer, IObservableArray, IObservableMapInitialValues, IObservableSetInitialValues, IObservableValue, ObservableMap, ObservableSet, Annotation, AnnotationsMap } from "../internal";
import type { ClassAccessorDecorator, ClassFieldDecorator } from "../types/decorator_fills";
export declare const OBSERVABLE = "observable";
export declare const OBSERVABLE_REF = "observable.ref";
export declare const OBSERVABLE_SHALLOW = "observable.shallow";
export declare const OBSERVABLE_STRUCT = "observable.struct";
export type CreateObservableOptions = {
name?: string;
equals?: IEqualsComparer<any>;
deep?: boolean;
defaultDecorator?: Annotation;
proxy?: boolean;
autoBind?: boolean;
};
export declare const defaultCreateObservableOptions: CreateObservableOptions;
export declare function asCreateObservableOptions(thing: any): CreateObservableOptions;
export declare function getEnhancerFromOptions(options: CreateObservableOptions): IEnhancer<any>;
export declare function getAnnotationFromOptions(options?: CreateObservableOptions): Annotation | undefined;
export declare function getEnhancerFromAnnotation(annotation?: Annotation): IEnhancer<any>;
export interface IObservableValueFactory {
<T>(value: T, options?: CreateObservableOptions): IObservableValue<T>;
<T>(value?: T, options?: CreateObservableOptions): IObservableValue<T | undefined>;
}
export interface IObservableFactory extends Annotation, PropertyDecorator, ClassAccessorDecorator, ClassFieldDecorator {
<T = any>(value: T[], options?: CreateObservableOptions): IObservableArray<T>;
<T = any>(value: Set<T>, options?: CreateObservableOptions): ObservableSet<T>;
<K = any, V = any>(value: Map<K, V>, options?: CreateObservableOptions): ObservableMap<K, V>;
<T extends object>(value: T, decorators?: AnnotationsMap<T, never>, options?: CreateObservableOptions): T;
box: IObservableValueFactory;
array: <T = any>(initialValues?: T[], options?: CreateObservableOptions) => IObservableArray<T>;
set: <T = any>(initialValues?: IObservableSetInitialValues<T>, options?: CreateObservableOptions) => ObservableSet<T>;
map: <K = any, V = any>(initialValues?: IObservableMapInitialValues<K, V>, options?: CreateObservableOptions) => ObservableMap<K, V>;
object: <T = any>(props: T, decorators?: AnnotationsMap<T, never>, options?: CreateObservableOptions) => T;
/**
* Decorator that creates an observable that only observes the references, but doesn't try to turn the assigned value into an observable.ts.
*/
ref: Annotation & PropertyDecorator & ClassAccessorDecorator & ClassFieldDecorator;
/**
* Decorator that creates an observable converts its value (objects, maps or arrays) into a shallow observable structure
*/
shallow: Annotation & PropertyDecorator & ClassAccessorDecorator & ClassFieldDecorator;
deep: Annotation & PropertyDecorator & ClassAccessorDecorator & ClassFieldDecorator;
struct: Annotation & PropertyDecorator & ClassAccessorDecorator & ClassFieldDecorator;
}
export declare var observable: IObservableFactory;

@ -0,0 +1,8 @@
import { IArrayDidChange, IComputedValue, IMapDidChange, IObjectDidChange, IObservableArray, IObservableValue, IValueDidChange, Lambda, ObservableMap, ObservableSet, ISetDidChange } from "../internal";
export declare function observe<T>(value: IObservableValue<T> | IComputedValue<T>, listener: (change: IValueDidChange<T>) => void, fireImmediately?: boolean): Lambda;
export declare function observe<T>(observableArray: IObservableArray<T> | Array<T>, listener: (change: IArrayDidChange<T>) => void, fireImmediately?: boolean): Lambda;
export declare function observe<V>(observableSet: ObservableSet<V> | Set<V>, listener: (change: ISetDidChange<V>) => void, fireImmediately?: boolean): Lambda;
export declare function observe<K, V>(observableMap: ObservableMap<K, V> | Map<K, V>, listener: (change: IMapDidChange<K, V>) => void, fireImmediately?: boolean): Lambda;
export declare function observe<K, V>(observableMap: ObservableMap<K, V> | Map<K, V>, property: K, listener: (change: IValueDidChange<V>) => void, fireImmediately?: boolean): Lambda;
export declare function observe(object: Object, listener: (change: IObjectDidChange) => void, fireImmediately?: boolean): Lambda;
export declare function observe<T, K extends keyof T>(object: T, property: K, listener: (change: IValueDidChange<T[K]>) => void, fireImmediately?: boolean): Lambda;

@ -0,0 +1,7 @@
/**
* Recursively converts an observable to it's non-observable native counterpart.
* It does NOT recurse into non-observables, these are left as they are, even if they contain observables.
* Computed and other non-enumerable properties are completely ignored.
* Complex scenarios require custom solution, eg implementing `toJSON` or using `serializr` lib.
*/
export declare function toJS<T>(source: T, options?: any): T;

@ -0,0 +1,3 @@
export declare function trace(thing?: any, prop?: string, enterBreakPoint?: boolean): void;
export declare function trace(thing?: any, enterBreakPoint?: boolean): void;
export declare function trace(enterBreakPoint?: boolean): void;

@ -0,0 +1,8 @@
/**
* During a transaction no views are updated until the end of the transaction.
* The transaction will be run synchronously nonetheless.
*
* @param action a function that updates some reactive state
* @returns any value that was returned by the 'action' parameter.
*/
export declare function transaction<T>(action: () => T, thisArg?: undefined): T;

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

Loading…
Cancel
Save