From be7bacd4b70925e5788b285d2d98a3da0b5f069e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E6=97=BA?= Date: Sun, 11 Jul 2021 13:06:28 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E5=BF=AB=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E5=B9=B3=E5=8F=B0=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lerna.json | 4 +- package.json | 1 + packages/shared/src/components.ts | 2 +- packages/shared/src/template.ts | 6 +- packages/shared/src/utils.ts | 6 + packages/taro-cli/package.json | 1 + packages/taro-cli/src/cli.ts | 3 +- packages/taro-cli/tsconfig.json | 3 +- packages/taro-components-qa/package.json | 2 +- .../src/components/taro-audio/img.js | 4 - .../src/components/taro-audio/index.ux | 3 +- .../src/components/taro-button/img.js | 1 - .../src/components/taro-button/index.ux | 249 +- .../{checkbox => taro-checkbox}/index.ux | 0 .../components/{icon => taro-icon}/index.ux | 0 .../src/components/taro-image/index.ux | 3 +- .../{navigator => taro-navigator}/index.ux | 0 .../src/components/taro-page/index.ux | 12 +- .../components/{radio => taro-radio}/index.ux | 0 .../{rich-text => taro-rich-text}/index.ux | 0 .../index.ux | 0 .../index.ux | 13 +- .../src/components/taro-text/index.ux | 49 - .../src/components/taro-video/index.ux | 5 +- .../{web-view => taro-web-view}/index.ux | 0 packages/taro-components/types/index.d.ts | 94 +- packages/taro-helper/src/constants.ts | 1 + packages/taro-loader/src/app.ts | 7 +- packages/taro-loader/src/component.ts | 3 +- packages/taro-loader/src/independentPage.ts | 3 +- packages/taro-loader/src/native-component.ts | 3 +- packages/taro-loader/src/page.ts | 3 +- packages/taro-loader/src/utils.ts | 4 + packages/taro-mini-runner/package.json | 1 + .../src/loaders/quickappStyleLoader.ts | 2 +- .../src/plugins/MiniPlugin.ts | 309 +- .../src/plugins/TaroLoadChunksPlugin.ts | 29 +- .../src/quickapp/script/index.ts | 3 + .../src/quickapp/script/mini-app.ts | 31 + .../src/quickapp/script/mini-component.ts | 23 + .../src/quickapp/script/mini-page.ts | 50 + .../src/quickapp/script/utils.ts | 8 + .../src/quickapp/style-rewriter2.ts | 83 + .../src/quickapp/template/serialize.ts | 4 +- .../src/template/component.ts | 10 +- .../taro-mini-runner/src/template/quickapp.ts | 3 + packages/taro-mini-runner/src/utils/helper.ts | 77 +- .../taro-mini-runner/src/webpack/base.conf.ts | 10 + .../src/webpack/build.conf.ts | 7 +- .../taro-mini-runner/src/webpack/chain.ts | 2 +- packages/taro-quickapp/README.md | 3 + packages/taro-quickapp/index.js | 3 + packages/taro-quickapp/package.json | 38 + packages/taro-quickapp/rollup.config.js | 62 + .../taro-quickapp/src/api/device/index.js | 95 + .../taro-quickapp/src/api/equipment/index.js | 203 ++ packages/taro-quickapp/src/api/index.js | 15 + .../src/api/interactive/index.js | 197 ++ packages/taro-quickapp/src/api/media/index.js | 75 + .../src/api/notification/index.js | 18 + .../taro-quickapp/src/api/request/index.js | 190 + .../taro-quickapp/src/api/router/index.js | 91 + packages/taro-quickapp/src/api/share/index.js | 29 + .../taro-quickapp/src/api/storage/index.js | 100 + .../taro-quickapp/src/api/system/index.js | 224 ++ .../src/api/unsupportedApi/index.js | 276 ++ packages/taro-quickapp/src/api/utils/index.js | 42 + packages/taro-quickapp/src/api/utils/path.js | 47 + .../taro-quickapp/src/api/webview/index.js | 9 + packages/taro-quickapp/src/apis.ts | 5 + packages/taro-quickapp/src/compile-utils.ts | 49 + .../taro-quickapp/src/components-react.ts | 71 + packages/taro-quickapp/src/components.ts | 187 + packages/taro-quickapp/src/index.ts | 186 + .../src}/manifest.default.json | 2 +- packages/taro-quickapp/src/program.ts | 78 + packages/taro-quickapp/src/runtime-utils.ts | 13 + packages/taro-quickapp/src/runtime.ts | 5 + packages/taro-quickapp/src/template.ts | 100 + packages/taro-quickapp/tsconfig.json | 28 + packages/taro-quickapp/types/apis.d.ts | 1 + .../taro-quickapp/types/compile-utils.d.ts | 2 + .../taro-quickapp/types/components-react.d.ts | 69 + packages/taro-quickapp/types/components.d.ts | 185 + packages/taro-quickapp/types/index.d.ts | 5 + packages/taro-quickapp/types/program.d.ts | 32 + .../taro-quickapp/types/runtime-utils.d.ts | 8 + packages/taro-quickapp/types/runtime.d.ts | 1 + .../taro-quickapp/types/shims-quickapp.d.ts | 1114 ++++++ packages/taro-quickapp/types/template.d.ts | 26 + packages/taro-quickapp/yarn.lock | 3070 +++++++++++++++++ packages/taro-react/src/props.ts | 8 +- packages/taro-runtime/src/dsl/common.ts | 44 +- packages/taro-runtime/src/dsl/instance.ts | 15 + packages/taro-runtime/src/index.ts | 2 +- packages/taro-runtime/src/reconciler.ts | 2 + .../taro-service/src/platform-plugin-base.ts | 13 + .../types/platform-plugin-base.d.ts | 4 + yarn.lock | 9 +- 99 files changed, 7813 insertions(+), 375 deletions(-) delete mode 100644 packages/taro-components-qa/src/components/taro-audio/img.js delete mode 100644 packages/taro-components-qa/src/components/taro-button/img.js rename packages/taro-components-qa/src/components/{checkbox => taro-checkbox}/index.ux (100%) rename packages/taro-components-qa/src/components/{icon => taro-icon}/index.ux (100%) rename packages/taro-components-qa/src/components/{navigator => taro-navigator}/index.ux (100%) rename packages/taro-components-qa/src/components/{radio => taro-radio}/index.ux (100%) rename packages/taro-components-qa/src/components/{rich-text => taro-rich-text}/index.ux (100%) rename packages/taro-components-qa/src/components/{scroll-view => taro-scroll-view}/index.ux (100%) rename packages/taro-components-qa/src/components/{swiper-item => taro-swiper-item}/index.ux (79%) delete mode 100644 packages/taro-components-qa/src/components/taro-text/index.ux rename packages/taro-components-qa/src/components/{web-view => taro-web-view}/index.ux (100%) create mode 100644 packages/taro-mini-runner/src/quickapp/script/index.ts create mode 100644 packages/taro-mini-runner/src/quickapp/script/mini-app.ts create mode 100644 packages/taro-mini-runner/src/quickapp/script/mini-component.ts create mode 100644 packages/taro-mini-runner/src/quickapp/script/mini-page.ts create mode 100644 packages/taro-mini-runner/src/quickapp/script/utils.ts create mode 100644 packages/taro-mini-runner/src/quickapp/style-rewriter2.ts create mode 100644 packages/taro-mini-runner/src/template/quickapp.ts create mode 100644 packages/taro-quickapp/README.md create mode 100644 packages/taro-quickapp/index.js create mode 100644 packages/taro-quickapp/package.json create mode 100644 packages/taro-quickapp/rollup.config.js create mode 100644 packages/taro-quickapp/src/api/device/index.js create mode 100644 packages/taro-quickapp/src/api/equipment/index.js create mode 100644 packages/taro-quickapp/src/api/index.js create mode 100644 packages/taro-quickapp/src/api/interactive/index.js create mode 100644 packages/taro-quickapp/src/api/media/index.js create mode 100644 packages/taro-quickapp/src/api/notification/index.js create mode 100644 packages/taro-quickapp/src/api/request/index.js create mode 100644 packages/taro-quickapp/src/api/router/index.js create mode 100644 packages/taro-quickapp/src/api/share/index.js create mode 100644 packages/taro-quickapp/src/api/storage/index.js create mode 100644 packages/taro-quickapp/src/api/system/index.js create mode 100644 packages/taro-quickapp/src/api/unsupportedApi/index.js create mode 100644 packages/taro-quickapp/src/api/utils/index.js create mode 100644 packages/taro-quickapp/src/api/utils/path.js create mode 100644 packages/taro-quickapp/src/api/webview/index.js create mode 100644 packages/taro-quickapp/src/apis.ts create mode 100644 packages/taro-quickapp/src/compile-utils.ts create mode 100644 packages/taro-quickapp/src/components-react.ts create mode 100644 packages/taro-quickapp/src/components.ts create mode 100644 packages/taro-quickapp/src/index.ts rename packages/{taro-cli/src/config => taro-quickapp/src}/manifest.default.json (96%) create mode 100644 packages/taro-quickapp/src/program.ts create mode 100644 packages/taro-quickapp/src/runtime-utils.ts create mode 100644 packages/taro-quickapp/src/runtime.ts create mode 100644 packages/taro-quickapp/src/template.ts create mode 100644 packages/taro-quickapp/tsconfig.json create mode 100644 packages/taro-quickapp/types/apis.d.ts create mode 100644 packages/taro-quickapp/types/compile-utils.d.ts create mode 100644 packages/taro-quickapp/types/components-react.d.ts create mode 100644 packages/taro-quickapp/types/components.d.ts create mode 100644 packages/taro-quickapp/types/index.d.ts create mode 100644 packages/taro-quickapp/types/program.d.ts create mode 100644 packages/taro-quickapp/types/runtime-utils.d.ts create mode 100644 packages/taro-quickapp/types/runtime.d.ts create mode 100644 packages/taro-quickapp/types/shims-quickapp.d.ts create mode 100644 packages/taro-quickapp/types/template.d.ts create mode 100644 packages/taro-quickapp/yarn.lock diff --git a/lerna.json b/lerna.json index 313106c71613..f91a8f26dbda 100644 --- a/lerna.json +++ b/lerna.json @@ -16,6 +16,7 @@ "packages/taro-components", "packages/taro-components-react", "packages/taro-components-rn", + "packages/taro-components-qa", "packages/taro-extend", "packages/taro-h5", "packages/taro-helper", @@ -43,7 +44,8 @@ "packages/taro-swan", "packages/taro-tt", "packages/taro-qq", - "packages/taro-jd" + "packages/taro-jd", + "packages/taro-quickapp" ], "command": { "publish": { diff --git a/package.json b/package.json index a6f21f59a519..321be19e18f5 100644 --- a/package.json +++ b/package.json @@ -167,6 +167,7 @@ "webpack-merge": "^4.2.2" }, "dependencies": { + "@rollup/plugin-json": "^4.1.0", "@types/babel__traverse": "^7.0.7", "@types/react-reconciler": "^0.18.0" } diff --git a/packages/shared/src/components.ts b/packages/shared/src/components.ts index 5e8088ed9ff3..653240c19cf1 100644 --- a/packages/shared/src/components.ts +++ b/packages/shared/src/components.ts @@ -132,7 +132,7 @@ const Input = { focus: 'false', 'confirm-type': singleQuote('done'), 'confirm-hold': 'false', - cursor: 'i.value.length', + cursor: '(i.value && i.value.length)', 'selection-start': '-1', 'selection-end': '-1', bindInput: '', diff --git a/packages/shared/src/template.ts b/packages/shared/src/template.ts index 217d0675d5a2..a232796d7d38 100644 --- a/packages/shared/src/template.ts +++ b/packages/shared/src/template.ts @@ -25,16 +25,16 @@ import { Shortcuts } from './shortcuts' import { isBooleanStringLiteral, isNumber, isFunction } from './is' import { toCamelCase, toKebabCase, toDashed, hasOwn } from './utils' -interface Component { +export interface Component { nodeName: string; attributes: Attributes; } -interface Components { +export interface Components { [key: string]: Record; } -interface ComponentConfig { +export interface ComponentConfig { includes: Set exclude: Set thirdPartyComponents: Map> diff --git a/packages/shared/src/utils.ts b/packages/shared/src/utils.ts index 2c781cf50208..889f2c4104fd 100644 --- a/packages/shared/src/utils.ts +++ b/packages/shared/src/utils.ts @@ -11,6 +11,12 @@ export const defaultReconciler = { // eslint-disable-next-line @typescript-eslint/no-unused-vars isBubbleEvent (eventName: string) { return BUBBLE_EVENTS.has(eventName) + }, + modifyBindEventName (eventName: string, compName: string) { + if (eventName === 'click' && compName in internalComponents) { + return 'tap' + } + return eventName } } diff --git a/packages/taro-cli/package.json b/packages/taro-cli/package.json index d8df241b8496..c9d065633ed9 100644 --- a/packages/taro-cli/package.json +++ b/packages/taro-cli/package.json @@ -51,6 +51,7 @@ "@tarojs/plugin-platform-swan": "3.2.16", "@tarojs/plugin-platform-tt": "3.2.16", "@tarojs/plugin-platform-weapp": "3.2.16", + "@tarojs/plugin-platform-quickapp": "3.2.16", "@tarojs/service": "3.2.16", "@tarojs/shared": "3.2.16", "@tarojs/taro": "3.2.16", diff --git a/packages/taro-cli/src/cli.ts b/packages/taro-cli/src/cli.ts index a770c139a107..a5124672ec4c 100644 --- a/packages/taro-cli/src/cli.ts +++ b/packages/taro-cli/src/cli.ts @@ -50,7 +50,8 @@ export default class CLI { '@tarojs/plugin-platform-swan', '@tarojs/plugin-platform-tt', '@tarojs/plugin-platform-qq', - '@tarojs/plugin-platform-jd' + '@tarojs/plugin-platform-jd', + '@tarojs/plugin-platform-quickapp' ] customCommand('build', kernel, { _: args._, diff --git a/packages/taro-cli/tsconfig.json b/packages/taro-cli/tsconfig.json index 09e0fc3936db..2b8e0132710b 100644 --- a/packages/taro-cli/tsconfig.json +++ b/packages/taro-cli/tsconfig.json @@ -18,7 +18,8 @@ "strictNullChecks": true, "target": "es2015", "traceResolution": false, - "types": ["node", "jest"] + "types": ["node", "jest"], + "skipLibCheck": true }, "include": [ "./src" diff --git a/packages/taro-components-qa/package.json b/packages/taro-components-qa/package.json index 648bdc389b83..88fb3cb5bf0c 100644 --- a/packages/taro-components-qa/package.json +++ b/packages/taro-components-qa/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/components-qa", - "version": "1.3.22", + "version": "3.2.16", "description": "多端解决方案基础组件(快应用)", "main": "./index.js", "files": [ diff --git a/packages/taro-components-qa/src/components/taro-audio/img.js b/packages/taro-components-qa/src/components/taro-audio/img.js deleted file mode 100644 index 786f335bf122..000000000000 --- a/packages/taro-components-qa/src/components/taro-audio/img.js +++ /dev/null @@ -1,4 +0,0 @@ -export const PAUSE_IMG = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAABMklEQVRoQ+2Z0Y3CQAxE7QqOEqAjbwd0QAmEDijhOliXBBVAB0YrATqdkGxl10SRZn/XmXiek/kx08oPr7x/goGlJ4gJrGICIrIhoiMR7YnoTkS/qnoa1XyPfugTEpEzMx/+NmxmJ1WdRpjo0Y8auDFzm8L7mNlFVXeDDMzWDxkopdinRmutoec9kz36oQZ6XuA13+579GEgQtirwQQyCXna+AeyCWXrI4UihL0apFAmIU8bKZRNKFsfKRQh7NUghTIJedpIoWxC2fpIoQhhrwYplEnI00YKZRPK1kcKRQh7NUihTEKe9rdSqC01fv41c621biMNejWllNn6oZ9YRCZmbhua9xm84JitHzLQun6aaCsmMrO2YhqynXkRmasfNuB9Bkvdw8BS5F/vxQQwgU4CD9RcRkCIkNZgAAAAAElFTkSuQmCC' -export const START_IMG = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAB2klEQVRoQ9WZfVEEMQzFEwXgACSAk+IAHIAC7hRwKAAJwQE4AAWAA1DwmDdTZjo3cNtuu023f3d282s+XtKqrHzpyu2XIoAQwqmZfYwEnQUQQggi8qCqxwC+RGRjZvcjgEwC8NRV9X3fWADPInJhZgRyWzkA16p695eF0RuEIIzLygHYqOrtIesA7MzsxoOgCQANB/AaQ6prkjcDiBDMhxsze+zljaYAv0YDMBG56pHgiwBEbzCUmOAMrcXWYgCJN6gZ26UIFgeI3lhMM7oAJAnOvGB+NFvdAJKQaqoZ3QESzaA3qhPcBaClZrgBtNIMd4BazRgCoEYzhgKYoxnDASQJnjVnDAmQQJxPzeDDAkSIrZltDsn26ACcLXZrBfgGcLbWEPoEEHJajRFD6AnAZe40NxIAQ4bDz8GY38+HUQDe4qkXd6fuAAB4RcmTn3XD5wnAkGGsV01oXgAv0fjqS7DuAAAm1bVkYO4JwNrOkGl6EdwLoKi2j+SBWbV9FIDZtd0doLa2ewI0qe1eAKzt7CBnKWqJ0eneJlWodW0vgckB+PeRT0Sy+/YSo0r25gDwmZVd4tHehxer7U0B+DE+dKsq+/QTEemeqFUzcclpeOydDCEPo0r+uXqAHzf0dkAxk0BxAAAAAElFTkSuQmCC' - -export default PAUSE_IMG diff --git a/packages/taro-components-qa/src/components/taro-audio/index.ux b/packages/taro-components-qa/src/components/taro-audio/index.ux index 753857fb2a8d..f76760ab6cd8 100644 --- a/packages/taro-components-qa/src/components/taro-audio/index.ux +++ b/packages/taro-components-qa/src/components/taro-audio/index.ux @@ -26,7 +26,8 @@ + onInit() { + this.btnClass = `taro-button taro-button-${this.type} taro-button-${this.size} ${this.plain ? `taro-button-plain` : `taro-button-noplain`} ${this.disabled ? `taro-button-disabled` : `taro-button-nodisabled`} ${this.circle ? `taro-button-circle` : `taro-button-nocircle`} ${this.className}`; + this.imageClass = `taro-spin taro-spin-${this.size}`; + this.spinType = this.spin; + this.circularClass = `taro-circular taro-circular-${this.type} taro-circular-${this.size}`; + }, + + onclick() {} +}; diff --git a/packages/taro-components-qa/src/components/checkbox/index.ux b/packages/taro-components-qa/src/components/taro-checkbox/index.ux similarity index 100% rename from packages/taro-components-qa/src/components/checkbox/index.ux rename to packages/taro-components-qa/src/components/taro-checkbox/index.ux diff --git a/packages/taro-components-qa/src/components/icon/index.ux b/packages/taro-components-qa/src/components/taro-icon/index.ux similarity index 100% rename from packages/taro-components-qa/src/components/icon/index.ux rename to packages/taro-components-qa/src/components/taro-icon/index.ux diff --git a/packages/taro-components-qa/src/components/taro-image/index.ux b/packages/taro-components-qa/src/components/taro-image/index.ux index 50b9a3c7c977..fb158e6a014d 100644 --- a/packages/taro-components-qa/src/components/taro-image/index.ux +++ b/packages/taro-components-qa/src/components/taro-image/index.ux @@ -51,7 +51,7 @@ }), onInit () { - let imageStyle = {} + this.imageStyle = Object.assign({}, this.customstyle) switch (this.mode) { case 'scaleToFill': this.imageStyle['object-fit'] = 'fill'; @@ -65,7 +65,6 @@ default: this.imageStyle['object-fit'] = 'fill'; } - this.imageStyle = Object.assign({}, this.customstyle) }, handleClick () { diff --git a/packages/taro-components-qa/src/components/navigator/index.ux b/packages/taro-components-qa/src/components/taro-navigator/index.ux similarity index 100% rename from packages/taro-components-qa/src/components/navigator/index.ux rename to packages/taro-components-qa/src/components/taro-navigator/index.ux diff --git a/packages/taro-components-qa/src/components/taro-page/index.ux b/packages/taro-components-qa/src/components/taro-page/index.ux index 064b7e34678f..81a465f06f86 100644 --- a/packages/taro-components-qa/src/components/taro-page/index.ux +++ b/packages/taro-components-qa/src/components/taro-page/index.ux @@ -63,14 +63,8 @@ - + - \ No newline at end of file diff --git a/packages/taro-components-qa/src/components/taro-text/index.ux b/packages/taro-components-qa/src/components/taro-text/index.ux deleted file mode 100644 index 4159dcedccb1..000000000000 --- a/packages/taro-components-qa/src/components/taro-text/index.ux +++ /dev/null @@ -1,49 +0,0 @@ - - - - - diff --git a/packages/taro-components-qa/src/components/taro-video/index.ux b/packages/taro-components-qa/src/components/taro-video/index.ux index 0bb16e02f100..6846fd99a69d 100644 --- a/packages/taro-components-qa/src/components/taro-video/index.ux +++ b/packages/taro-components-qa/src/components/taro-video/index.ux @@ -18,8 +18,7 @@ @seeked="handleSeeked" @timeupdate="handleTimeUpdate" @fullscreenchange="handleFullScreen" - > - + > @@ -77,7 +76,7 @@ }), onInit () { - + }, handlePrepared () { diff --git a/packages/taro-components-qa/src/components/web-view/index.ux b/packages/taro-components-qa/src/components/taro-web-view/index.ux similarity index 100% rename from packages/taro-components-qa/src/components/web-view/index.ux rename to packages/taro-components-qa/src/components/taro-web-view/index.ux diff --git a/packages/taro-components/types/index.d.ts b/packages/taro-components/types/index.d.ts index a6341b89835f..fc97804c4405 100644 --- a/packages/taro-components/types/index.d.ts +++ b/packages/taro-components/types/index.d.ts @@ -1,49 +1,49 @@ -export { ScrollView } from './ScrollView' -export { View } from './View' -export { Block } from './Block' -export { Swiper } from './Swiper' -export { SwiperItem } from './SwiperItem' -export { MatchMedia } from './MatchMedia' -export { MovableView } from './MovableView' -export { MovableArea } from './MovableArea' -export { CoverView } from './CoverView' -export { CoverImage } from './CoverImage' -export { Icon } from './Icon' -export { Text } from './Text' -export { RichText } from './RichText' -export { Progress } from './Progress' -export { Button, ButtonProps } from './Button' -export { Checkbox } from './Checkbox' -export { CheckboxGroup } from './CheckboxGroup' -export { Editor } from './Editor' -export { Form } from './Form' -export { Input } from './Input' -export { Label } from './Label' -export { Picker } from './Picker' -export { PickerView } from './PickerView' -export { PickerViewColumn } from './PickerViewColumn' -export { Radio } from './Radio' -export { RadioGroup } from './RadioGroup' -export { Slider } from './Slider' -export { Switch } from './Switch' -export { Textarea } from './Textarea' -export { Image } from './Image' -export { Navigator } from './Navigator' -export { Camera } from './Camera' -export { Canvas } from './Canvas' -export { OpenData } from './OpenData' -export { Video } from './Video' -export { Ad } from './Ad' -export { Audio } from './Audio' -export { FunctionalPageNavigator } from './FunctionalPageNavigator' -export { LivePlayer } from './LivePlayer' -export { LivePusher } from './LivePusher' -export { Map } from './Map' -export { WebView } from './WebView' -export { OfficialAccount } from './OfficialAccount' -export { NavigationBar } from './NavigationBar' -export { PageMeta } from './PageMeta' -export { Slot } from './Slot' -export { CustomWrapper } from './CustomWrapper' +export * from './ScrollView' +export * from './View' +export * from './Block' +export * from './Swiper' +export * from './SwiperItem' +export * from './MatchMedia' +export * from './MovableView' +export * from './MovableArea' +export * from './CoverView' +export * from './CoverImage' +export * from './Icon' +export * from './Text' +export * from './RichText' +export * from './Progress' +export * from './Button' +export * from './Checkbox' +export * from './CheckboxGroup' +export * from './Editor' +export * from './Form' +export * from './Input' +export * from './Label' +export * from './Picker' +export * from './PickerView' +export * from './PickerViewColumn' +export * from './Radio' +export * from './RadioGroup' +export * from './Slider' +export * from './Switch' +export * from './Textarea' +export * from './Image' +export * from './Navigator' +export * from './Camera' +export * from './Canvas' +export * from './OpenData' +export * from './Video' +export * from './Ad' +export * from './Audio' +export * from './FunctionalPageNavigator' +export * from './LivePlayer' +export * from './LivePusher' +export * from './Map' +export * from './WebView' +export * from './OfficialAccount' +export * from './NavigationBar' +export * from './PageMeta' +export * from './Slot' +export * from './CustomWrapper' export * from './common' export * from './event' diff --git a/packages/taro-helper/src/constants.ts b/packages/taro-helper/src/constants.ts index cc2d6070c44c..5aec88198568 100644 --- a/packages/taro-helper/src/constants.ts +++ b/packages/taro-helper/src/constants.ts @@ -155,6 +155,7 @@ export const UPDATE_PACKAGE_LIST = [ '@tarojs/plugin-platform-tt', '@tarojs/plugin-platform-qq', '@tarojs/plugin-platform-jd', + '@tarojs/plugin-platform-quickapp', 'nervjs', 'nerv-devtools' ] diff --git a/packages/taro-loader/src/app.ts b/packages/taro-loader/src/app.ts index 161923a22df9..24e589ab563c 100644 --- a/packages/taro-loader/src/app.ts +++ b/packages/taro-loader/src/app.ts @@ -2,7 +2,7 @@ import * as webpack from 'webpack' import { getOptions, stringifyRequest } from 'loader-utils' import { normalizePath } from '@tarojs/helper' -import { frameworkMeta } from './utils' +import { frameworkMeta, quickAppExportStr } from './utils' export default function (this: webpack.loader.LoaderContext) { const stringify = (s: string): string => stringifyRequest(this, s) @@ -33,7 +33,10 @@ var app = ${createApp} app.onLaunch() exports.taroApp = app ` - : `var inst = App(${createApp})` + : ` +var inst = App(${createApp}) +${quickAppExportStr} +` return `${setReconciler} import { ${creator}, window } from '@tarojs/runtime' diff --git a/packages/taro-loader/src/component.ts b/packages/taro-loader/src/component.ts index a53d24290780..7c0af8abb00f 100644 --- a/packages/taro-loader/src/component.ts +++ b/packages/taro-loader/src/component.ts @@ -2,7 +2,7 @@ import * as webpack from 'webpack' import { getOptions, stringifyRequest } from 'loader-utils' import { normalizePath } from '@tarojs/helper' import * as path from 'path' -import { frameworkMeta } from './utils' +import { frameworkMeta, quickAppExportStr } from './utils' export default function (this: webpack.loader.LoaderContext) { const options = getOptions(this) @@ -22,6 +22,7 @@ if (typeof PRERENDER !== 'undefined') { return `import { createComponentConfig } from '@tarojs/runtime' import component from ${stringify(componentPath)} var inst = Component(createComponentConfig(component, '${options.name}')) +${quickAppExportStr} ${options.prerender ? prerender : ''} ` } diff --git a/packages/taro-loader/src/independentPage.ts b/packages/taro-loader/src/independentPage.ts index c75bab47f62e..3deda497c6eb 100644 --- a/packages/taro-loader/src/independentPage.ts +++ b/packages/taro-loader/src/independentPage.ts @@ -1,7 +1,7 @@ import * as webpack from 'webpack' import { getOptions, stringifyRequest } from 'loader-utils' import * as path from 'path' -import { frameworkMeta } from './utils' +import { frameworkMeta, quickAppExportStr } from './utils' interface PageConfig { content: any @@ -49,6 +49,7 @@ ${creator}(App, ${frameworkArgsCopy}) ${config.enableShareTimeline ? 'component.enableShareTimeline = true' : ''} ${config.enableShareAppMessage ? 'component.enableShareAppMessage = true' : ''} var inst = Page(createPageConfig(component, '${options.name}', {}, config || {})) +${quickAppExportStr} ${options.prerender ? prerender : ''} ` } diff --git a/packages/taro-loader/src/native-component.ts b/packages/taro-loader/src/native-component.ts index e4f45810cf6d..2dd30a223978 100644 --- a/packages/taro-loader/src/native-component.ts +++ b/packages/taro-loader/src/native-component.ts @@ -2,7 +2,7 @@ import * as webpack from 'webpack' import { getOptions, stringifyRequest } from 'loader-utils' import { normalizePath } from '@tarojs/helper' import * as path from 'path' -import { frameworkMeta } from './utils' +import { frameworkMeta, quickAppExportStr } from './utils' import { getPageConfig } from './page' export default function (this: webpack.loader.LoaderContext) { @@ -35,6 +35,7 @@ import component from ${stringify(componentPath)} ${importFrameworkStatement} var config = ${configString}; var inst = Component(createNativeComponentConfig(component, ${frameworkArgs})) +${quickAppExportStr} ${options.prerender ? prerender : ''} ` } diff --git a/packages/taro-loader/src/page.ts b/packages/taro-loader/src/page.ts index a51b66bc7564..033c9e2fbe3c 100644 --- a/packages/taro-loader/src/page.ts +++ b/packages/taro-loader/src/page.ts @@ -4,7 +4,7 @@ import { normalizePath } from '@tarojs/helper' import * as path from 'path' import * as acorn from 'acorn' import * as walk from 'acorn-walk' -import { frameworkMeta } from './utils' +import { frameworkMeta, quickAppExportStr } from './utils' interface PageConfig { content: any @@ -40,6 +40,7 @@ var config = ${configString}; ${config.enableShareTimeline ? 'component.enableShareTimeline = true' : ''} ${config.enableShareAppMessage ? 'component.enableShareAppMessage = true' : ''} var inst = Page(createPageConfig(component, '${options.name}', {root:{cn:[]}}, config || {})) +${quickAppExportStr} ${options.prerender ? prerender : ''} ` } diff --git a/packages/taro-loader/src/utils.ts b/packages/taro-loader/src/utils.ts index 1f630336328c..86928e5d2e00 100644 --- a/packages/taro-loader/src/utils.ts +++ b/packages/taro-loader/src/utils.ts @@ -82,3 +82,7 @@ class App extends React.Component { compatComponentExtra: 'config.PullDownRefresh = PullDownRefresh' } } + +export const quickAppExportStr = ` +export default inst +` diff --git a/packages/taro-mini-runner/package.json b/packages/taro-mini-runner/package.json index 0824a5d821c5..9cd5c6b6a743 100644 --- a/packages/taro-mini-runner/package.json +++ b/packages/taro-mini-runner/package.json @@ -43,6 +43,7 @@ "@tarojs/plugin-platform-swan": "3.2.16", "@tarojs/plugin-platform-tt": "3.2.16", "@tarojs/plugin-platform-weapp": "3.2.16", + "@tarojs/plugin-platform-quickapp": "3.2.16", "@tarojs/runner-utils": "3.2.16", "@tarojs/runtime": "3.2.16", "@tarojs/shared": "3.2.16", diff --git a/packages/taro-mini-runner/src/loaders/quickappStyleLoader.ts b/packages/taro-mini-runner/src/loaders/quickappStyleLoader.ts index aab8c8eafb17..ca325b03f335 100644 --- a/packages/taro-mini-runner/src/loaders/quickappStyleLoader.ts +++ b/packages/taro-mini-runner/src/loaders/quickappStyleLoader.ts @@ -1,4 +1,4 @@ -import styleRewriter from '../quickapp/style-rewriter' +import styleRewriter from '../quickapp/style-rewriter2' export default function quickappStyleLoader (source) { return styleRewriter(source) diff --git a/packages/taro-mini-runner/src/plugins/MiniPlugin.ts b/packages/taro-mini-runner/src/plugins/MiniPlugin.ts index 2d2662b42a21..e1219f123bc9 100644 --- a/packages/taro-mini-runner/src/plugins/MiniPlugin.ts +++ b/packages/taro-mini-runner/src/plugins/MiniPlugin.ts @@ -39,6 +39,7 @@ import TaroLoadChunksPlugin from './TaroLoadChunksPlugin' import { componentConfig } from '../template/component' import { validatePrerenderPages, PrerenderConfig } from '../prerender/prerender' import { AddPageChunks, IComponent, IFileType, Func } from '../utils/types' +import { generateQuickAppManifest, getTaroJsQuickAppComponentsPath } from '../utils/helper' const PLUGIN_NAME = 'TaroMiniPlugin' @@ -47,6 +48,8 @@ interface ITaroMiniPluginOptions { constantsReplaceList: { [key: string]: any } + outputDir: string + nodeModulesPath: string sourceDir: string isBuildPlugin: boolean pluginConfig?: Record @@ -57,6 +60,7 @@ interface ITaroMiniPluginOptions { prerender?: PrerenderConfig addChunkPages?: AddPageChunks isBuildQuickapp: boolean + quickappJSON: any minifyXML?: { collapseWhitespace?: boolean } @@ -78,7 +82,7 @@ export interface IComponentObj { type?: string } -interface FilesConfig { +export interface FilesConfig { [configName: string]: { content: Config path: string @@ -320,6 +324,21 @@ export default class TaroMiniPlugin { } }) }) + + /** + * 快应用sourcemap会报错 + */ + compilation.hooks.afterOptimizeAssets.tap(PLUGIN_NAME, assets => { + if (this.options.isBuildQuickapp) { + Object.keys(assets).forEach(assetPath => { + const styleExt = fileType.style + '.map' + const scriptExt = fileType.script + '.map' + if (assetPath.endsWith(styleExt) || assetPath.endsWith(scriptExt)) { + delete assets[assetPath] + } + }) + } + }) }) compiler.hooks.emit.tapAsync( @@ -448,10 +467,14 @@ export default class TaroMiniPlugin { } } }) - if (!template.isSupportRecursive) { + if (this.options.isBuildQuickapp) { + this.addEntry(path.resolve(__dirname, '..', 'template/quickapp'), 'quickapp', META_TYPE.STATIC) + } else if (!template.isSupportRecursive) { this.addEntry(path.resolve(__dirname, '..', 'template/comp'), this.getIsBuildPluginPath('comp', true), META_TYPE.STATIC) } - this.addEntry(path.resolve(__dirname, '..', 'template/custom-wrapper'), this.getIsBuildPluginPath('custom-wrapper', true), META_TYPE.STATIC) + if (!this.options.isBuildQuickapp) { + this.addEntry(path.resolve(__dirname, '..', 'template/custom-wrapper'), this.getIsBuildPluginPath('custom-wrapper', true), META_TYPE.STATIC) + } normalFiles.forEach(item => { this.addEntry(item.path, item.name, META_TYPE.NORMAL) }) @@ -614,10 +637,14 @@ export default class TaroMiniPlugin { addEntries () { const { template } = this.options this.addEntry(this.appEntry, 'app', META_TYPE.ENTRY) - if (!template.isSupportRecursive) { - this.addEntry(path.resolve(__dirname, '..', 'template/comp'), 'comp', META_TYPE.STATIC) + if (this.options.isBuildQuickapp) { + this.addEntry(path.resolve(__dirname, '..', 'template/quickapp'), 'quickapp', META_TYPE.STATIC) + } else if (!template.isSupportRecursive) { + this.addEntry(path.resolve(__dirname, '..', 'template/comp'), this.getIsBuildPluginPath('comp', false), META_TYPE.STATIC) + } + if (!this.options.isBuildQuickapp) { + this.addEntry(path.resolve(__dirname, '..', 'template/custom-wrapper'), this.getIsBuildPluginPath('custom-wrapper', false), META_TYPE.STATIC) } - this.addEntry(path.resolve(__dirname, '..', 'template/custom-wrapper'), 'custom-wrapper', META_TYPE.STATIC) this.pages.forEach(item => { if (item.isNative) { this.addEntry(item.path, item.name, META_TYPE.NORMAL) @@ -894,63 +921,71 @@ export default class TaroMiniPlugin { if (typeof modifyMiniConfigs === 'function') { await modifyMiniConfigs(this.filesConfig) } - if (!this.options.blended && !isBuildPlugin) { - const appConfigPath = this.getConfigFilePath(this.appEntry) - const appConfigName = path.basename(appConfigPath).replace(path.extname(appConfigPath), '') - this.generateConfigFile(compilation, this.appEntry, this.filesConfig[appConfigName].content) - } - if (!template.isSupportRecursive) { - // 如微信、QQ 不支持递归模版的小程序,需要使用自定义组件协助递归 - this.generateTemplateFile(compilation, this.getIsBuildPluginPath(baseCompName, isBuildPlugin), template.buildBaseComponentTemplate, this.options.fileType.templ) - this.generateConfigFile(compilation, this.getIsBuildPluginPath(baseCompName, isBuildPlugin), { - component: true, - usingComponents: { - [baseCompName]: `./${baseCompName}`, - [customWrapperName]: `./${customWrapperName}` - } - }) - this.generateConfigFile(compilation, this.getIsBuildPluginPath(customWrapperName, isBuildPlugin), { - component: true, - usingComponents: { - [baseCompName]: `./${baseCompName}`, - [customWrapperName]: `./${customWrapperName}` - } - }) + + if (this.options.isBuildQuickapp) { + // 为快应用生成manifest文件 + this.generateQuickAppManifestFile(compilation) + this.generateTemplateFile(compilation, this.appEntry, () => '') } else { - this.generateConfigFile(compilation, this.getIsBuildPluginPath(customWrapperName, isBuildPlugin), { - component: true, - usingComponents: { - [customWrapperName]: `./${customWrapperName}` - } - }) - } - this.generateTemplateFile(compilation, baseTemplateName, template.buildTemplate, componentConfig) - this.generateTemplateFile(compilation, this.getIsBuildPluginPath(customWrapperName, isBuildPlugin), template.buildCustomComponentTemplate, this.options.fileType.templ) - this.generateXSFile(compilation, 'utils', isBuildPlugin) - // 为独立分包生成 base/comp/custom-wrapper - this.independentPackages.forEach((pages, name) => { - this.generateTemplateFile(compilation, `${name}/${baseTemplateName}`, template.buildTemplate, componentConfig) + // 生成base和custom-wrapper相关文件,快应用不需要这一步 + if (!this.options.blended && !isBuildPlugin) { + const appConfigPath = this.getConfigFilePath(this.appEntry) + const appConfigName = path.basename(appConfigPath).replace(path.extname(appConfigPath), '') + this.generateConfigFile(compilation, this.appEntry, this.filesConfig[appConfigName].content) + } if (!template.isSupportRecursive) { // 如微信、QQ 不支持递归模版的小程序,需要使用自定义组件协助递归 - this.generateConfigFile(compilation, `${name}/${baseCompName}`, { + this.generateTemplateFile(compilation, this.getIsBuildPluginPath(baseCompName, isBuildPlugin), template.buildBaseComponentTemplate, this.options.fileType.templ) + this.generateConfigFile(compilation, this.getIsBuildPluginPath(baseCompName, isBuildPlugin), { component: true, usingComponents: { [baseCompName]: `./${baseCompName}`, [customWrapperName]: `./${customWrapperName}` } }) - this.generateConfigFile(compilation, `${name}/${customWrapperName}`, { + this.generateConfigFile(compilation, this.getIsBuildPluginPath(customWrapperName, isBuildPlugin), { component: true, usingComponents: { [baseCompName]: `./${baseCompName}`, [customWrapperName]: `./${customWrapperName}` } }) - this.generateTemplateFile(compilation, `${name}/${baseCompName}`, template.buildBaseComponentTemplate, this.options.fileType.templ) + } else { + this.generateConfigFile(compilation, this.getIsBuildPluginPath(customWrapperName, isBuildPlugin), { + component: true, + usingComponents: { + [customWrapperName]: `./${customWrapperName}` + } + }) } - this.generateTemplateFile(compilation, `${name}/${customWrapperName}`, template.buildCustomComponentTemplate, this.options.fileType.templ) - this.generateXSFile(compilation, `${name}/utils`, isBuildPlugin) - }) + this.generateTemplateFile(compilation, baseTemplateName, template.buildTemplate, componentConfig) + this.generateTemplateFile(compilation, this.getIsBuildPluginPath(customWrapperName, isBuildPlugin), template.buildCustomComponentTemplate, this.options.fileType.templ) + this.generateXSFile(compilation, 'utils', isBuildPlugin) + // 为独立分包生成 base/comp/custom-wrapper + this.independentPackages.forEach((pages, name) => { + this.generateTemplateFile(compilation, `${name}/${baseTemplateName}`, template.buildTemplate, componentConfig) + if (!template.isSupportRecursive) { + // 如微信、QQ 不支持递归模版的小程序,需要使用自定义组件协助递归 + this.generateConfigFile(compilation, `${name}/${baseCompName}`, { + component: true, + usingComponents: { + [baseCompName]: `./${baseCompName}`, + [customWrapperName]: `./${customWrapperName}` + } + }) + this.generateConfigFile(compilation, `${name}/${customWrapperName}`, { + component: true, + usingComponents: { + [baseCompName]: `./${baseCompName}`, + [customWrapperName]: `./${customWrapperName}` + } + }) + this.generateTemplateFile(compilation, `${name}/${baseCompName}`, template.buildBaseComponentTemplate, this.options.fileType.templ) + } + this.generateTemplateFile(compilation, `${name}/${customWrapperName}`, template.buildCustomComponentTemplate, this.options.fileType.templ) + this.generateXSFile(compilation, `${name}/utils`, isBuildPlugin) + }) + } this.components.forEach(component => { const importBaseTemplatePath = promoteRelativePath(path.relative(component.path, path.join(sourceDir, this.getTemplatePath(baseTemplateName)))) const config = this.filesConfig[this.getConfigFilePath(component.name)] @@ -993,7 +1028,14 @@ export default class TaroMiniPlugin { } }) this.generateTabBarFiles(compilation) - this.injectCommonStyles(compilation) + + if (this.options.isBuildQuickapp) { + // 删除快应用模版 + delete compilation.assets[`quickapp${this.options.fileType.script}`] + } else { + this.injectCommonStyles(compilation) + } + if (this.themeLocation) { this.generateDarkModeFile(compilation) } @@ -1014,7 +1056,127 @@ export default class TaroMiniPlugin { } } + generateQuickAppManifestFile (compilation: webpack.compilation.Compilation) { + const pageConfigs = Array.from(this.pages).reduce>((obj, { name }) => { + const content = this.filesConfig[this.getConfigFilePath(name)].content + obj[name] = content + return obj + }, {}) + const quickappJSON = generateQuickAppManifest({ + appConfig: this.appConfig, + pageConfigs, + designWidth: this.options.designWidth, + quickappJSON: this.options.quickappJSON + }) + const quickappJSONStr = JSON.stringify(quickappJSON).replace(/\\\\/g, '/') + compilation.assets['./manifest.json'] = { + size: () => quickappJSONStr.length, + source: () => quickappJSONStr + } + } + + generateQuickAppTemplateFile (compilation: webpack.compilation.Compilation, componentName: string, templStr: string) { + const fileTemplName = this.getTemplatePath(componentName) + const fileScriptName = this.getScriptPath(componentName) + const fileStyleName = this.getStylePath(componentName) + + let baseTemplInfo: { + fileTemplName: string, + taroSelfComponents: string[], + templStr: string + } | undefined + + if (componentName !== 'app') { + let [templStr, taroSelfComponents] = this.options.template.buildTemplate(componentConfig) as any + if (this.options.minifyXML?.collapseWhitespace) { + templStr = minify(templStr, { + collapseWhitespace: true, + keepClosingSlash: true + }) + } + baseTemplInfo = { + fileTemplName: path.join(componentName, '..', `base${this.options.fileType.templ}`), + templStr, + taroSelfComponents + } + } + + if (baseTemplInfo) { + for (const item of baseTemplInfo.taroSelfComponents) { + const taroJsQuickAppComponentsPath = getTaroJsQuickAppComponentsPath(this.options.nodeModulesPath) + const absolutePath = path.join(taroJsQuickAppComponentsPath, item, `index${this.options.fileType.templ}`) + + if (!fs.existsSync(absolutePath)) { + continue + } + + const componentPath = this.getComponentName(absolutePath) + const templatePath = this.getTemplatePath(this.getComponentName(componentPath)) + + if (!compilation.assets[templatePath]) { + const content = fs.readFileSync(absolutePath).toString() + compilation.assets[templatePath] = { + size: () => content.length, + source: () => content + } + } + + const importPath = promoteRelativePath(path.relative(baseTemplInfo.fileTemplName, componentPath)) + baseTemplInfo.templStr = `\n` + baseTemplInfo.templStr + } + const scriptContent = compilation.assets[`quickapp${this.options.fileType.script}`].source() + baseTemplInfo.templStr += `\n` + } + + let hitScriptItem + + Object.keys(compilation.assets).forEach(item => { + if (baseTemplInfo && fileStyleName.indexOf(item) >= 0) { + const appFileStyleName = this.getStylePath('app') + const appRelativeStylePath = promoteRelativePath(path.relative(baseTemplInfo.fileTemplName, appFileStyleName)) + const relativeStylePath = promoteRelativePath(path.relative(baseTemplInfo.fileTemplName, fileStyleName)) + baseTemplInfo.templStr = ` +` + baseTemplInfo.templStr + } + + if (fileScriptName.indexOf(item) >= 0) { + const assetItem = compilation.assets[item] + const scriptContent = assetItem.source() + hitScriptItem = item + templStr += `\n` + } + }) + + if (hitScriptItem) { + delete compilation.assets[hitScriptItem] + } + + compilation.assets[fileTemplName] = { + size: () => templStr.length, + source: () => templStr + } + + if (baseTemplInfo) { + compilation.assets[baseTemplInfo.fileTemplName] = { + size: () => baseTemplInfo!.templStr.length, + source: () => baseTemplInfo!.templStr + } + } + } + generateConfigFile (compilation: webpack.compilation.Compilation, filePath: string, config: Config & { component?: boolean }) { + if (this.options.isBuildQuickapp) { + return + } + const fileConfigName = this.getConfigPath(this.getComponentName(filePath)) const unOfficalConfigs = ['enableShareAppMessage', 'enableShareTimeline', 'components'] unOfficalConfigs.forEach(item => { @@ -1029,7 +1191,9 @@ export default class TaroMiniPlugin { generateTemplateFile (compilation: webpack.compilation.Compilation, filePath: string, templateFn: (...args) => string, ...options) { let templStr = templateFn(...options) - const fileTemplName = this.getTemplatePath(this.getComponentName(filePath)) + + const componentName = this.getComponentName(filePath) + const fileTemplName = this.getTemplatePath(componentName) if (this.options.minifyXML?.collapseWhitespace) { templStr = minify(templStr, { @@ -1042,6 +1206,10 @@ export default class TaroMiniPlugin { size: () => templStr.length, source: () => templStr } + + if (this.options.isBuildQuickapp) { + this.generateQuickAppTemplateFile(compilation, componentName, templStr) + } } generateXSFile (compilation: webpack.compilation.Compilation, xsPath, isBuildPlugin: boolean) { @@ -1098,6 +1266,11 @@ export default class TaroMiniPlugin { return this.getTargetFilePath(filePath, this.options.fileType.config) } + /** 处理 config 文件后缀 */ + getScriptPath (filePath: string) { + return this.getTargetFilePath(filePath, this.options.fileType.script) + } + /** 处理 extname */ getTargetFilePath (filePath: string, targetExtname: string) { const extname = path.extname(filePath) @@ -1140,13 +1313,32 @@ export default class TaroMiniPlugin { }) } + /** + * 获取公共样式文件名 + */ + getCommonStyleAssets ({ assets }: webpack.compilation.Compilation) { + const commonStyleAssetNames: string[] = [] + + const styleExt = this.options.fileType.style + const REG_STYLE_EXT = new RegExp(`\\.(${styleExt.replace('.', '')})(\\?.*)?$`) + + Object.keys(assets).forEach(assetName => { + const fileName = path.basename(assetName, path.extname(assetName)) + if ((REG_STYLE.test(assetName) || REG_STYLE_EXT.test(assetName)) && this.options.commonChunks.includes(fileName)) { + commonStyleAssetNames.push(assetName) + } + }) + + return commonStyleAssetNames + } + /** * 小程序全局样式文件中引入 common chunks 中的公共样式文件 */ - injectCommonStyles ({ assets }: webpack.compilation.Compilation) { + injectCommonStyles (compilation: webpack.compilation.Compilation) { + const { assets } = compilation const styleExt = this.options.fileType.style const appStyle = `app${styleExt}` - const REG_STYLE_EXT = new RegExp(`\\.(${styleExt.replace('.', '')})(\\?.*)?$`) if (!assets[appStyle]) return @@ -1154,15 +1346,12 @@ export default class TaroMiniPlugin { const source = new ConcatSource() source.add(originSource) - Object.keys(assets).forEach(assetName => { - const fileName = path.basename(assetName, path.extname(assetName)) - if ((REG_STYLE.test(assetName) || REG_STYLE_EXT.test(assetName)) && this.options.commonChunks.includes(fileName)) { - source.add('\n') - source.add(`@import ${JSON.stringify(urlToRequest(assetName))};`) - assets[appStyle] = { - size: () => source.source().length, - source: () => source.source() - } + this.getCommonStyleAssets(compilation).forEach(assetName => { + source.add('\n') + source.add(`@import ${JSON.stringify(urlToRequest(assetName))};`) + assets[appStyle] = { + size: () => source.source().length, + source: () => source.source() } }) } diff --git a/packages/taro-mini-runner/src/plugins/TaroLoadChunksPlugin.ts b/packages/taro-mini-runner/src/plugins/TaroLoadChunksPlugin.ts index 40c1d5a5e83e..49f12504c7e0 100644 --- a/packages/taro-mini-runner/src/plugins/TaroLoadChunksPlugin.ts +++ b/packages/taro-mini-runner/src/plugins/TaroLoadChunksPlugin.ts @@ -103,6 +103,25 @@ export default class TaroLoadChunksPlugin { source.add(modules) return source } + // webpack4不支持addEntry时指定library,在这里模拟一下,导出快应用需要的exports + if (this.isBuildQuickapp) { + if ( + entryModule.miniType === META_TYPE.ENTRY || + entryModule.miniType === META_TYPE.PAGE || + entryModule.miniType === META_TYPE.COMPONENT + ) { + const source = new ConcatSource() + source.add(` +(function webpackUniversalModuleDefinition(root, factory) { + module.exports = Object.assign({}, factory().default); // 快应用会修改原对象 +})(global, function() { +return `) + source.add(modules) + source.add(` +});`) + return source + } + } } }) @@ -129,11 +148,11 @@ export default class TaroLoadChunksPlugin { return addRequireToSource(getIdOrName(chunk), modules, commonChunks) } - if (this.isBuildQuickapp && - (miniType === META_TYPE.PAGE || miniType === META_TYPE.COMPONENT) - ) { - return addRequireToSource(getIdOrName(chunk), modules, commonChunks) - } + // if (this.isBuildQuickapp && + // (miniType === META_TYPE.PAGE || miniType === META_TYPE.COMPONENT) + // ) { + // return addRequireToSource(getIdOrName(chunk), modules, commonChunks) + // } // addChunkPages if (fileChunks.size && diff --git a/packages/taro-mini-runner/src/quickapp/script/index.ts b/packages/taro-mini-runner/src/quickapp/script/index.ts new file mode 100644 index 000000000000..04e7aa888f44 --- /dev/null +++ b/packages/taro-mini-runner/src/quickapp/script/index.ts @@ -0,0 +1,3 @@ +export * from './mini-app' +export * from './mini-page' +export * from './mini-component' diff --git a/packages/taro-mini-runner/src/quickapp/script/mini-app.ts b/packages/taro-mini-runner/src/quickapp/script/mini-app.ts new file mode 100644 index 000000000000..0cee76b0f597 --- /dev/null +++ b/packages/taro-mini-runner/src/quickapp/script/mini-app.ts @@ -0,0 +1,31 @@ +import type { AppInstance } from '@tarojs/runtime' + +export function App (config: AppInstance) { + const { + onLaunch, + mount, + unmount, + onPageNotFound, + taroGlobalData, + + componentDidShow, + componentDidHide, + onShow, + onHide + } = config + + return { + onCreate: onLaunch, + onPageNotFound, + onError: null, + onDestroy: null, + onRequest: null, + onHide, + onShow, + mount, + unmount, + taroGlobalData, + componentDidShow, + componentDidHide + } +} diff --git a/packages/taro-mini-runner/src/quickapp/script/mini-component.ts b/packages/taro-mini-runner/src/quickapp/script/mini-component.ts new file mode 100644 index 000000000000..0cea166e7103 --- /dev/null +++ b/packages/taro-mini-runner/src/quickapp/script/mini-component.ts @@ -0,0 +1,23 @@ +import type { ComponentInstance } from '@tarojs/runtime' +import { setData } from './utils' + +export function Component (options: ComponentInstance) { + const { + data, + attached, + detached, + // pageLifetimes: { + // show = null, + // hide = null + // } = {}, + methods + } = options + + return { + data, + onReady: attached, + onDestroy: detached, + setData, + ...methods + } +} diff --git a/packages/taro-mini-runner/src/quickapp/script/mini-page.ts b/packages/taro-mini-runner/src/quickapp/script/mini-page.ts new file mode 100644 index 000000000000..49ba079778d3 --- /dev/null +++ b/packages/taro-mini-runner/src/quickapp/script/mini-page.ts @@ -0,0 +1,50 @@ +import type { PageInstance } from '@tarojs/runtime' +import { setData } from './utils' + +export function Page (config: PageInstance) { + const { + data, + path, + // options, + onPullDownRefresh, + onReachBottom, + onPageScroll, + // onShareAppMessage, + // onResize, + // onTabItemTap, + // onTitleClick, + // onOptionMenuClick, + // onPopMenuClick, + onReady, + // onPullIntercept, + // onShareTimeline, + // onAddToFavorites, + // eh, + onLoad, + onUnload, + + // componentDidShow, + // componentDidHide, + onShow, + onHide + } = config + + return { + path, + private: data, + onInit: onLoad, + onReady: onReady, + onShow: onShow, + onHide: onHide, + onDestroy: onUnload, + onBackPress: null, + onMenuPress: null, + onRefresh: null, + onConfigurationChanged: null, + onReachTop: onPullDownRefresh, + onReachBottom: onReachBottom, + onPageScroll: onPageScroll, + + setData + } +} diff --git a/packages/taro-mini-runner/src/quickapp/script/utils.ts b/packages/taro-mini-runner/src/quickapp/script/utils.ts new file mode 100644 index 000000000000..e5fc2ba5627f --- /dev/null +++ b/packages/taro-mini-runner/src/quickapp/script/utils.ts @@ -0,0 +1,8 @@ +export function setData (data: Record, cb?: () => void) { + for (const k in data) { + this.$set(k, data[k]) + } + + // nextTick + cb && setTimeout(cb) +} diff --git a/packages/taro-mini-runner/src/quickapp/style-rewriter2.ts b/packages/taro-mini-runner/src/quickapp/style-rewriter2.ts new file mode 100644 index 000000000000..7679b25a9118 --- /dev/null +++ b/packages/taro-mini-runner/src/quickapp/style-rewriter2.ts @@ -0,0 +1,83 @@ +import * as css from 'css' +import * as cssWhat from 'css-what' + +interface StyleLog { + line: number; + column: number; + reason: string; +} + +const textProperties = [ + 'color', 'font-size', 'font-style', 'font-weight', 'font-family', 'lines', + 'text-decoration', 'text-align', 'text-indent', 'line-height', 'text-overflow' +] + +export default function rewriter(code, isProduction?) { + const logs: StyleLog[] = [] + const ast = css.parse(code, { + silent: true + }) + // catch syntax error + if (ast.stylesheet.parsingErrors && ast.stylesheet.parsingErrors.length) { + ast.stylesheet.parsingErrors.forEach(function (error) { + logs.push({ + line: error.line, + column: error.column, + reason: error.toString() + }) + }) + } + // 针对快应用样式进行转换 + if (ast && ast.type === 'stylesheet' && ast.stylesheet && + ast.stylesheet.rules && ast.stylesheet.rules.length) { + const rules: any = [] + ast.stylesheet.rules.forEach(function (rule) { + const type = rule.type + + if (type === 'rule') { + const allDeclarations = rule.declarations.filter(declaration => + declaration.type === 'declaration'); + + const textDeclarations = allDeclarations.filter(declaration => + textProperties.includes(declaration.property) + ); + + if (textDeclarations.length) { + const parts: cssWhat.Selector[][] = rule.selectors.map(selector => cssWhat.parse(selector)[0]) + + // 新增一个 `.class text` 选择器来继承css文本属性 + const newRule = { ...rule } + newRule.selectors = parts.map(part => { + part = part.slice() + part.push({ type: 'descendant' }, { type: 'tag', name: 'text' }) + return cssWhat.stringify([part]) + }) + newRule.declarations = textDeclarations; + + rules.push(newRule) + + // 为了维持选择器优先级不变,在原选择器前面加上id + rule.selectors = parts.map(part => { + part = part.slice() + return '#taro-page ' + cssWhat.stringify([part]) // 无语,没有id和class类型的 + }) + } + } + + rules.push(rule) + }) + ast.stylesheet.rules = rules + } + if (!ast) { + return '' + } + // 输出转换结果 + try { + const resContent = css.stringify(ast, { + compress: !!isProduction + }) + return resContent + } catch (e) { + return '' + } +} diff --git a/packages/taro-mini-runner/src/quickapp/template/serialize.ts b/packages/taro-mini-runner/src/quickapp/template/serialize.ts index 5763ae13e211..08ed5d2ed20e 100644 --- a/packages/taro-mini-runner/src/quickapp/template/serialize.ts +++ b/packages/taro-mini-runner/src/quickapp/template/serialize.ts @@ -11,9 +11,9 @@ const createAttrsCode = (attrs) => { if (attrsKey.length) { attrsCode = ' ' + attrsKey.map(name => { if (!attrs[name] && ~ATTRS_NAME.indexOf(name)) { - return `${name}='true'` + return `${name}="true"` } - return name === 'else' ? `${name}` : `${name}='${attrs[name]}'` + return name === 'else' ? `${name}` : `${name}="${attrs[name]}"` }).join(' ') } return attrsCode diff --git a/packages/taro-mini-runner/src/template/component.ts b/packages/taro-mini-runner/src/template/component.ts index fe23331b8ca1..c943e2b96cd7 100644 --- a/packages/taro-mini-runner/src/template/component.ts +++ b/packages/taro-mini-runner/src/template/component.ts @@ -1,12 +1,6 @@ -type Tagname = string -type Attrs = Set +import { ComponentConfig } from '@tarojs/shared' -export const componentConfig: { - includes: Set - exclude: Set - thirdPartyComponents: Map - includeAll: boolean -} = { +export const componentConfig: ComponentConfig = { includes: new Set(['view', 'catch-view', 'static-view', 'pure-view', 'scroll-view', 'image', 'static-image', 'text', 'static-text']), exclude: new Set(), thirdPartyComponents: new Map(), diff --git a/packages/taro-mini-runner/src/template/quickapp.ts b/packages/taro-mini-runner/src/template/quickapp.ts new file mode 100644 index 000000000000..be4f2ceb356c --- /dev/null +++ b/packages/taro-mini-runner/src/template/quickapp.ts @@ -0,0 +1,3 @@ +import { createQuickAppConfig } from '@tarojs/runtime' + +module.exports = createQuickAppConfig() diff --git a/packages/taro-mini-runner/src/utils/helper.ts b/packages/taro-mini-runner/src/utils/helper.ts index 28613e6cb233..9d9f8f2553f4 100644 --- a/packages/taro-mini-runner/src/utils/helper.ts +++ b/packages/taro-mini-runner/src/utils/helper.ts @@ -2,81 +2,31 @@ import * as path from 'path' import { getInstalledNpmPkgPath, taroJsQuickAppComponents, - promoteRelativePath, - REG_STYLE, - REG_SCRIPT, - removeHeadSlash + removeHeadSlash, + printLog, + processTypeEnum } from '@tarojs/helper' +import { Config } from '@tarojs/taro' export function getTaroJsQuickAppComponentsPath (nodeModulesPath: string): string { const taroJsQuickAppComponentsPkg = getInstalledNpmPkgPath(taroJsQuickAppComponents, nodeModulesPath) if (!taroJsQuickAppComponentsPkg) { - // printLog(processTypeEnum.ERROR, '包安装', `缺少包 ${taroJsQuickAppComponents},请安装!`) + printLog(processTypeEnum.ERROR, '包安装', `缺少包 ${taroJsQuickAppComponents},请安装!`) process.exit(0) } return path.join(path.dirname(taroJsQuickAppComponentsPkg as string), 'src/components') } -export function getImportTaroSelfComponents (filePath, nodeModulesPath, outputDir, taroSelfComponents) { - const importTaroSelfComponents = new Set<{ path: string, name: string }>() - const taroJsQuickAppComponentsPath = getTaroJsQuickAppComponentsPath(nodeModulesPath) - taroSelfComponents.forEach(c => { - const cPath = path.join(taroJsQuickAppComponentsPath, c) - const cMainPath = path.join(cPath, 'index') - const cRelativePath = promoteRelativePath(path.relative(filePath, cMainPath.replace(nodeModulesPath, path.join(outputDir, 'npm')))) - importTaroSelfComponents.add({ - path: cRelativePath, - name: c - }) - }) - return importTaroSelfComponents -} - -export function generateQuickAppUx ({ - script, - template, - style, - imports -}: { - script?: string, - template?: string, - style?: string, - imports?: Set<{ - path: string, - name: string - }> -}) { - let uxTxt = '' - if (imports && imports.size) { - imports.forEach(item => { - uxTxt += `\n` - }) - } - if (style) { - if (REG_STYLE.test(style)) { - uxTxt += `\n` - } else { - uxTxt += `\n` - } - } - if (template) { - uxTxt += `\n` - } - if (script) { - if (REG_SCRIPT.test(script)) { - uxTxt += `\n` - } else { - uxTxt += `\n` - } - } - return uxTxt -} - export function generateQuickAppManifest ({ appConfig, quickappJSON, pageConfigs, designWidth +}: { + appConfig: Config, + quickappJSON: Record, + pageConfigs: Record, + designWidth: number }) { // 生成 router const pages = (appConfig.pages as string[]).concat() @@ -109,10 +59,9 @@ export function generateQuickAppManifest ({ // 生成 display const display = JSON.parse(JSON.stringify(appConfig.window || {})) display.pages = {} - pageConfigs.forEach((item, page) => { - if (item) { - display.pages[removeHeadSlash(path.dirname(page))] = item - } + Object.keys(pageConfigs).forEach((page) => { + const item = pageConfigs[page] + display.pages[removeHeadSlash(path.dirname(page))] = item }) quickappJSON.router = router quickappJSON.display = display diff --git a/packages/taro-mini-runner/src/webpack/base.conf.ts b/packages/taro-mini-runner/src/webpack/base.conf.ts index 2ef0d47075e2..cd22f481f9e9 100644 --- a/packages/taro-mini-runner/src/webpack/base.conf.ts +++ b/packages/taro-mini-runner/src/webpack/base.conf.ts @@ -1,10 +1,20 @@ import * as path from 'path' import * as Chain from 'webpack-chain' import { MultiPlatformPlugin } from '@tarojs/runner-utils' +import { isQuickAppPkg } from '@tarojs/helper' export default (appPath: string) => { const chain = new Chain() chain.merge({ + externals: [ + /** 快应用自身使用的npm包 */ + function (context, request, callback) { + if (isQuickAppPkg(request)) { + return callback(null, 'commonjs ' + request) + } + callback() + } + ], resolve: { extensions: ['.js', '.jsx', '.ts', '.tsx', '.mjs', '.vue'], mainFields: ['browser', 'module', 'main'], diff --git a/packages/taro-mini-runner/src/webpack/build.conf.ts b/packages/taro-mini-runner/src/webpack/build.conf.ts index e03e92536557..ec33045c8e9d 100644 --- a/packages/taro-mini-runner/src/webpack/build.conf.ts +++ b/packages/taro-mini-runner/src/webpack/build.conf.ts @@ -190,7 +190,12 @@ export default (appPath: string, mode, config: Partial): any => { requestAnimationFrame: ['@tarojs/runtime', 'requestAnimationFrame'], cancelAnimationFrame: ['@tarojs/runtime', 'cancelAnimationFrame'], Element: ['@tarojs/runtime', 'TaroElement'], - SVGElement: ['@tarojs/runtime', 'TaroElement'] + SVGElement: ['@tarojs/runtime', 'TaroElement'], + ...isBuildQuickapp ? { + App: [path.resolve(__dirname, '..', 'quickapp/script/mini-app'), 'App'], + Page: [path.resolve(__dirname, '..', 'quickapp/script/mini-page'), 'Page'], + Component: [path.resolve(__dirname, '..', 'quickapp/script/mini-component'), 'Component'] + } : {} }) const isCssoEnabled = !((csso && csso.enable === false)) diff --git a/packages/taro-mini-runner/src/webpack/chain.ts b/packages/taro-mini-runner/src/webpack/chain.ts index 85eb0e98c004..0f2f6b5bbfb0 100644 --- a/packages/taro-mini-runner/src/webpack/chain.ts +++ b/packages/taro-mini-runner/src/webpack/chain.ts @@ -325,8 +325,8 @@ export const getModule = (appPath: string, { }[] = [{ use: isBuildQuickapp ? [ extractCssLoader, - quickappStyleLoader, cssLoader, + quickappStyleLoader, postcssLoader ] : [ extractCssLoader, diff --git a/packages/taro-quickapp/README.md b/packages/taro-quickapp/README.md new file mode 100644 index 000000000000..5a2f9113dea0 --- /dev/null +++ b/packages/taro-quickapp/README.md @@ -0,0 +1,3 @@ +# `@tarojs/plugin-platform-quickapp` + +Taro 插件。用于支持编译为快应用。 diff --git a/packages/taro-quickapp/index.js b/packages/taro-quickapp/index.js new file mode 100644 index 000000000000..9c1d9fd9b931 --- /dev/null +++ b/packages/taro-quickapp/index.js @@ -0,0 +1,3 @@ +module.exports = require('./dist/index.js').default +module.exports.default = module.exports +module.exports.QuickApp = require('./dist/index.js').QuickApp diff --git a/packages/taro-quickapp/package.json b/packages/taro-quickapp/package.json new file mode 100644 index 000000000000..adec5228060d --- /dev/null +++ b/packages/taro-quickapp/package.json @@ -0,0 +1,38 @@ +{ + "name": "@tarojs/plugin-platform-quickapp", + "version": "3.2.16", + "description": "快应用平台插件", + "author": "drchan", + "homepage": "https://github.com/nervjs/taro/tree/master/packages/taro-quickapp#readme", + "license": "MIT", + "main": "index.js", + "keywords": [ + "taro" + ], + "files": [ + "index.js", + "dist", + "types" + ], + "types": "types/index.d.ts", + "repository": { + "type": "git", + "url": "git+https://github.com/NervJS/taro.git" + }, + "scripts": { + "build": "rollup -c", + "dev": "rollup -c -w" + }, + "bugs": { + "url": "https://github.com/NervJS/taro/issues" + }, + "dependencies": { + "@tarojs/components": "3.2.15", + "@tarojs/service": "3.2.15", + "@tarojs/shared": "3.2.15", + "@tarojs/taro": "3.2.15", + "@tarojs/components-qa": "3.2.15", + "ora": "^2.0.0", + "request": "^2.88.0" + } +} diff --git a/packages/taro-quickapp/rollup.config.js b/packages/taro-quickapp/rollup.config.js new file mode 100644 index 000000000000..cb1139eccf7c --- /dev/null +++ b/packages/taro-quickapp/rollup.config.js @@ -0,0 +1,62 @@ +const { join } = require('path') +const typescript = require('rollup-plugin-typescript2') +const nodeResolve = require('rollup-plugin-node-resolve') +const jsonResolve = require('@rollup/plugin-json') +const cwd = __dirname + +const base = { + external: ['@tarojs/shared', '@tarojs/service', '@tarojs/taro', 'request', 'fs-extra', 'ora'], + plugins: [ + jsonResolve(), + nodeResolve(), + typescript({ + useTsconfigDeclarationDir: true + })] +} + +// 供 CLI 编译时使用的 Taro 插件入口 +const comileConfig = { + input: join(cwd, 'src/index.ts'), + output: { + file: join(cwd, 'dist/index.js'), + format: 'cjs', + sourcemap: true, + exports: 'named' + }, + ...base +} + +// 供 Loader 使用的运行时入口 +const runtimeConfig = { + input: join(cwd, 'src/runtime.ts'), + output: { + file: join(cwd, 'dist/runtime.js'), + format: 'es', + sourcemap: true + }, + ...base +} + +// 供继承的包使用,为了能 tree-shaking +const runtimeUtilsConfig = { + input: join(cwd, 'src/runtime-utils.ts'), + output: { + file: join(cwd, 'dist/runtime-utils.js'), + format: 'es', + sourcemap: true + }, + ...base +} + +// React 下 webpack 会 alias @tarojs/components 为此文件 +const otherConfig = { + input: join(cwd, 'src/components-react.ts'), + output: { + file: join(cwd, 'dist/components-react.js'), + format: 'es', + sourcemap: true + }, + ...base +} + +module.exports = [comileConfig, runtimeConfig, runtimeUtilsConfig, otherConfig] diff --git a/packages/taro-quickapp/src/api/device/index.js b/packages/taro-quickapp/src/api/device/index.js new file mode 100644 index 000000000000..c5eb9d5fb01b --- /dev/null +++ b/packages/taro-quickapp/src/api/device/index.js @@ -0,0 +1,95 @@ +import contact from '@system.contact' +import sms from '@system.sms' + +export function getContactPick (opts = {}) { + const { success, fail, complete } = opts + const res = { errMsg: 'getContactPick:ok' } + return new Promise((resolve, reject) => { + contact.pick({ + success (data) { + res.result = data + success && success(data) + resolve(res) + }, + fail (data, code) { + res.errMsg = data + res.code = code + fail && fail(res) + complete && complete(res) + reject(res) + } + }) + }) +} + +export function getContactList (opts = {}) { + const { success, fail, complete } = opts + const res = { errMsg: 'getContactList:ok' } + return new Promise((resolve, reject) => { + contact.list({ + success (data) { + res.result = data + success && success(data) + resolve(res) + }, + fail (data, code) { + res.errMsg = data + res.code = code + fail && fail(res) + complete && complete(res) + reject(res) + } + }) + }) +} + +export function sendSms (opts = {}) { + const { address, content, success, fail, complete } = opts + const res = { errMsg: 'sendSms:ok' } + return new Promise((resolve, reject) => { + sms.send({ + address, + content, + success (data) { + res.result = data + success && success(data) + resolve(res) + }, + fail (data, code) { + res.errMsg = data + res.code = code + fail && fail(res) + complete && complete(res) + reject(res) + } + }) + }) +} + +export function readSmsSafely (opts = {}) { + const { timeout, success, fail, complete } = opts + const res = { errMsg: 'sendSms:ok' } + return new Promise((resolve, reject) => { + sms.readSafely({ + timeout, + success (data) { + res.result = data + success && success(data) + resolve(res) + }, + fail (data, code) { + res.errMsg = data + res.code = code + fail && fail(res) + complete && complete(res) + reject(res) + } + }) + }) +} + +export default { + getContactPick, + getContactList, + sendSms +} diff --git a/packages/taro-quickapp/src/api/equipment/index.js b/packages/taro-quickapp/src/api/equipment/index.js new file mode 100644 index 000000000000..062d30249864 --- /dev/null +++ b/packages/taro-quickapp/src/api/equipment/index.js @@ -0,0 +1,203 @@ +import barcode from '@system.barcode' +import vibrator from '@system.vibrator' +import clipboard from '@system.clipboard' +import sensor from '@system.sensor' +import geolocation from '@system.geolocation' + +import { makeSyncPromise } from '../utils' + +export function scanCode (options = {}) { + const { + success, + fail, + complete + } = options + + const res = { errMsg: 'scanCode:ok' } + + return new Promise((resolve, reject) => { + barcode.scan({ + success (data) { + res.result = data.result + success && success(res) + complete && complete(res) + resolve(res) + }, + cancel () { + res.errMsg = 'cancelScanCode: success' + success && success(res) + complete && complete(res) + res.result = '' + resolve(res) + }, + fail (data, code) { + res.errMsg = data + res.code = code + complete && complete(res) + fail && fail(res) + reject(res) + }, + + complete () { + complete && complete(res) + } + }) + }) +} + +export function vibrateShort (options = {}) { + return makeSyncPromise('vibrateShort', () => { + vibrator.vibrate({ + mode: 'short' + }) + }, options) +} + +export function vibrateLong (options = {}) { + return makeSyncPromise('vibrateLong', () => { + vibrator.vibrate({ + mode: 'long' + }) + }, options) +} + +export function setClipboardData (options = {}) { + const { + data, + success, + fail, + complete + } = options + + const res = { errMsg: 'setClipboardData:ok' } + + return new Promise((resolve, reject) => { + clipboard.set({ + text: data, + success (data) { + res.result = data.result + success && success(res) + resolve(res) + }, + fail (data, code) { + res.errMsg = data + res.code = code + fail && fail(res) + reject(res) + }, + complete () { + complete && complete(res) + } + }) + }) +} + +export function getClipboardData (options = {}) { + const { + success, + fail, + complete + } = options + + const res = { errMsg: 'getClipboardData:ok' } + + return new Promise((resolve, reject) => { + clipboard.get({ + success (data) { + res.data = data.text + success && success(res) + resolve(res) + }, + fail (data, code) { + res.errMsg = data + res.code = code + fail && fail(res) + reject(res) + }, + complete () { + complete && complete(res) + } + }) + }) +} + +export function startAccelerometer (options = {}) { + return makeSyncPromise('startAccelerometer', null, options) +} + +export function stopAccelerometer (options = {}) { + return makeSyncPromise('stopAccelerometer', () => { + sensor.unsubscribeAccelerometer() + }, options) +} + +export function onAccelerometerChange (callback) { + if (callback) { + sensor.subscribeAccelerometer({ + callback + }) + } +} + +export function startCompass (options = {}) { + return makeSyncPromise('startCompass', null, options) +} + +export function stopCompass (options = {}) { + return makeSyncPromise('stopCompass', () => { + sensor.unsubscribeCompass() + }, options) +} + +export function onCompassChange (callback) { + if (callback) { + sensor.subscribeCompass({ + callback + }) + } +} + +export function getLocation (options = {}) { + const { + success, + fail, + complete + } = options + const res = { errMsg: 'getLocation:ok' } + + return new Promise((resolve, reject) => { + geolocation.getLocation({ + success (data) { + res.latitude = data.latitude + res.longitude = data.longitude + res.accuracy = data.accuracy + success && success(res) + resolve(res) + }, + fail (data, code) { + res.errMsg = data + res.code = code + fail && fail(res) + reject(res) + }, + complete () { + complete && complete(res) + } + }) + }) +} + +export default { + scanCode, + vibrateShort, + vibrateLong, + setClipboardData, + getClipboardData, + startAccelerometer, + stopAccelerometer, + onAccelerometerChange, + startCompass, + stopCompass, + onCompassChange, + getLocation +} diff --git a/packages/taro-quickapp/src/api/index.js b/packages/taro-quickapp/src/api/index.js new file mode 100644 index 000000000000..586e77032088 --- /dev/null +++ b/packages/taro-quickapp/src/api/index.js @@ -0,0 +1,15 @@ +// 未实现 + +// 已实现 api +export * from './request' +export * from './storage' +export * from './router' +export * from './interactive' +export * from './equipment' +export * from './share' +export * from './notification' +export * from './system' +export * from './webview' +export * from './media' +export * from './device' +export * from './unsupportedApi' diff --git a/packages/taro-quickapp/src/api/interactive/index.js b/packages/taro-quickapp/src/api/interactive/index.js new file mode 100644 index 000000000000..5d30459126d2 --- /dev/null +++ b/packages/taro-quickapp/src/api/interactive/index.js @@ -0,0 +1,197 @@ +import prompt from '@system.prompt' + +export function showToast (options = {}) { + const { title = '', duration = 1500, success, complete, fail } = options + const res = { errMsg: 'showToast:ok' } + + return new Promise((resolve, reject) => { + try { + prompt.showToast({ + message: title, + duration + }) + success && success(res) + complete && complete(res) + resolve(res) + } catch (data) { + res.errMsg = 'showToast: error' + res.data = data + fail && fail(res) + reject(res) + } + }) +} + +export function showModal (options = {}) { + const { + title = '', + content = '', + showCancel = true, + cancelText = '取消', + cancelColor = '#000000', + confirmText = '确定', + confirmColor = '#3CC51F', + success, + fail, + complete + } = options + + const res = { errMsg: 'showModel:ok', confirm: false, cancel: false } + + const btnList = [{ text: confirmText, color: confirmColor }] + showCancel && btnList.push({ text: cancelText, color: cancelColor }) + + return new Promise((resolve, reject) => { + prompt.showDialog({ + title: title, + message: content, + buttons: btnList, + success: (data) => { + if (showCancel) { + res.confirm = data.index === 0 + res.cancel = data.index === 1 + } else { + res.confirm = true + } + success && success(res) + complete && complete(res) + resolve(res) + }, + cancel: () => { + success && success(res) + complete && complete(res) + res.cancel = true + resolve(res) + }, + fail: (data, code) => { + res.errMsg = data + res.code = code + fail && fail(res) + reject(res) + } + }) + }) +} + +export function showActionSheet (options = {}) { + const { + itemList, + itemColor = '#000000', + success, + fail, + complete + } = options + + const res = { errMsg: 'showActionSheet:ok' } + + return new Promise((resolve, reject) => { + if (!itemList) { + console.warn('itemList必传') + res.errMsg = 'itemList必传' + reject(res) + return + } + prompt.showContextMenu({ + itemList, + itemColor, + success: (data) => { + res.tapIndex = data.index + success && success(res) + complete && complete(res) + resolve(res) + }, + cancel: () => { + res.errMsg = 'cancelActionSheet: success' + success && success(res) + complete && complete(res) + res.tapIndex = -1 + resolve(res) + }, + fail: (data, code) => { + res.errMsg = data + res.code = code + complete && complete(res) + fail && fail(res) + reject(res) + } + }) + }) +} + +function setNavigationBar (params, fnName) { + const { success, complete, fail } = params + const res = { errMsg: `${fnName}: ok` } + return new Promise((resolve, reject) => { + // 这里动态加载,保证插件的runtime代码先运行 + const Taro = require('@tarojs/taro') + try { + Taro.eventCenter.trigger('TaroEvent:setNavigationBar', params) + success && success(res) + complete && complete(res) + resolve(res) + } catch (data) { + res.errMsg = `${fnName}: error` + res.data = data + fail && fail(res) + reject(res) + } + }) +} + +export function setNavigationBarTitle (params) { + setNavigationBar(params, 'setNavigationBarTitle') +} + +export function setNavigationBarColor (params) { + setNavigationBar(params, 'setNavigationBarColor') +} + +export function startPullDownRefresh (options = {}) { + const { success, complete, fail } = options + const res = { errMsg: 'startPullDownRefresh: ok' } + return new Promise((resolve, reject) => { + // 这里动态加载,保证插件的runtime代码先运行 + const Taro = require('@tarojs/taro') + try { + Taro.eventCenter.trigger('TaroPage:startPullDownRefresh') + success && success(res) + complete && complete(res) + resolve(res) + } catch (data) { + res.errMsg = 'startPullDownRefresh: error' + res.data = data + fail && fail(res) + reject(res) + } + }) +} + +export function stopPullDownRefresh (options = {}) { + const { success, complete, fail } = options + const res = { errMsg: 'stopPullDownRefresh: ok' } + return new Promise((resolve, reject) => { + // 这里动态加载,保证插件的runtime代码先运行 + const Taro = require('@tarojs/taro') + try { + Taro.eventCenter.trigger('TaroPage:stopPullDownRefresh') + success && success(res) + complete && complete(res) + resolve(res) + } catch (data) { + res.errMsg = 'stopPullDownRefresh: error' + res.data = data + fail && fail(res) + reject(res) + } + }) +} + +export default { + showToast, + showModal, + showActionSheet, + setNavigationBarTitle, + setNavigationBarColor, + startPullDownRefresh, + stopPullDownRefresh +} diff --git a/packages/taro-quickapp/src/api/media/index.js b/packages/taro-quickapp/src/api/media/index.js new file mode 100644 index 000000000000..04d14b42a58c --- /dev/null +++ b/packages/taro-quickapp/src/api/media/index.js @@ -0,0 +1,75 @@ +import audio from '@system.audio' +import device from '@system.device' +import record from '@system.record' + +export function createInnerAudioContext () { + return audio +} + +export function getPlayState (opts = {}) { + const { success, fail, complete } = opts + const res = { errMsg: 'getPlayState:ok' } + return new Promise((resolve, reject) => { + device.getCpuInfo({ + success (data) { + res.result = data + success && success(data) + resolve(res) + }, + fail (data, code) { + res.errMsg = data + res.code = code + fail && fail(res) + complete && complete(res) + reject(res) + } + }) + }) +} + +export function startRecord (opts = {}) { + const { + duration, + sampleRate, + numberOfChannels, + encodeBitRate, + format, + success, + fail, + complete + } = opts + const res = { errMsg: 'startRecord:ok' } + return new Promise((resolve, reject) => { + record.start({ + duration, + sampleRate, + numberOfChannels, + encodeBitRate, + format, + success (data) { + res.result = data + success && success(data) + resolve(res) + }, + fail (data, code) { + res.errMsg = data + res.code = code + fail && fail(res) + complete && complete(res) + reject(res) + } + }) + }) +} + +export function stopRecord () { + return record.stop() +} + +export default { + createInnerAudioContext, + createAudioContext: createInnerAudioContext, + getPlayState, + startRecord, + stopRecord +} diff --git a/packages/taro-quickapp/src/api/notification/index.js b/packages/taro-quickapp/src/api/notification/index.js new file mode 100644 index 000000000000..1bec9d4c770c --- /dev/null +++ b/packages/taro-quickapp/src/api/notification/index.js @@ -0,0 +1,18 @@ +import notification from '@system.notification' + +export function showNotification (opts = {}) { + const { contentTitle, contentText, clickAction } = opts + if (clickAction) { + const uri = clickAction.uri + clickAction.uri = uri.substr(0, uri.lastIndexOf('/')) + } + notification.show({ + contentTitle: contentTitle || undefined, + contentText: contentText || undefined, + clickAction: contentText || undefined + }) +} + +export default { + showNotification +} diff --git a/packages/taro-quickapp/src/api/request/index.js b/packages/taro-quickapp/src/api/request/index.js new file mode 100644 index 000000000000..931b37480c32 --- /dev/null +++ b/packages/taro-quickapp/src/api/request/index.js @@ -0,0 +1,190 @@ +import fetch from '@system.fetch' +import quickRequest from '@system.request' + +export function request (options = {}) { + return new Promise((resolve, reject) => { + if (typeof options === 'string') { + options = { + url: options + } + } + + const { + url = '', + method, + dataType = 'json', + success, + fail, + complete + } = options + + let { header, data = '' } = options + + // headers + if (typeof header !== 'object') header = {} + + if (!header['content-type'] && !header['Content-Type']) { + header['Content-Type'] = 'application/json' + } + + // method + const methodUpper = + typeof method === 'string' ? method.toUpperCase() : 'GET' + + // data + if (methodUpper === 'POST' && typeof data === 'object') { + const contentType = + header && (header['Content-Type'] || header['content-type']) + if (contentType === 'application/json') { + data = JSON.stringify(data) + } + } + + // params + const obj = { + url, + data, + header, + method: methodUpper, + success (res) { + let data = res.data + + if (dataType === 'json') data = JSON.parse(res.data) + + const reponse = { + data, + statusCode: res.code, + header: res.headers + } + typeof success === 'function' && success(reponse) + typeof complete === 'function' && complete(reponse) + resolve(reponse) + }, + fail (err, code) { + const reason = { + err, + code + } + typeof fail === 'function' && fail(reason) + typeof complete === 'function' && complete(reason) + reject(reason) + } + } + + fetch.fetch(obj) + }) +} + +export function uploadFile (options = {}) { + return new Promise((resolve, reject) => { + const { + url = '', + filePath, + name = 'file', + formData = {}, + success, + fail, + complete + } = options + let { header, method = 'POST', dataType, files = [], data = [] } = options + if (typeof header !== 'object') header = {} + if (files.length === 0) { + files.push({ + name, + uri: filePath + }) + } + if (data.length === 0) { + data.push(formData) + } + const methodUpper = typeof method === 'string' ? method.toUpperCase() : 'POST' + + const obj = { + url, + header, + method: methodUpper, + files, + data, + success (res) { + let data = res.data + + if (dataType === 'json') data = JSON.parse(res.data) + + const reponse = { + data, + statusCode: res.code, + header: res.headers + } + typeof success === 'function' && success(reponse) + typeof complete === 'function' && complete(reponse) + resolve(reponse) + }, + fail (err, code) { + const reason = { + err, + code + } + typeof fail === 'function' && fail(reason) + typeof complete === 'function' && complete(reason) + reject(reason) + } + } + + quickRequest.upload(obj) + }) +} + +export function downloadFile (options = {}) { + return new Promise((resolve, reject) => { + const { + url = '', + description = '', + filename, + success, + fail, + complete + } = options + let { header, dataType, data } = options + if (typeof header !== 'object') header = {} + + const obj = { + url, + header, + description, + data, + success (res) { + let data = res.data + + if (dataType === 'json') data = JSON.parse(res.data) + + const reponse = { + data, + statusCode: res.code, + header: res.headers + } + typeof success === 'function' && success(reponse) + typeof complete === 'function' && complete(reponse) + resolve(reponse) + }, + fail (err, code) { + const reason = { + err, + code + } + typeof fail === 'function' && fail(reason) + typeof complete === 'function' && complete(reason) + reject(reason) + } + } + + if (filename) obj.filename = filename + + quickRequest.download(obj) + }) +} + +export default { + request, + uploadFile, + downloadFile +} diff --git a/packages/taro-quickapp/src/api/router/index.js b/packages/taro-quickapp/src/api/router/index.js new file mode 100644 index 000000000000..0d65db3230cc --- /dev/null +++ b/packages/taro-quickapp/src/api/router/index.js @@ -0,0 +1,91 @@ +import router from '@system.router' +import * as path from '../utils/path' + +export function navigateTo (options = {}) { + return qappNavigate(options) +} + +export function redirectTo (options = {}) { + return qappNavigate(options, 'replace') +} + +export function navigateBack (options = { delta: 1 }) { + const path = getCurrentPages().reverse()[options.delta].path + router.back({ + path + }) +} + +export function switchTab (options = {}) { + router.clear() + return qappNavigate(options, 'replace') +} + +export function getCurrentPages () { + return router.getPages() +} + +export function reLaunch (options = {}) { + router.clear() + return qappNavigate(options, 'replace') +} + +function qappNavigate (options = {}, method = 'push') { + const { url = '', success, fail, complete } = options + const res = { errMsg: 'ok' } + + return new Promise((resolve, reject) => { + let params = {} + if (!url) { + res.errMsg = 'url不能为空' + fail && fail(res) + reject(res) + return + } + const [pathname, querystring] = url.split('?') + params = getUrlParams(querystring) + const parseUrl = getUrlPath(pathname) + + try { + router[method]({ + uri: parseUrl, + params + }) + success && success(res) + complete && complete(res) + resolve(res) + } catch (data) { + res.errMsg = 'error' + res.data = data + fail && fail(res) + reject(res) + } + }) +} + +function getUrlParams (querystring = '') { + const params = {} + querystring = querystring.replace(/#.*$/, '') + const queryArray = querystring.split('&') + queryArray.forEach(item => { + const match = item.match(/([^=]+)=([^=]+)/) + if (match != null) { + params[match[1]] = decodeURIComponent(match[2]) + } + }) + return params +} + +function getUrlPath (pathname = '') { + const currentPath = router.getState().path + return path.resolve(currentPath, pathname, '..') // 去除index +} + +export default { + reLaunch, + switchTab, + navigateTo, + redirectTo, + navigateBack, + getCurrentPages +} diff --git a/packages/taro-quickapp/src/api/share/index.js b/packages/taro-quickapp/src/api/share/index.js new file mode 100644 index 000000000000..d9e29cd10d0a --- /dev/null +++ b/packages/taro-quickapp/src/api/share/index.js @@ -0,0 +1,29 @@ +import share from '@system.share' + +export function showShareMenu (opts = {}) { + const { type, data, success, fail, complete } = opts + const res = { errMsg: 'showShareMenu:ok' } + + return new Promise((resolve, reject) => { + share.share({ + type, + data, + success () { + success && success(res) + complete && complete(res) + resolve(res) + }, + fail (message, code) { + res.errMsg = message + res.code = code + fail && fail(res) + complete && complete(res) + reject(res) + } + }) + }) +} + +export default { + showShareMenu +} diff --git a/packages/taro-quickapp/src/api/storage/index.js b/packages/taro-quickapp/src/api/storage/index.js new file mode 100644 index 000000000000..4eb627445da7 --- /dev/null +++ b/packages/taro-quickapp/src/api/storage/index.js @@ -0,0 +1,100 @@ +import storage from '@system.storage' +import { generateUnSupportApi } from '../utils' + +export function setStorage (opts = {}) { + const { key, data, success, fail, complete } = opts + const res = { errMsg: 'setStorage:ok' } + + return new Promise((resolve, reject) => { + storage.set({ + key, + value: JSON.stringify(data), + success: () => { + success && success(res) + complete && complete(res) + resolve(res) + }, + fail: (message, code) => { + res.errMsg = message + res.code = code + fail && fail(res) + complete && complete(res) + reject(res) + } + }) + }) +} + +export function getStorage (opts = {}) { + const { key, success, fail, complete } = opts + const res = { errMsg: 'getStorage:ok' } + + return new Promise((resolve, reject) => { + storage.get({ + key, + success: (data) => { + res.data = data ? JSON.parse(data) : data + success && success(res) + complete && complete(res) + resolve(res) + }, + fail: (message, code) => { + res.errMsg = message + res.code = code + fail && fail(res) + complete && complete(res) + reject(res) + } + }) + }) +} + +export function getStorageInfo () { + // eslint-disable-next-line + console.log('快应用暂不支持getStorageInfo api') +} + +export function removeStorage (opts = {}) { + const { key, success, fail, complete } = opts + const res = { errMsg: 'removeStorage:ok' } + + return new Promise((resolve, reject) => { + storage.delete({ + key, + success: () => { + success && success(res) + complete && complete(res) + resolve(res) + }, + fail: (message, code) => { + res.errMsg = message + res.code = code + fail && fail(res) + complete && complete(res) + reject(res) + } + }) + }) +} + +export function clearStorage () { + return storage.clear() +} + +let unSupportApis = ['setStorageSync', 'getStorageSync', 'getStorageInfoSync', 'removeStorageSync', 'clearStorageSync'] +unSupportApis = generateUnSupportApi( + '快应用暂不支持storage的同步存取', + unSupportApis +) + +const qStorage = { + setStorage, + getStorage, + getStorageInfo, + removeStorage, + clearStorage +} + +Object.assign(qStorage, unSupportApis) + +export default qStorage diff --git a/packages/taro-quickapp/src/api/system/index.js b/packages/taro-quickapp/src/api/system/index.js new file mode 100644 index 000000000000..7eee9e7022c4 --- /dev/null +++ b/packages/taro-quickapp/src/api/system/index.js @@ -0,0 +1,224 @@ +import device from '@system.device' +import { generateUnSupportApi } from '../utils' + +export function getSystemInfo (options = {}) { + const { success, fail, complete } = options + const res = { errMsg: 'getSystemInfo:ok' } + + return new Promise((resolve, reject) => { + device.getInfo({ + success (data) { + res.result = data + success && success(data) + resolve(data) + }, + fail (data, code) { + res.errMsg = data + res.code = code + fail && fail(res) + reject(res) + }, + complete () { + complete && complete(res) + } + }) + }) +} + +export function getSystemId (options = {}) { + const { success, fail, complete, type } = options + const res = { errMsg: 'getSystemId:ok' } + return new Promise((resolve, reject) => { + device.getId({ + type, + success (data) { + res.result = data + success && success(res) + resolve(res) + }, + fail (data, code) { + res.errMsg = data + res.code = code + fail && fail(res) + reject(res) + }, + complete () { + complete && complete(res) + } + }) + }) +} + +export function getSystemDeviceId (options = {}) { + const { success, fail, complete } = options + const res = { errMsg: 'getSystemDeviceId:ok' } + return new Promise((resolve, reject) => { + device.getDeviceId({ + success (data) { + res.result = data + success && success(res) + resolve(res) + }, + fail (data, code) { + res.errMsg = data + res.code = code + fail && fail(res) + complete && complete(res) + reject(res) + } + }) + }) +} + +export function getSystemUserId (options = {}) { + const { success, fail, complete } = options + const res = { errMsg: 'getSystemUserId:ok' } + return new Promise((resolve, reject) => { + device.getDeviceId({ + success (data) { + res.result = data + success && success(res) + resolve(res) + }, + fail (data, code) { + res.errMsg = data + res.code = code + fail && fail(res) + complete && complete(res) + reject(res) + } + }) + }) +} + +export function getSystemAdvertisingId (options = {}) { + const { success, fail, complete } = options + const res = { errMsg: 'getSystemAdvertisingId:ok' } + return new Promise((resolve, reject) => { + device.getAdvertisingId({ + success (data) { + res.result = data + success && success(res) + resolve(res) + }, + fail (data, code) { + res.errMsg = data + res.code = code + fail && fail(res) + complete && complete(res) + reject(res) + } + }) + }) +} + +export function getSystemSerial (options = {}) { + const { success, fail, complete } = options + const res = { errMsg: 'getSystemSerial:ok' } + return new Promise((resolve, reject) => { + device.getSerial({ + success (data) { + res.result = data + success && success(res) + resolve(res) + }, + fail (data, code) { + res.errMsg = data + res.code = code + fail && fail(res) + complete && complete(res) + reject(res) + } + }) + }) +} + +export function getSystemTotalStorage (options = {}) { + const { success, fail, complete } = options + const res = { errMsg: 'getSystemTotalStorage:ok' } + return new Promise((resolve, reject) => { + device.getTotalStorage({ + success (data) { + res.result = data + success && success(res) + resolve(res) + }, + fail (data, code) { + res.errMsg = data + res.code = code + fail && fail(res) + complete && complete(res) + reject(res) + } + }) + }) +} + +export function getSystemAvailableStorage (options = {}) { + const { success, fail, complete } = options + const res = { errMsg: 'getSystemAvailableStorage:ok' } + return new Promise((resolve, reject) => { + device.getAvailableStorage({ + success (data) { + res.result = data + success && success(res) + resolve(res) + }, + fail (data, code) { + res.errMsg = data + res.code = code + fail && fail(res) + complete && complete(res) + reject(res) + } + }) + }) +} + +export function getSystemCpuInfo (options = {}) { + const { success, fail, complete } = options + const res = { errMsg: 'getSystemCpuInfo:ok' } + return new Promise((resolve, reject) => { + device.getCpuInfo({ + success (data) { + res.result = data + success && success(res) + resolve(res) + }, + fail (data, code) { + res.errMsg = data + res.code = code + fail && fail(res) + complete && complete(res) + reject(res) + } + }) + }) +} + +export function getSystemPlatform () { + return device.platform +} + +let unSupportApis = ['getSystemInfoSync'] +unSupportApis = generateUnSupportApi( + '快应用暂不支持SystemInfo的同步接口', + unSupportApis +) + +const qSystem = { + getSystemInfo, + getSystemId, + getSystemDeviceId, + getSystemUserId, + getSystemAdvertisingId, + getSystemSerial, + getSystemTotalStorage, + getSystemAvailableStorage, + getSystemCpuInfo, + getSystemPlatform +} + +Object.assign(qSystem, unSupportApis) + +export default qSystem diff --git a/packages/taro-quickapp/src/api/unsupportedApi/index.js b/packages/taro-quickapp/src/api/unsupportedApi/index.js new file mode 100644 index 000000000000..ac3f8d1a11c9 --- /dev/null +++ b/packages/taro-quickapp/src/api/unsupportedApi/index.js @@ -0,0 +1,276 @@ +import { temporarilyNotSupport } from '../utils' + +// onAndSyncApis +export const onSocketOpen = temporarilyNotSupport('onSocketOpen') +export const onSocketError = temporarilyNotSupport('onSocketError') +export const onSocketMessage = temporarilyNotSupport('onSocketMessage') +export const onSocketClose = temporarilyNotSupport('onSocketClose') +export const onBackgroundAudioPlay = temporarilyNotSupport('onBackgroundAudioPlay') +export const onBackgroundAudioPause = temporarilyNotSupport('onBackgroundAudioPause') +export const onBackgroundAudioStop = temporarilyNotSupport('onBackgroundAudioStop') +export const onNetworkStatusChange = temporarilyNotSupport('onNetworkStatusChange') +// export const onAccelerometerChange = temporarilyNotSupport('onAccelerometerChange') +// export const onCompassChange = temporarilyNotSupport('onCompassChange') +export const onDeviceMotionChange = temporarilyNotSupport('onDeviceMotionChange') +export const onBluetoothAdapterStateChange = temporarilyNotSupport('onBluetoothAdapterStateChange') +export const onBluetoothDeviceFound = temporarilyNotSupport('onBluetoothDeviceFound') +export const onBLEConnectionStateChange = temporarilyNotSupport('onBLEConnectionStateChange') +export const onBLECharacteristicValueChange = temporarilyNotSupport('onBLECharacteristicValueChange') +export const onBeaconUpdate = temporarilyNotSupport('onBeaconUpdate') +export const onBeaconServiceChange = temporarilyNotSupport('onBeaconServiceChange') +export const onUserCaptureScreen = temporarilyNotSupport('onUserCaptureScreen') +export const onHCEMessage = temporarilyNotSupport('onHCEMessage') +export const onGetWifiList = temporarilyNotSupport('onGetWifiList') +export const onWifiConnected = temporarilyNotSupport('onWifiConnected') +export const setStorageSync = temporarilyNotSupport('setStorageSync') +export const getStorageSync = temporarilyNotSupport('getStorageSync') +export const getStorageInfoSync = temporarilyNotSupport('getStorageInfoSync') +export const removeStorageSync = temporarilyNotSupport('removeStorageSync') +export const clearStorageSync = temporarilyNotSupport('clearStorageSync') +export const getSystemInfoSync = temporarilyNotSupport('getSystemInfoSync') +export const getExtConfigSync = temporarilyNotSupport('getExtConfigSync') +export const getLogManager = temporarilyNotSupport('getLogManager') +export const onMemoryWarning = temporarilyNotSupport('onMemoryWarning') +export const reportAnalytics = temporarilyNotSupport('reportAnalytics') +export const navigateToSmartGameProgram = temporarilyNotSupport('navigateToSmartGameProgram') + +// 文件 +export const getFileSystemManager = temporarilyNotSupport('getFileSystemManager') + +// noPromiseApis +// 媒体 +// export const stopRecord = temporarilyNotSupport('stopRecord') +export const getRecorderManager = temporarilyNotSupport('getRecorderManager') +export const pauseVoice = temporarilyNotSupport('pauseVoice') +export const stopVoice = temporarilyNotSupport('stopVoice') +export const pauseBackgroundAudio = temporarilyNotSupport('pauseBackgroundAudio') +export const stopBackgroundAudio = temporarilyNotSupport('stopBackgroundAudio') +export const getBackgroundAudioManager = temporarilyNotSupport('getBackgroundAudioManager') +export const createAudioContext = temporarilyNotSupport('createAudioContext') +// export const createInnerAudioContext = temporarilyNotSupport('createInnerAudioContext') +export const createVideoContext = temporarilyNotSupport('createVideoContext') +export const createCameraContext = temporarilyNotSupport('createCameraContext') +export const createLivePlayerContext = temporarilyNotSupport('createLivePlayerContext') +export const createLivePusherContext = temporarilyNotSupport('createLivePusherContext') + +// 位置 +export const createMapContext = temporarilyNotSupport('createMapContext') + +// 设备 +export const canIUse = temporarilyNotSupport('canIUse') +// export const startAccelerometer = temporarilyNotSupport('startAccelerometer') +// export const stopAccelerometer = temporarilyNotSupport('stopAccelerometer') +// export const startCompass = temporarilyNotSupport('startCompass') +// export const stopCompass = temporarilyNotSupport('stopCompass') +export const startDeviceMotionListening = temporarilyNotSupport('startDeviceMotionListening') +export const stopDeviceMotionListening = temporarilyNotSupport('stopDeviceMotionListening') + +// 界面 +export const hideToast = temporarilyNotSupport('hideToast') +export const hideLoading = temporarilyNotSupport('hideLoading') +export const showNavigationBarLoading = temporarilyNotSupport('showNavigationBarLoading') +export const hideNavigationBarLoading = temporarilyNotSupport('hideNavigationBarLoading') +export const createAnimation = temporarilyNotSupport('createAnimation') +export const pageScrollTo = temporarilyNotSupport('pageScrollTo') +export const createSelectorQuery = temporarilyNotSupport('createSelectorQuery') +export const createCanvasContext = temporarilyNotSupport('createCanvasContext') +export const createContext = temporarilyNotSupport('createContext') +export const drawCanvas = temporarilyNotSupport('drawCanvas') +export const hideKeyboard = temporarilyNotSupport('hideKeyboard') +// export const stopPullDownRefresh = temporarilyNotSupport('stopPullDownRefresh') +export const createIntersectionObserver = temporarilyNotSupport('createIntersectionObserver') + +// 自定义组件 +export const nextTick = temporarilyNotSupport('nextTick') + +// 菜单 +export const getMenuButtonBoundingClientRect = temporarilyNotSupport('getMenuButtonBoundingClientRect') + +// 窗口 +export const onWindowResize = temporarilyNotSupport('onWindowResize') +export const offWindowResize = temporarilyNotSupport('offWindowResize') + +// 拓展接口 +export const arrayBufferToBase64 = temporarilyNotSupport('arrayBufferToBase64') +export const base64ToArrayBuffer = temporarilyNotSupport('base64ToArrayBuffer') + +export const getAccountInfoSync = temporarilyNotSupport('getAccountInfoSync') +export const getUpdateManager = temporarilyNotSupport('getUpdateManager') +export const createWorker = temporarilyNotSupport('createWorker') + +// otherApis +// 网络 +// export const uploadFile = temporarilyNotSupport('uploadFile') +// export const downloadFile = temporarilyNotSupport('downloadFile') +export const connectSocket = temporarilyNotSupport('connectSocket') +export const sendSocketMessage = temporarilyNotSupport('sendSocketMessage') +export const closeSocket = temporarilyNotSupport('closeSocket') + +// 媒体 +export const chooseImage = temporarilyNotSupport('chooseImage') +export const previewImage = temporarilyNotSupport('previewImage') +export const getImageInfo = temporarilyNotSupport('getImageInfo') +export const saveImageToPhotosAlbum = temporarilyNotSupport('saveImageToPhotosAlbum') +// export const startRecord = temporarilyNotSupport('startRecord') +export const playVoice = temporarilyNotSupport('playVoice') +export const setInnerAudioOption = temporarilyNotSupport('setInnerAudioOption') +export const getAvailableAudioSources = temporarilyNotSupport('getAvailableAudioSources') +export const getBackgroundAudioPlayerState = temporarilyNotSupport('getBackgroundAudioPlayerState') +export const playBackgroundAudio = temporarilyNotSupport('playBackgroundAudio') +export const seekBackgroundAudio = temporarilyNotSupport('seekBackgroundAudio') +export const chooseVideo = temporarilyNotSupport('chooseVideo') +export const saveVideoToPhotosAlbum = temporarilyNotSupport('saveVideoToPhotosAlbum') +export const loadFontFace = temporarilyNotSupport('loadFontFace') + +// 文件 +export const saveFile = temporarilyNotSupport('saveFile') +export const getFileInfo = temporarilyNotSupport('getFileInfo') +export const getSavedFileList = temporarilyNotSupport('getSavedFileList') +export const getSavedFileInfo = temporarilyNotSupport('getSavedFileInfo') +export const removeSavedFile = temporarilyNotSupport('removeSavedFile') +export const openDocument = temporarilyNotSupport('openDocument') + +// 数据缓存 +// export const setStorage = temporarilyNotSupport('setStorage') +// export const getStorage = temporarilyNotSupport('getStorage') +// export const getStorageInfo = temporarilyNotSupport('getStorageInfo') +// export const removeStorage = temporarilyNotSupport('removeStorage') +// export const clearStorage = temporarilyNotSupport('clearStorage') + +// 导航 +// export const navigateBack = temporarilyNotSupport('navigateBack') +// export const navigateTo = temporarilyNotSupport('navigateTo') +// export const redirectTo = temporarilyNotSupport('redirectTo') +// export const switchTab = temporarilyNotSupport('switchTab') +// export const reLaunch = temporarilyNotSupport('reLaunch') + +// 位置 +// export const getLocation = temporarilyNotSupport('getLocation') +export const chooseLocation = temporarilyNotSupport('chooseLocation') +export const openLocation = temporarilyNotSupport('openLocation') + +// 设备 +// export const getSystemInfo = temporarilyNotSupport('getSystemInfo') +export const getNetworkType = temporarilyNotSupport('getNetworkType') +export const makePhoneCall = temporarilyNotSupport('makePhoneCall') +// export const scanCode = temporarilyNotSupport('scanCode') +// export const setClipboardData = temporarilyNotSupport('setClipboardData') +// export const getClipboardData = temporarilyNotSupport('getClipboardData') +export const openBluetoothAdapter = temporarilyNotSupport('openBluetoothAdapter') +export const closeBluetoothAdapter = temporarilyNotSupport('closeBluetoothAdapter') +export const getBluetoothAdapterState = temporarilyNotSupport('getBluetoothAdapterState') +export const startBluetoothDevicesDiscovery = temporarilyNotSupport('startBluetoothDevicesDiscovery') +export const stopBluetoothDevicesDiscovery = temporarilyNotSupport('stopBluetoothDevicesDiscovery') +export const getBluetoothDevices = temporarilyNotSupport('getBluetoothDevices') +export const getConnectedBluetoothDevices = temporarilyNotSupport('getConnectedBluetoothDevices') +export const createBLEConnection = temporarilyNotSupport('createBLEConnection') +export const closeBLEConnection = temporarilyNotSupport('closeBLEConnection') +export const getBLEDeviceServices = temporarilyNotSupport('getBLEDeviceServices') +export const getBLEDeviceCharacteristics = temporarilyNotSupport('getBLEDeviceCharacteristics') +export const readBLECharacteristicValue = temporarilyNotSupport('readBLECharacteristicValue') +export const writeBLECharacteristicValue = temporarilyNotSupport('writeBLECharacteristicValue') +export const notifyBLECharacteristicValueChange = temporarilyNotSupport('notifyBLECharacteristicValueChange') +export const startBeaconDiscovery = temporarilyNotSupport('startBeaconDiscovery') +export const stopBeaconDiscovery = temporarilyNotSupport('stopBeaconDiscovery') +export const getBeacons = temporarilyNotSupport('getBeacons') +export const setScreenBrightness = temporarilyNotSupport('setScreenBrightness') +export const getScreenBrightness = temporarilyNotSupport('getScreenBrightness') +export const setKeepScreenOn = temporarilyNotSupport('setKeepScreenOn') +// export const vibrateLong = temporarilyNotSupport('vibrateLong') +// export const vibrateShort = temporarilyNotSupport('vibrateShort') +export const addPhoneContact = temporarilyNotSupport('addPhoneContact') +export const getHCEState = temporarilyNotSupport('getHCEState') +export const startHCE = temporarilyNotSupport('startHCE') +export const stopHCE = temporarilyNotSupport('stopHCE') +export const sendHCEMessage = temporarilyNotSupport('sendHCEMessage') +export const startWifi = temporarilyNotSupport('startWifi') +export const stopWifi = temporarilyNotSupport('stopWifi') +export const connectWifi = temporarilyNotSupport('connectWifi') +export const getWifiList = temporarilyNotSupport('getWifiList') +export const setWifiList = temporarilyNotSupport('setWifiList') +export const getConnectedWifi = temporarilyNotSupport('getConnectedWifi') + +// 界面 +// export const showToast = temporarilyNotSupport('showToast') +export const showLoading = temporarilyNotSupport('showLoading') +// export const showModal = temporarilyNotSupport('showModal') +// export const showActionSheet = temporarilyNotSupport('showActionSheet') +// export const setNavigationBarTitle = temporarilyNotSupport('setNavigationBarTitle') +// export const setNavigationBarColor = temporarilyNotSupport('setNavigationBarColor') +export const setTabBarBadge = temporarilyNotSupport('setTabBarBadge') +export const removeTabBarBadge = temporarilyNotSupport('removeTabBarBadge') +export const showTabBarRedDot = temporarilyNotSupport('showTabBarRedDot') +export const hideTabBarRedDot = temporarilyNotSupport('hideTabBarRedDot') +export const setTabBarStyle = temporarilyNotSupport('setTabBarStyle') +export const setTabBarItem = temporarilyNotSupport('setTabBarItem') +export const showTabBar = temporarilyNotSupport('showTabBar') +export const hideTabBar = temporarilyNotSupport('hideTabBar') +export const setTopBarText = temporarilyNotSupport('setTopBarText') +// export const startPullDownRefresh = temporarilyNotSupport('startPullDownRefresh') +export const canvasToTempFilePath = temporarilyNotSupport('canvasToTempFilePath') +export const canvasGetImageData = temporarilyNotSupport('canvasGetImageData') +export const canvasPutImageData = temporarilyNotSupport('canvasPutImageData') + +export const setBackgroundColor = temporarilyNotSupport('setBackgroundColor') +export const setBackgroundTextStyle = temporarilyNotSupport('setBackgroundTextStyle') + +// 第三方平台 +export const getExtConfig = temporarilyNotSupport('getExtConfig') + +// 开放接口 +export const login = temporarilyNotSupport('login') +export const checkSession = temporarilyNotSupport('checkSession') +export const authorize = temporarilyNotSupport('authorize') +export const getUserInfo = temporarilyNotSupport('getUserInfo') +export const checkIsSupportFacialRecognition = temporarilyNotSupport('checkIsSupportFacialRecognition') +export const startFacialRecognitionVerify = temporarilyNotSupport('startFacialRecognitionVerify') +export const startFacialRecognitionVerifyAndUploadVideo = temporarilyNotSupport('startFacialRecognitionVerifyAndUploadVideo') +export const faceVerifyForPay = temporarilyNotSupport('faceVerifyForPay') +export const requestPayment = temporarilyNotSupport('requestPayment') +// export const showShareMenu = temporarilyNotSupport('showShareMenu') +export const hideShareMenu = temporarilyNotSupport('hideShareMenu') +export const updateShareMenu = temporarilyNotSupport('updateShareMenu') +export const getShareInfo = temporarilyNotSupport('getShareInfo') +export const chooseAddress = temporarilyNotSupport('chooseAddress') +export const addCard = temporarilyNotSupport('addCard') +export const openCard = temporarilyNotSupport('openCard') +export const openSetting = temporarilyNotSupport('openSetting') +export const getSetting = temporarilyNotSupport('getSetting') +export const getWeRunData = temporarilyNotSupport('getWeRunData') +export const navigateToMiniProgram = temporarilyNotSupport('navigateToMiniProgram') +export const navigateBackMiniProgram = temporarilyNotSupport('navigateBackMiniProgram') +export const chooseInvoice = temporarilyNotSupport('chooseInvoice') +export const chooseInvoiceTitle = temporarilyNotSupport('chooseInvoiceTitle') +export const checkIsSupportSoterAuthentication = temporarilyNotSupport('checkIsSupportSoterAuthentication') +export const startSoterAuthentication = temporarilyNotSupport('startSoterAuthentication') +export const checkIsSoterEnrolledInDevice = temporarilyNotSupport('checkIsSoterEnrolledInDevice') + +export const setEnableDebug = temporarilyNotSupport('setEnableDebug') + +// 百度小程序专有 API +// 百度小程序 AI 相关 +export const ocrIdCard = temporarilyNotSupport('ocrIdCard') +export const ocrBankCard = temporarilyNotSupport('ocrBankCard') +export const ocrDrivingLicense = temporarilyNotSupport('ocrDrivingLicense') +export const ocrVehicleLicense = temporarilyNotSupport('ocrVehicleLicense') +export const textReview = temporarilyNotSupport('textReview') +export const textToAudio = temporarilyNotSupport('textToAudio') +export const imageAudit = temporarilyNotSupport('imageAudit') +export const advancedGeneralIdentify = temporarilyNotSupport('advancedGeneralIdentify') +export const objectDetectIdentify = temporarilyNotSupport('objectDetectIdentify') +export const carClassify = temporarilyNotSupport('carClassify') +export const dishClassify = temporarilyNotSupport('dishClassify') +export const logoClassify = temporarilyNotSupport('logoClassify') +export const animalClassify = temporarilyNotSupport('animalClassify') +export const plantClassify = temporarilyNotSupport('plantClassify') + +// 用户信息 +export const getSwanId = temporarilyNotSupport('getSwanId') + +// 百度收银台支付 +export const requestPolymerPayment = temporarilyNotSupport('requestPolymerPayment') + +// 打开小程序 +export const navigateToSmartProgram = temporarilyNotSupport('navigateToSmartProgram') +export const navigateBackSmartProgram = temporarilyNotSupport('navigateBackSmartProgram') +export const preloadSubPackage = temporarilyNotSupport('preloadSubPackage') diff --git a/packages/taro-quickapp/src/api/utils/index.js b/packages/taro-quickapp/src/api/utils/index.js new file mode 100644 index 000000000000..f5aaa2433cb0 --- /dev/null +++ b/packages/taro-quickapp/src/api/utils/index.js @@ -0,0 +1,42 @@ +export function generateUnSupportApi (errText, fnNames) { + const res = {} + fnNames.forEach((fnName) => { + res[fnName] = function () { + throw new Error(errText) + } + }) + return res +} + +export function makeSyncPromise (fnName, process, options = {}) { + const { + success, + fail, + complete + } = options + + const res = { errMsg: `${fnName}:ok` } + + return new Promise((resolve, reject) => { + try { + process && process() + success && success(res) + complete && complete(res) + resolve(res) + } catch (data) { + res.errMsg = `${fnName}:error` + res.data = data + fail && fail(res) + complete && complete(res) + reject(res) + } + }) +} + +export function temporarilyNotSupport (apiName) { + return () => { + const errMsg = `暂时不支持 API ${apiName}` + console.error(errMsg) + return Promise.reject(new Error(errMsg)) + } +} diff --git a/packages/taro-quickapp/src/api/utils/path.js b/packages/taro-quickapp/src/api/utils/path.js new file mode 100644 index 000000000000..12d836e25a77 --- /dev/null +++ b/packages/taro-quickapp/src/api/utils/path.js @@ -0,0 +1,47 @@ +// copy from https://github.com/jinder/path/blob/master/path.js +export function resolve () { + var resolvedPath = '' + var resolvedAbsolute = false + + for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { + var path = (i >= 0) ? arguments[i] : '/' + + if (!path) { + continue + } + + resolvedPath = path + '/' + resolvedPath + resolvedAbsolute = path[0] === '/' + } + + // At this point the path should be resolved to a full absolute path, but + // handle relative paths to be safe (might happen when process.cwd() fails) + + // Normalize the path + resolvedPath = normalizeArray(resolvedPath.split('/'), + !resolvedAbsolute).join('/') + + return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.' +} + +function normalizeArray (parts, allowAboveRoot) { + var res = [] + for (var i = 0; i < parts.length; i++) { + var p = parts[i] + + // ignore empty parts + if (!p || p === '.') { continue } + + if (p === '..') { + if (res.length && res[res.length - 1] !== '..') { + res.pop() + } else if (allowAboveRoot) { + res.push('..') + } + } else { + res.push(p) + } + } + + return res +} diff --git a/packages/taro-quickapp/src/api/webview/index.js b/packages/taro-quickapp/src/api/webview/index.js new file mode 100644 index 000000000000..be078005cb20 --- /dev/null +++ b/packages/taro-quickapp/src/api/webview/index.js @@ -0,0 +1,9 @@ +import webview from '@system.webview' + +export function webviewLoadUrl (opts = {}) { + return webview.loadUrl(opts) +} + +export default { + webviewLoadUrl +} diff --git a/packages/taro-quickapp/src/apis.ts b/packages/taro-quickapp/src/apis.ts new file mode 100644 index 000000000000..27a57a28eb78 --- /dev/null +++ b/packages/taro-quickapp/src/apis.ts @@ -0,0 +1,5 @@ +import * as supportApi from './api' + +export function initNativeApi (taro) { + Object.assign(taro, supportApi) +} diff --git a/packages/taro-quickapp/src/compile-utils.ts b/packages/taro-quickapp/src/compile-utils.ts new file mode 100644 index 000000000000..7ee6ca46a961 --- /dev/null +++ b/packages/taro-quickapp/src/compile-utils.ts @@ -0,0 +1,49 @@ +import fs from 'fs-extra' +import path from 'path' +import request from 'request' + +const GITHUB_API = 'https://api.github.com/' +const GITHUB = 'https://github.com.cnpmjs.org/' + +export function getGithubRepoLatestReleaseVersion (repoName: string) { + const latestReleaseApi = `${GITHUB_API}repos/${repoName}/releases/latest` + const p = new Promise((resolve) => { + request({ + url: latestReleaseApi, + headers: { + 'User-Agent': 'Awesome-Octocat-App' + } + }, (err, response, body) => { + if (err) { + throw new Error('快应用容器版本请求失败,请重试!' + err) + } + const res = JSON.parse(body) + resolve(res.tag_name) + }) + }) + return p +} + +export async function downloadGithubRepoLatestRelease (repoName: string, appPath: string, dest: string) { + // const latestTagName = await getGithubRepoLatestReleaseVersion(repoName) + const latestTagName = '1.2.0' + return new Promise((resolve, reject) => { + const downloadUrl = `${GITHUB}${repoName}/archive/${latestTagName}.zip` + const downloadTemp = 'download_temp.zip' + request({ + url: downloadUrl, + headers: { + 'User-Agent': 'Awesome-Octocat-App' + } + }) + .on('error', reject) + .on('complete', () => { + const downloadTempPath = path.join(appPath, downloadTemp) + if (fs.existsSync(downloadTempPath)) { + fs.moveSync(downloadTempPath, path.join(dest, downloadTemp)) + resolve() + } + }) + .pipe(fs.createWriteStream(downloadTemp)) + }) +} diff --git a/packages/taro-quickapp/src/components-react.ts b/packages/taro-quickapp/src/components-react.ts new file mode 100644 index 000000000000..9eea08e25822 --- /dev/null +++ b/packages/taro-quickapp/src/components-react.ts @@ -0,0 +1,71 @@ +export const View = 'div' +export const Icon = 'taro-icon' +export const Progress = 'taro-progress' +export const RichText = 'taro-rich-text' +export const Text = 'text' +export const Button = 'taro-button' +export const Checkbox = 'taro-checkbox' +export const CheckboxGroup = 'checkbox-group' +export const Form = 'form' +export const Input = 'taro-input' +export const Label = 'taro-label' +export const Picker = 'taro-picker' +export const PickerView = 'picker-view' +export const PickerViewColumn = 'picker-view-column' +export const Radio = 'taro-radio' +export const RadioGroup = 'radio-group' +export const Slider = 'taro-slider' +export const Switch = 'taro-switch' +export const CoverImage = 'cover-image' +export const Textarea = 'taro-textarea' +export const CoverView = 'cover-view' +export const MovableArea = 'movable-area' +export const MovableView = 'movable-view' +export const ScrollView = 'taro-scroll-view' +export const Swiper = 'taro-swiper' +export const SwiperItem = 'taro-swiper-item' +export const Navigator = 'taro-navigator' +export const Audio = 'taro-audio' +export const Camera = 'taro-camera' +export const Image = 'taro-image' +export const LivePlayer = 'live-player' +export const Video = 'taro-video' +export const Canvas = 'taro-canvas' +export const Ad = 'ad' +export const WebView = 'taro-web-view' +export const Block = 'block' +export const Map = 'taro-map' +export const Slot = 'slot' +export const CustomWrapper = 'block' + +// 快应用原生组件 +export const QkDiv = 'div' +export const QkList = 'list' +export const QkListItem = 'list-item' +export const QkPopup = 'popup' +export const QkRefresh = 'refresh' +export const QkRichText = 'richtext' +export const QkStack = 'stack' +export const QkSwiper = 'swiper' +export const QkTabs = 'tabs' +export const QkTabBar = 'tab-bar' +export const QkTabContent = 'tab-content' +export const QkA = 'a' +export const QkImage = 'image' +export const QkProgress = 'progress' +export const QkRating = 'rating' +export const QkSpan = 'span' +export const QkText = 'text' +export const QkMarquee = 'marquee' +export const QkInput = 'input' +export const QkLabel = 'label' +export const QkOption = 'option' +export const QkPicker = 'picker' +export const QkSelect = 'select' +export const QkSlider = 'slider' +export const QkSwitch = 'switch' +export const QkTextArea = 'textarea' +export const QkVideo = 'video' +export const QkCamera = 'camera' +export const QkCanvas = 'canvas' +export const QkWeb = 'web' diff --git a/packages/taro-quickapp/src/components.ts b/packages/taro-quickapp/src/components.ts new file mode 100644 index 000000000000..b9915ef3b1a1 --- /dev/null +++ b/packages/taro-quickapp/src/components.ts @@ -0,0 +1,187 @@ +import { singleQuote } from '@tarojs/shared' + +export const components = { + QkDiv: { + enablevideofullscreencontainer: 'false' + }, + QkList: { + scrollpage: 'false', + bindScroll: '', + bindScrollBottom: '', + bindScrollTop: '', + bindScrollEnd: '', + bindScrollTouchUp: '' + }, + QkListItem: { + type: singleQuote('') + }, + QkPopup: { + target: singleQuote(''), + placement: singleQuote('bottom'), + bindVisibilityChange: '' + }, + QkRefresh: { + offset: '132', + refreshing: 'false', + type: singleQuote('auto'), + enableRefresh: 'true', + bindRefresh: '' + }, + QkRichText: { + type: singleQuote('html'), + bindStart: '', + bindComplete: '' + }, + QkStack: { + bindFullScreenChange: '' + }, + QkSwiper: { + index: '0', + autoplay: 'false', + interval: '3000', + indicator: 'true', + loop: 'false', + duration: '0', + vertical: 'false', + previousMargin: singleQuote(''), + nextMargin: singleQuote(''), + enableSwipe: 'true', + bindChange: '' + }, + QkTabs: { + index: '0', + bindChange: '' + }, + QkTabBar: { + mode: singleQuote('fixed') + }, + QkTabContent: { + scrollable: 'true' + }, + QkA: { + href: singleQuote('') + }, + QkImage: { + src: singleQuote(''), + alt: singleQuote(''), + autoplay: 'true', + bindComplete: '', + bindError: '' + }, + QkProgress: { + percent: '0', + type: singleQuote('horizontal') + }, + QkRating: { + numstars: '5', + rating: '0', + stepsize: '0.5', + indicator: 'false', + bindChange: '' + }, + QkSpan: {}, + QkText: {}, + QkMarquee: { + scrollamount: '6', + loop: '-1', + direction: singleQuote('left'), + bindBounce: '', + bindFinish: '', + bindStart: '' + }, + QkInput: { + type: singleQuote('text'), + checked: 'false', + name: singleQuote(''), + value: singleQuote(''), + placeholder: singleQuote(''), + maxlength: '100', + enterkeytype: singleQuote('default'), + autocomplete: singleQuote('on'), + bindChange: '', + bindEnterkeyClick: '', + bindSelectionChange: '' + }, + QkLabel: { + target: singleQuote('') + }, + QkOption: { + selected: 'false', + value: singleQuote('') + }, + QkPicker: { + type: singleQuote('text'), + range: '[]', + selected: '0', + value: singleQuote(''), + start: singleQuote(''), + end: singleQuote('') + }, + QkSelect: { + bindChange: '' + }, + QkSlider: { + min: '0', + max: '100', + step: '1', + value: '0', + bindChange: '' + }, + QkSwitch: { + checked: 'false', + bindChange: '' + }, + QkTextArea: { + placeholder: singleQuote(''), + maxlength: '100', + bindChange: '', + bindSelectionChange: '', + bindLineChange: '' + }, + QkVideo: { + src: singleQuote(''), + autoplay: 'false', + poster: singleQuote(''), + controls: 'true', + muted: 'false', + orientation: singleQuote('landscape'), + titlebar: 'true', + title: singleQuote(''), + playcount: '1', + enablevideofullscreencontainer: 'false', + bindPrepared: '', + bindStart: '', + bindPause: '', + bindFinish: '', + bindError: '', + bindSeeking: '', + bindSeeked: '', + bindTimeUpdate: '', + bindFullScreenChange: '' + }, + QkCamera: { + deviceposition: singleQuote('front'), + flash: singleQuote('auto'), + framesize: singleQuote('normal'), + autoexposurelock: 'false', + autowhitebalancelock: 'false', + bindError: '', + bindCameraFrame: '', + bindCameraInitDone: '' + }, + QkCanvas: {}, + QkWeb: { + src: singleQuote(''), + trustedurl: '[]', + allowthirdpartycookies: 'false', + showloadingdialog: 'false', + supportzoom: 'true', + useragent: singleQuote(''), + bindPageStart: '', + bindPageFinish: '', + bindTitleReceive: '', + bindError: '', + bindMessage: '', + bindProgress: '' + } +} diff --git a/packages/taro-quickapp/src/index.ts b/packages/taro-quickapp/src/index.ts new file mode 100644 index 000000000000..3dc6b8664a25 --- /dev/null +++ b/packages/taro-quickapp/src/index.ts @@ -0,0 +1,186 @@ +import QuickApp from './program' +import type { IPluginContext } from '@tarojs/service' +import { downloadGithubRepoLatestRelease } from './compile-utils' +import path from 'path' +import { execSync } from 'child_process' +import ora from 'ora' +import defaultManifestJSON from './manifest.default.json' + +// 让其它平台插件可以继承此平台 +export { QuickApp } + +export default (ctx: IPluginContext) => { + ctx.registerPlatform({ + name: 'quickapp', + useConfigName: 'mini', + async fn ({ config }) { + const { appPath } = ctx.paths + const { + isWatch, + port, + release + } = ctx.runOpts + const { + fs, + printLog, + processTypeEnum, + chalk, + shouldUseYarn, + isWindows, + shouldUseCnpm, + unzip + } = ctx.helper + + const originalOutputRoot = config.outputRoot + + const isReady = await prepareQuickAppEnvironment({ + originalOutputRoot, + fs, + appPath, + chalk, + printLog, + shouldUseYarn, + isWindows, + shouldUseCnpm, + unzip + }) + if (!isReady) { + printLog(processTypeEnum.ERROR, chalk.red('快应用环境准备失败,请重试!')) + process.exit(0) + } + + // 读取 project.quickapp.json + const quickappJSONPath = path.join(appPath, 'project.quickapp.json') + let quickappJSON + if (fs.existsSync(quickappJSONPath)) { + quickappJSON = fs.readJSONSync(quickappJSONPath) + } else { + printLog(processTypeEnum.WARNING, '缺少配置', `检测到项目目录下未添加 ${chalk.bold('project.quickapp.json')} 文件,将使用默认配置,参考文档 https://nervjs.github.io/taro/docs/project-config.html`) + quickappJSON = defaultManifestJSON + } + + config.outputRoot = `${originalOutputRoot}/src` + ctx.paths.outputPath = `${ctx.paths.outputPath}/src` + config.isBuildQuickapp = true + config.quickappJSON = quickappJSON + + const program = new QuickApp(ctx, config) + await program.start() + + if (process.env.TARO_ENV === 'unexist') { + await runQuickApp({ + isWatch, + originalOutputRoot, + port, + release + }) + } + } + }) +} + +async function prepareQuickAppEnvironment ({ + originalOutputRoot, + fs, + appPath, + chalk, + printLog, + shouldUseYarn, + isWindows, + shouldUseCnpm, + unzip +}) { + const cwd = process.cwd() + let isReady = false + let needDownload = false + let needInstall = false + if (fs.existsSync(path.join(originalOutputRoot, 'sign'))) { + needDownload = false + } else { + needDownload = true + } + if (needDownload) { + const getSpinner = ora('开始下载快应用运行容器...').start() + await downloadGithubRepoLatestRelease('NervJS/quickapp-container', appPath, originalOutputRoot) + await unzip(path.join(originalOutputRoot, 'download_temp.zip')) + getSpinner.succeed('快应用运行容器下载完成') + } else { + printLog('remind', `${chalk.green('✔ ')} 快应用容器已经准备好`) + } + process.chdir(originalOutputRoot) + if (fs.existsSync(path.join(originalOutputRoot, 'node_modules'))) { + needInstall = false + } else { + needInstall = true + } + if (needInstall) { + let command + if (shouldUseYarn()) { + if (!isWindows) { + command = 'NODE_ENV=development yarn install' + } else { + command = 'yarn install' + } + } else if (shouldUseCnpm()) { + if (!isWindows) { + command = 'NODE_ENV=development cnpm install' + } else { + command = 'cnpm install' + } + } else { + if (!isWindows) { + command = 'NODE_ENV=development npm install' + } else { + command = 'npm install' + } + } + const installSpinner = ora('安装快应用依赖环境, 需要一会儿...').start() + try { + const stdout = execSync(command) + installSpinner.color = 'green' + installSpinner.succeed('安装成功') + printLog('remind', `${stdout}`) + isReady = true + } catch (error) { + installSpinner.color = 'red' + installSpinner.fail(chalk.red(`快应用依赖环境安装失败,请进入 ${path.basename(originalOutputRoot)} 重新安装!`)) + printLog('error', `${error}`) + isReady = false + } + } else { + printLog('remind', `${chalk.green('✔ ')} 快应用依赖已经安装好`) + isReady = true + } + process.chdir(cwd) + return isReady +} + +async function runQuickApp ({ + isWatch, + originalOutputRoot, + port, + release +}: { + isWatch: boolean | void, + originalOutputRoot: string, + port?: number, + release?: boolean +}) { + const { compile } = require(require.resolve('hap-toolkit/lib/commands/compile', { paths: [originalOutputRoot] })) + if (isWatch) { + const { launchServer } = require(require.resolve('@hap-toolkit/server', { paths: [originalOutputRoot] })) + launchServer({ + port: port || 12306, + watch: isWatch, + clearRecords: false, + disableADB: false + }) + compile('native', 'dev', true) + } else { + if (!release) { + compile('native', 'dev', false) + } else { + compile('native', 'prod', false) + } + } +} diff --git a/packages/taro-cli/src/config/manifest.default.json b/packages/taro-quickapp/src/manifest.default.json similarity index 96% rename from packages/taro-cli/src/config/manifest.default.json rename to packages/taro-quickapp/src/manifest.default.json index b243621b190a..c65f12fbdfdc 100644 --- a/packages/taro-cli/src/config/manifest.default.json +++ b/packages/taro-quickapp/src/manifest.default.json @@ -3,7 +3,7 @@ "name": "TaroQuickApp", "versionName": "1.0.0", "versionCode": 1, - "minPlatformVersion": 1040, + "minPlatformVersion": 1090, "features": [ { "name": "system.prompt" }, { "name": "system.router" }, diff --git a/packages/taro-quickapp/src/program.ts b/packages/taro-quickapp/src/program.ts new file mode 100644 index 000000000000..16628bd02c06 --- /dev/null +++ b/packages/taro-quickapp/src/program.ts @@ -0,0 +1,78 @@ +import { TaroPlatformBase } from '@tarojs/service' +import { Template } from './template' +import { components } from './components' + +const PACKAGE_NAME = '@tarojs/plugin-platform-quickapp' + +export default class QuickApp extends TaroPlatformBase { + platform = 'quickapp' + globalObject = 'global' + runtimePath = `${PACKAGE_NAME}/dist/runtime` + taroComponentsPath = `${PACKAGE_NAME}/dist/components-react` + fileType = { + templ: '.ux', + style: '.css', + config: '.json', + script: '.js' + } + + template = new Template() + + /** + * 1. setupTransaction - init + * 2. setup + * 3. setupTransaction - close + * 4. buildTransaction - init + * 5. build + * 6. buildTransaction - close + */ + constructor (ctx, config) { + super(ctx, config) + + this.setupTransaction.addWrapper({ + close: () => { + this.modifyMiniConfigs() + this.modifyTemplate() + } + }) + } + + /** + * 转换用户编写的配置(微信小程序标准)为快应用标准 + */ + modifyMiniConfigs () { + this.ctx.modifyMiniConfigs(({ configMap }) => { + const replaceKeyMap = { + navigationBarTitleText: 'titleBarText', + navigationBarBackgroundColor: 'titleBarBackgroundColor', + navigationBarTextStyle: 'titleBarTextColor', + pageOrientation: 'orientation', + backgroundTextStyle: false, + onReachBottomDistance: false, + backgroundColorBottom: false, + backgroundColorTop: false + } + Object.keys(configMap).forEach(key => { + const item = configMap[key] + if (item.content) { + this.recursiveReplaceObjectKeys(item.content, replaceKeyMap) + this.traverseModifyConfig(item.content, (key, value, parent) => { + if (key === 'navigationStyle' && value === 'custom') { + delete parent[key] + parent.fullScreen = true + parent.titleBar = false + } + }) + } + }) + }) + } + + /** + * 增加组件或修改组件属性 + */ + modifyTemplate () { + const template = this.template + template.mergeComponents(this.ctx, components) + } +} diff --git a/packages/taro-quickapp/src/runtime-utils.ts b/packages/taro-quickapp/src/runtime-utils.ts new file mode 100644 index 000000000000..9f21a635a63a --- /dev/null +++ b/packages/taro-quickapp/src/runtime-utils.ts @@ -0,0 +1,13 @@ +import { initNativeApi } from './apis' + +export { initNativeApi } +export * from './components' +export const hostConfig = { + initNativeApi, + getPathIndex (indexOfNode) { + return `${indexOfNode}` + }, + modifyBindEventName (eventName) { + return eventName + } +} diff --git a/packages/taro-quickapp/src/runtime.ts b/packages/taro-quickapp/src/runtime.ts new file mode 100644 index 000000000000..d8cccb2f4fb4 --- /dev/null +++ b/packages/taro-quickapp/src/runtime.ts @@ -0,0 +1,5 @@ +import { mergeReconciler, mergeInternalComponents } from '@tarojs/shared' +import { hostConfig, components } from './runtime-utils' + +mergeReconciler(hostConfig) +mergeInternalComponents(components) diff --git a/packages/taro-quickapp/src/template.ts b/packages/taro-quickapp/src/template.ts new file mode 100644 index 000000000000..4a75caac4e08 --- /dev/null +++ b/packages/taro-quickapp/src/template.ts @@ -0,0 +1,100 @@ +import { ComponentConfig, Attributes, RecursiveTemplate, toCamelCase, capitalize } from '@tarojs/shared' +import * as componentTagNames from './components-react' + +export class Template extends RecursiveTemplate { + Adapter = { + if: 'if', + else: 'else', + elseif: 'elif', + for: 'for', + forItem: '', + forIndex: '', + key: 'tid', + xs: '', + type: 'quickapp' + } + + protected replacePropName (name, value) { + name = name.toLowerCase() + if (name === 'bindlongtap') return 'onlongpress' + if (value === 'eh') return name.toLowerCase().replace('bind', 'on') + return name + } + + protected getEvents () { + return { + onclick: 'eh', + ontouchstart: 'eh', + ontouchmove: 'eh', + ontouchend: 'eh', + ontouchcancel: 'eh', + onlongpress: 'eh' + } + } + + public buildTemplate = (componentConfig: ComponentConfig) => { + const Adapter = this.Adapter + if (!this.miniComponents) { + this.miniComponents = this.createMiniComponents(this.internalComponents) + } + const components = Object.keys(this.miniComponents) + .filter(c => componentConfig.includes.size && !componentConfig.includeAll ? componentConfig.includes.has(c) : true) + + const mergedAttributes = components.reduce((current, nodeName) => { + const attributes = this.miniComponents[nodeName] + return Object.assign(current, attributes) + }, {}) + const attributesStr = Object.keys(mergedAttributes) + .map(k => { + return `${k}="${k.startsWith('bind') || k.startsWith('on') || k.startsWith('catch') ? mergedAttributes[k] : `{{${mergedAttributes[k]}}}`}"` + }) + .join(' ') + + const getNodeNameStr = "(i.nn === 'slot-view' || i.nn === 'catch-view' || i.nn === 'static-view' || i.nn === 'pure-view' ? 'view' : i.nn === 'static-text' ? 'text' : i.nn === 'static-image' ? 'image' : i.nn)" + const isTextNodeStr = "(i.nn === 'static-text' || i.nn === 'text')" + const isNestedTextStr = `(${isTextNodeStr} && parentIsText)` + + const template = ` + + +` + + const taroSelfComponents = components.map(name => { + name = capitalize(toCamelCase(name)) + return componentTagNames[name] + }).filter(Boolean) + + return [template, taroSelfComponents] as any + } + + public buildPageTemplate = (_baseTempPath: string) => { + const Adapter = this.Adapter + + const template = ` + + +` + + return template + } + + public buildCustomComponentTemplate = (_: string) => { + throw new Error('快应用不需要生成custom-wrapper') + } +} diff --git a/packages/taro-quickapp/tsconfig.json b/packages/taro-quickapp/tsconfig.json new file mode 100644 index 000000000000..3c13f0e545b1 --- /dev/null +++ b/packages/taro-quickapp/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "target": "es2017", + "module": "ES2015", + "rootDir": "./src", + "outDir": "dist", + "sourceMap": true, + "baseUrl": ".", + "noImplicitAny": false, + "noUnusedLocals": true, + "removeComments": false, + "strictNullChecks": true, + "allowSyntheticDefaultImports": true, + "experimentalDecorators": true, + "moduleResolution": "node", + "declaration": true, + "declarationDir": "types", + "resolveJsonModule": true, + }, + "include": [ + "./src" + ], + "exclude": [ + "**/*.test.ts", + "**/*.spec.ts" + ], + "compileOnSave": false +} diff --git a/packages/taro-quickapp/types/apis.d.ts b/packages/taro-quickapp/types/apis.d.ts new file mode 100644 index 000000000000..f924cabf700f --- /dev/null +++ b/packages/taro-quickapp/types/apis.d.ts @@ -0,0 +1 @@ +export declare function initNativeApi(taro: any): void; diff --git a/packages/taro-quickapp/types/compile-utils.d.ts b/packages/taro-quickapp/types/compile-utils.d.ts new file mode 100644 index 000000000000..9ff8eef46b30 --- /dev/null +++ b/packages/taro-quickapp/types/compile-utils.d.ts @@ -0,0 +1,2 @@ +export declare function getGithubRepoLatestReleaseVersion(repoName: string): Promise; +export declare function downloadGithubRepoLatestRelease(repoName: string, appPath: string, dest: string): Promise; diff --git a/packages/taro-quickapp/types/components-react.d.ts b/packages/taro-quickapp/types/components-react.d.ts new file mode 100644 index 000000000000..feeb8146952d --- /dev/null +++ b/packages/taro-quickapp/types/components-react.d.ts @@ -0,0 +1,69 @@ +export declare const View = "div"; +export declare const Icon = "taro-icon"; +export declare const Progress = "taro-progress"; +export declare const RichText = "taro-rich-text"; +export declare const Text = "text"; +export declare const Button = "taro-button"; +export declare const Checkbox = "taro-checkbox"; +export declare const CheckboxGroup = "checkbox-group"; +export declare const Form = "form"; +export declare const Input = "taro-input"; +export declare const Label = "taro-label"; +export declare const Picker = "taro-picker"; +export declare const PickerView = "picker-view"; +export declare const PickerViewColumn = "picker-view-column"; +export declare const Radio = "taro-radio"; +export declare const RadioGroup = "radio-group"; +export declare const Slider = "taro-slider"; +export declare const Switch = "taro-switch"; +export declare const CoverImage = "cover-image"; +export declare const Textarea = "taro-textarea"; +export declare const CoverView = "cover-view"; +export declare const MovableArea = "movable-area"; +export declare const MovableView = "movable-view"; +export declare const ScrollView = "taro-scroll-view"; +export declare const Swiper = "taro-swiper"; +export declare const SwiperItem = "taro-swiper-item"; +export declare const Navigator = "taro-navigator"; +export declare const Audio = "taro-audio"; +export declare const Camera = "taro-camera"; +export declare const Image = "taro-image"; +export declare const LivePlayer = "live-player"; +export declare const Video = "taro-video"; +export declare const Canvas = "taro-canvas"; +export declare const Ad = "ad"; +export declare const WebView = "taro-web-view"; +export declare const Block = "block"; +export declare const Map = "taro-map"; +export declare const Slot = "slot"; +export declare const CustomWrapper = "block"; +export declare const QkDiv = "div"; +export declare const QkList = "list"; +export declare const QkListItem = "list-item"; +export declare const QkPopup = "popup"; +export declare const QkRefresh = "refresh"; +export declare const QkRichText = "richtext"; +export declare const QkStack = "stack"; +export declare const QkSwiper = "swiper"; +export declare const QkTabs = "tabs"; +export declare const QkTabBar = "tab-bar"; +export declare const QkTabContent = "tab-content"; +export declare const QkA = "a"; +export declare const QkImage = "image"; +export declare const QkProgress = "progress"; +export declare const QkRating = "rating"; +export declare const QkSpan = "span"; +export declare const QkText = "text"; +export declare const QkMarquee = "marquee"; +export declare const QkInput = "input"; +export declare const QkLabel = "label"; +export declare const QkOption = "option"; +export declare const QkPicker = "picker"; +export declare const QkSelect = "select"; +export declare const QkSlider = "slider"; +export declare const QkSwitch = "switch"; +export declare const QkTextArea = "textarea"; +export declare const QkVideo = "video"; +export declare const QkCamera = "camera"; +export declare const QkCanvas = "canvas"; +export declare const QkWeb = "web"; diff --git a/packages/taro-quickapp/types/components.d.ts b/packages/taro-quickapp/types/components.d.ts new file mode 100644 index 000000000000..c59a62b81fd4 --- /dev/null +++ b/packages/taro-quickapp/types/components.d.ts @@ -0,0 +1,185 @@ +export declare const components: { + QkDiv: { + enablevideofullscreencontainer: string; + }; + QkList: { + scrollpage: string; + bindScroll: string; + bindScrollBottom: string; + bindScrollTop: string; + bindScrollEnd: string; + bindScrollTouchUp: string; + }; + QkListItem: { + type: string; + }; + QkPopup: { + target: string; + placement: string; + bindVisibilityChange: string; + }; + QkRefresh: { + offset: string; + refreshing: string; + type: string; + enableRefresh: string; + bindRefresh: string; + }; + QkRichText: { + type: string; + bindStart: string; + bindComplete: string; + }; + QkStack: { + bindFullScreenChange: string; + }; + QkSwiper: { + index: string; + autoplay: string; + interval: string; + indicator: string; + loop: string; + duration: string; + vertical: string; + previousMargin: string; + nextMargin: string; + enableSwipe: string; + bindChange: string; + }; + QkTabs: { + index: string; + bindChange: string; + }; + QkTabBar: { + mode: string; + }; + QkTabContent: { + scrollable: string; + }; + QkA: { + href: string; + }; + QkImage: { + src: string; + alt: string; + autoplay: string; + bindComplete: string; + bindError: string; + }; + QkProgress: { + percent: string; + type: string; + }; + QkRating: { + numstars: string; + rating: string; + stepsize: string; + indicator: string; + bindChange: string; + }; + QkSpan: {}; + QkText: {}; + QkMarquee: { + scrollamount: string; + loop: string; + direction: string; + bindBounce: string; + bindFinish: string; + bindStart: string; + }; + QkInput: { + type: string; + checked: string; + name: string; + value: string; + placeholder: string; + maxlength: string; + enterkeytype: string; + autocomplete: string; + bindChange: string; + bindEnterkeyClick: string; + bindSelectionChange: string; + }; + QkLabel: { + target: string; + }; + QkOption: { + selected: string; + value: string; + }; + QkPicker: { + type: string; + range: string; + selected: string; + value: string; + start: string; + end: string; + }; + QkSelect: { + bindChange: string; + }; + QkSlider: { + min: string; + max: string; + step: string; + value: string; + bindChange: string; + }; + QkSwitch: { + checked: string; + bindChange: string; + }; + QkTextArea: { + placeholder: string; + maxlength: string; + bindChange: string; + bindSelectionChange: string; + bindLineChange: string; + }; + QkVideo: { + src: string; + autoplay: string; + poster: string; + controls: string; + muted: string; + orientation: string; + titlebar: string; + title: string; + playcount: string; + enablevideofullscreencontainer: string; + bindPrepared: string; + bindStart: string; + bindPause: string; + bindFinish: string; + bindError: string; + bindSeeking: string; + bindSeeked: string; + bindTimeUpdate: string; + bindFullScreenChange: string; + }; + QkCamera: { + deviceposition: string; + flash: string; + framesize: string; + autoexposurelock: string; + autowhitebalancelock: string; + bindError: string; + bindCameraFrame: string; + bindCameraInitDone: string; + }; + QkCanvas: {}; + QkWeb: { + src: string; + trustedurl: string; + allowthirdpartycookies: string; + showloadingdialog: string; + supportzoom: string; + useragent: string; + bindPageStart: string; + bindPageFinish: string; + bindTitleReceive: string; + bindError: string; + bindMessage: string; + bindProgress: string; + }; +}; diff --git a/packages/taro-quickapp/types/index.d.ts b/packages/taro-quickapp/types/index.d.ts new file mode 100644 index 000000000000..876a74547b34 --- /dev/null +++ b/packages/taro-quickapp/types/index.d.ts @@ -0,0 +1,5 @@ +import QuickApp from './program'; +import type { IPluginContext } from '@tarojs/service'; +export { QuickApp }; +declare const _default: (ctx: IPluginContext) => void; +export default _default; diff --git a/packages/taro-quickapp/types/program.d.ts b/packages/taro-quickapp/types/program.d.ts new file mode 100644 index 000000000000..76ff9fd11b56 --- /dev/null +++ b/packages/taro-quickapp/types/program.d.ts @@ -0,0 +1,32 @@ +import { TaroPlatformBase } from '@tarojs/service'; +import { Template } from './template'; +export default class QuickApp extends TaroPlatformBase { + platform: string; + globalObject: string; + runtimePath: string; + taroComponentsPath: string; + fileType: { + templ: string; + style: string; + config: string; + script: string; + }; + template: Template; + /** + * 1. setupTransaction - init + * 2. setup + * 3. setupTransaction - close + * 4. buildTransaction - init + * 5. build + * 6. buildTransaction - close + */ + constructor(ctx: any, config: any); + /** + * 转换用户编写的配置(微信小程序标准)为快应用标准 + */ + modifyMiniConfigs(): void; + /** + * 增加组件或修改组件属性 + */ + modifyTemplate(): void; +} diff --git a/packages/taro-quickapp/types/runtime-utils.d.ts b/packages/taro-quickapp/types/runtime-utils.d.ts new file mode 100644 index 000000000000..24d962f84f89 --- /dev/null +++ b/packages/taro-quickapp/types/runtime-utils.d.ts @@ -0,0 +1,8 @@ +import { initNativeApi } from './apis'; +export { initNativeApi }; +export * from './components'; +export declare const hostConfig: { + initNativeApi: typeof initNativeApi; + getPathIndex(indexOfNode: any): string; + modifyBindEventName(eventName: any): any; +}; diff --git a/packages/taro-quickapp/types/runtime.d.ts b/packages/taro-quickapp/types/runtime.d.ts new file mode 100644 index 000000000000..509db1866f4b --- /dev/null +++ b/packages/taro-quickapp/types/runtime.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/packages/taro-quickapp/types/shims-quickapp.d.ts b/packages/taro-quickapp/types/shims-quickapp.d.ts new file mode 100644 index 000000000000..3094333306ca --- /dev/null +++ b/packages/taro-quickapp/types/shims-quickapp.d.ts @@ -0,0 +1,1114 @@ +import { ComponentType } from 'react' +import { BaseEventOrigFunction, CommonEventFunction, StandardProps, Text } from '@tarojs/components' + +interface DivProps extends StandardProps { + /** + * 若 video 组件的直接父组件为 div 组件,且其enablevideofullscreencontainer值为 true,则开启全屏显示自定义组件特性。默认值为 false,特性为关闭状态 + * @supported quickapp + */ + enablevideofullscreencontainer?: boolean +} + +interface ListProps extends StandardProps { + /** + * 是否将 list 顶部页面中非 list 部分随 list 一起滑出可视区域,开启该属性会降低 list 渲染性能 + * @supported quickapp + */ + scrollpage?: boolean + + /** + * 列表滑动 + * @supported quickapp(1010+) + */ + onScroll?: BaseEventOrigFunction<{ + scrollX: number + scrollY: number + /** + * 0: list 停止滑动 + * + * 1: list 正在通过用户的手势滑动 + * + * 2: list 正在滑动,用户已松手 + */ + scrollState: 0 | 1 | 2 + }> + + /** + * 列表滑动到底部 + * @supported quickapp + */ + onScrollBottom?: CommonEventFunction + + /** + * 列表滑动到顶部 + * @supported quickapp + */ + onScrollTop?: CommonEventFunction + + /** + * 列表滑动结束 + * @supported quickapp(1040+) + */ + onScrollEnd?: CommonEventFunction + + /** + * 列表滑动过程中手指抬起 + * @supported quickapp(1040+) + */ + onScrollTouchUp?: CommonEventFunction +} + +interface ListItemProps extends StandardProps { + /** + * list-item 类型,值为自定义的字符串,如'loadMore'。相同的 type 的 list-item 必须具备完全一致的 DOM 结构。因此,在 list-item 内部需谨慎使用 if 和 for,因为 if 和 for 可能造成相同的 type 的 list-item 的 DOM 结构不一致,从而引发错误 + * @supported quickapp + */ + type: string +} + +interface PopupProps extends StandardProps { + /** + * 目标元素选择器 + * @supported quickapp + */ + target: string + /** + * 弹出窗口位置, 默认值:'bottom' + * @supported quickapp + */ + placement?: 'left' | 'right' | 'top' | 'bottom' | 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight' + /** + * 当显隐状态变化时回调,true 显示,false 隐藏 + * @supported quickapp + */ + onVisibilityChange?: CommonEventFunction +} + +interface RefreshProps extends StandardProps { + /** + * 刷新组件静止时距离顶部距离,默认值:132px + * @supported quickapp + */ + offset?: number + /** + * 刷新组件是否正在刷新 + * @supported quickapp + */ + refreshing?: boolean + /** + * 两个可选值,不可动态修改 + * + * auto: 默认效果,列表界面拉到顶后,列表不移动,下拉后有转圈弹出。 + * + * pulldown: 列表界面拉到顶后,可以继续下拉一段,有回弹效果。 + * + * @supported quickapp(1040+) + */ + type?: 'auto' | 'pulldown' + /** + * 是否允许刷新组件下拉刷新, 默认值:true + * @supported quickapp(1080+) + */ + enableRefresh?: boolean + /** + * 下拉 refresh 组件,触发刷新操作 + * @supported quickapp + */ + onRefresh?: BaseEventOrigFunction<{ refreshing: boolean }> +} + +interface RichTextProps extends StandardProps { + /** + * 按照传统 WEB 页面的方式进行渲染 + * @supported quickapp + */ + type: 'html' + /** + * 开始加载时触发 + * @supported quickapp(1070+) + */ + onStart?: CommonEventFunction + /** + * 加载完成时触发 + * @supported quickapp(1070+) + */ + onComplete?: CommonEventFunction +} + +interface StackProps extends StandardProps { + /** + * 进入和退出全屏时触发 + * @supported quickapp(1050+) + */ + onFullScreenChange?: BaseEventOrigFunction<{ fullscreen: boolean }> +} + +interface SwiperProps extends StandardProps { + /** + * 当前显示的子组件索引,默认值:0 + * @supported quickapp + */ + index?: number + /** + * 渲染完成后,是否自动进行播放 + * @supported quickapp + */ + autoplay?: boolean + /** + * 自动播放时的时间间隔,单位毫秒。默认值:3000ms + * @supported quickapp + */ + interval?: number + /** + * 是否启用 indicator,默认 true + * @supported quickapp + */ + indicator?: boolean + /** + * 是否开启循环模式,1030及以下版本子组件数量大于 2 时才生效 + * @supported quickapp(1010+) + */ + loop?: boolean + /** + * 滑动动画时长(duration默认根据手指的速度动态计算) + * @supported quickapp(1040+) + */ + duration?: number + /** + * 滑动方向是否为纵向,纵向时indicator 也为纵向 + * @supported quickapp(1040+) + */ + vertical?: boolean + /** + * 前边距,可用于露出前一项的一小部分,支持单位:px和% + * @supported quickapp(1040+) + */ + previousMargin?: string + /** + * 后边距,可用于露出后一项的一小部分,支持单位:px和% + * @supported quickapp(1040+) + */ + nextMargin?: string + /** + * 是否支持手势滑动swiper,默认值:true + * @supported quickapp(1080+) + */ + enableSwipe?: boolean + /** + * 当前显示的组件索引变化时触发 + * @supported quickapp + */ + onChange?: BaseEventOrigFunction<{ index: number }> +} + +interface TabsProps extends StandardProps { + /** + * 当前 active tab 索引 + * @supported quickapp + */ + index?: number + /** + * tabs 子组件 active 变化时触发 + * @supported quickapp + */ + onChange?: BaseEventOrigFunction<{ index: number }> +} + +interface TabBarProps extends StandardProps { + /** + * mode 为 scrollable 时,子组件宽度为设置宽度,当宽度之和大于 tab-bar 宽度,子组件可以横向滚动;mode 为 fixed 时,子组件宽度均分 tab-bar 宽度,当宽度之和大于 tab-bar 宽度,子组件依旧均分宽度 + * + * 默认值:'fixed' + */ + mode?: 'scrollable' | 'fixed' +} + +interface TabContentProps extends StandardProps { + /** + * 是否可以通过滑动切换页面。设置为false后,页面的切换需通过与 tab-bar 的联动实现 + * + * 默认值:true + * @supported quickapp(1040+) + */ + scrollable?: boolean +} + +interface AProps extends StandardProps { + /** + * 支持的格式参见页面路由中的 uri 参数。 + * + * 额外的: + * + * href 还可以通过“?param1=value1”的方式添加参数,参数可以在页面中通过`this.param1`的方式使用 + * + * href 还支持 http 和 https 开头的网址,点击后会打开 webview 加载网页 + * + * @supported quickapp + * + * @example 示例: + * 关于 + * 关于 + * 快应用官方网站 + */ + href?: string +} + +interface ImageProps extends StandardProps { + /** + * 图片的 uri,同时支持本地和云端路径,支持的图片格式包括静态类型(png, jpg)和动态类型(gif)。 + * + * 另外,也支持 svg 类型(svg)1020+ 与 HEIF 类型(heic/heif) 1090+ 图片格式。 + * + * HEIF 格式图片浏览需设备硬件支持,以及Android 10+版本的系统 + * + * @supported quickapp + */ + src?: string + /** + * 加载时显示的占位图;只支持本地图片资源。 + * @supported quickapp(1060+) + */ + alt?: string | 'blank' + /** + * 控制 gif/webp 图片是否自动播放动画。值设置为 true,图片可见时自动播放,不可见时自动停止播放;值设置为 false,图片不自动播放,需要开发者调用播放接口启动动画。 + * @default true + * @supported quickapp(1080+) + */ + autoplay?: boolean + /** + * 图片加载完成时触发 + * @supported quickapp(1030+) + */ + onComplete?: BaseEventOrigFunction<{ width: number, height: number }> + /** + * 图片加载失败时触发 + * @supported quickapp(1030+) + */ + onError?: CommonEventFunction +} + +interface ProgressProps extends StandardProps { + /** + * 当前进度(type 为 circular 时不生效) + * @supported quickapp + */ + percent?: number + /** + * 进度条类型,不支持动态修改 + * @default 'horizontal' + * @supported quickapp + */ + type?: 'horizontal' | 'circular' +} + +interface RatingProps extends StandardProps { + /** + * 星级总数 + * @default 5 + * @supported quickapp + */ + numstars?: number + /** + * 评星数 + * @default 0 + * @supported quickapp + */ + rating?: number + /** + * 评星步长 + * @default 0.5 + * @supported quickapp + */ + stepsize?: number + /** + * 是否作为一个指示器(用户不可操作) + * @default false + * @supported quickapp + */ + indicator?: boolean + /** + * 评星数发生改变时触发 + * @supported quickapp + */ + onChange?: BaseEventOrigFunction<{ + rating: number, + /** + * 该事件是否由于用户拖动触发 + * @supported quickapp(1080+) + */ + isFromUser: boolean + }> +} + +interface MarqueeProps extends StandardProps { + /** + * 设置每次滚动时移动的长度,单位:px + * @default 6 + * @supported quickapp + */ + scrollamount?: number + /** + * 设置 marquee 滚动的次数。如果未指定值,默认值为 −1,表示 marquee 将连续滚动 + * @default -1 + * @supported quickapp + */ + loop?: number + /** + * 文字滚动方向,支持 left,right + * @default 'left' + * @supported quickapp + */ + direction?: 'left' | 'right' + /** + * 当 marquee 滚动到结尾时触发 + * @supported quickapp + */ + onBounce?: CommonEventFunction + /** + * 当 marquee 完成 loop 属性设置的值时触发。它只能在 loop 属性设置为大于 0 的某个数字时触发 + * @supported quickapp + */ + onFinish?: CommonEventFunction + /** + * 当 marquee 开始滚动时触发 + * @supported quickapp + */ + onStart?: CommonEventFunction +} + +interface InputProps extends StandardProps { + /** + * 支持动态修改 1030+ + * @default 'text' + * @supported quickapp(1050+) + */ + type?: 'button' | 'checkbox' | 'radio' | 'text' | 'email' | 'date' | 'time' | 'number' | 'password' | 'tel' + /** + * 当前组件的 checked 状态,可触发 checked 伪类,type 为 checkbox 时生效 + * @supported quickapp + */ + checked?: boolean + /** + * input 组件名称 + * @supported quickapp + */ + name?: string + /** + * input 组件的值 + * @supported quickapp + */ + value?: string + /** + * 提示文本的内容,type 为 text|email|date|time 时生效 + * @supported quickapp + */ + placeholder?: string + /** + * 组件可接收用户输入字符的最大长度 + * @supported quickapp(1010+) + */ + maxlength?: number + /** + * 设置软键盘 Enter 按钮的显示文本或图标. + * @supported quickapp(1010+) + */ + enterkeytype?: 'default' | 'send' | 'search' | 'next' | 'go' | 'done' | 'default' + /** + * 是否开启自动提示功能,当 type 为 tel 时生效 + * @default 'on' + * @supported quickapp(1050+) + */ + autocomplete?: 'on' | 'off' + /** + * 不同 type 参数不同,具体见下方 change 事件参数 input 组件的值、状态发生改变时触发, type 为 button 时无 change 事件 + * @supported quickapp + */ + onChange?: BaseEventOrigFunction<{ + value: string + }> + /** + * 软键盘 Enter 键点击事件 + * @supported quickapp(1010+) + */ + onEnterkeyClick?: BaseEventOrigFunction<{ + /** + * value 为用户输入的值 + */ + value: string + }> + /** + * 选中文本改变和光标移动时触发 + * @supported quickapp(1030+) + */ + onSelectionChange?: CommonEventFunction +} + +interface OptionProps extends StandardProps { + /** + * 选择项是否为下拉列表的默认项 + * @supported quickapp + */ + selected?: boolean + /** + * 选择项的值 + * @supported quickapp + */ + value: string +} + +interface LabelProps extends StandardProps { + /** + * 目标 input 组件 id + * @supported quickapp + */ + target?: string +} + +type PickerProps = PickerProps.NormalPickerProps | PickerProps.DatePickerProps | PickerProps.TimePickerProps | PickerProps.MultiPickerProps + +declare namespace PickerProps { + interface NormalPickerProps { + type: 'text' + /** 选择器的取值范围 */ + range?: any[] + /**选择器的默认取值,取值为 range 的索引 */ + selected?: number + /**选择器的值 */ + value: string + } + + interface DatePickerProps { + type: 'date' + /** + * 起始时间,格式为 yyyy-MM-dd + * @default '1970-1-1 + */ + start?: string + /** + * 结束时间,格式为 yyyy-MM-dd + * @default '2100-12-31' + */ + end?: string + /** + * 选择器的默认取值,格式为 yyyy-MM-dd + * @default 当前时间 + */ + selected?: string + /** + * 选择器的值 + */ + value?: string + } + + interface TimePickerProps { + /** + * 选择器的默认取值,格式为 hh:mm + * @default 当前时间 + */ + selected?: string + /** + * 选择器的值 + */ + value?: string + } + + interface MultiPickerProps { + /** + * range 为二维数组。长度表示多少列,数组的每项表示每列的数据,如 [["a","b"], ["c","d"]] + */ + range?: string[][] + /** + * 每一列被选中项对应的索引构成的数组 + */ + selected?: number[] + /** + * 每一列被选中项对应的值构成的数组 + */ + value?: string[] + } + +} + +interface SelectProps extends StandardProps { + /** + * 下拉选择器选择值后触发 + * @supported quickapp + */ + onChange?: BaseEventOrigFunction<{ newValue: string }> +} + +interface SliderProps extends StandardProps { + min?: number + /** @default 100 */ + max?: number + /** @default 1 */ + step?: number + value?: number + /** + * 完成一次拖动后触发的事件 + */ + onChange?: BaseEventOrigFunction<{ + progress: number, + /** + * 该事件是否由于用户拖动触发 + * @supported quickapp(1080+) + */ + isFromUser: boolean + }> +} + +interface SwitchProps extends StandardProps { + /** + * 可触发 checked 伪类 + */ + checked?: boolean + /** + * checked 状态改变时触发 + */ + onChange?: BaseEventOrigFunction<{ checked: boolean }> +} + +interface TextAreaProps extends StandardProps { + /** + * 提示文本的内容 + */ + placeholder?: string + /** + * 组件可接收用户输入字符的最大长度 + * @supported quickapp(1010+) + */ + maxlength?: number + /** + * 输入内容发生变化时触发 + */ + onChange?: BaseEventOrigFunction<{ text: string }> + /** + * 选中文本改变和光标移动时触发 + * @supported quickapp(1030+) + */ + onSelectionChange?: CommonEventFunction + /** + * 输入框行数变化时调用,height为当前输入框高度,lineCount为当前文本行数 + * @supported quickapp(1060+) + */ + onLineChange?: BaseEventOrigFunction<{ height: number, lineCount: number }> +} + +interface VideoProps extends StandardProps { + /** + * 视频播放内容的 uri + */ + src?: string + /** + * 渲染后是否自动播放 + */ + autoplay?: boolean + /** + * 视频预览海报 + */ + poster?: string + /** + * 是否显示默认控件 + * @default true + * @supported quickapp(1010+) + */ + controls?: boolean + /** + * 是否静音播放 + * @supported quickapp(1030+) + */ + muted?: boolean + /** + * 指定点击默认控件的全屏按钮时视频进入的全屏方向。 + * @default 'landscape' + * @supported quickapp(1070+) + */ + orientation?: 'landscape' | 'portrait' + /** + * 指定视频组件全屏播放时是否显示顶栏,true为显示,false为不显示,在非全屏时均不显示顶栏 + * @default true + * @supported quickapp(1070+) + */ + titlebar?: boolean + /** + * 配置全屏播放时顶栏显示的标题,最多只支持一行文案,超过会自动以省略号结尾截断 + * @supported quickapp(1070) + */ + title?: string + /** + * 循环播放次数,可设置为 infinite 无限次播放 + * @default 1 + * @supported quickapp(1080+) + */ + playcount?: number | 'infinite' + /** + * 若 video 组件的直接父组件为 div 组件,且其enablevideofullscreencontainer值为 true,则开启全屏显示自定义组件特性。默认值为 false,特性为关闭状态 + * @default false + * @supported quickapp(1080+) + */ + enablevideofullscreencontainer?: boolean + /** + * 视频连接成功时触发 + */ + onPrepared?: BaseEventOrigFunction<{ + /** 秒 */ + duration: number + }> + /** + * 开始播放时触发 + */ + onStart?: CommonEventFunction + /** + * 暂停时触发 + */ + onPause?: CommonEventFunction + /** + * 播放结束时触发 + */ + onFinish?: CommonEventFunction + /** + * 播放失败时触发 + */ + onError?: CommonEventFunction + /** + * 播放进度条滑动时触发 + */ + onSeeking?: BaseEventOrigFunction<{ + /** 秒 */ + currenttime: number + }> + /** + * 播放进度条滑动放开时触发 + */ + onSeeked?: BaseEventOrigFunction<{ + /** 秒 */ + currenttime: number + }> + /** + * 播放进度变化时触发,触发频率 4HZ + */ + onTimeUpdate?: BaseEventOrigFunction<{ + /** 秒 */ + currenttime: number + }> + /** + * 视频进入和退出全屏时触发 + */ + onFullScreenChange?: BaseEventOrigFunction<{ + fullscreen: boolean + }> +} + +interface CameraProps extends StandardProps { + /** + * 前置或后置,值为 front,back + */ + deviceposition?: 'front' | 'back' + /** + * 闪光灯,值为 auto,on,off,torch(手电筒常亮模式) + */ + flash?: 'auto' | 'on' | 'off' | 'torch' + /** + * 相机帧数据尺寸,值为 low,normal,high + * @default 'normal' + * @supported quickapp(1080+) + */ + framesize?: 'low' | 'normal' | 'high' + /** + * 曝光锁定 + * @supported quickapp(1080+) + */ + autoexposurelock?: boolean + /** + * 白平衡锁定 + * @supported quickapp(1080+) + */ + autowhitebalancelock?: boolean + /** + * 用户不允许使用摄像头时触发 + */ + onError?: CommonEventFunction + /** + * @supported quickapp(1080+) + */ + onCameraFrame?: BaseEventOrigFunction<{ + /** + * 图像像素点数据,一维数组,每四项表示一个像素点的 rgba + */ + data: ArrayBuffer + /** 图像数据矩形的宽度 */ + width: number + /** 图像数据矩形的高度 */ + height: number + }> + /** + * 相机初始化完成时触发 + * @supported quickapp(1080+) + */ + onCameraInitDone?: BaseEventOrigFunction +} + +interface WebProps extends StandardProps { + /** + * 需要加载的页面地址 + */ + src?: string + /** + * 可信任的网址,支持正则表达式。只有 trustedurl 中链接或者 src 链接的网页可以和框架进行双向通信 + * @supported quickapp(1020+) + */ + trustedurl?: string[] + /** + * 是否支持第三方 cookies,设置为 true 时开启接收第三方 cookies。 注意:allowthirdpartycookies只支持安卓 5.0 及以上系统。5.0 以下默认为 true + * @supported quickapp(1030+) + */ + allowthirdpartycookies?: boolean + /** + * 是否展示默认加载框 + * @supported quickapp(1070+) + */ + showloadingdialog?: boolean + /** + * 网页是否支持放大缩小 + * @default true + * @supported quickapp(1070+) + */ + supportzoom?: boolean + /** + * 设置web组件的userAgent,默认使用快应用的UA。 + * - 设置为system,表示使用系统默认UA。 + * - 设置其他字符串属于自定义UA。 + * - 不设置此字段或者传入空值,使用默认快应用UA。 + * + * @supported quickapp(1091+) + */ + useragent?: string + /** + * 开始加载网页时触发,参数详情说明如下 + */ + onPageStart?: BaseEventOrigFunction<{ + + url: string, + /** + * 是否可以向后浏览 + * @supported quickapp(1080+) + */ + canBack: boolean, + /** + * 是否可以向前浏览 + * @supported quickapp(1080+) + */ + canForward: boolean + }> + /** + * 网页加载完成时触发 + */ + onPageFinish?: BaseEventOrigFunction<{ url: string, canBack: boolean, canForward: boolean }> + /** + * 收到网页标题时触发 + */ + onTitleReceive?: BaseEventOrigFunction<{ title: string }> + /** + * 网页加载出现错误时触发,参数详情说明如下 + */ + onError?: BaseEventOrigFunction<{ + errorMsg: string, + /** + * webview加载资源出错时,当前访问资源的链接地址 + * @supported quickapp(1080+) + */ + url: string, + /** + * webview加载资源出错时,当前webview是否可以向后浏览 + * @supported quickapp(1080+) + */ + canBack: boolean, + /** + * webview加载资源出错时,当前webview是否可以向前浏览 + * @supported quickapp(1080+) + */ + canForward: boolean + /** + * webview加载资源出错时,当前错误的所属类型: + * 0:通用错误 + * 1:http错误 + * 2:证书错误 + * (1080+) + */ + errorType: 0 | 1 | 2, + /** + * webview加载资源出错时,当前返回的错误码,例如:404,500等 + * @supported quickapp(1080+) + */ + code: number, + /** + * webview加载资源出错时,当前的错误信息描述 + * @supported quickapp(1080+) + */ + description: string, + /** + * webview加载资源出错时,当前的异常域名是否已经授权(默认值为false,主要用于证书错误) + * @supported quickapp(1080+) + */ + isAuthorized: boolean + }> + /** + * 接收到网页发来的消息时触发 + * @supported quickapp(1020+) + */ + onMessage?: BaseEventOrigFunction<{ message: string, url: string }> + /** + * 当前进度,范围 0~100 + * @supported quickapp(1070+) + */ + onProgress?: BaseEventOrigFunction<{ progress: number }> +} + +declare module '@tarojs/components' { + /** + * 基本容器 + * @supported quickapp + * @see https://doc.quickapp.cn/widgets/div.html + */ + export const QkDiv: ComponentType + + /** + * 列表视图容器 + * + * 子组件:仅支持\ + * @supported quickapp + * @see https://doc.quickapp.cn/widgets/list.html + */ + export const QkList: ComponentType + + /** + * \的子组件,用来展示列表具体 item,宽度默认充满 list 组件 + * @supported quickapp + * @see https://doc.quickapp.cn/widgets/list-item.html + */ + export const QkListItem: ComponentType + + /** + * 在点击控件或者某个区域后,浮出一个气泡来引导用户,气泡内容通过子组件来定义。如果设置了遮罩层,可通过点击遮罩层的任意位置退出,否则点击气泡外的任意区域退出 + * @supported quickapp + * @see https://doc.quickapp.cn/widgets/popup.html + */ + export const QkPopup: ComponentType + + /** + * 下拉刷新容器 + * @supported quickapp + * @see https://doc.quickapp.cn/widgets/refresh.html + */ + export const QkRefresh: ComponentType + + /** + * 富文本容器 + * + * 文本内容直接写在标签内容区,内容格式需与 type 相匹配,只支持静态内容,由于需要实时编译,文本内容尽量不要频繁改变,否则可能导致性能问题 + * + * @supported quickapp + * @see https://doc.quickapp.cn/widgets/richtext.html + */ + export const QkRichText: ComponentType + + /** + * 基本容器,子组件排列方式为层叠排列,每个直接子组件按照先后顺序依次堆叠,覆盖前一个子组件 + * @supported quickapp + * @see https://doc.quickapp.cn/widgets/stack.html + */ + export const QkStack: ComponentType + + /** + * 滑块视图容器 + * @supported quickapp + * @see https://doc.quickapp.cn/widgets/swiper.html + */ + export const QkSwiper: ComponentType + + /** + * tab 容器 + * + * 子组件: 仅支持最多一个\和最多一个\ + * + * @supported quickapp + * @see https://doc.quickapp.cn/widgets/tabs.html + */ + export const QkTabs: ComponentType + + /** + * \的子组件,用来展示 tab 的标签区,子组件排列方式为横向排列 * + * @supported quickapp + * @see https://doc.quickapp.cn/widgets/tab-bar.html + */ + export const QkTabBar: ComponentType + + /** + * \的子组件,用来展示 tab 的内容区,高度默认充满 tabs 剩余空间,子组件排列方式为横向排列 + * @supported quickapp + * @see https://doc.quickapp.cn/widgets/tab-content.html + */ + export const QkTabContent: ComponentType + + /** + * 超链接(默认不带下划线) + * + * 文本内容写在标签内容区,支持转义字符"\" + * + * 子组件:仅支持\ + * + * @supported quickapp + * @see https://doc.quickapp.cn/widgets/tab-content.html + */ + export const QkA: ComponentType + + /** + * 渲染图片 + * @supported quickapp + * @see https://doc.quickapp.cn/widgets/image.html + */ + export const QkImage: ComponentType + + /** + * 进度条 + * @supported quickapp + * @see https://doc.quickapp.cn/widgets/progress.html + */ + export const QkProgress: ComponentType + + /** + * 星级评分 + * @supported quickapp + * @see https://doc.quickapp.cn/widgets/rating.html + */ + export const QkRating: ComponentType + + /** + * 格式化的文本,只能作为\、\和\的子组件 + * + * 子组件:仅支持\ (1050+) + * @supported quickapp + * @see https://doc.quickapp.cn/widgets/span.html + */ + export const QkSpan: ComponentType + + /** + * 文本 + * + * 文本内容写在标签内容区,支持转义字符"\" + * + * 子组件:仅支持\与\ + * + * @supported quickapp + * @see https://doc.quickapp.cn/widgets/text.html + */ + export const QkText: ComponentType + + /** + * 跑马灯 + * + * 跑马灯用来插入一段滚动的文字,默认为单行。 + * + * @supported quickapp + * @see https://doc.quickapp.cn/widgets/marquee.html + */ + export const QkMarquee: ComponentType + + /** + * 提供可交互的界面,接收用户的输入,默认为单行 + * @supported quickapp + * @see https://doc.quickapp.cn/widgets/input.html + */ + export const QkInput: ComponentType + + /** + * 为 input、textarea 组件定义标注 + * @supported quickapp + * @see https://doc.quickapp.cn/widgets/label.html + */ + export const QkLabel: ComponentType + + /** + * \