From 446ce78e18361feef9b947e1b440c343b6eaa584 Mon Sep 17 00:00:00 2001 From: qiang Date: Fri, 6 Aug 2021 14:53:51 +0800 Subject: [PATCH] feat(mp): add kuaishou --- package.json | 2 +- packages/global.d.ts | 10 +- packages/uni-mp-kuaishou/LICENSE | 202 +++ packages/uni-mp-kuaishou/build.json | 23 + packages/uni-mp-kuaishou/dist/uni.api.esm.js | 845 +++++++++++ packages/uni-mp-kuaishou/dist/uni.mp.esm.js | 1231 +++++++++++++++++ packages/uni-mp-kuaishou/package.json | 20 + packages/uni-mp-kuaishou/src/api/index.ts | 4 + packages/uni-mp-kuaishou/src/api/protocols.ts | 7 + packages/uni-mp-kuaishou/src/api/shims.ts | 8 + .../uni-mp-kuaishou/src/platform/index.ts | 3 + packages/uni-mp-kuaishou/src/runtime/index.ts | 12 + .../src/runtime/parseComponentOptions.ts | 26 + packages/uni-mp-kuaishou/tsconfig.json | 10 + .../uni-mp-weixin/src/runtime/fixSetData.ts | 38 + 15 files changed, 2439 insertions(+), 2 deletions(-) create mode 100755 packages/uni-mp-kuaishou/LICENSE create mode 100644 packages/uni-mp-kuaishou/build.json create mode 100644 packages/uni-mp-kuaishou/dist/uni.api.esm.js create mode 100644 packages/uni-mp-kuaishou/dist/uni.mp.esm.js create mode 100644 packages/uni-mp-kuaishou/package.json create mode 100644 packages/uni-mp-kuaishou/src/api/index.ts create mode 100644 packages/uni-mp-kuaishou/src/api/protocols.ts create mode 100644 packages/uni-mp-kuaishou/src/api/shims.ts create mode 100644 packages/uni-mp-kuaishou/src/platform/index.ts create mode 100644 packages/uni-mp-kuaishou/src/runtime/index.ts create mode 100644 packages/uni-mp-kuaishou/src/runtime/parseComponentOptions.ts create mode 100644 packages/uni-mp-kuaishou/tsconfig.json create mode 100644 packages/uni-mp-weixin/src/runtime/fixSetData.ts diff --git a/package.json b/package.json index 805bfdfb8..3a9a9cb91 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "build": "node scripts/build.js", "build:h5": "node scripts/build.js uni-app uni-cli-shared uni-h5 uni-i18n uni-shared uni-h5-vite vite-plugin-uni", "build:app": "node scripts/build.js uni-app-plus uni-app-vite uni-app-vue uni-cli-nvue", - "build:mp": "node scripts/build.js uni-mp-alipay uni-mp-baidu uni-mp-qq uni-mp-toutiao uni-mp-weixin uni-quickapp-webview", + "build:mp": "node scripts/build.js uni-mp-alipay uni-mp-baidu uni-mp-qq uni-mp-toutiao uni-mp-weixin uni-mp-kuaishou uni-quickapp-webview", "size": "npm run build size-check", "lint": "eslint packages/*/src/**/*.ts", "format": "prettier --write --parser typescript \"packages/**/*.ts?(x)\"", diff --git a/packages/global.d.ts b/packages/global.d.ts index 0754cd6f5..d8f745965 100644 --- a/packages/global.d.ts +++ b/packages/global.d.ts @@ -4,8 +4,16 @@ declare var tt: any declare var qa: any declare var swan: any declare var qq: any +declare var ks: any declare var __PLATFORM__: UniApp.PLATFORM -declare var __PLATFORM_PREFIX__: 'wx' | 'qq' | 'my' | 'swan' | 'tt' | 'qa' +declare var __PLATFORM_PREFIX__: + | 'wx' + | 'qq' + | 'my' + | 'swan' + | 'tt' + | 'qa' + | 'ks' declare var __GLOBAL__: Record // importMeta(es|cjs) diff --git a/packages/uni-mp-kuaishou/LICENSE b/packages/uni-mp-kuaishou/LICENSE new file mode 100755 index 000000000..7a4a3ea24 --- /dev/null +++ b/packages/uni-mp-kuaishou/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/packages/uni-mp-kuaishou/build.json b/packages/uni-mp-kuaishou/build.json new file mode 100644 index 000000000..2110c8cf8 --- /dev/null +++ b/packages/uni-mp-kuaishou/build.json @@ -0,0 +1,23 @@ +{ + "input": { + "src/runtime/index.ts": "dist/uni.mp.esm.js", + "src/api/index.ts": "dist/uni.api.esm.js" + }, + "alias": { + "entries": [ + { + "find": "@dcloudio/uni-platform", + "replacement": "packages/uni-mp-kuaishou/src/platform/index.ts" + }, + { + "find": "@dcloudio/uni-mp-platform", + "replacement": "packages/uni-mp-core/src/platform/index.ts" + } + ] + }, + "replacements": { + "__GLOBAL__": "ks", + "__PLATFORM__": "\"mp-kuaishou\"", + "__PLATFORM_TITLE__": "快手小程序" + } +} diff --git a/packages/uni-mp-kuaishou/dist/uni.api.esm.js b/packages/uni-mp-kuaishou/dist/uni.api.esm.js new file mode 100644 index 000000000..a1d2da6cc --- /dev/null +++ b/packages/uni-mp-kuaishou/dist/uni.api.esm.js @@ -0,0 +1,845 @@ +import { isArray, hasOwn, isString, isPlainObject, isObject, capitalize, toRawType, makeMap, isPromise, isFunction, extend } from '@vue/shared'; + +const eventChannels = {}; +const eventChannelStack = []; +let id = 0; +function initEventChannel(events, cache = true) { + id++; + const eventChannel = new ks.EventChannel(id, events); + if (cache) { + eventChannels[id] = eventChannel; + eventChannelStack.push(eventChannel); + } + return eventChannel; +} +function getEventChannel(id) { + if (id) { + const eventChannel = eventChannels[id]; + delete eventChannels[id]; + return eventChannel; + } + return eventChannelStack.shift(); +} +const navigateTo = { + args(fromArgs) { + const id = initEventChannel(fromArgs.events).id; + if (fromArgs.url) { + fromArgs.url = + fromArgs.url + + (fromArgs.url.indexOf('?') === -1 ? '?' : '&') + + '__id__=' + + id; + } + }, + returnValue(fromRes) { + fromRes.eventChannel = getEventChannel(); + }, +}; + +function getBaseSystemInfo() { + return ks.getSystemInfoSync() +} + +function validateProtocolFail(name, msg) { + console.warn(`${name}: ${msg}`); +} +function validateProtocol(name, data, protocol, onFail) { + if (!onFail) { + onFail = validateProtocolFail; + } + for (const key in protocol) { + const errMsg = validateProp(key, data[key], protocol[key], !hasOwn(data, key)); + if (isString(errMsg)) { + onFail(name, errMsg); + } + } +} +function validateProtocols(name, args, protocol, onFail) { + if (!protocol) { + return; + } + if (!isArray(protocol)) { + return validateProtocol(name, args[0] || Object.create(null), protocol, onFail); + } + const len = protocol.length; + const argsLen = args.length; + for (let i = 0; i < len; i++) { + const opts = protocol[i]; + const data = Object.create(null); + if (argsLen > i) { + data[opts.name] = args[i]; + } + validateProtocol(name, data, { [opts.name]: opts }, onFail); + } +} +function validateProp(name, value, prop, isAbsent) { + if (!isPlainObject(prop)) { + prop = { type: prop }; + } + const { type, required, validator } = prop; + // required! + if (required && isAbsent) { + return 'Missing required args: "' + name + '"'; + } + // missing but optional + if (value == null && !required) { + return; + } + // type check + if (type != null) { + let isValid = false; + const types = isArray(type) ? type : [type]; + const expectedTypes = []; + // value is valid as long as one of the specified types match + for (let i = 0; i < types.length && !isValid; i++) { + const { valid, expectedType } = assertType(value, types[i]); + expectedTypes.push(expectedType || ''); + isValid = valid; + } + if (!isValid) { + return getInvalidTypeMessage(name, value, expectedTypes); + } + } + // custom validator + if (validator) { + return validator(value); + } +} +const isSimpleType = /*#__PURE__*/ makeMap('String,Number,Boolean,Function,Symbol'); +function assertType(value, type) { + let valid; + const expectedType = getType(type); + if (isSimpleType(expectedType)) { + const t = typeof value; + valid = t === expectedType.toLowerCase(); + // for primitive wrapper objects + if (!valid && t === 'object') { + valid = value instanceof type; + } + } + else if (expectedType === 'Object') { + valid = isObject(value); + } + else if (expectedType === 'Array') { + valid = isArray(value); + } + else { + { + valid = value instanceof type; + } + } + return { + valid, + expectedType, + }; +} +function getInvalidTypeMessage(name, value, expectedTypes) { + let message = `Invalid args: type check failed for args "${name}".` + + ` Expected ${expectedTypes.map(capitalize).join(', ')}`; + const expectedType = expectedTypes[0]; + const receivedType = toRawType(value); + const expectedValue = styleValue(value, expectedType); + const receivedValue = styleValue(value, receivedType); + // check if we need to specify expected value + if (expectedTypes.length === 1 && + isExplicable(expectedType) && + !isBoolean(expectedType, receivedType)) { + message += ` with value ${expectedValue}`; + } + message += `, got ${receivedType} `; + // check if we need to specify received value + if (isExplicable(receivedType)) { + message += `with value ${receivedValue}.`; + } + return message; +} +function getType(ctor) { + const match = ctor && ctor.toString().match(/^\s*function (\w+)/); + return match ? match[1] : ''; +} +function styleValue(value, type) { + if (type === 'String') { + return `"${value}"`; + } + else if (type === 'Number') { + return `${Number(value)}`; + } + else { + return `${value}`; + } +} +function isExplicable(type) { + const explicitTypes = ['string', 'number', 'boolean']; + return explicitTypes.some((elem) => type.toLowerCase() === elem); +} +function isBoolean(...args) { + return args.some((elem) => elem.toLowerCase() === 'boolean'); +} + +const HOOK_SUCCESS = 'success'; +const HOOK_FAIL = 'fail'; +const HOOK_COMPLETE = 'complete'; +const globalInterceptors = {}; +const scopedInterceptors = {}; +function wrapperHook(hook) { + return function (data) { + return hook(data) || data; + }; +} +function queue(hooks, data) { + let promise = false; + for (let i = 0; i < hooks.length; i++) { + const hook = hooks[i]; + if (promise) { + promise = Promise.resolve(wrapperHook(hook)); + } + else { + const res = hook(data); + if (isPromise(res)) { + promise = Promise.resolve(res); + } + if (res === false) { + return { + then() { }, + catch() { }, + }; + } + } + } + return (promise || { + then(callback) { + return callback(data); + }, + catch() { }, + }); +} +function wrapperOptions(interceptors, options = {}) { + [HOOK_SUCCESS, HOOK_FAIL, HOOK_COMPLETE].forEach((name) => { + const hooks = interceptors[name]; + if (!isArray(hooks)) { + return; + } + const oldCallback = options[name]; + options[name] = function callbackInterceptor(res) { + queue(hooks, res).then((res) => { + return (isFunction(oldCallback) && oldCallback(res)) || res; + }); + }; + }); + return options; +} +function wrapperReturnValue(method, returnValue) { + const returnValueHooks = []; + if (isArray(globalInterceptors.returnValue)) { + returnValueHooks.push(...globalInterceptors.returnValue); + } + const interceptor = scopedInterceptors[method]; + if (interceptor && isArray(interceptor.returnValue)) { + returnValueHooks.push(...interceptor.returnValue); + } + returnValueHooks.forEach((hook) => { + returnValue = hook(returnValue) || returnValue; + }); + return returnValue; +} +function getApiInterceptorHooks(method) { + const interceptor = Object.create(null); + Object.keys(globalInterceptors).forEach((hook) => { + if (hook !== 'returnValue') { + interceptor[hook] = globalInterceptors[hook].slice(); + } + }); + const scopedInterceptor = scopedInterceptors[method]; + if (scopedInterceptor) { + Object.keys(scopedInterceptor).forEach((hook) => { + if (hook !== 'returnValue') { + interceptor[hook] = (interceptor[hook] || []).concat(scopedInterceptor[hook]); + } + }); + } + return interceptor; +} +function invokeApi(method, api, options, ...params) { + const interceptor = getApiInterceptorHooks(method); + if (interceptor && Object.keys(interceptor).length) { + if (isArray(interceptor.invoke)) { + const res = queue(interceptor.invoke, options); + return res.then((options) => { + return api(wrapperOptions(interceptor, options), ...params); + }); + } + else { + return api(wrapperOptions(interceptor, options), ...params); + } + } + return api(options, ...params); +} + +function handlePromise(promise) { + if (__UNI_FEATURE_PROMISE__) { + return promise + .then((data) => { + return [null, data]; + }) + .catch((err) => [err]); + } + return promise; +} + +function formatApiArgs(args, options) { + const params = args[0]; + if (!options || + (!isPlainObject(options.formatArgs) && isPlainObject(params))) { + return; + } + const formatArgs = options.formatArgs; + const keys = Object.keys(formatArgs); + for (let i = 0; i < keys.length; i++) { + const name = keys[i]; + const formatterOrDefaultValue = formatArgs[name]; + if (isFunction(formatterOrDefaultValue)) { + const errMsg = formatterOrDefaultValue(args[0][name], params); + if (isString(errMsg)) { + return errMsg; + } + } + else { + // defaultValue + if (!hasOwn(params, name)) { + params[name] = formatterOrDefaultValue; + } + } + } +} +function beforeInvokeApi(name, args, protocol, options) { + if ((process.env.NODE_ENV !== 'production')) { + validateProtocols(name, args, protocol); + } + if (options && options.beforeInvoke) { + const errMsg = options.beforeInvoke(args); + if (isString(errMsg)) { + return errMsg; + } + } + const errMsg = formatApiArgs(args, options); + if (errMsg) { + return errMsg; + } +} +function wrapperSyncApi(name, fn, protocol, options) { + return (...args) => { + const errMsg = beforeInvokeApi(name, args, protocol, options); + if (errMsg) { + throw new Error(errMsg); + } + return fn.apply(null, args); + }; +} +function defineSyncApi(name, fn, protocol, options) { + return wrapperSyncApi(name, fn, (process.env.NODE_ENV !== 'production') ? protocol : undefined, options); +} + +const API_UPX2PX = 'upx2px'; +const Upx2pxProtocol = [ + { + name: 'upx', + type: [Number, String], + required: true, + }, +]; + +const EPS = 1e-4; +const BASE_DEVICE_WIDTH = 750; +let isIOS = false; +let deviceWidth = 0; +let deviceDPR = 0; +function checkDeviceWidth() { + const { platform, pixelRatio, windowWidth } = getBaseSystemInfo(); + deviceWidth = windowWidth; + deviceDPR = pixelRatio; + isIOS = platform === 'ios'; +} +const upx2px = defineSyncApi(API_UPX2PX, (number, newDeviceWidth) => { + if (deviceWidth === 0) { + checkDeviceWidth(); + } + number = Number(number); + if (number === 0) { + return 0; + } + let width = newDeviceWidth || deviceWidth; + let result = (number / BASE_DEVICE_WIDTH) * width; + if (result < 0) { + result = -result; + } + result = Math.floor(result + EPS); + if (result === 0) { + if (deviceDPR === 1 || !isIOS) { + result = 1; + } + else { + result = 0.5; + } + } + return number < 0 ? -result : result; +}, Upx2pxProtocol); + +const API_ADD_INTERCEPTOR = 'addInterceptor'; +const API_REMOVE_INTERCEPTOR = 'removeInterceptor'; +const AddInterceptorProtocol = [ + { + name: 'method', + type: [String, Object], + required: true, + }, +]; +const RemoveInterceptorProtocol = AddInterceptorProtocol; + +function mergeInterceptorHook(interceptors, interceptor) { + Object.keys(interceptor).forEach((hook) => { + if (isFunction(interceptor[hook])) { + interceptors[hook] = mergeHook(interceptors[hook], interceptor[hook]); + } + }); +} +function removeInterceptorHook(interceptors, interceptor) { + if (!interceptors || !interceptor) { + return; + } + Object.keys(interceptor).forEach((hook) => { + if (isFunction(interceptor[hook])) { + removeHook(interceptors[hook], interceptor[hook]); + } + }); +} +function mergeHook(parentVal, childVal) { + const res = childVal + ? parentVal + ? parentVal.concat(childVal) + : isArray(childVal) + ? childVal + : [childVal] + : parentVal; + return res ? dedupeHooks(res) : res; +} +function dedupeHooks(hooks) { + const res = []; + for (let i = 0; i < hooks.length; i++) { + if (res.indexOf(hooks[i]) === -1) { + res.push(hooks[i]); + } + } + return res; +} +function removeHook(hooks, hook) { + if (!hooks) { + return; + } + const index = hooks.indexOf(hook); + if (index !== -1) { + hooks.splice(index, 1); + } +} +const addInterceptor = defineSyncApi(API_ADD_INTERCEPTOR, (method, interceptor) => { + if (typeof method === 'string' && isPlainObject(interceptor)) { + mergeInterceptorHook(scopedInterceptors[method] || (scopedInterceptors[method] = {}), interceptor); + } + else if (isPlainObject(method)) { + mergeInterceptorHook(globalInterceptors, method); + } +}, AddInterceptorProtocol); +const removeInterceptor = defineSyncApi(API_REMOVE_INTERCEPTOR, (method, interceptor) => { + if (typeof method === 'string') { + if (isPlainObject(interceptor)) { + removeInterceptorHook(scopedInterceptors[method], interceptor); + } + else { + delete scopedInterceptors[method]; + } + } + else if (isPlainObject(method)) { + removeInterceptorHook(globalInterceptors, method); + } +}, RemoveInterceptorProtocol); + +const API_ON = '$on'; +const OnProtocol = [ + { + name: 'event', + type: String, + required: true, + }, + { + name: 'callback', + type: Function, + required: true, + }, +]; +const API_ONCE = '$once'; +const OnceProtocol = OnProtocol; +const API_OFF = '$off'; +const OffProtocol = [ + { + name: 'event', + type: [String, Array], + }, + { + name: 'callback', + type: Function, + }, +]; +const API_EMIT = '$emit'; +const EmitProtocol = [ + { + name: 'event', + type: String, + required: true, + }, +]; + +const E = function () { + // Keep this empty so it's easier to inherit from + // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3) +}; +E.prototype = { + on: function (name, callback, ctx) { + var e = this.e || (this.e = {}); + (e[name] || (e[name] = [])).push({ + fn: callback, + ctx: ctx, + }); + return this; + }, + once: function (name, callback, ctx) { + var self = this; + function listener() { + self.off(name, listener); + callback.apply(ctx, arguments); + } + listener._ = callback; + return this.on(name, listener, ctx); + }, + emit: function (name) { + var data = [].slice.call(arguments, 1); + var evtArr = ((this.e || (this.e = {}))[name] || []).slice(); + var i = 0; + var len = evtArr.length; + for (i; i < len; i++) { + evtArr[i].fn.apply(evtArr[i].ctx, data); + } + return this; + }, + off: function (name, callback) { + var e = this.e || (this.e = {}); + var evts = e[name]; + var liveEvents = []; + if (evts && callback) { + for (var i = 0, len = evts.length; i < len; i++) { + if (evts[i].fn !== callback && evts[i].fn._ !== callback) + liveEvents.push(evts[i]); + } + } + // Remove event from queue to prevent memory leak + // Suggested by https://github.com/lazd + // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910 + liveEvents.length ? (e[name] = liveEvents) : delete e[name]; + return this; + }, +}; +var Emitter = E; + +const emitter = new Emitter(); +const $on = defineSyncApi(API_ON, (name, callback) => { + emitter.on(name, callback); + return () => emitter.off(name, callback); +}, OnProtocol); +const $once = defineSyncApi(API_ONCE, (name, callback) => { + emitter.once(name, callback); + return () => emitter.off(name, callback); +}, OnceProtocol); +const $off = defineSyncApi(API_OFF, (name, callback) => { + if (!name) { + emitter.e = {}; + return; + } + if (!Array.isArray(name)) + name = [name]; + name.forEach((n) => emitter.off(n, callback)); +}, OffProtocol); +const $emit = defineSyncApi(API_EMIT, (name, ...args) => { + emitter.emit(name, ...args); +}, EmitProtocol); + +const SYNC_API_RE = /^\$|sendNativeEvent|restoreGlobal|getCurrentSubNVue|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/; +const CONTEXT_API_RE = /^create|Manager$/; +// Context例外情况 +const CONTEXT_API_RE_EXC = ['createBLEConnection']; +// 同步例外情况 +const ASYNC_API = ['createBLEConnection']; +const CALLBACK_API_RE = /^on|^off/; +function isContextApi(name) { + return CONTEXT_API_RE.test(name) && CONTEXT_API_RE_EXC.indexOf(name) === -1; +} +function isSyncApi(name) { + return SYNC_API_RE.test(name) && ASYNC_API.indexOf(name) === -1; +} +function isCallbackApi(name) { + return CALLBACK_API_RE.test(name) && name !== 'onPush'; +} +function shouldPromise(name) { + if (isContextApi(name) || isSyncApi(name) || isCallbackApi(name)) { + return false; + } + return true; +} +/* eslint-disable no-extend-native */ +if (!Promise.prototype.finally) { + Promise.prototype.finally = function (onfinally) { + const promise = this.constructor; + return this.then((value) => promise.resolve(onfinally && onfinally()).then(() => value), (reason) => promise.resolve(onfinally && onfinally()).then(() => { + throw reason; + })); + }; +} +function promisify(name, api) { + if (!shouldPromise(name)) { + return api; + } + if (!isFunction(api)) { + return api; + } + return function promiseApi(options = {}) { + if (isFunction(options.success) || + isFunction(options.fail) || + isFunction(options.complete)) { + return wrapperReturnValue(name, invokeApi(name, api, options)); + } + return wrapperReturnValue(name, handlePromise(new Promise((resolve, reject) => { + invokeApi(name, api, extend({}, options, { + success: resolve, + fail: reject, + })); + }))); + }; +} + +const CALLBACKS = ['success', 'fail', 'cancel', 'complete']; +function initWrapper(protocols) { + function processCallback(methodName, method, returnValue) { + return function (res) { + return method(processReturnValue(methodName, res, returnValue)); + }; + } + function processArgs(methodName, fromArgs, argsOption = {}, returnValue = {}, keepFromArgs = false) { + if (isPlainObject(fromArgs)) { + // 一般 api 的参数解析 + const toArgs = (keepFromArgs === true ? fromArgs : {}); // returnValue 为 false 时,说明是格式化返回值,直接在返回值对象上修改赋值 + if (isFunction(argsOption)) { + argsOption = argsOption(fromArgs, toArgs) || {}; + } + for (const key in fromArgs) { + if (hasOwn(argsOption, key)) { + let keyOption = argsOption[key]; + if (isFunction(keyOption)) { + keyOption = keyOption(fromArgs[key], fromArgs, toArgs); + } + if (!keyOption) { + // 不支持的参数 + console.warn(`快手小程序 ${methodName} 暂不支持 ${key}`); + } + else if (isString(keyOption)) { + // 重写参数 key + toArgs[keyOption] = fromArgs[key]; + } + else if (isPlainObject(keyOption)) { + // {name:newName,value:value}可重新指定参数 key:value + toArgs[keyOption.name ? keyOption.name : key] = keyOption.value; + } + } + else if (CALLBACKS.indexOf(key) !== -1) { + const callback = fromArgs[key]; + if (isFunction(callback)) { + toArgs[key] = processCallback(methodName, callback, returnValue); + } + } + else { + if (!keepFromArgs && !hasOwn(toArgs, key)) { + toArgs[key] = fromArgs[key]; + } + } + } + return toArgs; + } + else if (isFunction(fromArgs)) { + fromArgs = processCallback(methodName, fromArgs, returnValue); + } + return fromArgs; + } + function processReturnValue(methodName, res, returnValue, keepReturnValue = false) { + if (isFunction(protocols.returnValue)) { + // 处理通用 returnValue + res = protocols.returnValue(methodName, res); + } + return processArgs(methodName, res, returnValue, {}, keepReturnValue); + } + return function wrapper(methodName, method) { + if (!hasOwn(protocols, methodName)) { + return method; + } + const protocol = protocols[methodName]; + if (!protocol) { + // 暂不支持的 api + return function () { + console.error(`快手小程序 暂不支持${methodName}`); + }; + } + return function (arg1, arg2) { + // 目前 api 最多两个参数 + let options = protocol; + if (isFunction(protocol)) { + options = protocol(arg1); + } + arg1 = processArgs(methodName, arg1, options.args, options.returnValue); + const args = [arg1]; + if (typeof arg2 !== 'undefined') { + args.push(arg2); + } + const returnValue = ks[options.name || methodName].apply(ks, args); + if (isSyncApi(methodName)) { + // 同步 api + return processReturnValue(methodName, returnValue, options.returnValue, isContextApi(methodName)); + } + return returnValue; + }; + }; +} + +const baseApis = { + $on, + $off, + $once, + $emit, + upx2px, + addInterceptor, + removeInterceptor, +}; +function initUni(api, protocols) { + const wrapper = initWrapper(protocols); + const UniProxyHandlers = { + get(target, key) { + if (hasOwn(target, key)) { + return target[key]; + } + if (hasOwn(api, key)) { + return promisify(key, api[key]); + } + if (hasOwn(baseApis, key)) { + return promisify(key, baseApis[key]); + } + // event-api + // provider-api? + return promisify(key, wrapper(key, ks[key])); + }, + }; + return new Proxy({}, UniProxyHandlers); +} + +function initGetProvider(providers) { + return function getProvider({ service, success, fail, complete, }) { + let res; + if (providers[service]) { + res = { + errMsg: 'getProvider:ok', + service, + provider: providers[service], + }; + isFunction(success) && success(res); + } + else { + res = { + errMsg: 'getProvider:fail:服务[' + service + ']不存在', + }; + isFunction(fail) && fail(res); + } + isFunction(complete) && complete(res); + }; +} + +function addSafeAreaInsets(fromRes, toRes) { + if (fromRes.safeArea) { + const safeArea = fromRes.safeArea; + toRes.safeAreaInsets = { + top: safeArea.top, + left: safeArea.left, + right: fromRes.windowWidth - safeArea.right, + bottom: fromRes.windowHeight - safeArea.bottom, + }; + } +} + +const getSystemInfo = { + returnValue: addSafeAreaInsets, +}; + +const getSystemInfoSync = getSystemInfo; + +const redirectTo = {}; + +const previewImage = { + args(fromArgs, toArgs) { + let currentIndex = parseInt(fromArgs.current); + if (isNaN(currentIndex)) { + return; + } + const urls = fromArgs.urls; + if (!isArray(urls)) { + return; + } + const len = urls.length; + if (!len) { + return; + } + if (currentIndex < 0) { + currentIndex = 0; + } + else if (currentIndex >= len) { + currentIndex = len - 1; + } + if (currentIndex > 0) { + toArgs.current = urls[currentIndex]; + toArgs.urls = urls.filter((item, index) => index < currentIndex ? item !== urls[currentIndex] : true); + } + else { + toArgs.current = urls[0]; + } + return { + indicator: false, + loop: false, + }; + }, +}; + +const getProvider = initGetProvider({ + oauth: ['kuaishou'], + share: ['kuaishou'], + payment: ['kuaishoupay'], + push: ['kuaishou'], +}); + +var shims = /*#__PURE__*/Object.freeze({ + __proto__: null, + getProvider: getProvider +}); + +var protocols = /*#__PURE__*/Object.freeze({ + __proto__: null, + redirectTo: redirectTo, + navigateTo: navigateTo, + previewImage: previewImage, + getSystemInfo: getSystemInfo, + getSystemInfoSync: getSystemInfoSync +}); + +var index = initUni(shims, protocols); + +export { index as default }; diff --git a/packages/uni-mp-kuaishou/dist/uni.mp.esm.js b/packages/uni-mp-kuaishou/dist/uni.mp.esm.js new file mode 100644 index 000000000..ac16bd244 --- /dev/null +++ b/packages/uni-mp-kuaishou/dist/uni.mp.esm.js @@ -0,0 +1,1231 @@ +import { isPlainObject, hasOwn, isArray, extend, hyphenate, isObject, toNumber, isFunction, NOOP, camelize } from '@vue/shared'; + +const encode = encodeURIComponent; +function stringifyQuery(obj, encodeStr = encode) { + const res = obj + ? Object.keys(obj) + .map((key) => { + let val = obj[key]; + if (typeof val === undefined || val === null) { + val = ''; + } + else if (isPlainObject(val)) { + val = JSON.stringify(val); + } + return encodeStr(key) + '=' + encodeStr(val); + }) + .filter((x) => x.length > 0) + .join('&') + : null; + return res ? `?${res}` : ''; +} + +function cache(fn) { + const cache = Object.create(null); + return (str) => { + const hit = cache[str]; + return hit || (cache[str] = fn(str)); + }; +} +const invokeArrayFns = (fns, arg) => { + let ret; + for (let i = 0; i < fns.length; i++) { + ret = fns[i](arg); + } + return ret; +}; +// lifecycle +// App and Page +const ON_SHOW = 'onShow'; +const ON_HIDE = 'onHide'; +//App +const ON_LAUNCH = 'onLaunch'; +const ON_ERROR = 'onError'; +const ON_THEME_CHANGE = 'onThemeChange'; +const ON_PAGE_NOT_FOUND = 'onPageNotFound'; +const ON_UNHANDLE_REJECTION = 'onUnhandledRejection'; +//Page +const ON_LOAD = 'onLoad'; +const ON_READY = 'onReady'; +const ON_UNLOAD = 'onUnload'; +const ON_RESIZE = 'onResize'; +const ON_TAB_ITEM_TAP = 'onTabItemTap'; +const ON_REACH_BOTTOM = 'onReachBottom'; +const ON_PULL_DOWN_REFRESH = 'onPullDownRefresh'; +const ON_ADD_TO_FAVORITES = 'onAddToFavorites'; + +class EventChannel { + constructor(id, events) { + this.id = id; + this.listener = {}; + this.emitCache = {}; + if (events) { + Object.keys(events).forEach((name) => { + this.on(name, events[name]); + }); + } + } + emit(eventName, ...args) { + const fns = this.listener[eventName]; + if (!fns) { + return (this.emitCache[eventName] || (this.emitCache[eventName] = [])).push(args); + } + fns.forEach((opt) => { + opt.fn.apply(opt.fn, args); + }); + this.listener[eventName] = fns.filter((opt) => opt.type !== 'once'); + } + on(eventName, fn) { + this._addListener(eventName, 'on', fn); + this._clearCache(eventName); + } + once(eventName, fn) { + this._addListener(eventName, 'once', fn); + this._clearCache(eventName); + } + off(eventName, fn) { + const fns = this.listener[eventName]; + if (!fns) { + return; + } + if (fn) { + for (let i = 0; i < fns.length;) { + if (fns[i].fn === fn) { + fns.splice(i, 1); + i--; + } + i++; + } + } + else { + delete this.listener[eventName]; + } + } + _clearCache(eventName) { + const cacheArgs = this.emitCache[eventName]; + if (cacheArgs) { + for (; cacheArgs.length > 0;) { + this.emit.apply(this, [eventName, ...cacheArgs.shift()]); + } + } + } + _addListener(eventName, type, fn) { + (this.listener[eventName] || (this.listener[eventName] = [])).push({ + fn, + type, + }); + } +} + +const eventChannels = {}; +const eventChannelStack = []; +function getEventChannel(id) { + if (id) { + const eventChannel = eventChannels[id]; + delete eventChannels[id]; + return eventChannel; + } + return eventChannelStack.shift(); +} + +function initBehavior(options) { + return Behavior(options); +} +function initVueIds(vueIds, mpInstance) { + if (!vueIds) { + return; + } + const ids = vueIds.split(','); + const len = ids.length; + if (len === 1) { + mpInstance._$vueId = ids[0]; + } + else if (len === 2) { + mpInstance._$vueId = ids[0]; + mpInstance._$vuePid = ids[1]; + } +} +const EXTRAS = ['externalClasses']; +function initExtraOptions(miniProgramComponentOptions, vueOptions) { + EXTRAS.forEach((name) => { + if (hasOwn(vueOptions, name)) { + miniProgramComponentOptions[name] = vueOptions[name]; + } + }); +} +function initWxsCallMethods(methods, wxsCallMethods) { + if (!isArray(wxsCallMethods)) { + return; + } + wxsCallMethods.forEach((callMethod) => { + methods[callMethod] = function (args) { + return this.$vm[callMethod](args); + }; + }); +} +function selectAllComponents(mpInstance, selector, $refs) { + const components = mpInstance.selectAllComponents(selector); + components.forEach((component) => { + const ref = component.dataset.ref; + $refs[ref] = component.$vm || component; + }); +} +function initRefs(instance, mpInstance) { + Object.defineProperty(instance, 'refs', { + get() { + const $refs = {}; + selectAllComponents(mpInstance, '.vue-ref', $refs); + const forComponents = mpInstance.selectAllComponents('.vue-ref-in-for'); + forComponents.forEach((component) => { + const ref = component.dataset.ref; + if (!$refs[ref]) { + $refs[ref] = []; + } + $refs[ref].push(component.$vm || component); + }); + return $refs; + }, + }); +} +function findVmByVueId(instance, vuePid) { + // 标准 vue3 中 没有 $children,定制了内核 + const $children = instance.$children; + // 优先查找直属(反向查找:https://github.com/dcloudio/uni-app/issues/1200) + for (let i = $children.length - 1; i >= 0; i--) { + const childVm = $children[i]; + if (childVm.$scope._$vueId === vuePid) { + return childVm; + } + } + // 反向递归查找 + let parentVm; + for (let i = $children.length - 1; i >= 0; i--) { + parentVm = findVmByVueId($children[i], vuePid); + if (parentVm) { + return parentVm; + } + } +} +function getTarget(obj, path) { + const parts = path.split('.'); + let key = parts[0]; + if (key.indexOf('__$n') === 0) { + //number index + key = parseInt(key.replace('__$n', '')); + } + if (!obj) { + obj = {}; + } + if (parts.length === 1) { + return obj[key]; + } + return getTarget(obj[key], parts.slice(1).join('.')); +} + +function getValue(dataPath, target) { + return getTarget(target || this, dataPath); +} +function getClass(dynamicClass, staticClass) { + return renderClass(staticClass, dynamicClass); +} +function getStyle(dynamicStyle, staticStyle) { + if (!dynamicStyle && !staticStyle) { + return ''; + } + var dynamicStyleObj = normalizeStyleBinding(dynamicStyle); + var styleObj = staticStyle + ? extend(staticStyle, dynamicStyleObj) + : dynamicStyleObj; + return Object.keys(styleObj) + .map(function (name) { + return hyphenate(name) + ':' + styleObj[name]; + }) + .join(';'); +} +function toObject(arr) { + var res = {}; + for (var i = 0; i < arr.length; i++) { + if (arr[i]) { + extend(res, arr[i]); + } + } + return res; +} +function normalizeStyleBinding(bindingStyle) { + if (Array.isArray(bindingStyle)) { + return toObject(bindingStyle); + } + if (typeof bindingStyle === 'string') { + return parseStyleText(bindingStyle); + } + return bindingStyle; +} +var parseStyleText = cache(function parseStyleText(cssText) { + var res = {}; + var listDelimiter = /;(?![^(]*\))/g; + var propertyDelimiter = /:(.+)/; + cssText.split(listDelimiter).forEach(function (item) { + if (item) { + var tmp = item.split(propertyDelimiter); + tmp.length > 1 && (res[tmp[0].trim()] = tmp[1].trim()); + } + }); + return res; +}); +function isDef(v) { + return v !== undefined && v !== null; +} +function renderClass(staticClass, dynamicClass) { + if (isDef(staticClass) || isDef(dynamicClass)) { + return concat(staticClass, stringifyClass(dynamicClass)); + } + /* istanbul ignore next */ + return ''; +} +function concat(a, b) { + return a ? (b ? a + ' ' + b : a) : b || ''; +} +function stringifyClass(value) { + if (Array.isArray(value)) { + return stringifyArray(value); + } + if (isObject(value)) { + return stringifyObject(value); + } + if (typeof value === 'string') { + return value; + } + /* istanbul ignore next */ + return ''; +} +function stringifyArray(value) { + var res = ''; + var stringified; + for (var i = 0, l = value.length; i < l; i++) { + if (isDef((stringified = stringifyClass(value[i]))) && stringified !== '') { + if (res) { + res += ' '; + } + res += stringified; + } + } + return res; +} +function stringifyObject(value) { + var res = ''; + for (var key in value) { + if (value[key]) { + if (res) { + res += ' '; + } + res += key; + } + } + return res; +} + +function setModel(target, key, value, modifiers) { + if (isArray(modifiers)) { + if (modifiers.indexOf('trim') !== -1) { + value = value.trim(); + } + if (modifiers.indexOf('number') !== -1) { + value = toNumber(value); + } + } + if (!target) { + target = this; + } + target[key] = value; +} +function setSync(target, key, value) { + if (!target) { + target = this; + } + target[key] = value; +} +function getOrig(data) { + if (isPlainObject(data)) { + return data.$orig || data; + } + return data; +} +function map(val, iteratee) { + let ret, i, l, keys, key; + if (isArray(val)) { + ret = new Array(val.length); + for (i = 0, l = val.length; i < l; i++) { + ret[i] = iteratee(val[i], i); + } + return ret; + } + else if (isObject(val)) { + keys = Object.keys(val); + ret = Object.create(null); + for (i = 0, l = keys.length; i < l; i++) { + key = keys[i]; + ret[key] = iteratee(val[key], key, i); + } + return ret; + } + return []; +} +const MP_METHODS = [ + 'createSelectorQuery', + 'createIntersectionObserver', + 'selectAllComponents', + 'selectComponent', +]; +function createEmitFn(oldEmit, ctx) { + return function emit(event, ...args) { + if (ctx.$scope && event) { + ctx.$scope.triggerEvent(event, { __args__: args }); + } + return oldEmit.apply(this, [event, ...args]); + }; +} +function initBaseInstance(instance, options) { + const ctx = instance.ctx; + // mp + ctx.mpType = options.mpType; // @deprecated + ctx.$mpType = options.mpType; + ctx.$scope = options.mpInstance; + // TODO @deprecated + ctx.$mp = {}; + if (__VUE_OPTIONS_API__) { + ctx._self = {}; + } + // $vm + ctx.$scope.$vm = instance.proxy; + // slots + { + instance.slots = {}; + if (isArray(options.slots) && options.slots.length) { + options.slots.forEach((name) => { + instance.slots[name] = true; + }); + } + } + ctx.getOpenerEventChannel = function () { + if (!this.__eventChannel__) { + this.__eventChannel__ = new EventChannel(); + } + return this.__eventChannel__; + }; + ctx.$hasHook = hasHook; + ctx.$callHook = callHook; + // $emit + instance.emit = createEmitFn(instance.emit, ctx); +} +function initComponentInstance(instance, options) { + initBaseInstance(instance, options); + const ctx = instance.ctx; + MP_METHODS.forEach((method) => { + ctx[method] = function (...args) { + const mpInstance = ctx.$scope; + if (mpInstance && mpInstance[method]) { + return mpInstance[method].apply(mpInstance, args); + } + }; + }); + // TODO other + ctx.__set_model = setModel; + ctx.__set_sync = setSync; + ctx.__get_orig = getOrig; + // TODO + ctx.__get_value = getValue; + ctx.__get_class = getClass; + ctx.__get_style = getStyle; + ctx.__map = map; +} +function initMocks(instance, mpInstance, mocks) { + const ctx = instance.ctx; + mocks.forEach((mock) => { + if (hasOwn(mpInstance, mock)) { + ctx[mock] = mpInstance[mock]; + } + }); +} +function hasHook(name) { + const hooks = this.$[name]; + if (hooks && hooks.length) { + return true; + } + return false; +} +function callHook(name, args) { + if (name === 'mounted') { + callHook.call(this, 'bm'); // beforeMount + this.$.isMounted = true; + name = 'm'; + } + else if (name === 'onLoad' && args && args.__id__) { + this.__eventChannel__ = getEventChannel(args.__id__); + delete args.__id__; + } + const hooks = this.$[name]; + return hooks && invokeArrayFns(hooks, args); +} + +const PAGE_HOOKS = [ + ON_LOAD, + ON_SHOW, + ON_HIDE, + ON_UNLOAD, + ON_RESIZE, + ON_TAB_ITEM_TAP, + ON_REACH_BOTTOM, + ON_PULL_DOWN_REFRESH, + ON_ADD_TO_FAVORITES, + // 'onReady', // lifetimes.ready + // 'onPageScroll', // 影响性能,开发者手动注册 + // 'onShareTimeline', // 右上角菜单,开发者手动注册 + // 'onShareAppMessage' // 右上角菜单,开发者手动注册 +]; +function findHooks(vueOptions, hooks = new Set()) { + if (vueOptions) { + Object.keys(vueOptions).forEach((name) => { + if (name.indexOf('on') === 0 && isFunction(vueOptions[name])) { + hooks.add(name); + } + }); + if (__VUE_OPTIONS_API__) { + const { extends: extendsOptions, mixins } = vueOptions; + if (mixins) { + mixins.forEach((mixin) => findHooks(mixin, hooks)); + } + if (extendsOptions) { + findHooks(extendsOptions, hooks); + } + } + } + return hooks; +} +function initHook$1(mpOptions, hook, excludes) { + if (excludes.indexOf(hook) === -1 && !hasOwn(mpOptions, hook)) { + mpOptions[hook] = function (args) { + return this.$vm && this.$vm.$callHook(hook, args); + }; + } +} +const EXCLUDE_HOOKS = [ON_READY]; +function initHooks(mpOptions, hooks, excludes = EXCLUDE_HOOKS) { + hooks.forEach((hook) => initHook$1(mpOptions, hook, excludes)); +} +function initUnknownHooks(mpOptions, vueOptions, excludes = EXCLUDE_HOOKS) { + findHooks(vueOptions).forEach((hook) => initHook$1(mpOptions, hook, excludes)); +} + +const HOOKS = [ + ON_SHOW, + ON_HIDE, + ON_ERROR, + ON_THEME_CHANGE, + ON_PAGE_NOT_FOUND, + ON_UNHANDLE_REJECTION, +]; +function parseApp(instance, parseAppOptions) { + const internalInstance = instance.$; + const appOptions = { + globalData: (instance.$options && instance.$options.globalData) || {}, + $vm: instance, + onLaunch(options) { + const ctx = internalInstance.ctx; + if (this.$vm && ctx.$scope) { + // 已经初始化过了,主要是为了百度,百度 onShow 在 onLaunch 之前 + return; + } + initBaseInstance(internalInstance, { + mpType: 'app', + mpInstance: this, + slots: [], + }); + ctx.globalData = this.globalData; + instance.$callHook(ON_LAUNCH, options); + }, + }; + const vueOptions = instance.$.type; + initHooks(appOptions, HOOKS); + initUnknownHooks(appOptions, vueOptions); + if (__VUE_OPTIONS_API__) { + const methods = vueOptions.methods; + methods && extend(appOptions, methods); + } + if (parseAppOptions) { + parseAppOptions.parse(appOptions); + } + return appOptions; +} +function initCreateApp(parseAppOptions) { + return function createApp(vm) { + return App(parseApp(vm, parseAppOptions)); + }; +} + +const PROP_TYPES = [String, Number, Boolean, Object, Array, null]; +function createObserver(name) { + return function observer(newVal) { + if (this.$vm) { + this.$vm.$.props[name] = newVal; // 为了触发其他非 render watcher + } + }; +} +function parsePropType(key, type, defaultValue) { + // [String]=>String + if (isArray(type) && type.length === 1) { + return type[0]; + } + return type; +} +function initDefaultProps(isBehavior = false) { + const properties = {}; + if (!isBehavior) { + properties.vueId = { + type: String, + value: '', + }; + // 小程序不能直接定义 $slots 的 props,所以通过 vueSlots 转换到 $slots + properties.vueSlots = { + type: null, + value: [], + observer: function (newVal) { + const $slots = Object.create(null); + newVal.forEach((slotName) => { + $slots[slotName] = true; + }); + this.setData({ + $slots, + }); + }, + }; + } + return properties; +} +function createProperty(key, prop) { + prop.observer = createObserver(key); + return prop; +} +function initProps(mpComponentOptions, rawProps, isBehavior = false) { + const properties = initDefaultProps(isBehavior); + if (isArray(rawProps)) { + rawProps.forEach((key) => { + properties[key] = createProperty(key, { + type: null, + }); + }); + } + else if (isPlainObject(rawProps)) { + Object.keys(rawProps).forEach((key) => { + const opts = rawProps[key]; + if (isPlainObject(opts)) { + // title:{type:String,default:''} + let value = opts.default; + if (isFunction(value)) { + value = value(); + } + const type = opts.type; + opts.type = parsePropType(key, type); + properties[key] = createProperty(key, { + type: PROP_TYPES.indexOf(type) !== -1 ? type : null, + value, + }); + } + else { + // content:String + const type = parsePropType(key, opts); + properties[key] = createProperty(key, { + type: PROP_TYPES.indexOf(type) !== -1 ? type : null, + }); + } + }); + } + mpComponentOptions.properties = properties; +} + +function initData(vueOptions) { + let data = vueOptions.data || {}; + if (typeof data === 'function') { + try { + const appConfig = getApp().$vm.$.appContext.config; + data = data.call(appConfig.globalProperties); + } + catch (e) { + if (process.env.VUE_APP_DEBUG) { + console.warn('根据 Vue 的 data 函数初始化小程序 data 失败,请尽量确保 data 函数中不访问 vm 对象,否则可能影响首次数据渲染速度。', data, e); + } + } + } + else { + try { + // 对 data 格式化 + data = JSON.parse(JSON.stringify(data)); + } + catch (e) { } + } + if (!isPlainObject(data)) { + data = {}; + } + return data; +} +function initBehaviors(vueOptions, initBehavior) { + const vueBehaviors = vueOptions.behaviors; + const vueExtends = vueOptions.extends; + const vueMixins = vueOptions.mixins; + let vueProps = vueOptions.props; + if (!vueProps) { + vueOptions.props = vueProps = []; + } + const behaviors = []; + if (isArray(vueBehaviors)) { + vueBehaviors.forEach((behavior) => { + behaviors.push(behavior.replace('uni://', `${__PLATFORM_PREFIX__}://`)); + if (behavior === 'uni://form-field') { + if (isArray(vueProps)) { + vueProps.push('name'); + vueProps.push('value'); + } + else { + vueProps.name = { + type: String, + default: '', + }; + vueProps.value = { + type: [String, Number, Boolean, Array, Object, Date], + default: '', + }; + } + } + }); + } + if (vueExtends && vueExtends.props) { + const behavior = {}; + initProps(behavior, vueExtends.props, true); + behaviors.push(initBehavior(behavior)); + } + if (isArray(vueMixins)) { + vueMixins.forEach((vueMixin) => { + if (vueMixin.props) { + const behavior = {}; + initProps(behavior, vueMixin.props, true); + behaviors.push(initBehavior(behavior)); + } + }); + } + return behaviors; +} +function applyOptions(componentOptions, vueOptions, initBehavior) { + componentOptions.data = initData(vueOptions); + componentOptions.behaviors = initBehaviors(vueOptions, initBehavior); +} + +function getExtraValue(instance, dataPathsArray) { + let context = instance; + dataPathsArray.forEach((dataPathArray) => { + const dataPath = dataPathArray[0]; + const value = dataPathArray[2]; + if (dataPath || typeof value !== 'undefined') { + // ['','',index,'disable'] + const propPath = dataPathArray[1]; + const valuePath = dataPathArray[3]; + let vFor; + if (Number.isInteger(dataPath)) { + vFor = dataPath; + } + else if (!dataPath) { + vFor = context; + } + else if (typeof dataPath === 'string' && dataPath) { + if (dataPath.indexOf('#s#') === 0) { + vFor = dataPath.substr(3); + } + else { + vFor = getTarget(context, dataPath); + } + } + if (Number.isInteger(vFor)) { + context = value; + } + else if (!propPath) { + context = vFor[value]; + } + else { + if (isArray(vFor)) { + context = vFor.find((vForItem) => { + return getTarget(vForItem, propPath) === value; + }); + } + else if (isPlainObject(vFor)) { + context = Object.keys(vFor).find((vForKey) => { + return getTarget(vFor[vForKey], propPath) === value; + }); + } + else { + console.error('v-for 暂不支持循环数据:', vFor); + } + } + if (valuePath) { + context = getTarget(context, valuePath); + } + } + }); + return context; +} +function processEventExtra(instance, extra, event) { + const extraObj = {}; + if (isArray(extra) && extra.length) { + /** + *[ + * ['data.items', 'data.id', item.data.id], + * ['metas', 'id', meta.id] + *], + *[ + * ['data.items', 'data.id', item.data.id], + * ['metas', 'id', meta.id] + *], + *'test' + */ + extra.forEach((dataPath, index) => { + if (typeof dataPath === 'string') { + if (!dataPath) { + // model,prop.sync + extraObj['$' + index] = instance; + } + else { + if (dataPath === '$event') { + // $event + extraObj['$' + index] = event; + } + else if (dataPath === 'arguments') { + if (event.detail && event.detail.__args__) { + extraObj['$' + index] = event.detail.__args__; + } + else { + extraObj['$' + index] = [event]; + } + } + else if (dataPath.indexOf('$event.') === 0) { + // $event.target.value + extraObj['$' + index] = getTarget(event, dataPath.replace('$event.', '')); + } + else { + extraObj['$' + index] = getTarget(instance, dataPath); + } + } + } + else { + extraObj['$' + index] = getExtraValue(instance, dataPath); + } + }); + } + return extraObj; +} +function getObjByArray(arr) { + const obj = {}; + for (let i = 1; i < arr.length; i++) { + const element = arr[i]; + obj[element[0]] = element[1]; + } + return obj; +} +function processEventArgs(instance, event, args = [], extra = [], isCustom, methodName) { + let isCustomMPEvent = false; // wxcomponent 组件,传递原始 event 对象 + if (isCustom) { + // 自定义事件 + isCustomMPEvent = + event.currentTarget && + event.currentTarget.dataset && + event.currentTarget.dataset.comType === 'wx'; + if (!args.length) { + // 无参数,直接传入 event 或 detail 数组 + if (isCustomMPEvent) { + return [event]; + } + return event.detail.__args__ || event.detail; + } + } + const extraObj = processEventExtra(instance, extra, event); + const ret = []; + args.forEach((arg) => { + if (arg === '$event') { + if (methodName === '__set_model' && !isCustom) { + // input v-model value + ret.push(event.target.value); + } + else { + if (isCustom && !isCustomMPEvent) { + ret.push(event.detail.__args__[0]); + } + else { + // wxcomponent 组件或内置组件 + ret.push(event); + } + } + } + else { + if (isArray(arg) && arg[0] === 'o') { + ret.push(getObjByArray(arg)); + } + else if (typeof arg === 'string' && hasOwn(extraObj, arg)) { + ret.push(extraObj[arg]); + } + else { + ret.push(arg); + } + } + }); + return ret; +} +function wrapper(event) { + event.stopPropagation = NOOP; + event.preventDefault = NOOP; + event.target = event.target || {}; + if (!hasOwn(event, 'detail')) { + event.detail = {}; + } + if (hasOwn(event, 'markerId')) { + event.detail = typeof event.detail === 'object' ? event.detail : {}; + event.detail.markerId = event.markerId; + } + if (isPlainObject(event.detail)) { + event.target = extend({}, event.target, event.detail); + } + return event; +} +const ONCE = '~'; +const CUSTOM = '^'; +function matchEventType(eventType, optType) { + return (eventType === optType || + (optType === 'regionchange' && + (eventType === 'begin' || eventType === 'end'))); +} +function handleEvent(event) { + event = wrapper(event); + // [['tap',[['handle',[1,2,a]],['handle1',[1,2,a]]]]] + const dataset = (event.currentTarget || event.target).dataset; + if (!dataset) { + return console.warn('事件信息不存在'); + } + const eventOpts = (dataset.eventOpts || + dataset['event-opts']); // 支付宝 web-view 组件 dataset 非驼峰 + if (!eventOpts) { + return console.warn('事件信息不存在'); + } + // [['handle',[1,2,a]],['handle1',[1,2,a]]] + const eventType = event.type; + const ret = []; + eventOpts.forEach((eventOpt) => { + let type = eventOpt[0]; + const eventsArray = eventOpt[1]; + const isCustom = type.charAt(0) === CUSTOM; + type = isCustom ? type.slice(1) : type; + const isOnce = type.charAt(0) === ONCE; + type = isOnce ? type.slice(1) : type; + if (eventsArray && matchEventType(eventType, type)) { + eventsArray.forEach((eventArray) => { + const methodName = eventArray[0]; + if (methodName) { + let handlerCtx = this.$vm; + if (handlerCtx.$options.generic && + handlerCtx.$parent && + handlerCtx.$parent.$parent) { + // mp-weixin,mp-toutiao 抽象节点模拟 scoped slots + handlerCtx = handlerCtx.$parent.$parent; + } + if (methodName === '$emit') { + handlerCtx.$emit.apply(handlerCtx, processEventArgs(this.$vm, event, eventArray[1], eventArray[2], isCustom, methodName)); + return; + } + const handler = handlerCtx[methodName]; + if (!isFunction(handler)) { + throw new Error(` _vm.${methodName} is not a function`); + } + if (isOnce) { + if (handler.once) { + return; + } + handler.once = true; + } + let params = processEventArgs(this.$vm, event, eventArray[1], eventArray[2], isCustom, methodName); + params = Array.isArray(params) ? params : []; + // 参数尾部增加原始事件对象用于复杂表达式内获取额外数据 + if (/=\s*\S+\.eventParams\s*\|\|\s*\S+\[['"]event-params['"]\]/.test(handler.toString())) { + // eslint-disable-next-line no-sparse-arrays + params = params.concat([, , , , , , , , , , event]); + } + ret.push(handler.apply(handlerCtx, params)); + } + }); + } + }); + if (eventType === 'input' && + ret.length === 1 && + typeof ret[0] !== 'undefined') { + return ret[0]; + } +} + +function parseComponent(vueOptions, { parse, mocks, isPage, initRelation, handleLink, initLifetimes, }) { + vueOptions = vueOptions.default || vueOptions; + const options = { + multipleSlots: true, + addGlobalClass: true, + }; + if (vueOptions.options) { + extend(options, vueOptions.options); + } + const mpComponentOptions = { + options, + lifetimes: initLifetimes({ mocks, isPage, initRelation, vueOptions }), + pageLifetimes: { + show() { + this.$vm && this.$vm.$callHook('onPageShow'); + }, + hide() { + this.$vm && this.$vm.$callHook('onPageHide'); + }, + resize(size) { + this.$vm && this.$vm.$callHook('onPageResize', size); + }, + }, + methods: { + __l: handleLink, + __e: handleEvent, + }, + }; + if (__VUE_OPTIONS_API__) { + applyOptions(mpComponentOptions, vueOptions, initBehavior); + } + initProps(mpComponentOptions, vueOptions.props, false); + initExtraOptions(mpComponentOptions, vueOptions); + initWxsCallMethods(mpComponentOptions.methods, vueOptions.wxsCallMethods); + if (parse) { + parse(mpComponentOptions, { handleLink }); + } + return mpComponentOptions; +} +function initCreateComponent(parseOptions) { + return function createComponent(vueComponentOptions) { + return Component(parseComponent(vueComponentOptions, parseOptions)); + }; +} +let $createComponentFn; +let $destroyComponentFn; +function $createComponent(initialVNode, options) { + if (!$createComponentFn) { + $createComponentFn = getApp().$vm.$createComponent; + } + return $createComponentFn(initialVNode, options); +} +function $destroyComponent(instance) { + if (!$destroyComponentFn) { + $destroyComponentFn = getApp().$vm.$destroyComponent; + } + return $destroyComponentFn(instance); +} + +function parsePage(vueOptions, parseOptions) { + const { parse, mocks, isPage, initRelation, handleLink, initLifetimes } = parseOptions; + const miniProgramPageOptions = parseComponent(vueOptions, { + mocks, + isPage, + initRelation, + handleLink, + initLifetimes, + }); + const methods = miniProgramPageOptions.methods; + methods.onLoad = function (query) { + this.options = query; + this.$page = { + fullPath: '/' + this.route + stringifyQuery(query), + }; + return this.$vm && this.$vm.$callHook(ON_LOAD, query); + }; + initHooks(methods, PAGE_HOOKS); + initUnknownHooks(methods, vueOptions); + parse && parse(miniProgramPageOptions, { handleLink }); + return miniProgramPageOptions; +} +function initCreatePage(parseOptions) { + return function createPage(vuePageOptions) { + return Component(parsePage(vuePageOptions, parseOptions)); + }; +} + +const MPPage = Page; +const MPComponent = Component; +const customizeRE = /:/g; +function customize(str) { + return camelize(str.replace(customizeRE, '-')); +} +function initTriggerEvent(mpInstance) { + const oldTriggerEvent = mpInstance.triggerEvent; + mpInstance.triggerEvent = function (event, ...args) { + return oldTriggerEvent.apply(mpInstance, [customize(event), ...args]); + }; +} +function initHook(name, options) { + const oldHook = options[name]; + if (!oldHook) { + options[name] = function () { + initTriggerEvent(this); + }; + } + else { + options[name] = function (...args) { + initTriggerEvent(this); + return oldHook.apply(this, args); + }; + } +} +Page = function (options) { + initHook(ON_LOAD, options); + return MPPage(options); +}; +Component = function (options) { + initHook('created', options); + return MPComponent(options); +}; + +function initLifetimes({ mocks, isPage, initRelation, vueOptions, }) { + return { + attached() { + const properties = this.properties; + initVueIds(properties.vueId, this); + const relationOptions = { + vuePid: this._$vuePid, + }; + // 处理父子关系 + initRelation(this, relationOptions); + // 初始化 vue 实例 + const mpInstance = this; + this.$vm = $createComponent({ + type: vueOptions, + props: properties, + }, { + mpType: isPage(mpInstance) ? 'page' : 'component', + mpInstance, + slots: properties.vueSlots, + parentComponent: relationOptions.parent && relationOptions.parent.$, + onBeforeSetup(instance, options) { + initRefs(instance, mpInstance); + initMocks(instance, mpInstance, mocks); + initComponentInstance(instance, options); + }, + }); + }, + ready() { + // 当组件 props 默认值为 true,初始化时传入 false 会导致 created,ready 触发, 但 attached 不触发 + // https://developers.weixin.qq.com/community/develop/doc/00066ae2844cc0f8eb883e2a557800 + if (this.$vm) { + this.$vm.$callHook('mounted'); + this.$vm.$callHook(ON_READY); + } + }, + detached() { + this.$vm && $destroyComponent(this.$vm); + }, + }; +} + +const mocks = ['__route__', '__wxExparserNodeId__', '__wxWebviewId__']; +function isPage(mpInstance) { + return !!mpInstance.route; +} +function initRelation(mpInstance, detail) { + mpInstance.triggerEvent('__l', detail); +} +function handleLink(event) { + // detail 是微信,value 是百度(dipatch) + const detail = (event.detail || + event.value); + const vuePid = detail.vuePid; + let parentVm; + if (vuePid) { + parentVm = findVmByVueId(this.$vm, vuePid); + } + if (!parentVm) { + parentVm = this.$vm; + } + detail.parent = parentVm; +} + +var baseParseOptions = /*#__PURE__*/Object.freeze({ + __proto__: null, + mocks: mocks, + isPage: isPage, + initRelation: initRelation, + handleLink: handleLink, + initLifetimes: initLifetimes +}); + +const createApp = initCreateApp(); +const createPage = initCreatePage(baseParseOptions); +const createComponent$1 = initCreateComponent(baseParseOptions); +wx.createApp = createApp; +wx.createPage = createPage; +wx.createComponent = createComponent$1; + +/** + * 用于延迟调用 setData + * 在 setData 真实调用的时机需执行 fixSetDataEnd + * @param {*} mpInstance + */ +function fixSetDataStart(mpInstance) { + const setData = mpInstance.setData; + const setDataArgs = []; + mpInstance.setData = function () { + setDataArgs.push(arguments); + }; + mpInstance.__fixInitData = function () { + this.setData = setData; + const fn = () => { + setDataArgs.forEach(args => { + setData.apply(this, args); + }); + }; + if (setDataArgs.length) { + if (this.groupSetData) { + this.groupSetData(fn); + } + else { + fn(); + } + } + }; +} +/** + * 恢复真实的 setData 方法 + * @param {*} mpInstance + */ +function fixSetDataEnd(mpInstance) { + if (mpInstance.__fixInitData) { + mpInstance.__fixInitData(); + delete mpInstance.__fixInitData; + } +} + +function parse(componentOptions) { + const oldAttached = componentOptions.lifetimes.attached; + componentOptions.lifetimes.attached = function attached() { + // 暂不区分版本 + if (isPage(this)) { + // 解决快手小程序页面 attached 生命周期 setData 导致数据同步异常的问题 + fixSetDataStart(this); + setTimeout(() => { + fixSetDataEnd(this); + }, 0); + } + oldAttached.call(this); + }; +} +var parseComponentOptions = extend({}, baseParseOptions, { + parse +}); + +const createComponent = initCreateComponent(parseComponentOptions); +ks.EventChannel = EventChannel; +ks.createApp = createApp; +ks.createPage = createPage; +ks.createComponent = createComponent; + +export { createApp, createComponent, createPage }; diff --git a/packages/uni-mp-kuaishou/package.json b/packages/uni-mp-kuaishou/package.json new file mode 100644 index 000000000..061a25bef --- /dev/null +++ b/packages/uni-mp-kuaishou/package.json @@ -0,0 +1,20 @@ +{ + "name": "@dcloudio/uni-mp-kuaishou", + "version": "3.0.0-alpha-3000020210730001", + "description": "uni-app mp-kuaishou", + "main": "dist/index.js", + "repository": { + "type": "git", + "url": "git+https://github.com/dcloudio/uni-app.git", + "directory": "packages/uni-mp-kuaishou" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "license": "Apache-2.0", + "uni-app": { + "name": "mp-kuaishou", + "title": "快手小程序" + }, + "gitHead": "4dd0e035b52584ff028ee3028c46adc555be0529" +} diff --git a/packages/uni-mp-kuaishou/src/api/index.ts b/packages/uni-mp-kuaishou/src/api/index.ts new file mode 100644 index 000000000..61ae52880 --- /dev/null +++ b/packages/uni-mp-kuaishou/src/api/index.ts @@ -0,0 +1,4 @@ +import { initUni } from '@dcloudio/uni-mp-core' +import * as shims from './shims' +import * as protocols from './protocols' +export default initUni(shims, protocols) diff --git a/packages/uni-mp-kuaishou/src/api/protocols.ts b/packages/uni-mp-kuaishou/src/api/protocols.ts new file mode 100644 index 000000000..0a42f0fbd --- /dev/null +++ b/packages/uni-mp-kuaishou/src/api/protocols.ts @@ -0,0 +1,7 @@ +export { + redirectTo, + navigateTo, + previewImage, + getSystemInfo, + getSystemInfoSync, +} from '@dcloudio/uni-mp-core' diff --git a/packages/uni-mp-kuaishou/src/api/shims.ts b/packages/uni-mp-kuaishou/src/api/shims.ts new file mode 100644 index 000000000..6e201e77b --- /dev/null +++ b/packages/uni-mp-kuaishou/src/api/shims.ts @@ -0,0 +1,8 @@ +import { initGetProvider } from '@dcloudio/uni-mp-core' + +export const getProvider = initGetProvider({ + oauth: ['kuaishou'], + share: ['kuaishou'], + payment: ['kuaishoupay'], + push: ['kuaishou'], +}) diff --git a/packages/uni-mp-kuaishou/src/platform/index.ts b/packages/uni-mp-kuaishou/src/platform/index.ts new file mode 100644 index 000000000..92ea23e46 --- /dev/null +++ b/packages/uni-mp-kuaishou/src/platform/index.ts @@ -0,0 +1,3 @@ +export function getBaseSystemInfo() { + return ks.getSystemInfoSync() +} diff --git a/packages/uni-mp-kuaishou/src/runtime/index.ts b/packages/uni-mp-kuaishou/src/runtime/index.ts new file mode 100644 index 000000000..5a9cc7a8a --- /dev/null +++ b/packages/uni-mp-kuaishou/src/runtime/index.ts @@ -0,0 +1,12 @@ +import { EventChannel } from '@dcloudio/uni-shared' +import { initCreateComponent } from '@dcloudio/uni-mp-core' +import { createApp, createPage } from '@dcloudio/uni-mp-weixin/src/runtime' + +import parseComponentOptions from './parseComponentOptions' + +export { createApp, createPage } from '@dcloudio/uni-mp-weixin/src/runtime' +export const createComponent = initCreateComponent(parseComponentOptions) +;(ks as any).EventChannel = EventChannel +;(ks as any).createApp = createApp +;(ks as any).createPage = createPage +;(ks as any).createComponent = createComponent diff --git a/packages/uni-mp-kuaishou/src/runtime/parseComponentOptions.ts b/packages/uni-mp-kuaishou/src/runtime/parseComponentOptions.ts new file mode 100644 index 000000000..a6edb663c --- /dev/null +++ b/packages/uni-mp-kuaishou/src/runtime/parseComponentOptions.ts @@ -0,0 +1,26 @@ +import { extend } from '@vue/shared' +import { MPComponentInstance, MPComponentOptions } from '@dcloudio/uni-mp-core' +import * as baseParseOptions from '@dcloudio/uni-mp-weixin/src/runtime/parseOptions' +import { + fixSetDataStart, + fixSetDataEnd, +} from '@dcloudio/uni-mp-weixin/src/runtime/fixSetData' + +export function parse(componentOptions: MPComponentOptions) { + const oldAttached = componentOptions.lifetimes!.attached + componentOptions.lifetimes!.attached = function attached() { + // 暂不区分版本 + if (baseParseOptions.isPage(this as MPComponentInstance)) { + // 解决快手小程序页面 attached 生命周期 setData 导致数据同步异常的问题 + fixSetDataStart(this as MPComponentInstance) + setTimeout(() => { + fixSetDataEnd(this as MPComponentInstance) + }, 0) + } + oldAttached!.call(this) + } +} + +export default extend({}, baseParseOptions, { + parse, +}) diff --git a/packages/uni-mp-kuaishou/tsconfig.json b/packages/uni-mp-kuaishou/tsconfig.json new file mode 100644 index 000000000..f74ba9d56 --- /dev/null +++ b/packages/uni-mp-kuaishou/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "paths": { + "@dcloudio/*": ["packages/*/src"], + "@dcloudio/uni-platform": ["packages/uni-mp-kuaishou/src/platform/index.ts"], + "@dcloudio/uni-mp-polyfill": ["packages/uni-mp-core/src/runtime/polyfill"] + } + } +} diff --git a/packages/uni-mp-weixin/src/runtime/fixSetData.ts b/packages/uni-mp-weixin/src/runtime/fixSetData.ts new file mode 100644 index 000000000..a64d69edc --- /dev/null +++ b/packages/uni-mp-weixin/src/runtime/fixSetData.ts @@ -0,0 +1,38 @@ +import { MPComponentInstance } from '@dcloudio/uni-mp-core' +/** + * 用于延迟调用 setData + * 在 setData 真实调用的时机需执行 fixSetDataEnd + * @param {*} mpInstance + */ +export function fixSetDataStart(mpInstance: MPComponentInstance) { + const setData = mpInstance.setData + const setDataArgs: any[] = [] + mpInstance.setData = function () { + setDataArgs.push(arguments) + } + mpInstance.__fixInitData = function () { + this.setData = setData + const fn = () => { + setDataArgs.forEach((args) => { + setData.apply(this, args) + }) + } + if (setDataArgs.length) { + if (this.groupSetData) { + this.groupSetData(fn) + } else { + fn() + } + } + } +} +/** + * 恢复真实的 setData 方法 + * @param {*} mpInstance + */ +export function fixSetDataEnd(mpInstance: MPComponentInstance) { + if (mpInstance.__fixInitData) { + mpInstance.__fixInitData() + delete mpInstance.__fixInitData + } +} -- GitLab