提交 d93855c9 编写于 作者: Q qiang

Merge branch 'dev' into alpha

# Conflicts:
#	packages/uni-h5/dist/index.umd.min.js
#	packages/uni-mp-kuaishou/dist/index.js
#	packages/vue-cli-plugin-uni/packages/mp-vue/dist/mp.runtime.esm.js
#	src/core/service/api/plugin/push.js
#	src/platforms/mp-alipay/runtime/wrapper/page-parser.js
#	src/platforms/mp-weixin/runtime/wrapper/page-base-parser.js
#	src/platforms/mp-xhs/runtime/wrapper/page-parser.js
......@@ -7,11 +7,11 @@ root = true
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
end_of_line = crlf
insert_final_newline = true
trim_trailing_whitespace = true
# md files
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false
\ No newline at end of file
trim_trailing_whitespace = false
......@@ -39,4 +39,5 @@ uni-polyfill.js
packages/uni-cli-shared/components/ad-fullscreen-video.vue
packages/uni-cli-shared/components/ad-interactive.vue
packages/uni-cli-shared/components/ad-interstitial.vue
packages/uni-cli-shared/components/ad-rewarded-video.vue
packages/uni-cli-shared/components/ad-rewarded-video.vue
packages/uni-cli-shared/lib/uni_modules/uni_modules.js
......@@ -46,6 +46,8 @@
* build:编译脚本
* lib:其他编译依赖
* apis.js 参与编译的接口列表
* modules.json 摇树优化接口类别划分
* dist:其他编译后的文件
* docs:~~文档目录~~ ,现已迁移
* examples:~~示例目录~~,现已迁移
......@@ -97,6 +99,8 @@
* assets:静态资源
* core:运行时公共部分
* helpers
* i18n:国际化资源文件
* protocol:App、H5 平台接口通用校验
* runtime
* service:逻辑层(App、H5)
* api:uni 接口实现(App、H5 平台公共部分)
......
......@@ -8,3 +8,4 @@ unpackage/
package-lock.json
!packages/vue-cli-plugin-uni/packages/**/*
tests/package.json
*.DS_Store
......@@ -20,10 +20,10 @@
## 扫码体验
开发一次,编译到11个平台。依次扫描11个二维码,亲自体验最全面的跨平台效果!
开发一次,编译到14个平台。依次扫描14个二维码,亲自体验最全面的跨平台效果!
<div align="center">
<img src="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-a90b5f95-90ba-4d30-a6a7-cd4d057327db/d6c073b7-9233-411d-b143-a74af382422c.jpg"/>
<img src="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-a90b5f95-90ba-4d30-a6a7-cd4d057327db/cf5727bc-fbe6-4d7e-bd92-e0d16e6f53b0.jpg"/>
</div>
*注: 某些平台不能提交简单demo,补充了一些其他功能。*
......
......@@ -46,7 +46,14 @@ const DEPS = {
['/core/view/components/swiper-item/index.vue', 'SwiperItem'],
['/core/view/components/movable-area/index.vue', 'MovableArea'],
['/core/view/components/movable-view/index.vue', 'MovableView'],
['/platforms/h5/components/system-routes/preview-image/index.vue', 'PreviewImage']
[
'/platforms/h5/components/app/popup/preview-image/index.vue',
'PreviewImage'
],
[
'/platforms/h5/components/app/popup/mixins/preview-image.js',
'PreviewImageMixin'
]
],
showToast: TOAST_DEPS,
hideToast: TOAST_DEPS,
......
......@@ -46,7 +46,13 @@ const location = [
'getLocation',
'chooseLocation',
'openLocation',
'createMapContext'
'createMapContext',
'onLocationChange',
'onLocationChangeError',
'startLocationUpdate',
'stopLocationUpdate',
'offLocationChange',
'offLocationChangeError'
]
const media = [
......
......@@ -48,7 +48,13 @@
"apiList": {
"uni.getLocation": true,
"uni.openLocation": true,
"uni.chooseLocation": true
"uni.chooseLocation": true,
"uni.onLocationChange": true,
"uni.onLocationChangeError": true,
"uni.startLocationUpdate": true,
"uni.stopLocationUpdate": true,
"uni.offLocationChange": true,
"uni.offLocationChangeError": true
}
}, {
"name": "media",
......@@ -225,7 +231,7 @@
"apiList": {
"uni.createRewardedVideoAd": true,
"uni.createFullScreenVideoAd": true,
"uni.'createInterstitialAd'": true,
"uni.'createInterstitialAd'": true,
"uni.'createInteractiveAd'": true
}
}]
......@@ -116,6 +116,7 @@
"my": true,
"swan": true,
"tt": true,
"ks": true,
"qh": true,
"qa": true,
"xhs": true,
......
src
yarn.lock
tsconfig.json
\ No newline at end of file
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
\ No newline at end of file
/// <reference types="@dcloudio/types" />
/// <reference types="@dcloudio/types" />
/// <reference types="@dcloudio/types" />
/// <reference types="@dcloudio/types" />
import { ComponentInternalInstance } from '@vue/composition-api';
export declare const onShow: (callback: ((options?: App.LaunchShowOption) => void) | (() => void), target?: ComponentInternalInstance | null) => Function;
export declare const onHide: (callback: (() => void) | (() => void), target?: ComponentInternalInstance | null) => Function;
export declare const onLaunch: (callback: (options?: App.LaunchShowOption) => void, target?: ComponentInternalInstance | null) => Function;
export declare const onError: (callback: (error: string) => void, target?: ComponentInternalInstance | null) => Function;
export declare const onPageNotFound: (callback: (options: App.PageNotFoundOption) => void, target?: ComponentInternalInstance | null) => Function;
export declare const onUnhandledRejection: (callback: (options: UniApp.OnUnhandledRejectionCallbackResult) => void, target?: ComponentInternalInstance | null) => Function;
export declare const onThemeChange: (callback: (options: UniApp.OnThemeChangeCallbackResult) => void, target?: ComponentInternalInstance | null) => Function;
export declare const onUniNViewMessage: (callback: (options: AnyObject) => void, target?: ComponentInternalInstance | null) => Function;
export declare const onInit: (callback: (query?: AnyObject) => void, target?: ComponentInternalInstance | null) => Function;
export declare const onLoad: (callback: (query?: AnyObject) => void, target?: ComponentInternalInstance | null) => Function;
export declare const onReady: (callback: () => void, target?: ComponentInternalInstance | null) => Function;
export declare const onUnload: (callback: () => void, target?: ComponentInternalInstance | null) => Function;
export declare const onPullDownRefresh: (callback: () => void, target?: ComponentInternalInstance | null) => Function;
export declare const onReachBottom: (callback: () => void, target?: ComponentInternalInstance | null) => Function;
export declare const onShareAppMessage: (callback: (options: Page.ShareAppMessageOption) => Page.CustomShareContent, target?: ComponentInternalInstance | null) => Function;
export declare const onShareTimeline: (callback: () => Page.ShareTimelineContent, target?: ComponentInternalInstance | null) => Function;
export declare const onAddToFavorites: (callback: (options: Page.AddToFavoritesOption) => Page.CustomFavoritesContent, target?: ComponentInternalInstance | null) => Function;
export declare const onPageScroll: (callback: (options: Page.PageScrollOption) => void, target?: ComponentInternalInstance | null) => Function;
export declare const onResize: (callback: (options: Page.PageScrollOption) => void, target?: ComponentInternalInstance | null) => Function;
export declare const onTabItemTap: (callback: (options: Page.TabItemTapOption) => void, target?: ComponentInternalInstance | null) => Function;
export declare const onNavigationBarButtonTap: (callback: (options: Page.NavigationBarButtonTapOption) => void, target?: ComponentInternalInstance | null) => Function;
export declare const onBackPress: (callback: (options: Page.BackPressOption) => any, target?: ComponentInternalInstance | null) => Function;
export declare const onNavigationBarSearchInputChanged: (callback: (event: Page.NavigationBarSearchInputEvent) => void, target?: ComponentInternalInstance | null) => Function;
export declare const onNavigationBarSearchInputConfirmed: (callback: (event: Page.NavigationBarSearchInputEvent) => void, target?: ComponentInternalInstance | null) => Function;
export declare const onNavigationBarSearchInputClicked: (callback: () => void, target?: ComponentInternalInstance | null) => Function;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.onNavigationBarSearchInputClicked = exports.onNavigationBarSearchInputConfirmed = exports.onNavigationBarSearchInputChanged = exports.onBackPress = exports.onNavigationBarButtonTap = exports.onTabItemTap = exports.onResize = exports.onPageScroll = exports.onAddToFavorites = exports.onShareTimeline = exports.onShareAppMessage = exports.onReachBottom = exports.onPullDownRefresh = exports.onUnload = exports.onReady = exports.onLoad = exports.onInit = exports.onUniNViewMessage = exports.onThemeChange = exports.onUnhandledRejection = exports.onPageNotFound = exports.onError = exports.onLaunch = exports.onHide = exports.onShow = void 0;
var composition_api_1 = require("@vue/composition-api");
var mp = require("./mp");
var lifecycles = [];
var createLifeCycle = function (lifecycle) {
lifecycles.push(lifecycle);
var fn = (0, composition_api_1.createLifeCycle)(lifecycle);
return function (callback, target) {
return fn(callback, target);
};
};
if (typeof plus === 'object') {
}
else if (typeof window === 'object' && 'document' in window) {
}
else {
mp.init(lifecycles);
}
exports.onShow = createLifeCycle('onShow');
exports.onHide = createLifeCycle('onHide');
exports.onLaunch = createLifeCycle('onLaunch');
exports.onError = createLifeCycle('onError');
exports.onPageNotFound = createLifeCycle('onPageNotFound');
exports.onUnhandledRejection = createLifeCycle('onUnhandledRejection');
exports.onThemeChange = createLifeCycle('onThemeChange');
exports.onUniNViewMessage = createLifeCycle('onUniNViewMessage');
exports.onInit = createLifeCycle('onInit');
exports.onLoad = createLifeCycle('onLoad');
exports.onReady = createLifeCycle('onReady');
exports.onUnload = createLifeCycle('onUnload');
exports.onPullDownRefresh = createLifeCycle('onPullDownRefresh');
exports.onReachBottom = createLifeCycle('onReachBottom');
exports.onShareAppMessage = createLifeCycle('onShareAppMessage');
exports.onShareTimeline = createLifeCycle('onShareTimeline');
exports.onAddToFavorites = createLifeCycle('onAddToFavorites');
exports.onPageScroll = createLifeCycle('onPageScroll');
exports.onResize = createLifeCycle('onResize');
exports.onTabItemTap = createLifeCycle('onTabItemTap');
exports.onNavigationBarButtonTap = createLifeCycle('onNavigationBarButtonTap');
exports.onBackPress = createLifeCycle('onBackPress');
exports.onNavigationBarSearchInputChanged = createLifeCycle('onNavigationBarSearchInputChanged');
exports.onNavigationBarSearchInputConfirmed = createLifeCycle('onNavigationBarSearchInputConfirmed');
exports.onNavigationBarSearchInputClicked = createLifeCycle('onNavigationBarSearchInputClicked');
export declare function init(lifecycles: string[]): void;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.init = void 0;
var vue_1 = require("vue");
function updateLifeCycle(lifecycles, setupLifecycles, fn) {
if (fn) {
if (fn.lifecycles) {
fn.lifecycles.forEach(function (item) {
if (!setupLifecycles.includes(item)) {
setupLifecycles.push(item);
}
});
}
else {
var fnString_1 = fn.toString();
lifecycles.forEach(function (item) {
if (!setupLifecycles.includes(item) && (new RegExp("\\b(".concat(item, ")\\b"))).test(fnString_1)) {
setupLifecycles.push(item);
}
});
}
}
}
function init(lifecycles) {
var setup = vue_1.default.config.optionMergeStrategies.setup;
var extend = vue_1.default.extend;
vue_1.default.extend = function () {
var extendedVue = extend.apply(this, arguments);
var newOptions = extendedVue.options;
var setup = newOptions.setup;
if (setup && setup.lifecycles) {
setup.lifecycles.forEach(function (item) {
newOptions[item] = newOptions[item] || [function noop() { }];
});
}
return extendedVue;
};
Object.defineProperty(vue_1.default.config.optionMergeStrategies, 'setup', {
set: function (fn) {
setup = fn;
},
get: function () {
return function (to, from) {
if (typeof setup === 'function') {
var newSetup = setup.apply(this, arguments);
newSetup.lifecycles = newSetup.lifecycles || [];
updateLifeCycle(lifecycles, newSetup.lifecycles, from);
updateLifeCycle(lifecycles, newSetup.lifecycles, to);
return newSetup;
}
};
}
});
}
exports.init = init;
{
"name": "@dcloudio/uni-app",
"version": "2.0.0-32920211029001",
"description": "uni-app composition-api",
"main": "dist/index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/dcloudio/uni-app.git",
"directory": "packages/uni-app"
},
"scripts": {
"build": "tsc -p . "
},
"peerDependencies": {
"@dcloudio/types": "^3.0.15",
"@vue/composition-api": "^1.7.0"
},
"author": "fxy060608",
"license": "Apache-2.0",
"gitHead": "9e2d0f8e244724fcd64880316c57d837d1778cf8",
"devDependencies": {
"@dcloudio/types": "^3.0.15",
"typescript": "^4.8.3"
}
}
/// <reference types="@dcloudio/types" />
import { createLifeCycle as createLifeCycleBase, ComponentInternalInstance } from '@vue/composition-api'
import * as mp from './mp'
const lifecycles: string[] = []
const createLifeCycle = <T extends Function>(lifecycle: string) => {
lifecycles.push(lifecycle)
const fn = createLifeCycleBase(lifecycle)
return (callback: T, target?: ComponentInternalInstance | null) => {
return fn(callback, target)
}
}
if (typeof plus === 'object') {
// TODO App
} else if (typeof window === 'object' && 'document' in window) {
// TODO H5
} else {
mp.init(lifecycles)
}
export const onShow = createLifeCycle<App.AppInstance['onShow'] | Page.PageInstance['onShow']>('onShow')
export const onHide = createLifeCycle<App.AppInstance['onHide'] | Page.PageInstance['onHide']>('onHide')
export const onLaunch = createLifeCycle<App.AppInstance['onLaunch']>('onLaunch')
export const onError = createLifeCycle<App.AppInstance['onError']>('onError')
export const onPageNotFound = createLifeCycle<App.AppInstance['onPageNotFound']>('onPageNotFound')
export const onUnhandledRejection = createLifeCycle<App.AppInstance['onUnhandledRejection']>('onUnhandledRejection')
export const onThemeChange = createLifeCycle<App.AppInstance['onThemeChange']>('onThemeChange')
export const onUniNViewMessage = createLifeCycle<App.AppInstance['onUniNViewMessage']>('onUniNViewMessage')
export const onInit = createLifeCycle<Page.PageInstance['onInit']>('onInit')
export const onLoad = createLifeCycle<Page.PageInstance['onLoad']>('onLoad')
export const onReady = createLifeCycle<Page.PageInstance['onReady']>('onReady')
export const onUnload = createLifeCycle<Page.PageInstance['onUnload']>('onUnload')
export const onPullDownRefresh = createLifeCycle<Page.PageInstance['onPullDownRefresh']>('onPullDownRefresh')
export const onReachBottom = createLifeCycle<Page.PageInstance['onReachBottom']>('onReachBottom')
export const onShareAppMessage = createLifeCycle<Page.PageInstance['onShareAppMessage']>('onShareAppMessage')
export const onShareTimeline = createLifeCycle<Page.PageInstance['onShareTimeline']>('onShareTimeline')
export const onAddToFavorites = createLifeCycle<Page.PageInstance['onAddToFavorites']>('onAddToFavorites')
export const onPageScroll = createLifeCycle<Page.PageInstance['onPageScroll']>('onPageScroll')
export const onResize = createLifeCycle<Page.PageInstance['onResize']>('onResize')
export const onTabItemTap = createLifeCycle<Page.PageInstance['onTabItemTap']>('onTabItemTap')
export const onNavigationBarButtonTap = createLifeCycle<Page.PageInstance['onNavigationBarButtonTap']>('onNavigationBarButtonTap')
export const onBackPress = createLifeCycle<Page.PageInstance['onBackPress']>('onBackPress')
export const onNavigationBarSearchInputChanged = createLifeCycle<Page.PageInstance['onNavigationBarSearchInputChanged']>('onNavigationBarSearchInputChanged')
export const onNavigationBarSearchInputConfirmed = createLifeCycle<Page.PageInstance['onNavigationBarSearchInputConfirmed']>('onNavigationBarSearchInputConfirmed')
export const onNavigationBarSearchInputClicked = createLifeCycle<Page.PageInstance['onNavigationBarSearchInputClicked']>('onNavigationBarSearchInputClicked')
import Vue from 'vue'
interface SetupFunction extends Function {
lifecycles?: string[]
}
function updateLifeCycle(lifecycles: string[], setupLifecycles: string[], fn?: SetupFunction) {
if (fn) {
if (fn.lifecycles) {
fn.lifecycles.forEach(item => {
if (!setupLifecycles.includes(item)) {
setupLifecycles.push(item)
}
})
} else {
const fnString = fn.toString()
lifecycles.forEach(item => {
if (!setupLifecycles.includes(item) && (new RegExp(`\\b(${item})\\b`)).test(fnString)) {
setupLifecycles.push(item)
}
})
}
}
}
export function init(lifecycles: string[]) {
// 通过 setup 函数简易分析使用到的生命周期,合并至 options 中
// TODO 编译过程静态分析 或 将页面 Vue 组件创建移至小程序组件创建之前
let setup = Vue.config.optionMergeStrategies.setup
const extend = Vue.extend
Vue.extend = function () {
const extendedVue = extend.apply(this, arguments)
const newOptions = extendedVue.options
const setup: SetupFunction | undefined = newOptions.setup
if (setup && setup.lifecycles) {
setup.lifecycles.forEach(item => {
newOptions[item] = newOptions[item] || [function noop() { }]
})
}
return extendedVue
}
Object.defineProperty(Vue.config.optionMergeStrategies, 'setup', {
set(fn) {
setup = fn
},
get() {
return function (to: Function, from: Function) {
if (typeof setup === 'function') {
const newSetup: SetupFunction = setup.apply(this, arguments)
newSetup.lifecycles = newSetup.lifecycles || []
updateLifeCycle(lifecycles, newSetup.lifecycles, from)
updateLifeCycle(lifecycles, newSetup.lifecycles, to)
return newSetup
}
}
}
})
}
{
"compilerOptions": {
"module": "CommonJS",
"target": "ES5",
"outDir": "dist",
"sourceMap": false,
"rootDir": "src",
"removeComments": true,
"declaration": true,
"skipLibCheck": true,
"paths": {
"@vue/composition-api": [
"../../packages/vue-cli-plugin-uni/packages/@vue/composition-api"
]
}
},
"include": [
"src"
]
}
\ No newline at end of file
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@dcloudio/types@^3.0.15":
version "3.0.15"
resolved "https://registry.yarnpkg.com/@dcloudio/types/-/types-3.0.15.tgz#ec72fadb8b276c9e35f97ff74af7cd3170301118"
integrity sha512-3ngPB4X1Nql8OxWn3sjXgGYAB57mPnAzzmlOBv1nppYGJMD/Hn/oet1LUK72IdJKxiCU5kMBftWylDPQAx6Y7g==
typescript@^4.8.3:
version "4.8.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.3.tgz#d59344522c4bc464a65a730ac695007fdb66dd88"
integrity sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==
......@@ -48,7 +48,7 @@
"pluginUni.entryDileNoExistsCheckAfterRetry": "{{0}} 入口文件不存在,请检查后重试",
"pluginUni.nvueCompileModeForDetail": "当前nvue编译模式:{{0}}。编译模式差异见 {{1}}",
"pluginUni.currentProjectDefaultSpaceId": "当前项目的uniCloud使用的默认服务空间spaceId为:{{0}}",
"pluginUni.unicloudReleaseH5": "发布H5,需要在uniCloud web控制台操作,绑定安全域名,否则会因为跨域问题而无法访问。教程参考:{{0}}",
"pluginUni.unicloudReleaseH5": "发布web站点需要在uniCloud web控制台操作,绑定安全域名,否则会因为跨域问题而无法访问。教程参考:{{0}}",
"pluginUni.unicloudShowedRunByHBuilderX": "当前项目使用了uniCloud,为避免云函数调用跨域问题,建议在HBuilderX内置浏览器里调试,如使用外部浏览器需处理跨域,详见:{{0}}",
"pluginUni.pleaseSpecifyPluginName": "请指定插件名",
"pluginUni.pluginNameNotExist": "插件名称不存在",
......
......@@ -54,12 +54,14 @@ class AdBase {
})
ad.onError(({
code,
message
message,
detail
}) => {
this._isLoading = false
const data = {
code: code,
errMsg: message
errMsg: message,
detail: detail
}
if (this._retry && code === -5008) {
......
const fs = require('fs')
const path = require('path')
const crypto = require('crypto')
const {
isNormalPage
} = require('./util')
/**
* 1.page-loader 缓存基础的 app.json page.json project.config.json
* 2.main-loader 缓存 app.json 中的 usingComponents 节点
......@@ -49,7 +52,9 @@ function getJsonFile (name) {
function getChangedJsonFileMap (clear = true) {
const changedJsonFileMap = new Map()
for (const name of changedJsonFileSet.values()) {
changedJsonFileMap.set(name + '.json', jsonFileMap.get(name))
if (isNormalPage(name)) {
changedJsonFileMap.set(name + '.json', jsonFileMap.get(name))
}
}
clear && changedJsonFileSet.clear()
return changedJsonFileMap
......@@ -361,4 +366,4 @@ module.exports = {
getChangedJsonFileMap,
getSpecialMethods,
supportGlobalUsingComponents
}
}
const path = require('path')
const isWin = /^win/.test(process.platform)
const normalizePath = path => (isWin ? path.replace(/\\/g, '/') : path)
const {
normalizeNodeModules
} = require('./util')
module.exports = {
loader: 'file-loader',
options: {
publicPath (url, resourcePath, context) {
return '/' + normalizePath(path.relative(process.env.UNI_INPUT_DIR, resourcePath))
return '/' + normalizeNodeModules(path.relative(process.env.UNI_INPUT_DIR, resourcePath))
},
outputPath (url, resourcePath, context) {
return normalizePath(path.relative(process.env.UNI_INPUT_DIR, resourcePath))
return normalizeNodeModules(path.relative(process.env.UNI_INPUT_DIR, resourcePath))
}
}
}
......@@ -112,5 +112,6 @@ module.exports = {
getPlatformGlobal,
getPlatformStat,
getPlatformPush,
getPlatformUniCloud
}
getPlatformUniCloud,
uniModulesLoader: normalizePath(require.resolve('./uni_modules-loader'))
}
......@@ -108,7 +108,7 @@ function isEnableUniPushV1 (manifestJson, platform) {
if (isEnableUniPushV2(manifestJson, platform)) {
return false
}
if (platform === 'app-plus') {
if (platform === 'app-plus') {
const platformOptions = manifestJson[platform]
const sdkConfigs = platformOptions && platformOptions.distribute && platformOptions.distribute.sdkConfigs
const push = sdkConfigs && sdkConfigs.push
......@@ -135,6 +135,19 @@ function isEnableUniPushV2 (manifestJson, platform) {
return platformOptions && platformOptions.unipush && platformOptions.unipush.enable === true
}
function isEnableSecureNetwork (manifestJson, platform) {
if (!manifestJson) {
manifestJson = getManifestJson()
}
const platformOptions = manifestJson[platform]
if (platform === 'app-plus') {
return !!(
platformOptions && platformOptions.modules && platformOptions.modules.SecureNetwork
)
}
return platformOptions && platformOptions.secureNetwork && platformOptions.secureNetwork.enable === true
}
function isUniPushOffline (manifestJson) {
if (!manifestJson) {
manifestJson = getManifestJson()
......@@ -149,8 +162,9 @@ module.exports = {
getManifestJson,
parseManifestJson,
getNetworkTimeout,
getH5Options,
getH5Options,
isEnableUniPushV1,
isEnableUniPushV2,
isUniPushOffline
}
isUniPushOffline,
isEnableSecureNetwork
}
......@@ -6,7 +6,8 @@ const {
removeExt,
normalizePath,
camelize,
capitalize
capitalize,
isNormalPage
} = require('./util')
const {
......@@ -113,7 +114,9 @@ function isNVuePage (page, root = '') {
function isValidPage (page, root = '') {
if (typeof page === 'string' || !page.path) { // 不合法的配置
console.warn(uniI18n.__('cliShared.pagesJsonError', { 0: 'https://uniapp.dcloud.io/collocation/pages?id=pages' }))
console.warn(uniI18n.__('cliShared.pagesJsonError', {
0: 'https://uniapp.dcloud.io/collocation/pages?id=pages'
}))
return false
}
let pagePath = page.path
......@@ -213,7 +216,10 @@ function parseEntry (pagesJson) {
const weixinConfig = manifestConfig['mp-weixin'] || {}
const independentSwitch = !!weixinConfig.independent
if (independentSwitch) {
Object.values(process.UNI_SUBPACKAGES).forEach(({ root, independent = false }) => {
Object.values(process.UNI_SUBPACKAGES).forEach(({
root,
independent = false
}) => {
if (root && independent) {
const pkgRootMainJsKey = `${root}/common/main`
// const pkgRootMainJsPath = `${process.env.UNI_INPUT_DIR}/${root}/main.js`;
......@@ -239,7 +245,9 @@ function parseEntry (pagesJson) {
// pages
pagesJson.pages.forEach(page => {
process.UNI_ENTRY[page.path] = getMainJsPath(page.path)
if (isNormalPage(page.path)) {
process.UNI_ENTRY[page.path] = getMainJsPath(page.path)
}
})
// subPackages
if (Array.isArray(pagesJson.subPackages) && pagesJson.subPackages.length) {
......@@ -404,7 +412,11 @@ function initAutoComponents () {
})
if (conflictFiles.length > 0) {
conflictFiles.forEach(files => {
console.warn(uniI18n.__('cliShared.easycomConflict', { 0: '[' + files.map((file, index) => { return file }).join(',') + ']' }))
console.warn(uniI18n.__('cliShared.easycomConflict', {
0: '[' + files.map((file, index) => {
return file
}).join(',') + ']'
}))
console.log('\n')
})
}
......@@ -519,7 +531,9 @@ function parseUsingAutoImportComponents (usingAutoImportComponents) {
const BUILT_IN_COMPONENTS = ['page-meta', 'navigation-bar', 'uni-match-media']
const BUILT_IN_EASYCOMS = ['unicloud-db', 'uniad', 'ad-rewarded-video', 'ad-fullscreen-video', 'ad-interstitial', 'ad-interactive']
const BUILT_IN_EASYCOMS = ['unicloud-db', 'uniad', 'ad-rewarded-video', 'ad-fullscreen-video', 'ad-interstitial',
'ad-interactive'
]
function isBuiltInComponent (name) { // uni-template-compiler/lib/util.js 识别微信内置组件
return BUILT_IN_COMPONENTS.includes(name)
......@@ -551,4 +565,4 @@ module.exports = {
getGlobalUsingComponentsCode,
parseUsingAutoImportComponents,
generateGlobalUsingComponentsCode
}
}
const {
genUniModulesExports
} = require('./uni_modules/uni_modules')
module.exports = function () {
this.cacheable && this.cacheable()
return genUniModulesExports()
}
'use strict'
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { default: mod }
}
Object.defineProperty(exports, '__esModule', { value: true })
exports.parseDefines = exports.parseExports = exports.genUniModulesExports = void 0
const path_1 = __importDefault(require('path'))
const fs_extra_1 = __importDefault(require('fs-extra'))
const merge_1 = require('merge')
function genUniModulesExports () {
const uniModulesDir = path_1.default.resolve(process.env.UNI_INPUT_DIR, 'uni_modules')
if (!fs_extra_1.default.existsSync(uniModulesDir)) {
return ''
}
const importCodes = []
const assignCodes = []
fs_extra_1.default.readdirSync(uniModulesDir).forEach((uniModuleDir) => {
var _a, _b
const pkgPath = path_1.default.resolve(uniModulesDir, uniModuleDir, 'package.json')
if (!fs_extra_1.default.existsSync(pkgPath)) {
return
}
const exports = (_b = (_a = JSON.parse(fs_extra_1.default.readFileSync(pkgPath, 'utf8'))) === null || _a === void 0 ? void 0 : _a.uni_modules) === null || _b === void 0 ? void 0 : _b.exports
if (exports) {
const [exportsImportCodes, exportsAssignCodes] = parseExports(process.env.UNI_PLATFORM === 'h5' ? 'web' : process.env.UNI_PLATFORM, `@/uni_modules/${uniModuleDir}`, exports)
importCodes.push(...exportsImportCodes)
assignCodes.push(...exportsAssignCodes)
}
})
if (!importCodes.length) {
return ''
}
return `${importCodes.join('\n')}
${assignCodes.join('\n')}`
}
exports.genUniModulesExports = genUniModulesExports
function parseExports (platform, source, exports = {}) {
const rootDefines = {}
Object.keys(exports).forEach((name) => {
if (name.startsWith('uni')) {
rootDefines[name] = exports[name]
}
})
const platformDefines = exports[platform]
// 该平台不支持
if (platformDefines === false) {
return [[], []]
}
return parseDefines(source, (0, merge_1.recursive)(true, rootDefines, platformDefines))
}
exports.parseExports = parseExports
function parseDefines (source, defines = {}) {
const importCodes = []
const assignCodes = []
Object.keys(defines).forEach((name) => {
const [defineImportCodes, defineAssignCodes] = parseDefine(source, name, defines[name])
importCodes.push(...defineImportCodes)
assignCodes.push(...defineAssignCodes)
})
return [importCodes, assignCodes]
}
exports.parseDefines = parseDefines
/**
* uni:'getBatteryInfo'
* import getBatteryInfo from '..'
*
* uni:['getBatteryInfo']
* import { getBatteryInfo } from '..'
*
* uni:['openLocation','chooseLocation']
* import { openLocation, chooseLocation } from '..'
*
* uni:{
* onUserCaptureScreen: "onCaptureScreen"
* offUserCaptureScreen: "offCaptureScreen"
* }
*
* uni.getBatteryInfo = getBatteryInfo
* @param source
* @param globalObject
* @param define
* @returns
*/
function parseDefine (source, globalObject, define) {
const importCodes = []
const assignCodes = []
if (typeof define === 'string') {
importCodes.push(`import ${define} from '${source}'`)
assignCodes.push(`${globalObject}.${define} = ${define}`)
} else if (Array.isArray(define)) {
importCodes.push(`import { ${define.join(', ')} } from '${source}'`)
define.forEach((d) => {
assignCodes.push(`${globalObject}.${d} = ${d}`)
})
} else {
const keys = Object.keys(define)
const specifiers = []
keys.forEach((d) => {
if (d !== define[d]) {
specifiers.push(`${define[d]} as ${d}`)
} else {
specifiers.push(d)
}
assignCodes.push(`${globalObject}.${d} = ${d}`)
})
importCodes.push(`import { ${specifiers.join(', ')} } from '${source}'`)
}
return [importCodes, assignCodes]
}
......@@ -150,8 +150,17 @@ function pathToGlob (pathString, glob, options = {}) {
}
return path.posix.join(safeStr, glob)
}
/**
* 字节跳动小程序可以配置 ext:// 开头的插件页面模板,如 ext://microapp-trade-plugin/order-confirm
* @param pagePath
* @returns
*/
function isNormalPage (pagePath) {
return !pagePath.startsWith('ext://')
}
module.exports = {
isNormalPage,
isInHBuilderX,
isInHBuilderXAlpha,
getCLIContext,
......
......@@ -317,6 +317,30 @@
]
]
],
"onLocationChange": [
"/platforms/h5/service/api/location/location-change.js",
[]
],
"onLocationChangeError": [
"/platforms/h5/service/api/location/location-change.js",
[]
],
"startLocationUpdate": [
"/platforms/h5/service/api/location/location-change.js",
[]
],
"stopLocationUpdate": [
"/platforms/h5/service/api/location/location-change.js",
[]
],
"offLocationChange": [
"/platforms/h5/service/api/location/location-change.js",
[]
],
"offLocationChangeError": [
"/platforms/h5/service/api/location/location-change.js",
[]
],
"chooseImage": [
"/platforms/h5/service/api/media/choose-image.js",
[
......@@ -359,8 +383,12 @@
"MovableView"
],
[
"/platforms/h5/components/system-routes/preview-image/index.vue",
"/platforms/h5/components/app/popup/preview-image/index.vue",
"PreviewImage"
],
[
"/platforms/h5/components/app/popup/mixins/preview-image.js",
"PreviewImageMixin"
]
]
],
......
......@@ -11,7 +11,8 @@ module.exports = {
style: '.css',
template: '.ksml'
},
project: 'project.ks.json'
project: 'project.ks.json',
subPackages: true
},
copyWebpackOptions (platformOptions, vueOptions) {
const copyOptions = ['kscomponents', 'ext.json']
......
......@@ -58,7 +58,7 @@ const tags = {
'login',
'inline-payment-panel'
],
'mp-weixin': [
'mp-weixin': [
'page-container',
'page-meta',
'navigation-bar',
......@@ -76,7 +76,8 @@ const tags = {
'ix-grid',
'ix-native-grid',
'ix-native-list',
'mkt'
'mkt',
'page-container'
]
}
......@@ -161,4 +162,4 @@ module.exports = function getCompilerOptions (platform) {
baseCompiler,
require(id + '/lib/uni.compiler.js')
)
}
}
......@@ -91,6 +91,7 @@ const plugins = [
UNI_PLATFORM: JSON.stringify(process.env.UNI_PLATFORM),
VUE_APP_PLATFORM: JSON.stringify(process.env.UNI_PLATFORM),
UNI_CLOUD_PROVIDER: process.env.UNI_CLOUD_PROVIDER,
UNI_SECURE_NETWORK: process.env.UNI_SECURE_NETWORK,
UNICLOUD_DEBUG: process.env.UNICLOUD_DEBUG,
RUN_BY_HBUILDERX: process.env.RUN_BY_HBUILDERX,
UNI_AUTOMATOR_WS_ENDPOINT: JSON.stringify(process.env.UNI_AUTOMATOR_WS_ENDPOINT),
......
......@@ -210,8 +210,7 @@ async function build (args, api, options) {
if (process.env.UNI_PLATFORM === 'h5' && !isInHBuilderX) {
console.log()
console.log('欢迎将H5站部署到uniCloud前端网页托管平台,高速、免费、安全、省心,详见:')
console.log('https://uniapp.dcloud.io/uniCloud/hosting')
console.log('欢迎将web站点部署到uniCloud前端网页托管平台,高速、免费、安全、省心,详见:https://uniapp.dcloud.io/uniCloud/hosting')
}
} else {
const dirMsg = runByHBuilderX ? ''
......
......@@ -52,6 +52,7 @@ module.exports = (api, options, rootOptions) => {
scripts: {}
},
dependencies: {
'@dcloudio/uni-app': version,
'@dcloudio/uni-app-plus': version,
'@dcloudio/uni-h5': version,
'@dcloudio/uni-mp-vue': version,
......
......@@ -5,7 +5,8 @@ const {
getMainEntry,
getPlatformStat,
getPlatformPush,
getPlatformUniCloud
getPlatformUniCloud,
uniModulesLoader
} = require('@dcloudio/uni-cli-shared')
const vueLoader = require('@dcloudio/uni-cli-shared/lib/vue-loader')
......@@ -65,7 +66,7 @@ const v3 = {
const pushCode = getPlatformPush()
const uniCloudCode = getPlatformUniCloud()
const beforeCode = 'import \'uni-pages\';'
const beforeCode = `import 'uni-pages';import '${uniModulesLoader}!';`
if (!webpackConfig.optimization) {
webpackConfig.optimization = {}
}
......@@ -163,7 +164,7 @@ const v3 = {
compiler: vueLoader.compiler,
before: [
beforeCode + require('../util').getAutomatorCode() + statCode + pushCode + uniCloudCode +
getGlobalUsingComponentsCode()
getGlobalUsingComponentsCode()
]
}
}]
......@@ -278,4 +279,4 @@ if (process.env.UNI_USING_V3) {
module.exports = v3
} else {
module.exports = require('../mp')
}
}
......@@ -135,6 +135,7 @@ module.exports = function chainWebpack (platformOptions, vueOptions, api) {
'process.env.UNI_PLATFORM': JSON.stringify(process.env.UNI_PLATFORM),
'process.env.UNI_SUB_PLATFORM': JSON.stringify(process.env.UNI_SUB_PLATFORM),
'process.env.UNI_CLOUD_PROVIDER': process.env.UNI_CLOUD_PROVIDER,
'process.env.UNI_SECURE_NETWORK': process.env.UNI_SECURE_NETWORK,
'process.env.UNICLOUD_DEBUG': process.env.UNICLOUD_DEBUG,
'process.env.RUN_BY_HBUILDERX': process.env.RUN_BY_HBUILDERX,
'process.env.UNI_AUTOMATOR_WS_ENDPOINT': JSON.stringify(process.env.UNI_AUTOMATOR_WS_ENDPOINT),
......@@ -160,6 +161,14 @@ module.exports = function chainWebpack (platformOptions, vueOptions, api) {
defines.__UNI_ROUTER_MODE__ = JSON.stringify('hash')
}
if (process.env.UNI_CLOUD_PROVIDER && process.env.NODE_ENV !== 'development') {
webpackConfig.optimization.minimizer('terser').tap((args) => {
// reduce_vars 优化常量
args[0].terserOptions.compress.reduce_vars = true
return args
})
}
webpackConfig
.plugin('uni-define')
.use(require.resolve('webpack/lib/DefinePlugin'), [defines])
......
......@@ -383,7 +383,8 @@ module.exports = function configureWebpack (platformOptions, manifestPlatformOpt
JSON.stringify({
type: 'stat'
}),
vuex: require.resolve('@dcloudio/vue-cli-plugin-uni/packages/vuex3')
vuex: require.resolve('@dcloudio/vue-cli-plugin-uni/packages/vuex3'),
'@vue/composition-api': require.resolve('@dcloudio/vue-cli-plugin-uni/packages/@vue/composition-api')
},
modules: [
process.env.UNI_INPUT_DIR,
......
......@@ -24,7 +24,8 @@ const {
getManifestJson,
isEnableUniPushV1,
isEnableUniPushV2,
isUniPushOffline
isUniPushOffline,
isEnableSecureNetwork
} = require('@dcloudio/uni-cli-shared/lib/manifest')
const manifestJsonObj = getManifestJson()
......@@ -129,6 +130,9 @@ if (!process.env.UNI_CLOUD_PROVIDER && process.env.UNI_CLOUD_SPACES) {
} catch (e) {}
}
// 安全网络
process.env.UNI_SECURE_NETWORK = isEnableSecureNetwork(manifestJsonObj, process.env.UNI_PLATFORM)
// 初始化环境变量
process.env.UNI_CLI_CONTEXT = require('@dcloudio/uni-cli-shared/lib/util').getCLIContext()
......
......@@ -7,7 +7,8 @@ const {
getH5Options,
getPlatformStat,
getPlatformPush,
getPlatformUniCloud
getPlatformUniCloud,
uniModulesLoader
} = require('@dcloudio/uni-cli-shared')
const {
......@@ -103,7 +104,7 @@ module.exports = {
} catch (e) {}
const beforeCode = (useBuiltIns === 'entry' ? 'import \'@babel/polyfill\';' : '') +
`import 'uni-pages';import 'uni-${process.env.UNI_PLATFORM}';`
`import 'uni-pages';import 'uni-${process.env.UNI_PLATFORM}';import '${uniModulesLoader}!';`
return {
resolve: {
......@@ -194,4 +195,4 @@ module.exports = {
require('./cssnano-options')(webpackConfig)
}
}
}
}
......@@ -9,7 +9,8 @@ const {
getPlatformCssnano,
getPlatformStat,
getPlatformPush,
getPlatformUniCloud
getPlatformUniCloud,
uniModulesLoader
} = require('@dcloudio/uni-cli-shared')
const WebpackUniAppPlugin = require('../../packages/webpack-uni-app-loader/plugin/index')
......@@ -181,7 +182,7 @@ module.exports = {
const pushCode = getPlatformPush()
const uniCloudCode = getPlatformUniCloud()
let beforeCode = 'import \'uni-pages\';'
let beforeCode = `import 'uni-pages';import '${uniModulesLoader}!';`
const plugins = [
new WebpackUniAppPlugin(),
......
MIT License
Copyright (c) 2019-present, liximomo(X.L)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# @vue/composition-api
Vue 2 plugin for **Composition API**
[![npm](https://img.shields.io/npm/v/@vue/composition-api)](https://www.npmjs.com/package/@vue/composition-api)
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/vuejs/composition-api/Build%20&%20Test)](https://github.com/vuejs/composition-api/actions?query=workflow%3A%22Build+%26+Test%22)
[![Minzipped size](https://badgen.net/bundlephobia/minzip/@vue/composition-api)](https://bundlephobia.com/result?p=@vue/composition-api)
English | [中文](./README.zh-CN.md)[**Composition API Docs**](https://v3.vuejs.org/guide/composition-api-introduction.html)
> ⚠️ With the release of [Vue 2.7](https://blog.vuejs.org/posts/vue-2-7-naruto.html), which has Composition API built-in, **you no longer need this plugin**. Thereby this plugin has entered maintenance mode and will only support Vue 2.6 or earlier. This project will reach End of Life by the end of 2022.
## Installation
### NPM
```bash
npm install @vue/composition-api
# or
yarn add @vue/composition-api
```
You must install `@vue/composition-api` as a plugin via `Vue.use()` before you can use the [Composition API](https://composition-api.vuejs.org/) to compose your component.
```js
import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'
Vue.use(VueCompositionAPI)
```
```js
// use the APIs
import { ref, reactive } from '@vue/composition-api'
```
> :bulb: When you migrate to Vue 3, just replacing `@vue/composition-api` to `vue` and your code should just work.
### CDN
Include `@vue/composition-api` after Vue and it will install itself automatically.
<!--cdn-links-start-->
```html
<script src="https://cdn.jsdelivr.net/npm/vue@2.6"></script>
<script src="https://cdn.jsdelivr.net/npm/@vue/composition-api@1.7.0"></script>
```
<!--cdn-links-end-->
`@vue/composition-api` will be exposed to global variable `window.VueCompositionAPI`.
```ts
const { ref, reactive } = VueCompositionAPI
```
## TypeScript Support
> TypeScript version **>4.2** is required
To let TypeScript properly infer types inside Vue component options, you need to define components with `defineComponent`
```ts
import { defineComponent } from '@vue/composition-api'
export default defineComponent({
// type inference enabled
})
```
### JSX/TSX
JSX is now officially supported on [vuejs/jsx](https://github.com/vuejs/jsx). You can enable it by following [this document](https://github.com/vuejs/jsx/tree/dev/packages/babel-preset-jsx#usage). A community maintained version can be found at [babel-preset-vca-jsx](https://github.com/luwanquan/babel-preset-vca-jsx) by [@luwanquan](https://github.com/luwanquan).
To support TSX, create a declaration file with the following content in your project.
```ts
// file: shim-tsx.d.ts
import Vue, { VNode } from 'vue';
import { ComponentRenderProxy } from '@vue/composition-api';
declare global {
namespace JSX {
interface Element extends VNode {}
interface ElementClass extends ComponentRenderProxy {}
interface ElementAttributesProperty {
$props: any; // specify the property name to use
}
interface IntrinsicElements {
[elem: string]: any;
}
}
}
```
## SSR
Even if there is no definitive Vue 3 API for SSR yet, this plugin implements the `onServerPrefetch` lifecycle hook that allows you to use the `serverPrefetch` hook found in the classic API.
```js
import { onServerPrefetch } from '@vue/composition-api'
export default {
setup(props, { ssrContext }) {
const result = ref()
onServerPrefetch(async () => {
result.value = await callApi(ssrContext.someId)
})
return {
result,
}
}
}
```
## Browser Compatibility
`@vue/composition-api` supports all modern browsers and IE11+. For lower versions IE you should install `WeakMap` polyfill (for example from `core-js` package).
## Limitations
> :white_check_mark: Support &nbsp;&nbsp;&nbsp;&nbsp;:x: Not Supported
### `Ref` Unwrap
<details>
<summary>
<b>Should NOT</b> use <code>ref</code> in a plain object when working with <code>Array</code>
</summary>
```js
const a = {
count: ref(0),
}
const b = reactive({
list: [a], // `a.count` will not unwrap!!
})
// no unwrap for `count`, `.value` is required
b.list[0].count.value === 0 // true
```
```js
const b = reactive({
list: [
{
count: ref(0), // no unwrap!!
},
],
})
// no unwrap for `count`, `.value` is required
b.list[0].count.value === 0 // true
```
</details>
<details>
<summary>
<b>Should</b> always use <code>ref</code> in a <code>reactive</code> when working with <code>Array</code>
</summary>
```js
const a = reactive({
list: [
reactive({
count: ref(0),
}),
]
})
// unwrapped
a.list[0].count === 0 // true
a.list.push(
reactive({
count: ref(1),
})
)
// unwrapped
a.list[1].count === 1 // true
```
</details>
### Template Refs
<details>
<summary>
✅ String ref && return it from <code>setup()</code>
</summary>
```html
<template>
<div ref="root"></div>
</template>
<script>
export default {
setup() {
const root = ref(null)
onMounted(() => {
// the DOM element will be assigned to the ref after initial render
console.log(root.value) // <div/>
})
return {
root,
}
},
}
</script>
```
</details>
<details>
<summary>
✅ String ref && return it from <code>setup()</code> && Render Function / JSX
</summary>
```jsx
export default {
setup() {
const root = ref(null)
onMounted(() => {
// the DOM element will be assigned to the ref after initial render
console.log(root.value) // <div/>
})
return {
root,
}
},
render() {
// with JSX
return () => <div ref="root" />
},
}
```
</details>
<details>
<summary>
❌ Function ref
</summary>
```html
<template>
<div :ref="el => root = el"></div>
</template>
<script>
export default {
setup() {
const root = ref(null)
return {
root,
}
},
}
</script>
```
</details>
<details>
<summary>
❌ Render Function / JSX in <code>setup()</code>
</summary>
```jsx
export default {
setup() {
const root = ref(null)
return () =>
h('div', {
ref: root,
})
// with JSX
return () => <div ref={root} />
},
}
```
</details>
<details>
<summary>
⚠️ <code>$refs</code> accessing workaround
</summary>
<br>
> :warning: **Warning**: The `SetupContext.refs` won't exist in `Vue 3.0`. `@vue/composition-api` provide it as a workaround here.
If you really want to use template refs in this case, you can access `vm.$refs` via `SetupContext.refs`
```jsx
export default {
setup(initProps, setupContext) {
const refs = setupContext.refs
onMounted(() => {
// the DOM element will be assigned to the ref after initial render
console.log(refs.root) // <div/>
})
return () =>
h('div', {
ref: 'root',
})
// with JSX
return () => <div ref="root" />
},
}
```
</details>
### Reactive
<details>
<summary>
⚠️ <code>reactive()</code> <b>mutates</b> the original object
</summary>
`reactive` uses `Vue.observable` underneath which will ***mutate*** the original object.
> :bulb: In Vue 3, it will return an new proxy object.
</details>
<details>
<summary>
⚠️ <code>set</code> and <code>del</code> workaround for adding and deleting reactive properties
</summary>
> ⚠️ Warning: `set` and `del` do NOT exist in Vue 3. We provide them as a workaround here, due to the limitation of [Vue 2.x reactivity system](https://vuejs.org/v2/guide/reactivity.html#For-Objects).
>
> In Vue 2, you will need to call `set` to track new keys on an `object`(similar to `Vue.set` but for `reactive objects` created by the Composition API). In Vue 3, you can just assign them like normal objects.
>
> Similarly, in Vue 2 you will need to call `del` to [ensure a key deletion triggers view updates](https://vuejs.org/v2/api/#Vue-delete) in reactive objects (similar to `Vue.delete` but for `reactive objects` created by the Composition API). In Vue 3 you can just delete them by calling `delete foo.bar`.
```ts
import { reactive, set, del } from '@vue/composition-api'
const a = reactive({
foo: 1
})
// add new reactive key
set(a, 'bar', 1)
// remove a key and trigger reactivity
del(a, 'bar')
```
</details>
### Watch
<details>
<summary>
<code>onTrack</code> and <code>onTrigger</code> are not available in <code>WatchOptions</code>
</summary>
```js
watch(() => {
/* ... */
}, {
immediate: true,
onTrack() {}, // not available
onTrigger() {}, // not available
})
```
</details>
### `createApp`
<details>
<summary>
⚠️ <code>createApp()</code> is global
</summary>
In Vue 3, `createApp()` is introduced to provide context(plugin, components, etc.) isolation between app instances. Due the the design of Vue 2, in this plugin, we provide `createApp()` as a forward compatible API which is just an alias of the global.
```ts
const app1 = createApp(RootComponent1)
app1.component('Foo', Foo) // equivalent to Vue.component('Foo', Foo)
app1.use(VueRouter) // equivalent to Vue.use(VueRouter)
const app2 = createApp(RootComponent2)
app2.component('Bar', Bar) // equivalent to Vue.use('Bar', Bar)
```
</details>
### `createElement` / `h`
<details>
<summary>
⚠️ <code>createElement</code> / <code>h</code> workaround
</summary>
<br>
`createElement` / `h` in Vue 2 is only accessable in `render()` function. To use it outside of `render()`, you can explicitly bind a component instance to it.
> :warning: **Warning**: This ability is provided as a workaround Vue 2, it's not part of the Vue 3 API.
```jsx
import { h as _h } from '@vue/composition-api'
export default {
setup() {
const vm = getCurrentInstance()
const h = _h.bind(vm)
return () =>
h('div', {
ref: 'root',
})
},
}
```
</details>
### `shallowReadonly`
<details>
<summary>
⚠️ <code>shallowReadonly()</code> will create a new object and with the same root properties, new properties added will <b>not</b> be readonly or reactive.
</summary>
> :bulb: In Vue 3, it will return an new proxy object.
</details>
### `readonly`
<details>
<summary>
⚠️ <code>readonly()</code> provides <b>only type-level</b> readonly check.
</summary>
`readonly()` is provided as API alignment with Vue 3 on type-level only. Use <code>isReadonly()</code> on it or it's properties can not be guaranteed.
</details>
### `props`
<details>
<summary>
⚠️ <code>toRefs(props.foo)</code> will incorrectly warn when accessing nested levels of props. <br>
&nbsp;&nbsp;&nbsp;&nbsp;⚠️ <code>isReactive(props.foo)</code> will return false.
</summary>
```ts
defineComponent({
setup(props) {
const { bar } = toRefs(props.foo) // it will `warn`
// use this instead
const { foo } = toRefs(props)
const a = foo.value.bar
}
})
```
</details>
### `computed().effect`
<details>
<summary>
⚠️ <code>computed()</code> has a property <code>effect</code> set to <code>true</code> instead of a <code>ReactiveEffect<T></code>.
</summary>
Due to the difference in implementation, there is no such concept as a `ReactiveEffect` in `@vue/composition-api`. Therefore, `effect` is merely `true` to enable differentiating computed from refs:
```ts
function isComputed<T>(o: ComputedRef<T> | unknown): o is ComputedRef<T>
function isComputed(o: any): o is ComputedRef {
return !!(isRef(o) && o.effect)
}
```
</details>
### Missing APIs
The following APIs introduced in Vue 3 are not available in this plugin.
- `onRenderTracked`
- `onRenderTriggered`
- `isProxy`
### Reactive APIs in `data()`
<details>
<summary>
❌ Passing <code>ref</code>, <code>reactive</code> or other reactive apis to <code>data()</code> would not work.
</summary>
```jsx
export default {
data() {
return {
// will result { a: { value: 1 } } in template
a: ref(1),
}
},
}
```
</details>
### `emits` Options
<details>
<summary>
<code>emits</code> option is provided in type-level only, in order to align with Vue 3's type interface. Does NOT have actual effects on the code.
</summary>
```ts
defineComponent({
emits: {
// has no effects
submit: (eventOption) => {
if (...) {
return true
} else {
console.warn('Invalid submit event payload!')
return false
}
}
}
})
```
</details>
### Performance Impact
Due the the limitation of Vue2's public API. `@vue/composition-api` inevitably introduces some performance overhead. Note that in most scenarios, this shouldn't be the source of performance issues.
You can check the [benchmark results](https://antfu.github.io/vue-composition-api-benchmark-results/) for more details.
# @vue/composition-api
用于提供 **组合式 API** 的 Vue 2 插件.
[![npm](https://img.shields.io/npm/v/@vue/composition-api)](https://www.npmjs.com/package/@vue/composition-api)
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/vuejs/composition-api/Build%20&%20Test)](https://github.com/vuejs/composition-api/actions?query=workflow%3A%22Build+%26+Test%22)
[English](./README.md) | 中文 ・ [**组合式 API 文档**](https://v3.cn.vuejs.org/guide/composition-api-introduction.html)
> ⚠️ 随着 [Vue 2.7](https://blog.vuejs.org/posts/vue-2-7-naruto.html)的发布,它内置了Composition API,**你不再需要这个插件了**。因此,这个插件已经进入维护模式,将只支持Vue 2.6 或更早的版本。本项目将在 2022 年底达到生命终点(EOL)。
## 安装
### NPM
```bash
npm install @vue/composition-api
# or
yarn add @vue/composition-api
```
在使用 `@vue/composition-api` 前,必须先通过 `Vue.use()` 进行安装。之后才可使用新的 [**组合式 API**](https://composition-api.vuejs.org/zh) 进行组件开发。
```js
import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'
Vue.use(VueCompositionAPI)
```
```js
// 使用 API
import { ref, reactive } from '@vue/composition-api'
```
> :bulb: 当迁移到 Vue 3 时,只需简单的将 `@vue/composition-api` 替换成 `vue` 即可。你现有的代码几乎无需进行额外的改动。
### CDN
在 Vue 之后引入 `@vue/composition-api` ,插件将会自动完成安装。
<!--cdn-links-start-->
```html
<script src="https://cdn.jsdelivr.net/npm/vue@2.6"></script>
<script src="https://cdn.jsdelivr.net/npm/@vue/composition-api@1.7.0"></script>
```
<!--cdn-links-end-->
`@vue/composition-api` 将会暴露在全局变量 `window.VueCompositionAPI` 中。
```ts
const { ref, reactive } = VueCompositionAPI
```
## TypeScript 支持
> 本插件要求使用 TypeScript **4.2** 或以上版本
为了让 TypeScript 在 Vue 组件选项中正确地进行类型推导,我们必须使用 `defineComponent` 来定义组件:
```ts
import { defineComponent } from '@vue/composition-api'
export default defineComponent({
// 类型推断启用
})
```
### JSX/TSX
JSX 现已在 [vuejs/jsx](https://github.com/vuejs/jsx) 中官方支持。你可以根据[这篇文档](https://github.com/vuejs/jsx/tree/dev/packages/babel-preset-jsx#usage)开启支持。你也可以使用由 [@luwanquan](https://github.com/luwanquan) 维护的社区版本 [babel-preset-vca-jsx](https://github.com/luwanquan/babel-preset-vca-jsx)
对于 TSX 支持,请在你的项目中创建如下声明文件:
```ts
// file: shim-tsx.d.ts
import Vue, { VNode } from 'vue';
import { ComponentRenderProxy } from '@vue/composition-api';
declare global {
namespace JSX {
interface Element extends VNode {}
interface ElementClass extends ComponentRenderProxy {}
interface ElementAttributesProperty {
$props: any; // specify the property name to use
}
interface IntrinsicElements {
[elem: string]: any;
}
}
}
```
## SSR
尽管 Vue 3 暂时没有给出确定的 SSR 的 API,这个插件实现了 `onServerPrefetch` 生命周期钩子函数。这个钩子允许你使用传统 API 中的 `serverPrefetch` 函数。
```js
import { onServerPrefetch } from '@vue/composition-api'
export default {
setup(props, { ssrContext }) {
const result = ref()
onServerPrefetch(async () => {
result.value = await callApi(ssrContext.someId)
})
return {
result,
}
},
}
```
## 浏览器兼容性
`@vue/composition-api` 支持所有现代浏览器以及IE11+。对于更低版本的IE浏览器你需要安装`WeakMap` polyfill (例如使用 `core-js`库)。
## 限制
> :white_check_mark: 支持 &nbsp;&nbsp;&nbsp;&nbsp;:x: 不支持
### `Ref` 自动展开 (unwrap)
<details>
<summary>
<b>不要</b> 在数组中使用含有 <code>ref</code> 的普通对象
</summary>
```js
const a = {
count: ref(0),
}
const b = reactive({
list: [a], // `a.count` 不会自动展开!!
})
// `count` 不会自动展开, 须使用 `.value`
b.list[0].count.value === 0 // true
```
```js
const b = reactive({
list: [
{
count: ref(0), // 不会自动展开!!
},
],
})
// `count` 不会自动展开, 须使用 `.value`
b.list[0].count.value === 0 // true
```
</details>
<details>
<summary>
✅ 在数组中,<b>应该</b> 总是将 <code>ref</code> 存放到 <code>reactive</code> 对象中
</summary>
```js
const a = reactive({
count: ref(0),
})
const b = reactive({
list: [a],
})
// 自动展开
b.list[0].count === 0 // true
b.list.push(
reactive({
count: ref(1),
})
)
// 自动展开
b.list[1].count === 1 // true
```
</details>
### 模板 Refs
<details>
<summary>
✅ 字符串 ref && 从 <code>setup()</code> 返回 ref
</summary>
```html
<template>
<div ref="root"></div>
</template>
<script>
export default {
setup() {
const root = ref(null)
onMounted(() => {
// 在初次渲染后 DOM 元素会被赋值给 ref
console.log(root.value) // <div/>
})
return {
root,
}
},
}
</script>
```
</details>
<details>
<summary>
✅ 字符串 ref && 从 <code>setup()</code> 返回 ref && 渲染函数 / JSX
</summary>
```jsx
export default {
setup() {
const root = ref(null)
onMounted(() => {
// 在初次渲染后 DOM 元素会被赋值给 ref
console.log(root.value) // <div/>
})
return {
root,
}
},
render() {
// 使用 JSX
return () => <div ref="root" />
},
}
```
</details>
<details>
<summary>
❌ 函数 ref
</summary>
```html
<template>
<div :ref="el => root = el"></div>
</template>
<script>
export default {
setup() {
const root = ref(null)
return {
root,
}
},
}
</script>
```
</details>
<details>
<summary>
❌ 在 <code>setup()</code> 中的渲染函数 / JSX
</summary>
```jsx
export default {
setup() {
const root = ref(null)
return () =>
h('div', {
ref: root,
})
// 使用 JSX
return () => <div ref={root} />
},
}
```
</details>
<details>
<summary>
⚠️ <code>$refs</code> 访问的变通方案
</summary>
> :warning: **警告**: `SetupContext.refs` 并非 `Vue 3.0` 的一部分, `@vue/composition-api` 将其暴露在 `SetupContext` 中只是临时提供一种变通方案。
如果你依然选择在 `setup()` 中写 `render` 函数,那么你可以使用 `SetupContext.refs` 来访问模板引用,它等价于 Vue 2.x 中的 `this.$refs`:
```js
export default {
setup(initProps, setupContext) {
const refs = setupContext.refs
onMounted(() => {
// 在初次渲染后 DOM 元素会被赋值给 ref
console.log(refs.root) // <div/>
})
return () =>
h('div', {
ref: 'root',
})
// 使用 JSX
return () => <div ref="root" />
},
}
```
如果项目使用了 TypeScript,你还需要扩展 `SetupContext` 类型:
```ts
import Vue from 'vue'
declare module '@vue/composition-api' {
interface SetupContext {
readonly refs: { [key: string]: Vue | Element | Vue[] | Element[] }
}
}
```
</details>
### Reactive
<details>
<summary>
⚠️ <code>reactive()</code> 会返回一个<b>修改过的</b>原始的对象
</summary>
此行为与 Vue 2 中的 `Vue.observable` 一致
> :bulb: 在 Vue 3 中,`reactive()` 会返回一个新的的代理对象
</details>
<details>
<summary>
⚠️ <code>set</code><code>del</code> 添加与刪除响应式属性变通方案
</summary>
> ⚠️ 警告: `set` 和 `del` 并非 Vue 3 的一部分。由于 [Vue 2.x 响应式系统的限制](https://vuejs.org/v2/guide/reactivity.html#For-Objects), 我们在这里提供它们作为一种变通方案。
> 在 Vue 2中,你将需要调用`set` 去追踪`object`上新的属性 (与`Vue.set`类似,但用于由 Composition API 创建的`reactive objects`)。在 Vue 3 中,你只需要像对待普通对象一样直接为属性赋值即可。
>
> 同样地, 在 Vue 2 中你将需要调用`del`去 [确保响应式对象中属性的删除将触发视图更新](https://vuejs.org/v2/api/#Vue-delete) (与`Vue.delete`类似,但用于由 Composition API 创建的`reactive objects`)。在Vue3中,你只需要通过调用 `delete foo.bar` 来删除它们。
```ts
import { reactive, set, del } from '@vue/composition-api'
const a = reactive({
foo: 1
})
// 添加新的响应式属性
set(a, 'bar', 1)
// 刪除属性并触发响应式更新
del(a, 'bar')
```
</details>
### Watch
<details>
<summary>
❌ 不支持 <code>onTrack</code><code>onTrigger</code> 选项
</summary>
```js
watch(
() => {
/* ... */
},
{
immediate: true,
onTrack() {}, // 不可用
onTrigger() {}, // 不可用
}
)
```
</details>
### `createApp`
<details>
<summary>
⚠️ <code>createApp()</code> 是全局的
</summary>
在 Vue3 中,引入了 `createApp()` 来隔离不同应用实例的上下文(plugin, components 等)。 由于 Vue2 的设计,在这个插件中,我们提供 `createApp()` 作为一个向前兼容的 API ,它只是全局的一个别名。
```ts
const app1 = createApp(RootComponent1)
app1.component('Foo', Foo) // 相当于 Vue.component('Foo', Foo)
app1.use(VueRouter) // 相当于 Vue.use(VueRouter)
const app2 = createApp(RootComponent2)
app2.component('Bar', Bar) // 相当于 Vue.use('Bar', Bar)
```
</details>
### `createElement` / `h`
<details>
<summary>
⚠️ <code>createElement</code> / <code>h</code> 变通方案
</summary>
<br>
在 Vue2中 `createElement` / `h` 只能通过 `render()` 函数访问。要在 `render()`之外使用它, 你可以显式地给它绑定一个组件实例。
> :warning: **警告**: 此功能是作为 Vue 2 的变通方法提供的,它不是 Vue 3 API 的一部分。
```jsx
import { h as _h } from '@vue/composition-api'
export default {
setup() {
const vm = getCurrentInstance()
const h = _h.bind(vm)
return () =>
h('div', {
ref: 'root',
})
},
}
```
</details>
### `shallowReadonly`
<details>
<summary>
⚠️ <code>shallowReadonly()</code> 会返回一个新的浅拷贝对象,在此之后新加的字段<b>将不会</b>获得只读或响应式状态。
</summary>
> :bulb: 在 Vue 3 中,`shallowReadonly()` 会返回一个新的的代理对象
</details>
### `readonly`
<details>
<summary>
⚠️ <code>readonly()</code> <b>只提供类型层面</b>的只读。
</summary>
`readonly()` 只在类型层面提供和 Vue 3 的对齐。在其返回值或其属性上使用 <code>isReadonly()</code> 检查的结果将无法保证。
</details>
### `props`
<details>
<summary>
⚠️ 当使用 <code>toRefs</code> 访问深层属性对象 (如 <code>toRefs(props.foo)</code> 时将会得到不正确的警告。<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;⚠️ <code>isReactive(props.foo)</code> 将会返回 false。
</summary>
```ts
defineComponent({
setup(props) {
const { bar } = toRefs(props.foo) // it will `warn`
// use this instead
const { foo } = toRefs(props)
const a = foo.value.bar
}
})
```
</details>
### `computed().effect`
<details>
<summary>
⚠️ <code>computed()</code> 拥有一个被设置为 <code>true</code><code>effect</code> 属性,用来代替 <code>ReactiveEffect<T></code>
</summary>
由于实现上的不同, 在 `@vue/composition-api` 中没有 `ReactiveEffect` 这种概念。 因此, `effect``true` 只是为了能够区分 computed 和 refs:
```ts
function isComputed<T>(o: ComputedRef<T> | unknown): o is ComputedRef<T>
function isComputed(o: any): o is ComputedRef {
return !!(isRef(o) && o.effect)
}
```
</details>
### 缺失的 API
以下在 Vue 3 新引入的 API ,在本插件中暂不适用:
- `onRenderTracked`
- `onRenderTriggered`
- `isProxy`
### 在 `data()` 中使用组合式 API
<details>
<summary>
❌ 在 <code>data()</code> 中使用 <code>ref</code>, <code>reactive</code> 或其他组合式 API 将不会生效
</summary>
```jsx
export default {
data() {
return {
// 在模版中会成为 { a: { value: 1 } }
a: ref(1),
}
},
}
```
</details>
### `emit` 选项
<details>
<summary>
<code>emit</code> 仅因在类型定义中对齐 Vue3 的选项而提供,<b>不会</b>有任何效果。
</summary>
```ts
defineComponent({
emit: {
// 无效
submit: (eventOption) => {
if (...) {
return true
} else {
console.warn('Invalid submit event payload!')
return false
}
}
}
})
```
</details>
### 性能影响
由于 Vue 2 的公共 API 的限制,`@vue/composition-api` 不可避免地引入了额外的性能开销。除非在极端情况下,否则这并不会对你造成影响。
你可以查看这个 [跑分结果](https://antfu.github.io/vue-composition-api-benchmark-results/) 了解更多信息。
'use strict'
if (process.env.NODE_ENV === 'production') {
module.exports = require('./dist/vue-composition-api.common.prod.js')
} else {
module.exports = require('./dist/vue-composition-api.common.js')
}
{
"name": "@vue/composition-api",
"version": "1.7.0",
"packageManager": "pnpm@7.0.0",
"description": "Provide logic composition capabilities for Vue.",
"keywords": [
"vue",
"composition-api"
],
"repository": {
"type": "git",
"url": "git+https://github.com/vuejs/composition-api.git"
},
"main": "./index.js",
"module": "./dist/vue-composition-api.mjs",
"unpkg": "./dist/vue-composition-api.prod.js",
"jsdelivr": "./dist/vue-composition-api.prod.js",
"types": "./dist/vue-composition-api.d.ts",
"exports": {
".": {
"import": "./dist/vue-composition-api.mjs",
"require": "./index.js"
},
"./*": "./*"
},
"author": {
"name": "liximomo",
"email": "liximomo@gmail.com"
},
"license": "MIT",
"sideEffects": false,
"files": [
"dist",
"index.js"
],
"scripts": {
"start": "rollup -c -w",
"build": "rimraf dist && rollup -c",
"lint": "prettier --write --parser typescript \"{src,test,test-dts}/**/*.ts?(x)\" && prettier --write \"{src,test}/**/*.js\"",
"test": "cross-env NODE_ENV=test jest",
"test:all": "pnpm run test && pnpm run test:dts",
"test:dts": "tsc -p ./test-dts/tsconfig.json && tsc -p ./test-dts/tsconfig.vue3.json && pnpm run build && tsc -p ./test-dts/tsconfig.build.json",
"update-readme": "node ./scripts/update-readme.js",
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s && pnpm run update-readme && git add CHANGELOG.md README.*",
"release": "bumpp -x \"npm run changelog\" --all --tag --commit --push && npm publish",
"release-gh": "conventional-github-releaser -p angular",
"prepublishOnly": "npm run build"
},
"bugs": {
"url": "https://github.com/vuejs/composition-api/issues"
},
"homepage": "https://github.com/vuejs/composition-api#readme",
"peerDependencies": {
"vue": ">= 2.5 < 2.7"
},
"devDependencies": {
"@rollup/plugin-node-resolve": "^13.3.0",
"@rollup/plugin-replace": "^4.0.0",
"@types/jest": "^26.0.24",
"@types/node": "^17.0.31",
"bumpp": "^7.1.1",
"conventional-changelog-cli": "^2.2.2",
"conventional-github-releaser": "^3.1.5",
"cross-env": "^7.0.3",
"jest": "^26.6.3",
"lint-staged": "^12.4.1",
"prettier": "^2.6.2",
"rimraf": "^3.0.2",
"rollup": "^2.72.0",
"rollup-plugin-dts": "^4.2.1",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-typescript2": "^0.31.2",
"simple-git-hooks": "^2.7.0",
"ts-jest": "^26.5.6",
"tslib": "^2.4.0",
"typescript": "^4.6.4",
"vue": "^2.6.14",
"vue-router": "^3.5.3",
"vue-server-renderer": "^2.6.14",
"vue3": "npm:vue@3.2.21"
},
"simple-git-hooks": {
"pre-commit": "lint-staged"
},
"lint-staged": {
"*.js": [
"prettier --write"
],
"*.ts?(x)": [
"prettier --parser=typescript --write"
]
},
"jest": {
"verbose": true,
"globals": {
"__DEV__": true,
"__VERSION__": "0.0.0"
},
"setupFiles": [
"<rootDir>/test/setupTest.js"
],
"setupFilesAfterEnv": [
"<rootDir>/test/helpers/wait-for-update.js"
],
"moduleFileExtensions": [
"ts",
"js"
],
"testMatch": [
"<rootDir>/test/**/*.spec.{js,ts}"
],
"preset": "ts-jest"
},
"prettier": {
"semi": false,
"singleQuote": true,
"printWidth": 80
}
}
......@@ -5420,6 +5420,8 @@ Vue.version = '2.6.11';
*/
var ARRAYTYPE = '[object Array]';
var OBJECTTYPE = '[object Object]';
var NULLTYPE = '[object Null]';
var UNDEFINEDTYPE = '[object Undefined]';
// const FUNCTIONTYPE = '[object Function]'
function diff(current, pre) {
......@@ -5453,6 +5455,16 @@ function syncKeys(current, pre) {
}
}
function nullOrUndefined(currentType, preType) {
if(
(currentType === NULLTYPE || currentType === UNDEFINEDTYPE) &&
(preType === NULLTYPE || preType === UNDEFINEDTYPE)
) {
return false
}
return true
}
function _diff(current, pre, path, result) {
if (current === pre) { return }
var rootCurrentType = type(current);
......@@ -5467,7 +5479,7 @@ function _diff(current, pre, path, result) {
var currentType = type(currentValue);
var preType = type(preValue);
if (currentType != ARRAYTYPE && currentType != OBJECTTYPE) {
if (currentValue !== pre[key]) {
if (currentValue !== pre[key] && nullOrUndefined(currentType, preType)) {
setResult(result, (path == '' ? '' : path + ".") + key, currentValue);
}
} else if (currentType == ARRAYTYPE) {
......@@ -5585,6 +5597,16 @@ function nextTick$1(vm, cb) {
/* */
function clearInstance(key, value) {
// 简易去除 Vue 和小程序组件实例
if (value) {
if (value._isVue || (value.$vm && value.$vm._isVue)) {
return {}
}
}
return value
}
function cloneWithData(vm) {
// 确保当前 vm 所有数据被同步
var ret = Object.create(null);
......@@ -5616,7 +5638,7 @@ function cloneWithData(vm) {
ret['value'] = vm.value;
}
return JSON.parse(JSON.stringify(ret))
return JSON.parse(JSON.stringify(ret, clearInstance))
}
var patch = function(oldVnode, vnode) {
......
......@@ -39,9 +39,11 @@ const {
// 将开发者手动设置的 usingComponents 调整名称,方便与自动解析到的 usingComponents 做最后合并
function renameUsingComponents (jsonObj) {
if (jsonObj.usingComponents) {
jsonObj.customUsingComponents = jsonObj.usingComponents
if (jsonObj.usingComponents || jsonObj.usingSwanComponents) {
// 暂定 usingComponents 优先级高于 usingSwanComponents
jsonObj.customUsingComponents = Object.assign({}, jsonObj.usingSwanComponents, jsonObj.usingComponents)
delete jsonObj.usingComponents
delete jsonObj.usingSwanComponents
}
return jsonObj
}
......
......@@ -257,32 +257,6 @@ const genSystemRoutes = function () {
return [
`
{
path: '/preview-image',
component: {
render (createElement) {
return createElement(
'Page',
{
props:{
navigationStyle:'custom'
}
},
[
createElement('system-preview-image', {
slot: 'page'
})
]
)
}
},
meta:{
name:'preview-image',
pagePath:'/preview-image'
}
}
`,
`
{
path: '/choose-location',
component: {
render (createElement) {
......
......@@ -49,9 +49,11 @@ function deepCopy (name, value, json) {
const pagesJson2AppJson = {
globalStyle: function (name, value, json) {
json.window = parseStyle(value)
if (json.window.usingComponents) {
json.usingComponents = json.window.usingComponents
if (json.window.usingComponents || json.window.usingSwanComponents) {
// 暂定 usingComponents 优先级高于 usingSwanComponents
json.usingComponents = Object.assign({}, json.window.usingSwanComponents, json.window.usingComponents)
delete json.window.usingComponents
delete json.window.usingSwanComponents
} else {
json.usingComponents = {}
}
......
......@@ -133,6 +133,7 @@ function parseTabBar (style = {}) {
const NON_APP_JSON_KEYS = [
'appid',
'unipush',
'secureNetwork',
'usingComponents',
'optimization',
'scopedSlotsCompiler',
......
......@@ -67,7 +67,7 @@ if (typeof Proxy !== 'undefined' && __PLATFORM__ !== 'app-plus') {
if (eventApi[name]) {
return eventApi[name]
}
if (!hasOwn(__GLOBAL__, name) && !hasOwn(protocols, name)) {
if (typeof __GLOBAL__[name] !== 'function' && !hasOwn(protocols, name)) {
return
}
return promisify(name, wrapper(name, __GLOBAL__[name]))
......
......@@ -50,7 +50,7 @@ function hasHook (hook, vueOptions) {
return false
}
if (isFn(vueOptions[hook])) {
if (isFn(vueOptions[hook]) || Array.isArray(vueOptions[hook])) {
return true
}
const mixins = vueOptions.mixins
......
......@@ -133,7 +133,7 @@ export const onPushMessage = (fn) => {
onPushMessageCallbacks.push(fn)
}
// 不能程序启动时就监听,因为离线事件,仅触发一次,框架监听后,无法转发给还没开始监听的开发者
if (__PLATFORM__ === 'app' && !listening) {
if (__PLATFORM__ === 'app-plus' && !listening) {
listening = true
plus.push.addEventListener('click', (result) => {
invokePushCallback({
......
......@@ -29,7 +29,6 @@ function isiOS () {
return false
}
let textChanging = false
export default {
name: 'Editor',
mixins: [subscriber, emitter, keyboard],
......@@ -106,6 +105,9 @@ export default {
})
},
methods: {
_textChangeHandler () {
this.$trigger('input', {}, this.getContents())
},
_handleSubscribe ({
type,
data
......@@ -161,18 +163,19 @@ export default {
range = quill.getSelection(true)
const { src = '', alt = '', width = '', height = '', extClass = '', data = {} } = options
const path = this.$getRealPath(src)
quill.insertEmbed(range.index, 'image', path, Quill.sources.USER)
quill.insertEmbed(range.index, 'image', path, Quill.sources.SILENT)
const local = /^(file|blob):/.test(path) ? path : false
// 防止 formatText 多次触发 Quill.events.TEXT_CHANGE 事件
textChanging = true
quill.formatText(range.index, 1, 'data-local', local)
quill.formatText(range.index, 1, 'alt', alt)
quill.formatText(range.index, 1, 'width', width)
quill.formatText(range.index, 1, 'height', height)
quill.formatText(range.index, 1, 'class', extClass)
textChanging = false
quill.formatText(range.index, 1, 'data-custom', Object.keys(data).map(key => `${key}=${data[key]}`).join('&'))
quill.formatText(range.index, 1, 'data-local', local, Quill.sources.SILENT)
quill.formatText(range.index, 1, 'alt', alt, Quill.sources.SILENT)
quill.formatText(range.index, 1, 'width', width, Quill.sources.SILENT)
quill.formatText(range.index, 1, 'height', height, Quill.sources.SILENT)
quill.formatText(range.index, 1, 'class', extClass, Quill.sources.SILENT)
quill.formatText(range.index, 1, 'data-custom', Object.keys(data).map(key => `${key}=${data[key]}`).join('&'), Quill.sources.SILENT)
quill.setSelection(range.index + 1, Quill.sources.SILENT)
quill.scrollIntoView()
setTimeout(() => {
this._textChangeHandler()
}, 1000)
}
break
case 'insertText':
......@@ -289,11 +292,7 @@ export default {
}
})
})
quill.on(Quill.events.TEXT_CHANGE, () => {
if (!textChanging) {
this.$trigger('input', {}, this.getContents())
}
})
quill.on(Quill.events.TEXT_CHANGE, this._textChangeHandler)
quill.on(Quill.events.SELECTION_CHANGE, this.updateStatus.bind(this))
quill.on(Quill.events.SCROLL_OPTIMIZE, () => {
const range = quill.selection.getRange()[0]
......
import parseBaseComponent from '../../../mp-weixin/runtime/wrapper/component-parser'
export default function parseComponent (vueComponentOptions) {
const componentOptions = parseBaseComponent(vueComponentOptions)
export default function parseComponent (vueComponentOptions, needVueOptions) {
const [componentOptions, vueOptions] = parseBaseComponent(vueComponentOptions, true)
componentOptions.methods.$getAppWebview = function () {
return plus.webview.getWebviewById(`${this.__wxWebviewId__}`)
}
return componentOptions
}
return needVueOptions ? [componentOptions, vueOptions] : componentOptions
}
......@@ -64,7 +64,9 @@ class AdBase {
const data = {
code: e.code,
errMsg: e.message
errCode: e.code,
errMsg: e.message,
detail: e.detail
}
this._adError = data
......@@ -74,6 +76,7 @@ class AdBase {
const error = new Error(JSON.stringify(this._adError))
error.code = e.code
error.errMsg = e.message
error.detail = e.detail
if (this._loadPromiseReject != null) {
this._loadPromiseReject(error)
......
......@@ -29,6 +29,7 @@ export * from './file/open-document'
export * from './location/choose-location'
export * from './location/get-location'
export * from './location/open-location'
export * from './location/location-change'
export * from './media/audio'
export * from './media/choose-image'
......
......@@ -21,11 +21,12 @@ export default class UniHoverElement extends UniAnimationElement {
set hovering (hovering) {
this._hovering = hovering
const hoverClass = this.getAttribute('hover-class')
const hoverClass = this.getAttribute('hover-class').split(' ').filter(Boolean)
const ClassList = this.classList
if (hovering) {
this.classList.add(hoverClass)
ClassList.add.apply(ClassList, hoverClass)
} else {
this.classList.remove(hoverClass)
ClassList.remove.apply(ClassList, hoverClass)
}
}
......
import Toast from './toast'
import Modal from './modal'
import ActionSheet from './actionSheet'
import PreviewImage from './preview-image'
export default {
Toast,
Modal,
ActionSheet
ActionSheet,
PreviewImage
}
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册