From 7325d4b3889a2d9f82d50e0352fea5f62932f670 Mon Sep 17 00:00:00 2001 From: fxy060608 Date: Sat, 19 Sep 2020 17:36:54 +0800 Subject: [PATCH] feat(mp): vue@3.0.0 --- packages/uni-mp-alipay/dist/uni.api.esm.js | 67 +- packages/uni-mp-alipay/dist/uni.mp.esm.js | 78 +- packages/uni-mp-baidu/dist/index.js | 5 + packages/uni-mp-baidu/dist/uni.api.esm.js | 67 +- packages/uni-mp-baidu/dist/uni.mp.esm.js | 67 +- packages/uni-mp-kuaishou/dist/index.js | 100 +- packages/uni-mp-qq/dist/uni.api.esm.js | 67 +- packages/uni-mp-qq/dist/uni.mp.esm.js | 65 +- packages/uni-mp-toutiao/dist/uni.api.esm.js | 65 +- packages/uni-mp-toutiao/dist/uni.mp.esm.js | 65 +- packages/uni-mp-vue/dist/vue.runtime.esm.js | 1027 +++++++++++------ packages/uni-mp-weixin/dist/uni.api.esm.js | 67 +- packages/uni-mp-weixin/dist/uni.mp.esm.js | 65 +- .../uni-quickapp-webview/dist/uni.api.esm.js | 67 +- .../uni-quickapp-webview/dist/uni.mp.esm.js | 67 +- packages/vue-cli-plugin-uni/generator.js | 2 +- .../mp-baidu/runtime/wrapper/page-parser.js | 5 + 17 files changed, 1320 insertions(+), 626 deletions(-) diff --git a/packages/uni-mp-alipay/dist/uni.api.esm.js b/packages/uni-mp-alipay/dist/uni.api.esm.js index 0410bd296..28f3b6713 100644 --- a/packages/uni-mp-alipay/dist/uni.api.esm.js +++ b/packages/uni-mp-alipay/dist/uni.api.esm.js @@ -1,5 +1,32 @@ import { isArray, isPromise, isFunction, isPlainObject, hasOwn, isString } from '@vue/shared'; +const API_TYPE_SYNC = 1; +function validateProtocol(_name, _args, _protocol) { + return true; +} +function formatApiArgs(args, options) { + if (!options) { + return args; + } +} +function createApi({ type, name, options }, fn, protocol) { + return function (...args) { + if (type === API_TYPE_SYNC) { + if (!((process.env.NODE_ENV !== 'production') && protocol && !validateProtocol())) { + return fn.apply(null, formatApiArgs(args, options)); + } + } + }; +} + +const Upx2pxProtocol = [ + { + name: 'upx', + type: [Number, String], + required: true + } +]; + const EPS = 1e-4; const BASE_DEVICE_WIDTH = 750; let isIOS = false; @@ -11,7 +38,7 @@ function checkDeviceWidth() { deviceDPR = pixelRatio; isIOS = platform === 'ios'; } -function upx2px(number, newDeviceWidth) { +const upx2px = createApi({ type: API_TYPE_SYNC, name: 'upx2px' }, (number, newDeviceWidth) => { if (deviceWidth === 0) { checkDeviceWidth(); } @@ -33,7 +60,7 @@ function upx2px(number, newDeviceWidth) { } } return number < 0 ? -result : result; -} +}, Upx2pxProtocol); var HOOKS; (function (HOOKS) { @@ -139,6 +166,15 @@ function invokeApi(method, api, options, ...params) { return api(options, ...params); } +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])) { @@ -184,15 +220,15 @@ function removeHook(hooks, hook) { hooks.splice(index, 1); } } -function addInterceptor(method, interceptor) { +const addInterceptor = createApi({ type: API_TYPE_SYNC, name: 'addInterceptor' }, (method, interceptor) => { if (typeof method === 'string' && isPlainObject(interceptor)) { mergeInterceptorHook(scopedInterceptors[method] || (scopedInterceptors[method] = {}), interceptor); } else if (isPlainObject(method)) { mergeInterceptorHook(globalInterceptors, method); } -} -function removeInterceptor(method, interceptor) { +}, AddInterceptorProtocol); +const removeInterceptor = createApi({ type: API_TYPE_SYNC, name: 'removeInterceptor' }, (method, interceptor) => { if (typeof method === 'string') { if (isPlainObject(interceptor)) { removeInterceptorHook(scopedInterceptors[method], interceptor); @@ -204,7 +240,7 @@ function removeInterceptor(method, interceptor) { else if (isPlainObject(method)) { removeInterceptorHook(globalInterceptors, method); } -} +}, RemoveInterceptorProtocol); 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$/; @@ -413,7 +449,20 @@ function addSafeAreaInsets(fromRes, toRes) { bottom: fromRes.windowHeight - safeArea.bottom }; } -} +} +const redirectTo = {}; +const createCanvasContext = { + returnValue(fromRes, toRes) { + const measureText = fromRes.measureText; + toRes.measureText = function (text, callback) { + const textMetrics = measureText.call(this, text); + if (typeof callback === 'function') { + setTimeout(() => callback(textMetrics), 0); + } + return textMetrics; + }; + } +}; const getProvider = initGetProvider({ oauth: ['alipay'], @@ -1000,7 +1049,9 @@ var protocols = /*#__PURE__*/Object.freeze({ hideHomeButton: hideHomeButton, saveImageToPhotosAlbum: saveImageToPhotosAlbum, saveVideoToPhotosAlbum: saveVideoToPhotosAlbum, - chooseAddress: chooseAddress + chooseAddress: chooseAddress, + redirectTo: redirectTo, + createCanvasContext: createCanvasContext }); var index = initUni(shims, protocols); diff --git a/packages/uni-mp-alipay/dist/uni.mp.esm.js b/packages/uni-mp-alipay/dist/uni.mp.esm.js index 800eda2b8..ad5532f09 100644 --- a/packages/uni-mp-alipay/dist/uni.mp.esm.js +++ b/packages/uni-mp-alipay/dist/uni.mp.esm.js @@ -52,28 +52,6 @@ const MP_METHODS = [ 'selectAllComponents', 'selectComponent' ]; -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'; - } - const hooks = this.$[name]; - let ret; - if (hooks) { - for (let i = 0; i < hooks.length; i++) { - ret = hooks[i](args); - } - } - return ret; -} function createEmitFn(oldEmit, ctx) { return function emit(event, ...args) { if (ctx.$scope && event) { @@ -89,9 +67,6 @@ function createEmitFn(oldEmit, ctx) { return oldEmit.apply(this, [event, ...args]); }; } -function set(target, key, val) { - return (target[key] = val); -} function initBaseInstance(instance, options) { const ctx = instance.ctx; // mp @@ -100,7 +75,9 @@ function initBaseInstance(instance, options) { ctx.$scope = options.mpInstance; // TODO @deprecated ctx.$mp = {}; - ctx._self = {}; + if (__VUE_OPTIONS_API__) { + ctx._self = {}; + } // $vm ctx.$scope.$vm = instance.proxy; // slots @@ -111,15 +88,8 @@ function initBaseInstance(instance, options) { } }); } - if (__VUE_OPTIONS_API__) { - // $set - ctx.$set = set; - } // $emit instance.emit = createEmitFn(instance.emit, ctx); - // $callHook - ctx.$hasHook = hasHook; - ctx.$callHook = callHook; } function initComponentInstance(instance, options) { initBaseInstance(instance, options); @@ -216,7 +186,7 @@ function parseApp(instance, parseAppOptions) { $vm: instance, onLaunch(options) { const ctx = internalInstance.ctx; - if (this.$vm && ctx.$callHook) { + if (this.$vm && ctx.$scope) { // 已经初始化过了,主要是为了百度,百度 onShow 在 onLaunch 之前 return; } @@ -247,6 +217,26 @@ function initCreateApp(parseAppOptions) { }; } +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 initVueIds(vueIds, mpInstance) { if (!vueIds) { return; @@ -261,6 +251,16 @@ function initVueIds(vueIds, mpInstance) { mpInstance._$vuePid = ids[1]; } } +function initWxsCallMethods(methods, wxsCallMethods) { + if (!isArray(wxsCallMethods)) { + return; + } + wxsCallMethods.forEach((callMethod) => { + methods[callMethod] = function (args) { + return this.$vm[callMethod](args); + }; + }); +} function findVmByVueId(instance, vuePid) { // TODO vue3 中 没有 $children const $children = instance.$children; @@ -971,11 +971,15 @@ function createVueComponent(mpType, mpInstance, vueOptions, parent) { function createPage(vueOptions) { vueOptions = vueOptions.default || vueOptions; const pageOptions = { - onLoad(args) { + onLoad(query) { + this.options = query; + this.$page = { + fullPath: '/' + this.route + stringifyQuery(query) + }; // 初始化 vue 实例 this.$vm = createVueComponent('page', this, vueOptions); initSpecialMethods(this); - this.$vm.$callHook('onLoad', args); + this.$vm.$callHook('onLoad', query); }, onReady() { initChildVues(this); @@ -1003,6 +1007,7 @@ function createPage(vueOptions) { } initHooks(pageOptions, PAGE_HOOKS); initUnknownHooks(pageOptions, vueOptions); + initWxsCallMethods(pageOptions, vueOptions.wxsCallMethods); return Page(pageOptions); } @@ -1099,6 +1104,7 @@ function createComponent(vueOptions) { else { mpComponentOptions.didUpdate = createObserver(true); } + initWxsCallMethods(mpComponentOptions.methods, vueOptions.wxsCallMethods); return Component(mpComponentOptions); } diff --git a/packages/uni-mp-baidu/dist/index.js b/packages/uni-mp-baidu/dist/index.js index 2946522c2..d7827fe3f 100644 --- a/packages/uni-mp-baidu/dist/index.js +++ b/packages/uni-mp-baidu/dist/index.js @@ -1897,6 +1897,11 @@ function parsePage (vuePageOptions) { initRelation }); + const onInit = (vuePageOptions.default || vuePageOptions).onInit; + if (onInit) { + pageOptions.methods.onInit = onInit; + } + // 纠正百度小程序生命周期methods:onShow在methods:onLoad之前触发的问题 pageOptions.methods.onShow = function onShow () { if (this.$vm && this.$vm.$mp.query) { diff --git a/packages/uni-mp-baidu/dist/uni.api.esm.js b/packages/uni-mp-baidu/dist/uni.api.esm.js index c4450efaa..5801e1d58 100644 --- a/packages/uni-mp-baidu/dist/uni.api.esm.js +++ b/packages/uni-mp-baidu/dist/uni.api.esm.js @@ -1,5 +1,32 @@ import { isArray, isPromise, isFunction, isPlainObject, hasOwn, isString } from '@vue/shared'; +const API_TYPE_SYNC = 1; +function validateProtocol(_name, _args, _protocol) { + return true; +} +function formatApiArgs(args, options) { + if (!options) { + return args; + } +} +function createApi({ type, name, options }, fn, protocol) { + return function (...args) { + if (type === API_TYPE_SYNC) { + if (!((process.env.NODE_ENV !== 'production') && protocol && !validateProtocol())) { + return fn.apply(null, formatApiArgs(args, options)); + } + } + }; +} + +const Upx2pxProtocol = [ + { + name: 'upx', + type: [Number, String], + required: true + } +]; + const EPS = 1e-4; const BASE_DEVICE_WIDTH = 750; let isIOS = false; @@ -11,7 +38,7 @@ function checkDeviceWidth() { deviceDPR = pixelRatio; isIOS = platform === 'ios'; } -function upx2px(number, newDeviceWidth) { +const upx2px = createApi({ type: API_TYPE_SYNC, name: 'upx2px' }, (number, newDeviceWidth) => { if (deviceWidth === 0) { checkDeviceWidth(); } @@ -33,7 +60,7 @@ function upx2px(number, newDeviceWidth) { } } return number < 0 ? -result : result; -} +}, Upx2pxProtocol); var HOOKS; (function (HOOKS) { @@ -139,6 +166,15 @@ function invokeApi(method, api, options, ...params) { return api(options, ...params); } +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])) { @@ -184,15 +220,15 @@ function removeHook(hooks, hook) { hooks.splice(index, 1); } } -function addInterceptor(method, interceptor) { +const addInterceptor = createApi({ type: API_TYPE_SYNC, name: 'addInterceptor' }, (method, interceptor) => { if (typeof method === 'string' && isPlainObject(interceptor)) { mergeInterceptorHook(scopedInterceptors[method] || (scopedInterceptors[method] = {}), interceptor); } else if (isPlainObject(method)) { mergeInterceptorHook(globalInterceptors, method); } -} -function removeInterceptor(method, interceptor) { +}, AddInterceptorProtocol); +const removeInterceptor = createApi({ type: API_TYPE_SYNC, name: 'removeInterceptor' }, (method, interceptor) => { if (typeof method === 'string') { if (isPlainObject(interceptor)) { removeInterceptorHook(scopedInterceptors[method], interceptor); @@ -204,7 +240,7 @@ function removeInterceptor(method, interceptor) { else if (isPlainObject(method)) { removeInterceptorHook(globalInterceptors, method); } -} +}, RemoveInterceptorProtocol); 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$/; @@ -450,7 +486,20 @@ function addSafeAreaInsets(fromRes, toRes) { const getSystemInfo = { returnValue: addSafeAreaInsets }; -const getSystemInfoSync = getSystemInfo; +const getSystemInfoSync = getSystemInfo; +const redirectTo = {}; +const createCanvasContext = { + returnValue(fromRes, toRes) { + const measureText = fromRes.measureText; + toRes.measureText = function (text, callback) { + const textMetrics = measureText.call(this, text); + if (typeof callback === 'function') { + setTimeout(() => callback(textMetrics), 0); + } + return textMetrics; + }; + } +}; const getProvider = initGetProvider({ oauth: ['baidu'], @@ -565,9 +614,11 @@ var protocols = /*#__PURE__*/Object.freeze({ navigateBackMiniProgram: navigateBackMiniProgram, showShareMenu: showShareMenu, getAccountInfoSync: getAccountInfoSync, + redirectTo: redirectTo, previewImage: previewImage, getSystemInfo: getSystemInfo, - getSystemInfoSync: getSystemInfoSync + getSystemInfoSync: getSystemInfoSync, + createCanvasContext: createCanvasContext }); var index = initUni(shims, protocols); diff --git a/packages/uni-mp-baidu/dist/uni.mp.esm.js b/packages/uni-mp-baidu/dist/uni.mp.esm.js index 27b5adaf5..c2b202cdf 100644 --- a/packages/uni-mp-baidu/dist/uni.mp.esm.js +++ b/packages/uni-mp-baidu/dist/uni.mp.esm.js @@ -52,28 +52,6 @@ const MP_METHODS = [ 'selectAllComponents', 'selectComponent' ]; -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'; - } - const hooks = this.$[name]; - let ret; - if (hooks) { - for (let i = 0; i < hooks.length; i++) { - ret = hooks[i](args); - } - } - return ret; -} function createEmitFn(oldEmit, ctx) { return function emit(event, ...args) { if (ctx.$scope && event) { @@ -82,9 +60,6 @@ function createEmitFn(oldEmit, ctx) { return oldEmit.apply(this, [event, ...args]); }; } -function set(target, key, val) { - return (target[key] = val); -} function initBaseInstance(instance, options) { const ctx = instance.ctx; // mp @@ -93,7 +68,9 @@ function initBaseInstance(instance, options) { ctx.$scope = options.mpInstance; // TODO @deprecated ctx.$mp = {}; - ctx._self = {}; + if (__VUE_OPTIONS_API__) { + ctx._self = {}; + } // $vm ctx.$scope.$vm = instance.proxy; // slots @@ -105,15 +82,8 @@ function initBaseInstance(instance, options) { }); } } - if (__VUE_OPTIONS_API__) { - // $set - ctx.$set = set; - } // $emit instance.emit = createEmitFn(instance.emit, ctx); - // $callHook - ctx.$hasHook = hasHook; - ctx.$callHook = callHook; } function initComponentInstance(instance, options) { initBaseInstance(instance, options); @@ -207,7 +177,7 @@ function parseApp(instance, parseAppOptions) { $vm: instance, onLaunch(options) { const ctx = internalInstance.ctx; - if (this.$vm && ctx.$callHook) { + if (this.$vm && ctx.$scope) { // 已经初始化过了,主要是为了百度,百度 onShow 在 onLaunch 之前 return; } @@ -238,6 +208,26 @@ function initCreateApp(parseAppOptions) { }; } +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 initBehavior(options) { return Behavior(options); } @@ -810,6 +800,13 @@ function parsePage(vueOptions, parseOptions) { 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('onLoad', query); + }; initHooks(methods, PAGE_HOOKS); initUnknownHooks(methods, vueOptions); parse && parse(miniProgramPageOptions, { handleLink }); @@ -929,7 +926,7 @@ function handleLink(event) { const mocks = ['nodeId', 'componentName', '_componentId', 'uniquePrefix']; function isPage(mpInstance) { - return !mpInstance.ownerId; + return !hasOwn(mpInstance, 'ownerId'); } function initRelation(mpInstance, detail) { mpInstance.dispatch('__l', detail); diff --git a/packages/uni-mp-kuaishou/dist/index.js b/packages/uni-mp-kuaishou/dist/index.js index 8afd8bd0c..ec8bca4ef 100644 --- a/packages/uni-mp-kuaishou/dist/index.js +++ b/packages/uni-mp-kuaishou/dist/index.js @@ -1317,7 +1317,9 @@ const hooks = [ 'onShow', 'onHide', 'onError', - 'onPageNotFound' + 'onPageNotFound', + 'onThemeChange', + 'onUnhandledRejection' ]; function parseBaseApp (vm, { @@ -1393,17 +1395,19 @@ function parseBaseApp (vm, { return appOptions } -/* 快手也使用__wxExparserNodeId__和__wxWebviewId__ */ const mocks = ['__route__', '__wxExparserNodeId__', '__wxWebviewId__']; function findVmByVueId (vm, vuePid) { const $children = vm.$children; - // 优先查找直属 - let parentVm = $children.find(childVm => childVm.$scope._$vueId === vuePid); - if (parentVm) { - return parentVm + // 优先查找直属(反向查找: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) { @@ -1473,6 +1477,10 @@ function parseApp (vm) { }) } +function parseApp$1 (vm) { + return parseApp(vm) +} + function createApp (vm) { Vue.prototype.getOpenerEventChannel = function () { if (!this.__eventChannel__) { @@ -1488,10 +1496,53 @@ function createApp (vm) { } return callHook.call(this, hook, args) }; - App(parseApp(vm)); + App(parseApp$1(vm)); return vm } +const encodeReserveRE = /[!'()*]/g; +const encodeReserveReplacer = c => '%' + c.charCodeAt(0).toString(16); +const commaRE = /%2C/g; + +// fixed encodeURIComponent which is more conformant to RFC3986: +// - escapes [!'()*] +// - preserve commas +const encode = str => encodeURIComponent(str) + .replace(encodeReserveRE, encodeReserveReplacer) + .replace(commaRE, ','); + +function stringifyQuery (obj, encodeStr = encode) { + const res = obj ? Object.keys(obj).map(key => { + const val = obj[key]; + + if (val === undefined) { + return '' + } + + if (val === null) { + return encodeStr(key) + } + + if (Array.isArray(val)) { + const result = []; + val.forEach(val2 => { + if (val2 === undefined) { + return + } + if (val2 === null) { + result.push(encodeStr(key)); + } else { + result.push(encodeStr(key) + '=' + encodeStr(val2)); + } + }); + return result.join('&') + } + + return encodeStr(key) + '=' + encodeStr(val) + }).filter(x => x.length > 0).join('&') : null; + return res ? `?${res}` : '' +} + function parseBaseComponent (vueComponentOptions, { isPage, initRelation @@ -1500,7 +1551,8 @@ function parseBaseComponent (vueComponentOptions, { const options = { multipleSlots: true, - addGlobalClass: true + addGlobalClass: true, + ...(vueOptions.options || {}) }; const componentOptions = { @@ -1545,7 +1597,7 @@ function parseBaseComponent (vueComponentOptions, { } }, detached () { - this.$vm.$destroy(); + this.$vm && this.$vm.$destroy(); } }, pageLifetimes: { @@ -1564,6 +1616,10 @@ function parseBaseComponent (vueComponentOptions, { __e: handleEvent } }; + // externalClasses + if (vueOptions.externalClasses) { + componentOptions.externalClasses = vueOptions.externalClasses; + } if (Array.isArray(vueOptions.wxsCallMethods)) { vueOptions.wxsCallMethods.forEach(callMethod => { @@ -1586,6 +1642,10 @@ function parseComponent (vueComponentOptions) { }) } +function parseComponent$1 (vueComponentOptions) { + return parseComponent(vueComponentOptions) +} + const hooks$1 = [ 'onShow', 'onHide', @@ -1598,13 +1658,19 @@ function parseBasePage (vuePageOptions, { isPage, initRelation }) { - const pageOptions = parseComponent(vuePageOptions); + const pageOptions = parseComponent$1(vuePageOptions); initHooks(pageOptions.methods, hooks$1, vuePageOptions); - pageOptions.methods.onLoad = function (args) { - this.$vm.$mp.query = args; // 兼容 mpvue - this.$vm.__call_hook('onLoad', args); + pageOptions.methods.onLoad = function (query) { + this.options = query; + const copyQuery = Object.assign({}, query); + delete copyQuery.__id__; + this.$page = { + fullPath: '/' + (this.route || this.is) + stringifyQuery(copyQuery) + }; + this.$vm.$mp.query = query; // 兼容 mpvue + this.$vm.__call_hook('onLoad', query); }; return pageOptions @@ -1617,15 +1683,19 @@ function parsePage (vuePageOptions) { }) } +function parsePage$1 (vuePageOptions) { + return parsePage(vuePageOptions) +} + function createPage (vuePageOptions) { { - return Component(parsePage(vuePageOptions)) + return Component(parsePage$1(vuePageOptions)) } } function createComponent (vueOptions) { { - return Component(parseComponent(vueOptions)) + return Component(parseComponent$1(vueOptions)) } } diff --git a/packages/uni-mp-qq/dist/uni.api.esm.js b/packages/uni-mp-qq/dist/uni.api.esm.js index 9a9838e27..ef851c825 100644 --- a/packages/uni-mp-qq/dist/uni.api.esm.js +++ b/packages/uni-mp-qq/dist/uni.api.esm.js @@ -1,5 +1,32 @@ import { isArray, isPromise, isFunction, isPlainObject, hasOwn, isString } from '@vue/shared'; +const API_TYPE_SYNC = 1; +function validateProtocol(_name, _args, _protocol) { + return true; +} +function formatApiArgs(args, options) { + if (!options) { + return args; + } +} +function createApi({ type, name, options }, fn, protocol) { + return function (...args) { + if (type === API_TYPE_SYNC) { + if (!((process.env.NODE_ENV !== 'production') && protocol && !validateProtocol())) { + return fn.apply(null, formatApiArgs(args, options)); + } + } + }; +} + +const Upx2pxProtocol = [ + { + name: 'upx', + type: [Number, String], + required: true + } +]; + const EPS = 1e-4; const BASE_DEVICE_WIDTH = 750; let isIOS = false; @@ -11,7 +38,7 @@ function checkDeviceWidth() { deviceDPR = pixelRatio; isIOS = platform === 'ios'; } -function upx2px(number, newDeviceWidth) { +const upx2px = createApi({ type: API_TYPE_SYNC, name: 'upx2px' }, (number, newDeviceWidth) => { if (deviceWidth === 0) { checkDeviceWidth(); } @@ -33,7 +60,7 @@ function upx2px(number, newDeviceWidth) { } } return number < 0 ? -result : result; -} +}, Upx2pxProtocol); var HOOKS; (function (HOOKS) { @@ -139,6 +166,15 @@ function invokeApi(method, api, options, ...params) { return api(options, ...params); } +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])) { @@ -184,15 +220,15 @@ function removeHook(hooks, hook) { hooks.splice(index, 1); } } -function addInterceptor(method, interceptor) { +const addInterceptor = createApi({ type: API_TYPE_SYNC, name: 'addInterceptor' }, (method, interceptor) => { if (typeof method === 'string' && isPlainObject(interceptor)) { mergeInterceptorHook(scopedInterceptors[method] || (scopedInterceptors[method] = {}), interceptor); } else if (isPlainObject(method)) { mergeInterceptorHook(globalInterceptors, method); } -} -function removeInterceptor(method, interceptor) { +}, AddInterceptorProtocol); +const removeInterceptor = createApi({ type: API_TYPE_SYNC, name: 'removeInterceptor' }, (method, interceptor) => { if (typeof method === 'string') { if (isPlainObject(interceptor)) { removeInterceptorHook(scopedInterceptors[method], interceptor); @@ -204,7 +240,7 @@ function removeInterceptor(method, interceptor) { else if (isPlainObject(method)) { removeInterceptorHook(globalInterceptors, method); } -} +}, RemoveInterceptorProtocol); 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$/; @@ -450,7 +486,20 @@ function addSafeAreaInsets(fromRes, toRes) { const getSystemInfo = { returnValue: addSafeAreaInsets }; -const getSystemInfoSync = getSystemInfo; +const getSystemInfoSync = getSystemInfo; +const redirectTo = {}; +const createCanvasContext = { + returnValue(fromRes, toRes) { + const measureText = fromRes.measureText; + toRes.measureText = function (text, callback) { + const textMetrics = measureText.call(this, text); + if (typeof callback === 'function') { + setTimeout(() => callback(textMetrics), 0); + } + return textMetrics; + }; + } +}; const getProvider = initGetProvider({ oauth: ['qq'], @@ -466,9 +515,11 @@ var shims = /*#__PURE__*/Object.freeze({ var protocols = /*#__PURE__*/Object.freeze({ __proto__: null, + redirectTo: redirectTo, previewImage: previewImage, getSystemInfo: getSystemInfo, - getSystemInfoSync: getSystemInfoSync + getSystemInfoSync: getSystemInfoSync, + createCanvasContext: createCanvasContext }); var index = initUni(shims, protocols); diff --git a/packages/uni-mp-qq/dist/uni.mp.esm.js b/packages/uni-mp-qq/dist/uni.mp.esm.js index 07b630412..64d1d3b87 100644 --- a/packages/uni-mp-qq/dist/uni.mp.esm.js +++ b/packages/uni-mp-qq/dist/uni.mp.esm.js @@ -52,28 +52,6 @@ const MP_METHODS = [ 'selectAllComponents', 'selectComponent' ]; -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'; - } - const hooks = this.$[name]; - let ret; - if (hooks) { - for (let i = 0; i < hooks.length; i++) { - ret = hooks[i](args); - } - } - return ret; -} function createEmitFn(oldEmit, ctx) { return function emit(event, ...args) { if (ctx.$scope && event) { @@ -82,9 +60,6 @@ function createEmitFn(oldEmit, ctx) { return oldEmit.apply(this, [event, ...args]); }; } -function set(target, key, val) { - return (target[key] = val); -} function initBaseInstance(instance, options) { const ctx = instance.ctx; // mp @@ -93,7 +68,9 @@ function initBaseInstance(instance, options) { ctx.$scope = options.mpInstance; // TODO @deprecated ctx.$mp = {}; - ctx._self = {}; + if (__VUE_OPTIONS_API__) { + ctx._self = {}; + } // $vm ctx.$scope.$vm = instance.proxy; // slots @@ -105,15 +82,8 @@ function initBaseInstance(instance, options) { }); } } - if (__VUE_OPTIONS_API__) { - // $set - ctx.$set = set; - } // $emit instance.emit = createEmitFn(instance.emit, ctx); - // $callHook - ctx.$hasHook = hasHook; - ctx.$callHook = callHook; } function initComponentInstance(instance, options) { initBaseInstance(instance, options); @@ -207,7 +177,7 @@ function parseApp(instance, parseAppOptions) { $vm: instance, onLaunch(options) { const ctx = internalInstance.ctx; - if (this.$vm && ctx.$callHook) { + if (this.$vm && ctx.$scope) { // 已经初始化过了,主要是为了百度,百度 onShow 在 onLaunch 之前 return; } @@ -238,6 +208,26 @@ function initCreateApp(parseAppOptions) { }; } +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 initBehavior(options) { return Behavior(options); } @@ -791,6 +781,13 @@ function parsePage(vueOptions, parseOptions) { 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('onLoad', query); + }; initHooks(methods, PAGE_HOOKS); initUnknownHooks(methods, vueOptions); parse && parse(miniProgramPageOptions, { handleLink }); diff --git a/packages/uni-mp-toutiao/dist/uni.api.esm.js b/packages/uni-mp-toutiao/dist/uni.api.esm.js index be898dda1..9d0ce5b12 100644 --- a/packages/uni-mp-toutiao/dist/uni.api.esm.js +++ b/packages/uni-mp-toutiao/dist/uni.api.esm.js @@ -1,5 +1,32 @@ import { isArray, isPromise, isFunction, isPlainObject, hasOwn, isString } from '@vue/shared'; +const API_TYPE_SYNC = 1; +function validateProtocol(_name, _args, _protocol) { + return true; +} +function formatApiArgs(args, options) { + if (!options) { + return args; + } +} +function createApi({ type, name, options }, fn, protocol) { + return function (...args) { + if (type === API_TYPE_SYNC) { + if (!((process.env.NODE_ENV !== 'production') && protocol && !validateProtocol())) { + return fn.apply(null, formatApiArgs(args, options)); + } + } + }; +} + +const Upx2pxProtocol = [ + { + name: 'upx', + type: [Number, String], + required: true + } +]; + const EPS = 1e-4; const BASE_DEVICE_WIDTH = 750; let isIOS = false; @@ -11,7 +38,7 @@ function checkDeviceWidth() { deviceDPR = pixelRatio; isIOS = platform === 'ios'; } -function upx2px(number, newDeviceWidth) { +const upx2px = createApi({ type: API_TYPE_SYNC, name: 'upx2px' }, (number, newDeviceWidth) => { if (deviceWidth === 0) { checkDeviceWidth(); } @@ -33,7 +60,7 @@ function upx2px(number, newDeviceWidth) { } } return number < 0 ? -result : result; -} +}, Upx2pxProtocol); var HOOKS; (function (HOOKS) { @@ -139,6 +166,15 @@ function invokeApi(method, api, options, ...params) { return api(options, ...params); } +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])) { @@ -184,15 +220,15 @@ function removeHook(hooks, hook) { hooks.splice(index, 1); } } -function addInterceptor(method, interceptor) { +const addInterceptor = createApi({ type: API_TYPE_SYNC, name: 'addInterceptor' }, (method, interceptor) => { if (typeof method === 'string' && isPlainObject(interceptor)) { mergeInterceptorHook(scopedInterceptors[method] || (scopedInterceptors[method] = {}), interceptor); } else if (isPlainObject(method)) { mergeInterceptorHook(globalInterceptors, method); } -} -function removeInterceptor(method, interceptor) { +}, AddInterceptorProtocol); +const removeInterceptor = createApi({ type: API_TYPE_SYNC, name: 'removeInterceptor' }, (method, interceptor) => { if (typeof method === 'string') { if (isPlainObject(interceptor)) { removeInterceptorHook(scopedInterceptors[method], interceptor); @@ -204,7 +240,7 @@ function removeInterceptor(method, interceptor) { else if (isPlainObject(method)) { removeInterceptorHook(globalInterceptors, method); } -} +}, RemoveInterceptorProtocol); 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$/; @@ -435,6 +471,19 @@ const previewImage = { loop: false }; } +}; +const redirectTo = {}; +const createCanvasContext = { + returnValue(fromRes, toRes) { + const measureText = fromRes.measureText; + toRes.measureText = function (text, callback) { + const textMetrics = measureText.call(this, text); + if (typeof callback === 'function') { + setTimeout(() => callback(textMetrics), 0); + } + return textMetrics; + }; + } }; const getProvider = initGetProvider({ @@ -536,7 +585,9 @@ var protocols = /*#__PURE__*/Object.freeze({ getUserInfo: getUserInfo, requestPayment: requestPayment, getFileInfo: getFileInfo, - previewImage: previewImage + redirectTo: redirectTo, + previewImage: previewImage, + createCanvasContext: createCanvasContext }); var index = initUni(shims, protocols); diff --git a/packages/uni-mp-toutiao/dist/uni.mp.esm.js b/packages/uni-mp-toutiao/dist/uni.mp.esm.js index d8cfc6a87..e88b77fbe 100644 --- a/packages/uni-mp-toutiao/dist/uni.mp.esm.js +++ b/packages/uni-mp-toutiao/dist/uni.mp.esm.js @@ -52,28 +52,6 @@ const MP_METHODS = [ 'selectAllComponents', 'selectComponent' ]; -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'; - } - const hooks = this.$[name]; - let ret; - if (hooks) { - for (let i = 0; i < hooks.length; i++) { - ret = hooks[i](args); - } - } - return ret; -} function createEmitFn(oldEmit, ctx) { return function emit(event, ...args) { if (ctx.$scope && event) { @@ -82,9 +60,6 @@ function createEmitFn(oldEmit, ctx) { return oldEmit.apply(this, [event, ...args]); }; } -function set(target, key, val) { - return (target[key] = val); -} function initBaseInstance(instance, options) { const ctx = instance.ctx; // mp @@ -93,7 +68,9 @@ function initBaseInstance(instance, options) { ctx.$scope = options.mpInstance; // TODO @deprecated ctx.$mp = {}; - ctx._self = {}; + if (__VUE_OPTIONS_API__) { + ctx._self = {}; + } // $vm ctx.$scope.$vm = instance.proxy; // slots @@ -105,15 +82,8 @@ function initBaseInstance(instance, options) { }); } } - if (__VUE_OPTIONS_API__) { - // $set - ctx.$set = set; - } // $emit instance.emit = createEmitFn(instance.emit, ctx); - // $callHook - ctx.$hasHook = hasHook; - ctx.$callHook = callHook; } function initComponentInstance(instance, options) { initBaseInstance(instance, options); @@ -210,7 +180,7 @@ function parseApp(instance, parseAppOptions) { $vm: instance, onLaunch(options) { const ctx = internalInstance.ctx; - if (this.$vm && ctx.$callHook) { + if (this.$vm && ctx.$scope) { // 已经初始化过了,主要是为了百度,百度 onShow 在 onLaunch 之前 return; } @@ -241,6 +211,26 @@ function initCreateApp(parseAppOptions) { }; } +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 initBehavior(options) { return Behavior(options); } @@ -800,6 +790,13 @@ function parsePage(vueOptions, parseOptions) { 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('onLoad', query); + }; initHooks(methods, PAGE_HOOKS); initUnknownHooks(methods, vueOptions); parse && parse(miniProgramPageOptions, { handleLink }); diff --git a/packages/uni-mp-vue/dist/vue.runtime.esm.js b/packages/uni-mp-vue/dist/vue.runtime.esm.js index f5735ef54..0846d821b 100644 --- a/packages/uni-mp-vue/dist/vue.runtime.esm.js +++ b/packages/uni-mp-vue/dist/vue.runtime.esm.js @@ -1,4 +1,4 @@ -import { EMPTY_OBJ, isArray, isSymbol, extend, hasOwn, isObject, hasChanged, capitalize, toRawType, def, makeMap, isFunction, NOOP, isString, isPromise, hyphenate, isOn, isReservedProp, camelize, EMPTY_ARR, remove, NO, isGloballyWhitelisted, toTypeString, invokeArrayFns } from '@vue/shared'; +import { isSymbol, extend, isMap, isObject, toRawType, def, isArray, isString, isFunction, isPromise, capitalize, remove, EMPTY_OBJ, NOOP, isGloballyWhitelisted, isIntegerKey, hasOwn, hasChanged, NO, invokeArrayFns, isSet, makeMap, hyphenate, isReservedProp, camelize, EMPTY_ARR, toTypeString, isOn } from '@vue/shared'; export { camelize } from '@vue/shared'; const targetMap = new WeakMap(); @@ -115,7 +115,7 @@ function trigger(target, type, key, newValue, oldValue, oldTarget) { const add = (effectsToAdd) => { if (effectsToAdd) { effectsToAdd.forEach(effect => { - if (effect !== activeEffect || !shouldTrack) { + if (effect !== activeEffect || effect.options.allowRecurse) { effects.add(effect); } }); @@ -139,14 +139,32 @@ function trigger(target, type, key, newValue, oldValue, oldTarget) { add(depsMap.get(key)); } // also run for iteration key on ADD | DELETE | Map.SET - const isAddOrDelete = type === "add" /* ADD */ || - (type === "delete" /* DELETE */ && !isArray(target)); - if (isAddOrDelete || - (type === "set" /* SET */ && target instanceof Map)) { - add(depsMap.get(isArray(target) ? 'length' : ITERATE_KEY)); - } - if (isAddOrDelete && target instanceof Map) { - add(depsMap.get(MAP_KEY_ITERATE_KEY)); + switch (type) { + case "add" /* ADD */: + if (!isArray(target)) { + add(depsMap.get(ITERATE_KEY)); + if (isMap(target)) { + add(depsMap.get(MAP_KEY_ITERATE_KEY)); + } + } + else if (isIntegerKey(key)) { + // new index added to array -> length changes + add(depsMap.get('length')); + } + break; + case "delete" /* DELETE */: + if (!isArray(target)) { + add(depsMap.get(ITERATE_KEY)); + if (isMap(target)) { + add(depsMap.get(MAP_KEY_ITERATE_KEY)); + } + } + break; + case "set" /* SET */: + if (isMap(target)) { + add(depsMap.get(ITERATE_KEY)); + } + break; } } const run = (effect) => { @@ -180,22 +198,32 @@ const readonlyGet = /*#__PURE__*/ createGetter(true); const shallowReadonlyGet = /*#__PURE__*/ createGetter(true, true); const arrayInstrumentations = {}; ['includes', 'indexOf', 'lastIndexOf'].forEach(key => { + const method = Array.prototype[key]; arrayInstrumentations[key] = function (...args) { const arr = toRaw(this); for (let i = 0, l = this.length; i < l; i++) { track(arr, "get" /* GET */, i + ''); } // we run the method using the original args first (which may be reactive) - const res = arr[key](...args); + const res = method.apply(arr, args); if (res === -1 || res === false) { // if that didn't work, run it again using raw values. - return arr[key](...args.map(toRaw)); + return method.apply(arr, args.map(toRaw)); } else { return res; } }; }); +['push', 'pop', 'shift', 'unshift', 'splice'].forEach(key => { + const method = Array.prototype[key]; + arrayInstrumentations[key] = function (...args) { + pauseTracking(); + const res = method.apply(this, args); + enableTracking(); + return res; + }; +}); function createGetter(isReadonly = false, shallow = false) { return function get(target, key, receiver) { if (key === "__v_isReactive" /* IS_REACTIVE */) { @@ -205,10 +233,7 @@ function createGetter(isReadonly = false, shallow = false) { return isReadonly; } else if (key === "__v_raw" /* RAW */ && - receiver === - (isReadonly - ? target["__v_readonly" /* READONLY */] - : target["__v_reactive" /* REACTIVE */])) { + receiver === (isReadonly ? readonlyMap : reactiveMap).get(target)) { return target; } const targetIsArray = isArray(target); @@ -216,7 +241,8 @@ function createGetter(isReadonly = false, shallow = false) { return Reflect.get(arrayInstrumentations, key, receiver); } const res = Reflect.get(target, key, receiver); - if (isSymbol(key) + const keyIsSymbol = isSymbol(key); + if (keyIsSymbol ? builtInSymbols.has(key) : key === `__proto__` || key === `__v_isRef`) { return res; @@ -228,8 +254,9 @@ function createGetter(isReadonly = false, shallow = false) { return res; } if (isRef(res)) { - // ref unwrapping, only for Objects, not for Arrays. - return targetIsArray ? res : res.value; + // ref unwrapping - does not apply for Array + integer key. + const shouldUnwrap = !targetIsArray || !isIntegerKey(key); + return shouldUnwrap ? res.value : res; } if (isObject(res)) { // Convert returned value into a proxy as well. we do the isObject check @@ -252,7 +279,9 @@ function createSetter(shallow = false) { return true; } } - const hadKey = hasOwn(target, key); + const hadKey = isArray(target) && isIntegerKey(key) + ? Number(key) < target.length + : hasOwn(target, key); const result = Reflect.set(target, key, value, receiver); // don't trigger if target is something up in the prototype chain of original if (target === toRaw(receiver)) { @@ -295,8 +324,6 @@ const mutableHandlers = { }; const readonlyHandlers = { get: readonlyGet, - has, - ownKeys, set(target, key) { if ((process.env.NODE_ENV !== 'production')) { console.warn(`Set operation on key "${String(key)}" failed: target is readonly.`, target); @@ -325,42 +352,48 @@ const toReactive = (value) => isObject(value) ? reactive(value) : value; const toReadonly = (value) => isObject(value) ? readonly(value) : value; const toShallow = (value) => value; const getProto = (v) => Reflect.getPrototypeOf(v); -function get$1(target, key, wrap) { - target = toRaw(target); +function get$1(target, key, isReadonly = false, isShallow = false) { + // #1772: readonly(reactive(Map)) should return readonly + reactive version + // of the value + target = target["__v_raw" /* RAW */]; + const rawTarget = toRaw(target); const rawKey = toRaw(key); if (key !== rawKey) { - track(target, "get" /* GET */, key); + !isReadonly && track(rawTarget, "get" /* GET */, key); } - track(target, "get" /* GET */, rawKey); - const { has, get } = getProto(target); - if (has.call(target, key)) { - return wrap(get.call(target, key)); + !isReadonly && track(rawTarget, "get" /* GET */, rawKey); + const { has } = getProto(rawTarget); + const wrap = isReadonly ? toReadonly : isShallow ? toShallow : toReactive; + if (has.call(rawTarget, key)) { + return wrap(target.get(key)); } - else if (has.call(target, rawKey)) { - return wrap(get.call(target, rawKey)); + else if (has.call(rawTarget, rawKey)) { + return wrap(target.get(rawKey)); } } -function has$1(key) { - const target = toRaw(this); +function has$1(key, isReadonly = false) { + const target = this["__v_raw" /* RAW */]; + const rawTarget = toRaw(target); const rawKey = toRaw(key); if (key !== rawKey) { - track(target, "has" /* HAS */, key); + !isReadonly && track(rawTarget, "has" /* HAS */, key); } - track(target, "has" /* HAS */, rawKey); - const has = getProto(target).has; - return has.call(target, key) || has.call(target, rawKey); + !isReadonly && track(rawTarget, "has" /* HAS */, rawKey); + return key === rawKey + ? target.has(key) + : target.has(key) || target.has(rawKey); } -function size(target) { - target = toRaw(target); - track(target, "iterate" /* ITERATE */, ITERATE_KEY); - return Reflect.get(getProto(target), 'size', target); +function size(target, isReadonly = false) { + target = target["__v_raw" /* RAW */]; + !isReadonly && track(toRaw(target), "iterate" /* ITERATE */, ITERATE_KEY); + return Reflect.get(target, 'size', target); } function add(value) { value = toRaw(value); const target = toRaw(this); const proto = getProto(target); const hadKey = proto.has.call(target, value); - const result = proto.add.call(target, value); + const result = target.add(value); if (!hadKey) { trigger(target, "add" /* ADD */, value, value); } @@ -369,7 +402,7 @@ function add(value) { function set$1(key, value) { value = toRaw(value); const target = toRaw(this); - const { has, get, set } = getProto(target); + const { has, get } = getProto(target); let hadKey = has.call(target, key); if (!hadKey) { key = toRaw(key); @@ -379,7 +412,7 @@ function set$1(key, value) { checkIdentityKeys(target, has, key); } const oldValue = get.call(target, key); - const result = set.call(target, key, value); + const result = target.set(key, value); if (!hadKey) { trigger(target, "add" /* ADD */, key, value); } @@ -390,7 +423,7 @@ function set$1(key, value) { } function deleteEntry(key) { const target = toRaw(this); - const { has, get, delete: del } = getProto(target); + const { has, get } = getProto(target); let hadKey = has.call(target, key); if (!hadKey) { key = toRaw(key); @@ -401,7 +434,7 @@ function deleteEntry(key) { } const oldValue = get ? get.call(target, key) : undefined; // forward the operation before queueing reactions - const result = del.call(target, key); + const result = target.delete(key); if (hadKey) { trigger(target, "delete" /* DELETE */, key, undefined, oldValue); } @@ -411,42 +444,43 @@ function clear() { const target = toRaw(this); const hadItems = target.size !== 0; const oldTarget = (process.env.NODE_ENV !== 'production') - ? target instanceof Map + ? isMap(target) ? new Map(target) : new Set(target) : undefined; // forward the operation before queueing reactions - const result = getProto(target).clear.call(target); + const result = target.clear(); if (hadItems) { trigger(target, "clear" /* CLEAR */, undefined, undefined, oldTarget); } return result; } -function createForEach(isReadonly, shallow) { +function createForEach(isReadonly, isShallow) { return function forEach(callback, thisArg) { const observed = this; - const target = toRaw(observed); - const wrap = isReadonly ? toReadonly : shallow ? toShallow : toReactive; - !isReadonly && track(target, "iterate" /* ITERATE */, ITERATE_KEY); - // important: create sure the callback is - // 1. invoked with the reactive map as `this` and 3rd arg - // 2. the value received should be a corresponding reactive/readonly. - function wrappedCallback(value, key) { + const target = observed["__v_raw" /* RAW */]; + const rawTarget = toRaw(target); + const wrap = isReadonly ? toReadonly : isShallow ? toShallow : toReactive; + !isReadonly && track(rawTarget, "iterate" /* ITERATE */, ITERATE_KEY); + return target.forEach((value, key) => { + // important: make sure the callback is + // 1. invoked with the reactive map as `this` and 3rd arg + // 2. the value received should be a corresponding reactive/readonly. return callback.call(thisArg, wrap(value), wrap(key), observed); - } - return getProto(target).forEach.call(target, wrappedCallback); + }); }; } -function createIterableMethod(method, isReadonly, shallow) { +function createIterableMethod(method, isReadonly, isShallow) { return function (...args) { - const target = toRaw(this); - const isMap = target instanceof Map; - const isPair = method === 'entries' || (method === Symbol.iterator && isMap); - const isKeyOnly = method === 'keys' && isMap; - const innerIterator = getProto(target)[method].apply(target, args); - const wrap = isReadonly ? toReadonly : shallow ? toShallow : toReactive; + const target = this["__v_raw" /* RAW */]; + const rawTarget = toRaw(target); + const targetIsMap = isMap(rawTarget); + const isPair = method === 'entries' || (method === Symbol.iterator && targetIsMap); + const isKeyOnly = method === 'keys' && targetIsMap; + const innerIterator = target[method](...args); + const wrap = isReadonly ? toReadonly : isShallow ? toShallow : toReactive; !isReadonly && - track(target, "iterate" /* ITERATE */, isKeyOnly ? MAP_KEY_ITERATE_KEY : ITERATE_KEY); + track(rawTarget, "iterate" /* ITERATE */, isKeyOnly ? MAP_KEY_ITERATE_KEY : ITERATE_KEY); // return a wrapped iterator which returns observed versions of the // values emitted from the real iterator return { @@ -478,7 +512,7 @@ function createReadonlyMethod(type) { } const mutableInstrumentations = { get(key) { - return get$1(this, key, toReactive); + return get$1(this, key); }, get size() { return size(this); @@ -492,7 +526,7 @@ const mutableInstrumentations = { }; const shallowInstrumentations = { get(key) { - return get$1(this, key, toShallow); + return get$1(this, key, false, true); }, get size() { return size(this); @@ -506,12 +540,14 @@ const shallowInstrumentations = { }; const readonlyInstrumentations = { get(key) { - return get$1(this, key, toReadonly); + return get$1(this, key, true); }, get size() { - return size(this); + return size(this, true); + }, + has(key) { + return has$1.call(this, key, true); }, - has: has$1, add: createReadonlyMethod("add" /* ADD */), set: createReadonlyMethod("set" /* SET */), delete: createReadonlyMethod("delete" /* DELETE */), @@ -566,13 +602,27 @@ function checkIdentityKeys(target, has, key) { } } -const collectionTypes = new Set([Set, Map, WeakMap, WeakSet]); -const isObservableType = /*#__PURE__*/ makeMap('Object,Array,Map,Set,WeakMap,WeakSet'); -const canObserve = (value) => { - return (!value["__v_skip" /* SKIP */] && - isObservableType(toRawType(value)) && - !Object.isFrozen(value)); -}; +const reactiveMap = new WeakMap(); +const readonlyMap = new WeakMap(); +function targetTypeMap(rawType) { + switch (rawType) { + case 'Object': + case 'Array': + return 1 /* COMMON */; + case 'Map': + case 'Set': + case 'WeakMap': + case 'WeakSet': + return 2 /* COLLECTION */; + default: + return 0 /* INVALID */; + } +} +function getTargetType(value) { + return value["__v_skip" /* SKIP */] || !Object.isExtensible(value) + ? 0 /* INVALID */ + : targetTypeMap(toRawType(value)); +} function reactive(target) { // if trying to observe a readonly proxy, return the readonly version. if (target && target["__v_isReadonly" /* IS_READONLY */]) { @@ -610,19 +660,19 @@ function createReactiveObject(target, isReadonly, baseHandlers, collectionHandle return target; } // target already has corresponding Proxy - const reactiveFlag = isReadonly - ? "__v_readonly" /* READONLY */ - : "__v_reactive" /* REACTIVE */; - if (hasOwn(target, reactiveFlag)) { - return target[reactiveFlag]; + const proxyMap = isReadonly ? readonlyMap : reactiveMap; + const existingProxy = proxyMap.get(target); + if (existingProxy) { + return existingProxy; } // only a whitelist of value types can be observed. - if (!canObserve(target)) { + const targetType = getTargetType(target); + if (targetType === 0 /* INVALID */) { return target; } - const observed = new Proxy(target, collectionTypes.has(target.constructor) ? collectionHandlers : baseHandlers); - def(target, reactiveFlag, observed); - return observed; + const proxy = new Proxy(target, targetType === 2 /* COLLECTION */ ? collectionHandlers : baseHandlers); + proxyMap.set(target, proxy); + return proxy; } function isReactive(value) { if (isReadonly(value)) { @@ -646,7 +696,7 @@ function markRaw(value) { const convert = (val) => isObject(val) ? reactive(val) : val; function isRef(r) { - return r ? r.__v_isRef === true : false; + return Boolean(r && r.__v_isRef === true); } function ref(value) { return createRef(value); @@ -654,68 +704,129 @@ function ref(value) { function shallowRef(value) { return createRef(value, true); } +class RefImpl { + constructor(_rawValue, _shallow = false) { + this._rawValue = _rawValue; + this._shallow = _shallow; + this.__v_isRef = true; + this._value = _shallow ? _rawValue : convert(_rawValue); + } + get value() { + track(toRaw(this), "get" /* GET */, 'value'); + return this._value; + } + set value(newVal) { + if (hasChanged(toRaw(newVal), this._rawValue)) { + this._rawValue = newVal; + this._value = this._shallow ? newVal : convert(newVal); + trigger(toRaw(this), "set" /* SET */, 'value', newVal); + } + } +} function createRef(rawValue, shallow = false) { if (isRef(rawValue)) { return rawValue; } - let value = shallow ? rawValue : convert(rawValue); - const r = { - __v_isRef: true, - get value() { - track(r, "get" /* GET */, 'value'); - return value; - }, - set value(newVal) { - if (hasChanged(toRaw(newVal), rawValue)) { - rawValue = newVal; - value = shallow ? newVal : convert(newVal); - trigger(r, "set" /* SET */, 'value', (process.env.NODE_ENV !== 'production') ? { newValue: newVal } : void 0); - } - } - }; - return r; + return new RefImpl(rawValue, shallow); } function triggerRef(ref) { - trigger(ref, "set" /* SET */, 'value', (process.env.NODE_ENV !== 'production') ? { newValue: ref.value } : void 0); + trigger(ref, "set" /* SET */, 'value', (process.env.NODE_ENV !== 'production') ? ref.value : void 0); } function unref(ref) { return isRef(ref) ? ref.value : ref; } -function customRef(factory) { - const { get, set } = factory(() => track(r, "get" /* GET */, 'value'), () => trigger(r, "set" /* SET */, 'value')); - const r = { - __v_isRef: true, - get value() { - return get(); - }, - set value(v) { - set(v); +const shallowUnwrapHandlers = { + get: (target, key, receiver) => unref(Reflect.get(target, key, receiver)), + set: (target, key, value, receiver) => { + const oldValue = target[key]; + if (isRef(oldValue) && !isRef(value)) { + oldValue.value = value; + return true; } - }; - return r; + else { + return Reflect.set(target, key, value, receiver); + } + } +}; +function proxyRefs(objectWithRefs) { + return isReactive(objectWithRefs) + ? objectWithRefs + : new Proxy(objectWithRefs, shallowUnwrapHandlers); +} +class CustomRefImpl { + constructor(factory) { + this.__v_isRef = true; + const { get, set } = factory(() => track(this, "get" /* GET */, 'value'), () => trigger(this, "set" /* SET */, 'value')); + this._get = get; + this._set = set; + } + get value() { + return this._get(); + } + set value(newVal) { + this._set(newVal); + } +} +function customRef(factory) { + return new CustomRefImpl(factory); } function toRefs(object) { if ((process.env.NODE_ENV !== 'production') && !isProxy(object)) { console.warn(`toRefs() expects a reactive object but received a plain one.`); } - const ret = {}; + const ret = isArray(object) ? new Array(object.length) : {}; for (const key in object) { ret[key] = toRef(object, key); } return ret; } +class ObjectRefImpl { + constructor(_object, _key) { + this._object = _object; + this._key = _key; + this.__v_isRef = true; + } + get value() { + return this._object[this._key]; + } + set value(newVal) { + this._object[this._key] = newVal; + } +} function toRef(object, key) { - return { - __v_isRef: true, - get value() { - return object[key]; - }, - set value(newVal) { - object[key] = newVal; - } - }; + return isRef(object[key]) + ? object[key] + : new ObjectRefImpl(object, key); } +class ComputedRefImpl { + constructor(getter, _setter, isReadonly) { + this._setter = _setter; + this._dirty = true; + this.__v_isRef = true; + this.effect = effect(getter, { + lazy: true, + scheduler: () => { + if (!this._dirty) { + this._dirty = true; + trigger(toRaw(this), "set" /* SET */, 'value'); + } + } + }); + this["__v_isReadonly" /* IS_READONLY */] = isReadonly; + } + get value() { + if (this._dirty) { + this._value = this.effect(); + this._dirty = false; + } + track(toRaw(this), "get" /* GET */, 'value'); + return this._value; + } + set value(newValue) { + this._setter(newValue); + } +} function computed(getterOrOptions) { let getter; let setter; @@ -731,36 +842,7 @@ function computed(getterOrOptions) { getter = getterOrOptions.get; setter = getterOrOptions.set; } - let dirty = true; - let value; - let computed; - const runner = effect(getter, { - lazy: true, - scheduler: () => { - if (!dirty) { - dirty = true; - trigger(computed, "set" /* SET */, 'value'); - } - } - }); - computed = { - __v_isRef: true, - ["__v_isReadonly" /* IS_READONLY */]: isFunction(getterOrOptions) || !getterOrOptions.set, - // expose effect so computed can be stopped - effect: runner, - get value() { - if (dirty) { - value = runner(); - dirty = false; - } - track(computed, "get" /* GET */, 'value'); - return value; - }, - set value(newValue) { - setter(newValue); - } - }; - return computed; + return new ComputedRefImpl(getter, setter, isFunction(getterOrOptions) || !getterOrOptions.set); } const stack = []; @@ -934,14 +1016,14 @@ function callWithAsyncErrorHandling(fn, instance, type, args) { } return values; } -function handleError(err, instance, type) { +function handleError(err, instance, type, throwInDev = true) { const contextVNode = instance ? instance.vnode : null; if (instance) { let cur = instance.parent; // the exposed instance is the render proxy to keep it consistent with 2.x const exposedInstance = instance.proxy; // in production the hook receives only the error code - const errorInfo = (process.env.NODE_ENV !== 'production') ? ErrorTypeStrings[type] || type : type; // fixed by xxxxxx + const errorInfo = (process.env.NODE_ENV !== 'production') ? ErrorTypeStrings[type] || type : type; // fixed by xxxxxxx while (cur) { const errorCapturedHooks = cur.ec; if (errorCapturedHooks) { @@ -960,91 +1042,146 @@ function handleError(err, instance, type) { return; } } - logError(err, type, contextVNode); + logError(err, type, contextVNode, throwInDev); } // fixed by xxxxxx -function logError(err, type, contextVNode) { - // default behavior is crash in prod & test, recover in dev. - if ((process.env.NODE_ENV !== 'production') && ( !false)) { +function logError(err, type, contextVNode, throwInDev = true) { + if ((process.env.NODE_ENV !== 'production')) { const info = ErrorTypeStrings[type] || type; // fixed by xxxxxx if (contextVNode) { pushWarningContext(contextVNode); } warn(`Unhandled error${info ? ` during execution of ${info}` : ``}`); - console.error(err); if (contextVNode) { popWarningContext(); } + // crash in dev by default so it's more noticeable + if (throwInDev) { + throw err; + } + else { + console.error(err); + } } else { - throw err; + // recover in prod to reduce the impact on end-user + console.error(err); } } -// fixed by xxxxxx -const queue = []; -const postFlushCbs = []; -const p = Promise.resolve(); let isFlushing = false; let isFlushPending = false; +// fixed by xxxxxx +const queue = []; let flushIndex = 0; -let pendingPostFlushCbs = null; -let pendingPostFlushIndex = 0; +const pendingPreFlushCbs = []; +let activePreFlushCbs = null; +let preFlushIndex = 0; +const pendingPostFlushCbs = []; +let activePostFlushCbs = null; +let postFlushIndex = 0; +const resolvedPromise = Promise.resolve(); +let currentFlushPromise = null; +let currentPreFlushParentJob = null; const RECURSION_LIMIT = 100; function nextTick(fn) { + const p = currentFlushPromise || resolvedPromise; return fn ? p.then(fn) : p; } function queueJob(job) { - if (!queue.includes(job, flushIndex)) { + // the dedupe search uses the startIndex argument of Array.includes() + // by default the search index includes the current job that is being run + // so it cannot recursively trigger itself again. + // if the job is a watch() callback, the search will start with a +1 index to + // allow it recursively trigger itself - it is the user's responsibility to + // ensure it doesn't end up in an infinite loop. + if ((!queue.length || + !queue.includes(job, isFlushing && job.allowRecurse ? flushIndex + 1 : flushIndex)) && + job !== currentPreFlushParentJob) { queue.push(job); queueFlush(); } } -function queuePostFlushCb(cb) { +function queueFlush() { + if (!isFlushing && !isFlushPending) { + isFlushPending = true; + currentFlushPromise = resolvedPromise.then(flushJobs); + } +} +function queueCb(cb, activeQueue, pendingQueue, index) { if (!isArray(cb)) { - if (!pendingPostFlushCbs || - !pendingPostFlushCbs.includes(cb, pendingPostFlushIndex)) { - postFlushCbs.push(cb); + if (!activeQueue || + !activeQueue.includes(cb, cb.allowRecurse ? index + 1 : index)) { + pendingQueue.push(cb); } } else { // if cb is an array, it is a component lifecycle hook which can only be // triggered by a job, which is already deduped in the main queue, so - // we can skip dupicate check here to improve perf - postFlushCbs.push(...cb); + // we can skip duplicate check here to improve perf + pendingQueue.push(...cb); } queueFlush(); } -function queueFlush() { - if (!isFlushing && !isFlushPending) { - isFlushPending = true; - nextTick(flushJobs); +function queuePreFlushCb(cb) { + queueCb(cb, activePreFlushCbs, pendingPreFlushCbs, preFlushIndex); +} +function queuePostFlushCb(cb) { + queueCb(cb, activePostFlushCbs, pendingPostFlushCbs, postFlushIndex); +} +function flushPreFlushCbs(seen, parentJob = null) { + if (pendingPreFlushCbs.length) { + currentPreFlushParentJob = parentJob; + activePreFlushCbs = [...new Set(pendingPreFlushCbs)]; + pendingPreFlushCbs.length = 0; + if ((process.env.NODE_ENV !== 'production')) { + seen = seen || new Map(); + } + for (preFlushIndex = 0; preFlushIndex < activePreFlushCbs.length; preFlushIndex++) { + if ((process.env.NODE_ENV !== 'production')) { + checkRecursiveUpdates(seen, activePreFlushCbs[preFlushIndex]); + } + activePreFlushCbs[preFlushIndex](); + } + activePreFlushCbs = null; + preFlushIndex = 0; + currentPreFlushParentJob = null; + // recursively flush until it drains + flushPreFlushCbs(seen, parentJob); } } function flushPostFlushCbs(seen) { - if (postFlushCbs.length) { - pendingPostFlushCbs = [...new Set(postFlushCbs)]; - postFlushCbs.length = 0; + if (pendingPostFlushCbs.length) { + const deduped = [...new Set(pendingPostFlushCbs)]; + pendingPostFlushCbs.length = 0; + // #1947 already has active queue, nested flushPostFlushCbs call + if (activePostFlushCbs) { + activePostFlushCbs.push(...deduped); + return; + } + activePostFlushCbs = deduped; if ((process.env.NODE_ENV !== 'production')) { seen = seen || new Map(); } - for (pendingPostFlushIndex = 0; pendingPostFlushIndex < pendingPostFlushCbs.length; pendingPostFlushIndex++) { + activePostFlushCbs.sort((a, b) => getId(a) - getId(b)); + for (postFlushIndex = 0; postFlushIndex < activePostFlushCbs.length; postFlushIndex++) { if ((process.env.NODE_ENV !== 'production')) { - checkRecursiveUpdates(seen, pendingPostFlushCbs[pendingPostFlushIndex]); + checkRecursiveUpdates(seen, activePostFlushCbs[postFlushIndex]); } - pendingPostFlushCbs[pendingPostFlushIndex](); + activePostFlushCbs[postFlushIndex](); } - pendingPostFlushCbs = null; - pendingPostFlushIndex = 0; + activePostFlushCbs = null; + postFlushIndex = 0; } } -const getId = (job) => (job.id == null ? Infinity : job.id); +const getId = (job) => job.id == null ? Infinity : job.id; function flushJobs(seen) { isFlushPending = false; isFlushing = true; if ((process.env.NODE_ENV !== 'production')) { seen = seen || new Map(); } + flushPreFlushCbs(seen); // Sort queue before flush. // This ensures that: // 1. Components are updated from parent to child. (because parent is always @@ -1055,23 +1192,28 @@ function flushJobs(seen) { // Jobs can never be null before flush starts, since they are only invalidated // during execution of another flushed job. queue.sort((a, b) => getId(a) - getId(b)); - for (flushIndex = 0; flushIndex < queue.length; flushIndex++) { - const job = queue[flushIndex]; - if (job) { - if ((process.env.NODE_ENV !== 'production')) { - checkRecursiveUpdates(seen, job); + try { + for (flushIndex = 0; flushIndex < queue.length; flushIndex++) { + const job = queue[flushIndex]; + if (job) { + if ((process.env.NODE_ENV !== 'production')) { + checkRecursiveUpdates(seen, job); + } + callWithErrorHandling(job, null, 14 /* SCHEDULER */); } - callWithErrorHandling(job, null, 14 /* SCHEDULER */); } } - flushIndex = 0; - queue.length = 0; - flushPostFlushCbs(seen); - isFlushing = false; - // some postFlushCb queued jobs! - // keep flushing until it drains. - if (queue.length || postFlushCbs.length) { - flushJobs(seen); + finally { + flushIndex = 0; + queue.length = 0; + flushPostFlushCbs(seen); + isFlushing = false; + currentFlushPromise = null; + // some postFlushCb queued jobs! + // keep flushing until it drains. + if (queue.length || pendingPostFlushCbs.length) { + flushJobs(seen); + } } } function checkRecursiveUpdates(seen, fn) { @@ -1081,9 +1223,11 @@ function checkRecursiveUpdates(seen, fn) { else { const count = seen.get(fn); if (count > RECURSION_LIMIT) { - throw new Error('Maximum recursive updates exceeded. ' + - "You may have code that is mutating state in your component's " + - 'render function or updated hook or watcher source function.'); + throw new Error(`Maximum recursive updates exceeded. ` + + `This means you have a reactive effect that is mutating its own ` + + `dependencies and thus recursively triggering itself. Possible sources ` + + `include component template, render function, updated hook or ` + + `watcher source function.`); } else { seen.set(fn, count + 1); @@ -1091,26 +1235,19 @@ function checkRecursiveUpdates(seen, fn) { } } -// mark the current rendering instance for asset resolution (e.g. -// resolveComponent, resolveDirective) during render -let currentRenderingInstance = null; -function markAttrsAccessed() { -} - function emit(instance, event, ...args) { const props = instance.vnode.props || EMPTY_OBJ; if ((process.env.NODE_ENV !== 'production')) { - const options = normalizeEmitsOptions(instance.type); - if (options) { - if (!(event in options)) { - const propsOptions = normalizePropsOptions(instance.type)[0]; + const { emitsOptions, propsOptions: [propsOptions] } = instance; + if (emitsOptions) { + if (!(event in emitsOptions)) { if (!propsOptions || !(`on` + capitalize(event) in propsOptions)) { warn(`Component emitted event "${event}" but it is neither declared in ` + `the emits option nor as an "on${capitalize(event)}" prop.`); } } else { - const validator = options[event]; + const validator = emitsOptions[event]; if (isFunction(validator)) { const isValid = validator(...args); if (!isValid) { @@ -1120,6 +1257,7 @@ function emit(instance, event, ...args) { } } } + if ((process.env.NODE_ENV !== 'production') || false) ; let handlerName = `on${capitalize(event)}`; let handler = props[handlerName]; // for v-model update:xxx events, also trigger kebab-case equivalent @@ -1141,26 +1279,34 @@ function emit(instance, event, ...args) { callWithAsyncErrorHandling(handler, instance, 6 /* COMPONENT_EVENT_HANDLER */, args); } } -function normalizeEmitsOptions(comp) { - if (hasOwn(comp, '__emits')) { - return comp.__emits; +function normalizeEmitsOptions(comp, appContext, asMixin = false) { + const appId = appContext.app ? appContext.app._uid : -1; + const cache = comp.__emits || (comp.__emits = {}); + const cached = cache[appId]; + if (cached !== undefined) { + return cached; } const raw = comp.emits; let normalized = {}; // apply mixin/extends props let hasExtends = false; if (__VUE_OPTIONS_API__ && !isFunction(comp)) { - if (comp.extends) { + const extendEmits = (raw) => { hasExtends = true; - extend(normalized, normalizeEmitsOptions(comp.extends)); + extend(normalized, normalizeEmitsOptions(raw, appContext, true)); + }; + if (!asMixin && appContext.mixins.length) { + appContext.mixins.forEach(extendEmits); + } + if (comp.extends) { + extendEmits(comp.extends); } if (comp.mixins) { - hasExtends = true; - comp.mixins.forEach(m => extend(normalized, normalizeEmitsOptions(m))); + comp.mixins.forEach(extendEmits); } } if (!raw && !hasExtends) { - return (comp.__emits = undefined); + return (cache[appId] = null); } if (isArray(raw)) { raw.forEach(key => (normalized[key] = null)); @@ -1168,31 +1314,36 @@ function normalizeEmitsOptions(comp) { else { extend(normalized, raw); } - return (comp.__emits = normalized); + return (cache[appId] = normalized); } // Check if an incoming prop key is a declared emit event listener. // e.g. With `emits: { click: null }`, props named `onClick` and `onclick` are // both considered matched listeners. -function isEmitListener(comp, key) { - let emits; - if (!isOn(key) || !(emits = normalizeEmitsOptions(comp))) { +function isEmitListener(options, key) { + if (!options || !isOn(key)) { return false; } key = key.replace(/Once$/, ''); - return (hasOwn(emits, key[2].toLowerCase() + key.slice(3)) || - hasOwn(emits, key.slice(2))); + return (hasOwn(options, key[2].toLowerCase() + key.slice(3)) || + hasOwn(options, key.slice(2))); +} + +// mark the current rendering instance for asset resolution (e.g. +// resolveComponent, resolveDirective) during render +let currentRenderingInstance = null; +function markAttrsAccessed() { } function initProps(instance, rawProps, isStateful, // result of bitwise flag comparison isSSR = false) { const props = {}; const attrs = {}; - // def(attrs, InternalObjectKey, 1) // fixed by xxxxx + // def(attrs, InternalObjectKey, 1) // fixed by xxxxxx def(attrs, '__vInternal', 1); setFullProps(instance, rawProps, props, attrs); // validation if ((process.env.NODE_ENV !== 'production')) { - validateProps(props, instance.type); + validateProps(props, instance); } if (isStateful) { // stateful @@ -1211,7 +1362,7 @@ isSSR = false) { instance.attrs = attrs; } function setFullProps(instance, rawProps, props, attrs) { - const [options, needCastKeys] = normalizePropsOptions(instance.type); + const [options, needCastKeys] = instance.propsOptions; if (rawProps) { for (const key in rawProps) { const value = rawProps[key]; @@ -1225,7 +1376,7 @@ function setFullProps(instance, rawProps, props, attrs) { if (options && hasOwn(options, (camelKey = camelize(key)))) { props[camelKey] = value; } - else if (!isEmitListener(instance.type, key)) { + else if (!isEmitListener(instance.emitsOptions, key)) { // Any non-declared (either as a prop or an emitted event) props are put // into a separate `attrs` object for spreading. Make sure to preserve // original key casing @@ -1237,21 +1388,25 @@ function setFullProps(instance, rawProps, props, attrs) { const rawCurrentProps = toRaw(props); for (let i = 0; i < needCastKeys.length; i++) { const key = needCastKeys[i]; - props[key] = resolvePropValue(options, rawCurrentProps, key, rawCurrentProps[key]); + props[key] = resolvePropValue(options, rawCurrentProps, key, rawCurrentProps[key], instance); } } } -function resolvePropValue(options, props, key, value) { +function resolvePropValue(options, props, key, value, instance) { const opt = options[key]; if (opt != null) { const hasDefault = hasOwn(opt, 'default'); // default values if (hasDefault && value === undefined) { const defaultValue = opt.default; - value = - opt.type !== Function && isFunction(defaultValue) - ? defaultValue() - : defaultValue; + if (opt.type !== Function && isFunction(defaultValue)) { + setCurrentInstance(instance); + value = defaultValue(props); + setCurrentInstance(null); + } + else { + value = defaultValue; + } } // boolean casting if (opt[0 /* shouldCast */]) { @@ -1266,9 +1421,12 @@ function resolvePropValue(options, props, key, value) { } return value; } -function normalizePropsOptions(comp) { - if (comp.__props) { - return comp.__props; +function normalizePropsOptions(comp, appContext, asMixin = false) { + const appId = appContext.app ? appContext.app._uid : -1; + const cache = comp.__props || (comp.__props = {}); + const cached = cache[appId]; + if (cached) { + return cached; } const raw = comp.props; const normalized = {}; @@ -1277,22 +1435,24 @@ function normalizePropsOptions(comp) { let hasExtends = false; if (__VUE_OPTIONS_API__ && !isFunction(comp)) { const extendProps = (raw) => { - const [props, keys] = normalizePropsOptions(raw); + hasExtends = true; + const [props, keys] = normalizePropsOptions(raw, appContext, true); extend(normalized, props); if (keys) needCastKeys.push(...keys); }; + if (!asMixin && appContext.mixins.length) { + appContext.mixins.forEach(extendProps); + } if (comp.extends) { - hasExtends = true; extendProps(comp.extends); } if (comp.mixins) { - hasExtends = true; comp.mixins.forEach(extendProps); } } if (!raw && !hasExtends) { - return (comp.__props = EMPTY_ARR); + return (cache[appId] = EMPTY_ARR); } if (isArray(raw)) { for (let i = 0; i < raw.length; i++) { @@ -1329,9 +1489,7 @@ function normalizePropsOptions(comp) { } } } - const normalizedEntry = [normalized, needCastKeys]; - comp.__props = normalizedEntry; - return normalizedEntry; + return (cache[appId] = [normalized, needCastKeys]); } // use function string name to check type constructors // so that it works across vms / iframes. @@ -1358,9 +1516,9 @@ function getTypeIndex(type, expectedTypes) { /** * dev only */ -function validateProps(props, comp) { +function validateProps(props, instance) { const rawValues = toRaw(props); - const options = normalizePropsOptions(comp)[0]; + const options = instance.propsOptions[0]; for (const key in options) { let opt = options[key]; if (opt == null) @@ -1431,7 +1589,7 @@ function assertType(value, type) { } } else if (expectedType === 'Object') { - valid = toRawType(value) === 'Object'; + valid = isObject(value); } else if (expectedType === 'Array') { valid = isArray(value); @@ -1524,6 +1682,7 @@ function injectHook(type, hook, target = currentInstance, prepend = false) { else { hooks.push(wrappedHook); } + return wrappedHook; } else if ((process.env.NODE_ENV !== 'production')) { const apiName = `on${capitalize(ErrorTypeStrings[type].replace(/ hook$/, ''))}`; @@ -1588,9 +1747,11 @@ function registerKeepAliveHook(hook, type, target = currentInstance) { } } function injectToKeepAliveRoot(hook, type, target, keepAliveRoot) { - injectHook(type, hook, keepAliveRoot, true /* prepend */); + // injectHook wraps the original for error handling, so make sure to remove + // the wrapped version. + const injected = injectHook(type, hook, keepAliveRoot, true /* prepend */); onUnmounted(() => { - remove(keepAliveRoot[type], hook); + remove(keepAliveRoot[type], injected); }, target); } @@ -1631,6 +1792,7 @@ function createAppContext() { provides: Object.create(null) }; } +let uid$1 = 0; // fixed by xxxxxx function createAppAPI() { return function createApp(rootComponent, rootProps = null) { @@ -1643,6 +1805,7 @@ function createAppAPI() { // fixed by xxxxxx // let isMounted = false const app = (context.app = { + _uid: uid$1++, _component: rootComponent, _props: rootProps, _container: null, @@ -1767,7 +1930,8 @@ function doWatch(source, cb, { immediate, deep, flush, onTrack, onTrigger } = EM `a reactive object, or an array of these types.`); }; let getter; - if (isRef(source)) { + const isRefSource = isRef(source); + if (isRefSource) { getter = () => source.value; } else if (isReactive(source)) { @@ -1830,7 +1994,7 @@ function doWatch(source, cb, { immediate, deep, flush, onTrack, onTrigger } = EM if (cb) { // watch(source, cb) const newValue = runner(); - if (deep || hasChanged(newValue, oldValue)) { + if (deep || isRefSource || hasChanged(newValue, oldValue)) { // cleanup before running cb again if (cleanup) { cleanup(); @@ -1849,16 +2013,21 @@ function doWatch(source, cb, { immediate, deep, flush, onTrack, onTrigger } = EM runner(); } }; + // important: mark the job as a watcher callback so that scheduler knows it + // it is allowed to self-trigger (#1727) + job.allowRecurse = !!cb; let scheduler; if (flush === 'sync') { scheduler = job; } - else if (flush === 'pre') { - // ensure it's queued before component updates (which have positive ids) - job.id = -1; + else if (flush === 'post') { + scheduler = () => queuePostRenderEffect(job, instance && instance.suspense); + } + else { + // default: 'pre' scheduler = () => { if (!instance || instance.isMounted) { - queueJob(job); + queuePreFlushCb(job); } else { // with 'pre' option, the first call must happen before @@ -1867,9 +2036,6 @@ function doWatch(source, cb, { immediate, deep, flush, onTrack, onTrigger } = EM } }; } - else { - scheduler = () => queuePostRenderEffect(job, instance && instance.suspense); - } const runner = effect(getter, { lazy: true, onTrack, @@ -1886,6 +2052,9 @@ function doWatch(source, cb, { immediate, deep, flush, onTrack, onTrigger } = EM oldValue = runner(); } } + else if (flush === 'post') { + queuePostRenderEffect(runner, instance && instance.suspense); + } else { runner(); } @@ -1909,18 +2078,21 @@ function traverse(value, seen = new Set()) { return value; } seen.add(value); - if (isArray(value)) { + if (isRef(value)) { + traverse(value.value, seen); + } + else if (isArray(value)) { for (let i = 0; i < value.length; i++) { traverse(value[i], seen); } } - else if (value instanceof Map) { - value.forEach((v, key) => { + else if (isMap(value)) { + value.forEach((_, key) => { // to register mutation dep for existing keys traverse(value.get(key), seen); }); } - else if (value instanceof Set) { + else if (isSet(value)) { value.forEach(v => { traverse(v, seen); }); @@ -1954,7 +2126,7 @@ function provide(key, value) { provides[key] = value; } } -function inject(key, defaultValue) { +function inject(key, defaultValue, treatDefaultAsFactory = false) { // fallback to `currentRenderingInstance` so that this can be called in // a functional component const instance = currentInstance || currentRenderingInstance; @@ -1965,7 +2137,9 @@ function inject(key, defaultValue) { return provides[key]; } else if (arguments.length > 1) { - return defaultValue; + return treatDefaultAsFactory && isFunction(defaultValue) + ? defaultValue() + : defaultValue; } else if ((process.env.NODE_ENV !== 'production')) { warn(`injection "${String(key)}" not found.`); @@ -1987,21 +2161,28 @@ function createDuplicateChecker() { } }; } +let isInBeforeCreate = false; function applyOptions(instance, options, deferredData = [], deferredWatch = [], asMixin = false) { const { // composition mixins, extends: extendsOptions, // state data: dataOptions, computed: computedOptions, methods, watch: watchOptions, provide: provideOptions, inject: injectOptions, + // assets + components, directives, // lifecycle - beforeMount, mounted, beforeUpdate, updated, activated, deactivated, beforeUnmount, unmounted, renderTracked, renderTriggered, errorCaptured } = options; + beforeMount, mounted, beforeUpdate, updated, activated, deactivated, beforeDestroy, beforeUnmount, destroyed, unmounted, render, renderTracked, renderTriggered, errorCaptured } = options; const publicThis = instance.proxy; const ctx = instance.ctx; const globalMixins = instance.appContext.mixins; - // call it only during dev + if (asMixin && render && instance.render === NOOP) { + instance.render = render; + } // applyOptions is called non-as-mixin once per instance if (!asMixin) { + isInBeforeCreate = true; callSyncHook('beforeCreate', options, publicThis, globalMixins); + isInBeforeCreate = false; // global mixins are applied first applyMixins(instance, globalMixins, deferredData, deferredWatch); } @@ -2015,7 +2196,7 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], } const checkDuplicateProperties = (process.env.NODE_ENV !== 'production') ? createDuplicateChecker() : null; if ((process.env.NODE_ENV !== 'production')) { - const propsOptions = normalizePropsOptions(options)[0]; + const [propsOptions] = instance.propsOptions; if (propsOptions) { for (const key in propsOptions) { checkDuplicateProperties("Props" /* PROPS */, key); @@ -2044,7 +2225,7 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], for (const key in injectOptions) { const opt = injectOptions[key]; if (isObject(opt)) { - ctx[key] = inject(opt.from, opt.default); + ctx[key] = inject(opt.from || key, opt.default, true /* treat default function as factory */); } else { ctx[key] = inject(opt); @@ -2070,22 +2251,13 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], } } } - if (dataOptions) { - if ((process.env.NODE_ENV !== 'production') && !isFunction(dataOptions)) { - warn(`The data option must be a function. ` + - `Plain object usage is no longer supported.`); - } - if (asMixin) { - deferredData.push(dataOptions); - } - else { - resolveData(instance, dataOptions, publicThis); - } - } if (!asMixin) { if (deferredData.length) { deferredData.forEach(dataFn => resolveData(instance, dataFn, publicThis)); } + if (dataOptions) { + resolveData(instance, dataOptions, publicThis); + } if ((process.env.NODE_ENV !== 'production')) { const rawData = toRaw(instance.data); for (const key in rawData) { @@ -2102,6 +2274,9 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], } } } + else if (dataOptions) { + deferredData.push(dataOptions); + } if (computedOptions) { for (const key in computedOptions) { const opt = computedOptions[key]; @@ -2154,6 +2329,19 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], provide(key, provides[key]); } } + // asset options. + // To reduce memory usage, only components with mixins or extends will have + // resolved asset registry attached to instance. + if (asMixin) { + if (components) { + extend(instance.components || + (instance.components = extend({}, instance.type.components)), components); + } + if (directives) { + extend(instance.directives || + (instance.directives = extend({}, instance.type.directives)), directives); + } + } // fixed by xxxxxx // lifecycle options if (__VUE_CREATED_DEFERRED__) { @@ -2191,9 +2379,15 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], if (renderTriggered) { onRenderTriggered(renderTriggered.bind(publicThis)); } + if ((process.env.NODE_ENV !== 'production') && beforeDestroy) { + warn(`\`beforeDestroy\` has been renamed to \`beforeUnmount\`.`); + } if (beforeUnmount) { onBeforeUnmount(beforeUnmount.bind(publicThis)); } + if ((process.env.NODE_ENV !== 'production') && destroyed) { + warn(`\`destroyed\` has been renamed to \`unmounted\`.`); + } if (unmounted) { onUnmounted(unmounted.bind(publicThis)); } @@ -2204,11 +2398,10 @@ function applyOptions(instance, options, deferredData = [], deferredWatch = [], } function callSyncHook(name, options, ctx, globalMixins) { callHookFromMixins(name, globalMixins, ctx); - const baseHook = options.extends && options.extends[name]; - if (baseHook) { - baseHook.call(ctx); + const { extends: base, mixins } = options; + if (base) { + callHookFromExtends(name, base, ctx); } - const mixins = options.mixins; if (mixins) { callHookFromMixins(name, mixins, ctx); } @@ -2217,8 +2410,21 @@ function callSyncHook(name, options, ctx, globalMixins) { selfHook.call(ctx); } } +function callHookFromExtends(name, base, ctx) { + if (base.extends) { + callHookFromExtends(name, base.extends, ctx); + } + const baseHook = base[name]; + if (baseHook) { + baseHook.call(ctx); + } +} function callHookFromMixins(name, mixins, ctx) { for (let i = 0; i < mixins.length; i++) { + const chainedMixins = mixins[i].mixins; + if (chainedMixins) { + callHookFromMixins(name, chainedMixins, ctx); + } const fn = mixins[i][name]; if (fn) { fn.call(ctx); @@ -2231,6 +2437,10 @@ function applyMixins(instance, mixins, deferredData, deferredWatch) { } } function resolveData(instance, dataFn, publicThis) { + if ((process.env.NODE_ENV !== 'production') && !isFunction(dataFn)) { + warn(`The data option must be a function. ` + + `Plain object usage is no longer supported.`); + } const data = dataFn.call(publicThis, publicThis); if ((process.env.NODE_ENV !== 'production') && isPromise(data)) { warn(`data() returned a Promise - note data() cannot be async; If you ` + @@ -2249,7 +2459,9 @@ function resolveData(instance, dataFn, publicThis) { } } function createWatcher(raw, ctx, publicThis, key) { - const getter = () => publicThis[key]; + const getter = key.includes('.') + ? createPathGetter(publicThis, key) + : () => publicThis[key]; if (isString(raw)) { const handler = ctx[raw]; if (isFunction(handler)) { @@ -2267,13 +2479,31 @@ function createWatcher(raw, ctx, publicThis, key) { raw.forEach(r => createWatcher(r, ctx, publicThis, key)); } else { - watch(getter, raw.handler.bind(publicThis), raw); + const handler = isFunction(raw.handler) + ? raw.handler.bind(publicThis) + : ctx[raw.handler]; + if (isFunction(handler)) { + watch(getter, handler, raw); + } + else if ((process.env.NODE_ENV !== 'production')) { + warn(`Invalid watch handler specified by key "${raw.handler}"`, handler); + } } } else if ((process.env.NODE_ENV !== 'production')) { - warn(`Invalid watch option: "${key}"`); + warn(`Invalid watch option: "${key}"`, raw); } } +function createPathGetter(ctx, path) { + const segments = path.split('.'); + return () => { + let cur = ctx; + for (let i = 0; i < segments.length && cur; i++) { + cur = cur[segments[i]]; + } + return cur; + }; +} function resolveMergedOptions(instance) { const raw = instance.type; const { __merged, mixins, extends: extendsOptions } = raw; @@ -2284,18 +2514,20 @@ function resolveMergedOptions(instance) { return raw; const options = {}; globalMixins.forEach(m => mergeOptions(options, m, instance)); - extendsOptions && mergeOptions(options, extendsOptions, instance); - mixins && mixins.forEach(m => mergeOptions(options, m, instance)); mergeOptions(options, raw, instance); return (raw.__merged = options); } function mergeOptions(to, from, instance) { const strats = instance.appContext.config.optionMergeStrategies; + const { mixins, extends: extendsOptions } = from; + extendsOptions && mergeOptions(to, extendsOptions, instance); + mixins && + mixins.forEach((m) => mergeOptions(to, m, instance)); for (const key in from) { if (strats && hasOwn(strats, key)) { to[key] = strats[key](to[key], from[key], instance.proxy, key); } - else if (!hasOwn(to, key)) { + else { to[key] = from[key]; } } @@ -2357,7 +2589,7 @@ const PublicInstanceProxyHandlers = { else if ( // only cache other properties when instance has declared (thus stable) // props - (normalizedProps = normalizePropsOptions(type)[0]) && + (normalizedProps = instance.propsOptions[0]) && hasOwn(normalizedProps, key)) { accessCache[key] = 2 /* PROPS */; return props[key]; @@ -2366,7 +2598,7 @@ const PublicInstanceProxyHandlers = { accessCache[key] = 3 /* CONTEXT */; return ctx[key]; } - else { + else if (!__VUE_OPTIONS_API__ || !isInBeforeCreate) { accessCache[key] = 4 /* OTHER */; } } @@ -2399,12 +2631,15 @@ const PublicInstanceProxyHandlers = { } else if ((process.env.NODE_ENV !== 'production') && currentRenderingInstance && - // #1091 avoid internal isRef/isVNode checks on component instance leading - // to infinite warning loop - key.indexOf('__v') !== 0) { - if (data !== EMPTY_OBJ && key[0] === '$' && hasOwn(data, key)) { + (!isString(key) || + // #1091 avoid internal isRef/isVNode checks on component instance leading + // to infinite warning loop + key.indexOf('__v') !== 0)) { + if (data !== EMPTY_OBJ && + (key[0] === '$' || key[0] === '_') && + hasOwn(data, key)) { warn(`Property ${JSON.stringify(key)} must be accessed via $data because it starts with a reserved ` + - `character and is not proxied on the render context.`); + `character ("$" or "_") and is not proxied on the render context.`); } else { warn(`Property ${JSON.stringify(key)} was accessed during render ` + @@ -2445,13 +2680,12 @@ const PublicInstanceProxyHandlers = { } return true; }, - has({ _: { data, setupState, accessCache, ctx, type, appContext } }, key) { + has({ _: { data, setupState, accessCache, ctx, appContext, propsOptions } }, key) { let normalizedProps; return (accessCache[key] !== undefined || (data !== EMPTY_OBJ && hasOwn(data, key)) || (setupState !== EMPTY_OBJ && hasOwn(setupState, key)) || - ((normalizedProps = normalizePropsOptions(type)[0]) && - hasOwn(normalizedProps, key)) || + ((normalizedProps = propsOptions[0]) && hasOwn(normalizedProps, key)) || hasOwn(ctx, key) || hasOwn(publicPropertiesMap, key) || hasOwn(appContext.config.globalProperties, key)); @@ -2516,8 +2750,7 @@ function createRenderContext(instance) { } // dev only function exposePropsOnRenderContext(instance) { - const { ctx, type } = instance; - const propsOptions = normalizePropsOptions(type)[0]; + const { ctx, propsOptions: [propsOptions] } = instance; if (propsOptions) { Object.keys(propsOptions).forEach(key => { Object.defineProperty(ctx, key, { @@ -2533,6 +2766,11 @@ function exposePropsOnRenderContext(instance) { function exposeSetupStateOnRenderContext(instance) { const { ctx, setupState } = instance; Object.keys(toRaw(setupState)).forEach(key => { + if (key[0] === '$' || key[0] === '_') { + warn(`setup() return property ${JSON.stringify(key)} should not start with "$" or "_" ` + + `which are reserved prefixes for Vue internals.`); + return; + } Object.defineProperty(ctx, key, { enumerable: true, configurable: true, @@ -2543,13 +2781,13 @@ function exposeSetupStateOnRenderContext(instance) { } const emptyAppContext = createAppContext(); -let uid$1 = 0; +let uid$2 = 0; function createComponentInstance(vnode, parent, suspense) { const type = vnode.type; // inherit parent app context - or - if root, adopt from root vnode const appContext = (parent ? parent.appContext : vnode.appContext) || emptyAppContext; const instance = { - uid: uid$1++, + uid: uid$2++, vnode, type, parent, @@ -2565,6 +2803,15 @@ function createComponentInstance(vnode, parent, suspense) { provides: parent ? parent.provides : Object.create(appContext.provides), accessCache: null, renderCache: [], + // local resovled assets + components: null, + directives: null, + // resolved props and emits options + propsOptions: normalizePropsOptions(type, appContext), + emitsOptions: normalizeEmitsOptions(type, appContext), + // emit + emit: null, + emitted: null, // state ctx: EMPTY_OBJ, data: EMPTY_OBJ, @@ -2576,6 +2823,7 @@ function createComponentInstance(vnode, parent, suspense) { setupContext: null, // suspense related suspense, + suspenseId: suspense ? suspense.pendingId : 0, asyncDep: null, asyncResolved: false, // lifecycle hooks @@ -2595,9 +2843,7 @@ function createComponentInstance(vnode, parent, suspense) { a: null, rtg: null, rtc: null, - ec: null, - emit: null, - emitted: null + ec: null }; if ((process.env.NODE_ENV !== 'production')) { instance.ctx = createRenderContext(instance); @@ -2705,7 +2951,10 @@ function handleSetupResult(instance, setupResult, isSSR) { // } // setup returned bindings. // assuming a render function compiled from template is present. - instance.setupState = reactive(setupResult); + if ((process.env.NODE_ENV !== 'production') || false) { + instance.devtoolsRawSetupState = setupResult; + } + instance.setupState = proxyRefs(setupResult); if ((process.env.NODE_ENV !== 'production')) { exposeSetupStateOnRenderContext(instance); } @@ -2719,18 +2968,6 @@ function finishComponentSetup(instance, isSSR) { const Component = instance.type; // template / render function normalization if (!instance.render) { - if ((process.env.NODE_ENV !== 'production') && !Component.render) { - /* istanbul ignore if */ - if ( Component.template) { - warn(`Component provided template option but ` + - `runtime compilation is not supported in this build of Vue.` + - ( ` Configure your bundler to alias "vue" to "vue/dist/vue.esm-bundler.js".` - ) /* should not happen */); - } - else { - warn(`Component is missing template or render function.`); - } - } instance.render = (Component.render || NOOP); // for runtime-compiled render functions using `with` blocks, the render // proxy used needs a different `has` handler which is more performant and @@ -2745,6 +2982,19 @@ function finishComponentSetup(instance, isSSR) { applyOptions(instance, Component); currentInstance = null; } + // warn missing template/render + if ((process.env.NODE_ENV !== 'production') && !Component.render && instance.render === NOOP) { + /* istanbul ignore if */ + if ( Component.template) { + warn(`Component provided template option but ` + + `runtime compilation is not supported in this build of Vue.` + + ( ` Configure your bundler to alias "vue" to "vue/dist/vue.esm-bundler.js".` + ) /* should not happen */); + } + else { + warn(`Component is missing template or render function.`); + } + } } const attrHandlers = { get: (target, key) => { @@ -2814,7 +3064,8 @@ function formatComponentName(instance, Component, isRoot = false) { } }; name = - inferFromRegistry(instance.parent.type.components) || inferFromRegistry(instance.appContext.components); + inferFromRegistry(instance.components || + instance.parent.type.components) || inferFromRegistry(instance.appContext.components); } return name ? classify(name) : isRoot ? `App` : `Anonymous`; } @@ -2826,7 +3077,7 @@ function computed$1(getterOrOptions) { } // Core API ------------------------------------------------------------------ -const version = "3.0.0-rc.4"; +const version = "3.0.0"; // import deepCopy from './deepCopy' /** @@ -3084,31 +3335,14 @@ function patch(instance) { } } -function errorHandler(err, instance, info) { - let hasOnError = false; - if (instance) { - const appInstance = instance.$.appContext.$appInstance; - hasOnError = appInstance && appInstance.$hasHook("onError" /* ON_ERROR */); - hasOnError && appInstance.$callHook("onError" /* ON_ERROR */, err); - } - logError(err, info, instance ? instance.$.vnode : null); -} function initAppConfig(appConfig) { - appConfig.errorHandler = errorHandler; appConfig.globalProperties.$nextTick = function $nextTick(fn) { return nextTick$1(this.$, fn); }; } function onApplyOptions(options, instance, publicThis) { - Object.keys(options).forEach(name => { - if (name.indexOf('on') === 0) { - const hook = options[name]; - if (isFunction(hook)) { - injectHook(name, hook.bind(publicThis), instance); - } - } - }); + instance.appContext.config.globalProperties.$applyOptions(options, instance, publicThis); const computedOptions = options.computed; if (computedOptions) { const keys = Object.keys(computedOptions); @@ -3218,7 +3452,7 @@ function unmountComponent(instance) { }); } const oldCreateApp = createAppAPI(); -function createApp(rootComponent, rootProps = null) { +function createVueApp(rootComponent, rootProps = null) { const app = oldCreateApp(rootComponent, rootProps); const appContext = app._context; initAppConfig(appContext.config); @@ -3234,6 +3468,7 @@ function createApp(rootComponent, rootProps = null) { return component && unmountComponent(component.$); }; app.mount = function mount() { + rootComponent.render = NOOP; const instance = mountComponent(createVNode({ type: rootComponent }), { mpType: MPType.APP, mpInstance: null, @@ -3245,7 +3480,6 @@ function createApp(rootComponent, rootProps = null) { instance.$createComponent = createComponent; instance.$destroyComponent = destroyComponent; appContext.$appInstance = instance; - createMiniProgramApp(instance); return instance; }; app.unmount = function unmount() { @@ -3254,17 +3488,96 @@ function createApp(rootComponent, rootProps = null) { return app; } -const createHook$1 = (lifecycle) => (hook, target = currentInstance) => +function applyOptions$1(options, instance, publicThis) { + Object.keys(options).forEach(name => { + if (name.indexOf('on') === 0) { + const hook = options[name]; + if (isFunction(hook)) { + injectHook(name, hook.bind(publicThis), instance); + } + } + }); +} + +function set$2(target, key, val) { + return (target[key] = val); +} +function hasHook(name) { + const hooks = this.$[name]; + if (hooks && hooks.length) { + return true; + } + return false; +} +function callHook(name, args) { + const hooks = this.$[name]; + let ret; + if (hooks) { + for (let i = 0; i < hooks.length; i++) { + ret = hooks[i](args); + } + } + return ret; +} + +function errorHandler(err, instance, info) { + if (!instance) { + throw err; + } + const appInstance = instance.$.appContext.$appInstance; + if (!appInstance) { + throw err; + } + appInstance.$callHook('onError', err, info); +} + +function initApp(app) { + const appConfig = app._context.config; + if (isFunction(app._component.onError)) { + appConfig.errorHandler = errorHandler; + } + const globalProperties = appConfig.globalProperties; + globalProperties.$hasHook = hasHook; + globalProperties.$callHook = callHook; + if (__VUE_OPTIONS_API__) { + globalProperties.$set = set$2; + globalProperties.$applyOptions = applyOptions$1; + } +} + +var plugin = { + install(app) { + initApp(app); + const globalProperties = app._context.config.globalProperties; + const oldCallHook = globalProperties.$callHook; + globalProperties.$callHook = function callHook(name, args) { + if (name === 'mounted') { + oldCallHook.call(this, 'bm'); // beforeMount + this.$.isMounted = true; + name = 'm'; + } + return oldCallHook.call(this, name, args); + }; + const oldMount = app.mount; + app.mount = function mount(rootContainer) { + const instance = oldMount.call(app, rootContainer); + // @ts-ignore + createMiniProgramApp(instance); + return instance; + }; + } +}; + +// @ts-ignore +const createHook$1 = (lifecycle) => (hook, target) => // post-create lifecycle registrations are noops during SSR -!isInSSRComponentSetup && - injectHook(lifecycle, hook, target); +!isInSSRComponentSetup && injectHook(lifecycle, hook, target); const onShow = /*#__PURE__*/ createHook$1("onShow" /* ON_SHOW */); const onHide = /*#__PURE__*/ createHook$1("onHide" /* ON_HIDE */); const onLaunch = /*#__PURE__*/ createHook$1("onLaunch" /* ON_LAUCH */); const onError = /*#__PURE__*/ createHook$1("onError" /* ON_ERROR */); const onThemeChange = /*#__PURE__*/ createHook$1("onThemeChange" /* ON_THEME_CHANGE */); const onPageNotFound = /*#__PURE__*/ createHook$1("onPageNotFound" /* ON_PAGE_NOT_FOUND */); -const onUniNViewMessage = /*#__PURE__*/ createHook$1("onUniNViewMessage" /* ON_UNI_NVIEW_MESSAGE */); const onUnhandledRejection = /*#__PURE__*/ createHook$1("onUnhandledRejection" /* ON_UNHANDLE_REJECTION */); const onLoad = /*#__PURE__*/ createHook$1("onLoad" /* ON_LOAD */); const onReady = /*#__PURE__*/ createHook$1("onReady" /* ON_READY */); @@ -3284,4 +3597,8 @@ const onNavigationBarSearchInputClicked = /*#__PURE__*/ createHook$1("onNavigati const onNavigationBarSearchInputConfirmed = /*#__PURE__*/ createHook$1("onNavigationBarSearchInputConfirmed" /* ON_NAVIGATION_BAR_SEARCH_INPUT_CONFIRMED */); const onNavigationBarSearchInputFocusChanged = /*#__PURE__*/ createHook$1("onNavigationBarSearchInputFocusChanged" /* ON_NAVIGATION_BAR_SEARCH_INPUT_FOCUS_CHANGED */); -export { callWithAsyncErrorHandling, callWithErrorHandling, computed$1 as computed, createApp, createHook$1 as createHook, customRef, inject, isProxy, isReactive, isReadonly, isRef, markRaw, nextTick, onActivated, onAddToFavorites, onBackPress, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onDeactivated, onError, onErrorCaptured, onHide, onLaunch, onLoad, onMounted, onNavigationBarButtonTap, onNavigationBarSearchInputChanged, onNavigationBarSearchInputClicked, onNavigationBarSearchInputConfirmed, onNavigationBarSearchInputFocusChanged, onPageNotFound, onPageScroll, onPullDownRefresh, onReachBottom, onReady, onRenderTracked, onRenderTriggered, onResize, onShareAppMessage, onShareTimeline, onShow, onTabItemTap, onThemeChange, onUnhandledRejection, onUniNViewMessage, onUnload, onUnmounted, onUpdated, provide, reactive, readonly, ref, shallowReactive, shallowReadonly, shallowRef, toRaw, toRef, toRefs, triggerRef, unref, version, warn, watch, watchEffect }; +function createApp(rootComponent, rootProps = null) { + return createVueApp(rootComponent, rootProps).use(plugin); +} + +export { callWithAsyncErrorHandling, callWithErrorHandling, computed$1 as computed, createApp, createHook$1 as createHook, createVueApp, customRef, inject, injectHook, isInSSRComponentSetup, isProxy, isReactive, isReadonly, isRef, logError, markRaw, nextTick, onActivated, onAddToFavorites, onBackPress, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onDeactivated, onError, onErrorCaptured, onHide, onLaunch, onLoad, onMounted, onNavigationBarButtonTap, onNavigationBarSearchInputChanged, onNavigationBarSearchInputClicked, onNavigationBarSearchInputConfirmed, onNavigationBarSearchInputFocusChanged, onPageNotFound, onPageScroll, onPullDownRefresh, onReachBottom, onReady, onRenderTracked, onRenderTriggered, onResize, onShareAppMessage, onShareTimeline, onShow, onTabItemTap, onThemeChange, onUnhandledRejection, onUnload, onUnmounted, onUpdated, provide, reactive, readonly, ref, shallowReactive, shallowReadonly, shallowRef, toRaw, toRef, toRefs, triggerRef, unref, version, warn, watch, watchEffect }; diff --git a/packages/uni-mp-weixin/dist/uni.api.esm.js b/packages/uni-mp-weixin/dist/uni.api.esm.js index ce82670af..ea7871836 100644 --- a/packages/uni-mp-weixin/dist/uni.api.esm.js +++ b/packages/uni-mp-weixin/dist/uni.api.esm.js @@ -1,5 +1,32 @@ import { isArray, isPromise, isFunction, isPlainObject, hasOwn, isString } from '@vue/shared'; +const API_TYPE_SYNC = 1; +function validateProtocol(_name, _args, _protocol) { + return true; +} +function formatApiArgs(args, options) { + if (!options) { + return args; + } +} +function createApi({ type, name, options }, fn, protocol) { + return function (...args) { + if (type === API_TYPE_SYNC) { + if (!((process.env.NODE_ENV !== 'production') && protocol && !validateProtocol())) { + return fn.apply(null, formatApiArgs(args, options)); + } + } + }; +} + +const Upx2pxProtocol = [ + { + name: 'upx', + type: [Number, String], + required: true + } +]; + const EPS = 1e-4; const BASE_DEVICE_WIDTH = 750; let isIOS = false; @@ -11,7 +38,7 @@ function checkDeviceWidth() { deviceDPR = pixelRatio; isIOS = platform === 'ios'; } -function upx2px(number, newDeviceWidth) { +const upx2px = createApi({ type: API_TYPE_SYNC, name: 'upx2px' }, (number, newDeviceWidth) => { if (deviceWidth === 0) { checkDeviceWidth(); } @@ -33,7 +60,7 @@ function upx2px(number, newDeviceWidth) { } } return number < 0 ? -result : result; -} +}, Upx2pxProtocol); var HOOKS; (function (HOOKS) { @@ -139,6 +166,15 @@ function invokeApi(method, api, options, ...params) { return api(options, ...params); } +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])) { @@ -184,15 +220,15 @@ function removeHook(hooks, hook) { hooks.splice(index, 1); } } -function addInterceptor(method, interceptor) { +const addInterceptor = createApi({ type: API_TYPE_SYNC, name: 'addInterceptor' }, (method, interceptor) => { if (typeof method === 'string' && isPlainObject(interceptor)) { mergeInterceptorHook(scopedInterceptors[method] || (scopedInterceptors[method] = {}), interceptor); } else if (isPlainObject(method)) { mergeInterceptorHook(globalInterceptors, method); } -} -function removeInterceptor(method, interceptor) { +}, AddInterceptorProtocol); +const removeInterceptor = createApi({ type: API_TYPE_SYNC, name: 'removeInterceptor' }, (method, interceptor) => { if (typeof method === 'string') { if (isPlainObject(interceptor)) { removeInterceptorHook(scopedInterceptors[method], interceptor); @@ -204,7 +240,7 @@ function removeInterceptor(method, interceptor) { else if (isPlainObject(method)) { removeInterceptorHook(globalInterceptors, method); } -} +}, RemoveInterceptorProtocol); 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$/; @@ -450,7 +486,20 @@ function addSafeAreaInsets(fromRes, toRes) { const getSystemInfo = { returnValue: addSafeAreaInsets }; -const getSystemInfoSync = getSystemInfo; +const getSystemInfoSync = getSystemInfo; +const redirectTo = {}; +const createCanvasContext = { + returnValue(fromRes, toRes) { + const measureText = fromRes.measureText; + toRes.measureText = function (text, callback) { + const textMetrics = measureText.call(this, text); + if (typeof callback === 'function') { + setTimeout(() => callback(textMetrics), 0); + } + return textMetrics; + }; + } +}; const getProvider = initGetProvider({ oauth: ['weixin'], @@ -466,9 +515,11 @@ var shims = /*#__PURE__*/Object.freeze({ var protocols = /*#__PURE__*/Object.freeze({ __proto__: null, + redirectTo: redirectTo, previewImage: previewImage, getSystemInfo: getSystemInfo, - getSystemInfoSync: getSystemInfoSync + getSystemInfoSync: getSystemInfoSync, + createCanvasContext: createCanvasContext }); var index = initUni(shims, protocols); diff --git a/packages/uni-mp-weixin/dist/uni.mp.esm.js b/packages/uni-mp-weixin/dist/uni.mp.esm.js index 07b630412..64d1d3b87 100644 --- a/packages/uni-mp-weixin/dist/uni.mp.esm.js +++ b/packages/uni-mp-weixin/dist/uni.mp.esm.js @@ -52,28 +52,6 @@ const MP_METHODS = [ 'selectAllComponents', 'selectComponent' ]; -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'; - } - const hooks = this.$[name]; - let ret; - if (hooks) { - for (let i = 0; i < hooks.length; i++) { - ret = hooks[i](args); - } - } - return ret; -} function createEmitFn(oldEmit, ctx) { return function emit(event, ...args) { if (ctx.$scope && event) { @@ -82,9 +60,6 @@ function createEmitFn(oldEmit, ctx) { return oldEmit.apply(this, [event, ...args]); }; } -function set(target, key, val) { - return (target[key] = val); -} function initBaseInstance(instance, options) { const ctx = instance.ctx; // mp @@ -93,7 +68,9 @@ function initBaseInstance(instance, options) { ctx.$scope = options.mpInstance; // TODO @deprecated ctx.$mp = {}; - ctx._self = {}; + if (__VUE_OPTIONS_API__) { + ctx._self = {}; + } // $vm ctx.$scope.$vm = instance.proxy; // slots @@ -105,15 +82,8 @@ function initBaseInstance(instance, options) { }); } } - if (__VUE_OPTIONS_API__) { - // $set - ctx.$set = set; - } // $emit instance.emit = createEmitFn(instance.emit, ctx); - // $callHook - ctx.$hasHook = hasHook; - ctx.$callHook = callHook; } function initComponentInstance(instance, options) { initBaseInstance(instance, options); @@ -207,7 +177,7 @@ function parseApp(instance, parseAppOptions) { $vm: instance, onLaunch(options) { const ctx = internalInstance.ctx; - if (this.$vm && ctx.$callHook) { + if (this.$vm && ctx.$scope) { // 已经初始化过了,主要是为了百度,百度 onShow 在 onLaunch 之前 return; } @@ -238,6 +208,26 @@ function initCreateApp(parseAppOptions) { }; } +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 initBehavior(options) { return Behavior(options); } @@ -791,6 +781,13 @@ function parsePage(vueOptions, parseOptions) { 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('onLoad', query); + }; initHooks(methods, PAGE_HOOKS); initUnknownHooks(methods, vueOptions); parse && parse(miniProgramPageOptions, { handleLink }); diff --git a/packages/uni-quickapp-webview/dist/uni.api.esm.js b/packages/uni-quickapp-webview/dist/uni.api.esm.js index d83a85881..09c73991a 100644 --- a/packages/uni-quickapp-webview/dist/uni.api.esm.js +++ b/packages/uni-quickapp-webview/dist/uni.api.esm.js @@ -1,5 +1,32 @@ import { isArray, isPromise, isFunction, isPlainObject, hasOwn, isString } from '@vue/shared'; +const API_TYPE_SYNC = 1; +function validateProtocol(_name, _args, _protocol) { + return true; +} +function formatApiArgs(args, options) { + if (!options) { + return args; + } +} +function createApi({ type, name, options }, fn, protocol) { + return function (...args) { + if (type === API_TYPE_SYNC) { + if (!((process.env.NODE_ENV !== 'production') && protocol && !validateProtocol())) { + return fn.apply(null, formatApiArgs(args, options)); + } + } + }; +} + +const Upx2pxProtocol = [ + { + name: 'upx', + type: [Number, String], + required: true + } +]; + const EPS = 1e-4; const BASE_DEVICE_WIDTH = 750; let isIOS = false; @@ -11,7 +38,7 @@ function checkDeviceWidth() { deviceDPR = pixelRatio; isIOS = platform === 'ios'; } -function upx2px(number, newDeviceWidth) { +const upx2px = createApi({ type: API_TYPE_SYNC, name: 'upx2px' }, (number, newDeviceWidth) => { if (deviceWidth === 0) { checkDeviceWidth(); } @@ -33,7 +60,7 @@ function upx2px(number, newDeviceWidth) { } } return number < 0 ? -result : result; -} +}, Upx2pxProtocol); var HOOKS; (function (HOOKS) { @@ -139,6 +166,15 @@ function invokeApi(method, api, options, ...params) { return api(options, ...params); } +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])) { @@ -184,15 +220,15 @@ function removeHook(hooks, hook) { hooks.splice(index, 1); } } -function addInterceptor(method, interceptor) { +const addInterceptor = createApi({ type: API_TYPE_SYNC, name: 'addInterceptor' }, (method, interceptor) => { if (typeof method === 'string' && isPlainObject(interceptor)) { mergeInterceptorHook(scopedInterceptors[method] || (scopedInterceptors[method] = {}), interceptor); } else if (isPlainObject(method)) { mergeInterceptorHook(globalInterceptors, method); } -} -function removeInterceptor(method, interceptor) { +}, AddInterceptorProtocol); +const removeInterceptor = createApi({ type: API_TYPE_SYNC, name: 'removeInterceptor' }, (method, interceptor) => { if (typeof method === 'string') { if (isPlainObject(interceptor)) { removeInterceptorHook(scopedInterceptors[method], interceptor); @@ -204,7 +240,7 @@ function removeInterceptor(method, interceptor) { else if (isPlainObject(method)) { removeInterceptorHook(globalInterceptors, method); } -} +}, RemoveInterceptorProtocol); 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$/; @@ -450,7 +486,20 @@ function addSafeAreaInsets(fromRes, toRes) { const getSystemInfo = { returnValue: addSafeAreaInsets }; -const getSystemInfoSync = getSystemInfo; +const getSystemInfoSync = getSystemInfo; +const redirectTo = {}; +const createCanvasContext = { + returnValue(fromRes, toRes) { + const measureText = fromRes.measureText; + toRes.measureText = function (text, callback) { + const textMetrics = measureText.call(this, text); + if (typeof callback === 'function') { + setTimeout(() => callback(textMetrics), 0); + } + return textMetrics; + }; + } +}; const providers = { oauth: [], @@ -473,9 +522,11 @@ var shims = /*#__PURE__*/Object.freeze({ var protocols = /*#__PURE__*/Object.freeze({ __proto__: null, + redirectTo: redirectTo, previewImage: previewImage, getSystemInfo: getSystemInfo, - getSystemInfoSync: getSystemInfoSync + getSystemInfoSync: getSystemInfoSync, + createCanvasContext: createCanvasContext }); var index = initUni(shims, protocols); diff --git a/packages/uni-quickapp-webview/dist/uni.mp.esm.js b/packages/uni-quickapp-webview/dist/uni.mp.esm.js index 039b17e67..2888e94ce 100644 --- a/packages/uni-quickapp-webview/dist/uni.mp.esm.js +++ b/packages/uni-quickapp-webview/dist/uni.mp.esm.js @@ -52,28 +52,6 @@ const MP_METHODS = [ 'selectAllComponents', 'selectComponent' ]; -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'; - } - const hooks = this.$[name]; - let ret; - if (hooks) { - for (let i = 0; i < hooks.length; i++) { - ret = hooks[i](args); - } - } - return ret; -} function createEmitFn(oldEmit, ctx) { return function emit(event, ...args) { if (ctx.$scope && event) { @@ -82,9 +60,6 @@ function createEmitFn(oldEmit, ctx) { return oldEmit.apply(this, [event, ...args]); }; } -function set(target, key, val) { - return (target[key] = val); -} function initBaseInstance(instance, options) { const ctx = instance.ctx; // mp @@ -93,7 +68,9 @@ function initBaseInstance(instance, options) { ctx.$scope = options.mpInstance; // TODO @deprecated ctx.$mp = {}; - ctx._self = {}; + if (__VUE_OPTIONS_API__) { + ctx._self = {}; + } // $vm ctx.$scope.$vm = instance.proxy; // slots @@ -105,15 +82,8 @@ function initBaseInstance(instance, options) { }); } } - if (__VUE_OPTIONS_API__) { - // $set - ctx.$set = set; - } // $emit instance.emit = createEmitFn(instance.emit, ctx); - // $callHook - ctx.$hasHook = hasHook; - ctx.$callHook = callHook; } function initComponentInstance(instance, options) { initBaseInstance(instance, options); @@ -207,7 +177,7 @@ function parseApp(instance, parseAppOptions) { $vm: instance, onLaunch(options) { const ctx = internalInstance.ctx; - if (this.$vm && ctx.$callHook) { + if (this.$vm && ctx.$scope) { // 已经初始化过了,主要是为了百度,百度 onShow 在 onLaunch 之前 return; } @@ -238,6 +208,26 @@ function initCreateApp(parseAppOptions) { }; } +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 initBehavior(options) { return Behavior(options); } @@ -772,6 +762,13 @@ function parsePage(vueOptions, parseOptions) { 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('onLoad', query); + }; initHooks(methods, PAGE_HOOKS); initUnknownHooks(methods, vueOptions); parse && parse(miniProgramPageOptions, { handleLink }); @@ -969,7 +966,7 @@ function initLifetimes$1(lifetimesOptions) { const mocks = ['nodeId', 'componentName', '_componentId', 'uniquePrefix']; function isPage(mpInstance) { - return !mpInstance.ownerId; + return !hasOwn(mpInstance, 'ownerId'); } function initRelation(mpInstance) { diff --git a/packages/vue-cli-plugin-uni/generator.js b/packages/vue-cli-plugin-uni/generator.js index 683faba1f..ab6db703c 100644 --- a/packages/vue-cli-plugin-uni/generator.js +++ b/packages/vue-cli-plugin-uni/generator.js @@ -58,7 +58,7 @@ module.exports = (api, options, rootOptions) => { '@dcloudio/uni-quickapp-native': version, '@dcloudio/uni-quickapp-webview': version, '@dcloudio/uni-stat': version, - '@vue/shared': '^3.0.0-rc.4', // TODO + '@vue/shared': '^3.0.0', flyio: '^0.6.2', vuex: '^3.2.0' }, diff --git a/src/platforms/mp-baidu/runtime/wrapper/page-parser.js b/src/platforms/mp-baidu/runtime/wrapper/page-parser.js index be8c97bde..baac54112 100644 --- a/src/platforms/mp-baidu/runtime/wrapper/page-parser.js +++ b/src/platforms/mp-baidu/runtime/wrapper/page-parser.js @@ -29,6 +29,11 @@ export default function parsePage (vuePageOptions) { initRelation }) + const onInit = (vuePageOptions.default || vuePageOptions).onInit + if (onInit) { + pageOptions.methods.onInit = onInit + } + // 纠正百度小程序生命周期methods:onShow在methods:onLoad之前触发的问题 pageOptions.methods.onShow = function onShow () { if (this.$vm && this.$vm.$mp.query) { -- GitLab