first commit

This commit is contained in:
2026-09-08 20:28:54 +08:00
commit 2ada8d3d5a
37380 changed files with 4886169 additions and 0 deletions
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@@ -0,0 +1,37 @@
<template>
<view @click="_onclick">
<slot :options="options" :loading="loading" :error="errorMessage" />
<!-- #ifdef MP-WEIXIN -->
<uniad-plugin class="uniad-plugin" data-com-type="wx" :adpid="adpid" :unit-id="unitId" @load="_onmpload" @close="_onmpclose" @error="_onmperror" @nextChannel="_onnextchannel"></uniad-plugin>
<uniad-plugin-wx v-if="wxchannel" class="uniad-plugin-wx" data-com-type="wx" @load="_onmpload" @close="_onmpclose" @error="_onwxchannelerror"></uniad-plugin-wx>
<!-- #endif -->
<!-- #ifdef MP-ALIPAY -->
<uniad-plugin class="uniad-plugin" :adpid="adpid" @create="_handleAdRef" @load="_onmpload" @close="_onmpclose" @error="_onmperror"></uniad-plugin>
<!-- #endif -->
</view>
</template>
<script>
// #ifdef APP
import adMixin from "./ad.mixin.app.js"
// #endif
// #ifdef MP-WEIXIN
import adMixin from "./ad.mixin.mp-weixin.js"
// #endif
// #ifdef MP-ALIPAY
import adMixin from "./ad.mixin.mp-alipay.js"
// #endif
export default {
name: 'AdFullscreenVideo',
mixins: [adMixin],
props: {
adType: {
type: String,
default: 'FullScreenVideo'
}
},
methods: {
}
}
</script>
+151
View File
@@ -0,0 +1,151 @@
<template>
<view @click="onclick">
<slot :options="options" :data="adData" :loading="loading" :error="errorMessage" />
</view>
</template>
<script>
const AD_URL = 'https://wxac1.dcloud.net.cn/openPage/acs'
const AD_REPORT_URL = 'https://wxac1.dcloud.net.cn/openPage/acs'
//const WEBVIEW_PATH = '/uni_modules/uni-ad-interactive/pages/uni-ad-interactive/uni-ad-interactive'
const events = {
load: 'load',
close: 'close',
error: 'error'
}
const OpenTypes = {
Interactive: 'interactive'
}
export default {
name: 'AdInteractive',
props: {
options: {
type: [Object, Array],
default () {
return {}
}
},
disabled: {
type: [Boolean, String],
default: false
},
adpid: {
type: [Number, String],
default: ''
},
openType: {
type: String,
default: 'interactive'
},
openPagePath: {
type: String,
default: ""
}
},
data() {
return {
adData: null,
loading: false,
errorMessage: ""
}
},
created() {
this._uniAdPlugin = null
this._interactiveUrl = null
if (this.openPagePath) {
this.getAdData()
}
},
methods: {
show() {
if (this._uniAdPlugin === null) {
this._uniAdPlugin = this.selectComponent('.uni-ad-plugin')
}
this._uniAdPlugin.show()
},
getAdData() {
this.loading = true
uni.request({
url: AD_URL,
method: 'POST',
data: {
adpid: this.adpid || '',
appid: uni.getAppBaseInfo().appId
},
timeout: 5000,
dataType: 'json',
success: (res) => {
if (res.statusCode !== 200) {
this.$emit(events.error, {
errCode: res.statusCode,
errMsg: res.statusCode
})
return
}
const responseData = res.data
if (responseData.ret === 0) {
this._interactiveUrl = responseData.data.adp_url
this.adData = {
imgUrl: responseData.data.icon_url,
openPath: this.openPagePath + '?url=' + encodeURIComponent(this._interactiveUrl)
}
this.$emit(events.load, this.adData)
} else {
const errMsg = {
errCode: responseData.ret,
errMsg: responseData.msg
}
this.errorMessage = errMsg
this.$emit(events.error, errMsg)
}
},
fail: (err) => {
this.$emit(events.error, {
errCode: '',
errMsg: err.errMsg
})
},
complete: () => {
this.loading = false
}
})
},
onclick() {
if (this.disabled) {
return
}
if (!this._interactiveUrl) {
return
}
uni.navigateTo({
url: this.adData.openPath
})
this._report()
},
_report() {
uni.request({
url: AD_REPORT_URL,
data: {
adpid: this.adpid,
t: '10019'
},
timeout: 5000,
dataType: 'json'
})
}
}
}
</script>
<style>
view {
display: block;
}
</style>
+43
View File
@@ -0,0 +1,43 @@
<template>
<view @click="_onclick">
<slot :options="options" :loading="loading" :error="errorMessage" />
<!-- #ifdef MP-WEIXIN -->
<uniad-plugin class="uniad-plugin" data-com-type="wx" :adpid="adpid" :unit-id="unitId" @load="_onmpload" @close="_onmpclose" @error="_onmperror" @nextChannel="_onnextchannel"></uniad-plugin>
<uniad-plugin-wx v-if="wxchannel" class="uniad-plugin-wx" data-com-type="wx" @load="_onmpload" @close="_onmpclose" @error="_onwxchannelerror"></uniad-plugin-wx>
<!-- #endif -->
<!-- #ifdef MP-ALIPAY -->
<uniad-plugin class="uniad-plugin" :adpid="adpid" @create="_handleAdRef" @load="_onmpload" @close="_onmpclose" @error="_onmperror"></uniad-plugin>
<!-- #endif -->
<!-- #ifdef H5 -->
<div ref="container" />
<!-- #endif -->
</view>
</template>
<script>
// #ifdef APP
import adMixin from "./ad.mixin.app.js"
// #endif
// #ifdef H5
import adMixin from "./ad-interstitial.web.js"
// #endif
// #ifdef MP-WEIXIN
import adMixin from "./ad.mixin.mp-weixin.js"
// #endif
// #ifdef MP-ALIPAY
import adMixin from "./ad.mixin.mp-alipay.js"
// #endif
export default {
name: 'AdInterstitial',
mixins: [adMixin],
props: {
adType: {
type: String,
default: 'Interstitial'
}
},
methods: {
}
}
</script>
+327
View File
@@ -0,0 +1,327 @@
const EventType = {
Load: 'load',
Close: 'close',
Error: 'error'
}
export default {
props: {
options: {
type: [Object, Array],
default () {
return {}
}
},
adpid: {
type: [Number, String],
default: ''
},
preload: {
type: [Boolean, String],
default: true
},
loadnext: {
type: [Boolean, String],
default: false
}
},
watch: {
adpid (val) {
if (val) {
this._loadData(val)
}
}
},
data () {
return {
loading: false,
errorMessage: null
}
},
created () {
this._pc = {}
this._pl = []
this._loadData()
},
methods: {
load () {
this._dispatchEvent(EventType.Load, {})
},
show () {
this.errorMessage = null
const data = this._pl[0]
const providerConfig = this._pc[data.a1][data.t]
AdScript.instance.load(data.t, providerConfig.script, () => {
this._renderData(data)
}, (err) => {
this.errorMessage = err.message
this._dispatchEvent(EventType.Error, err)
})
},
_onclick () {
this.show()
},
_loadData (adpid) {
this.loading = true
const id = adpid || this.adpid
AdConfig.instance.get(id, (a, b) => {
this._pc = a
this._pl = b
this.loading = false
}, (err) => {
this.loading = false
this.errorMessage = err
this._dispatchEvent(EventType.Error, err)
})
},
_renderData (data) {
const id = this._createView()
const coral = new window.CoralAdv({
app_id: data.a2,
placement_id: data.a3,
type: data.a4,
display_type: data.a5,
container_id: id,
count: 1
})
coral.ready().then(async (res) => {
if (res.ret === 0) {
} else {
this._dispatchEvent(EventType.Error, res)
}
}).catch((err) => {
this._dispatchEvent(EventType.Error, err)
})
},
_dispatchEvent (type, data) {
this.$emit(type, {
detail: data
})
},
_createView () {
const id = this._randomId()
const adView = document.createElement('div')
adView.setAttribute('id', id)
this.$refs.container.innerHTML = ''
this.$refs.container.append(adView)
return id
},
_randomId () {
let result = ''
for (let i = 0; i < 4; i++) {
result += (65536 * (1 + Math.random()) | 0).toString(16).substring(1)
}
return '_u' + result
}
}
}
// let IC = 0
// let IS = 0
class AdConfig {
static get instance () {
if (this._instance == null) {
this._instance = new AdConfig()
this._instance._init()
}
return this._instance
}
constructor () {
this._instance = null
this._adConfig = null
this._isLoading = false
this._lastError = null
this._callbacks = []
}
get adConfig () {
return this._adConfig
}
get isExpired () {
if (this._adConfig == null) {
return true
}
return (Math.abs(Date.now() - this._adConfig.last) > this.CACHE_TIME)
}
_init () {
var config = this._getConfig()
if (config === null || !config.last) {
return
}
if (!this.isExpired) {
this._adConfig = config.data
}
}
get (adpid, success, fail) {
// IC++
if (this._adConfig != null) {
this._doCallback(adpid, success, fail)
if (this.isExpired) {
this._loadAdConfig(adpid)
}
return
}
this._callbacks.push({
adpid: adpid,
success: success,
fail: fail
})
this._loadAdConfig(adpid)
}
_doCallback (adpid, success, fail) {
// IS++
var { a, b } = this._adConfig
if (a[adpid]) {
success(b, a[adpid])
} else {
fail(this.ERROR_INVALID_ADPID)
}
}
_loadAdConfig (adpid) {
if (this._isLoading === true) {
return
}
this._isLoading = true
uni.request({
url: this.URL,
method: 'GET',
timeout: 8000,
data: {
d: location.hostname,
a: adpid
},
dataType: 'json',
success: (res) => {
const rd = res.data
if (rd.ret === 0) {
const data = rd.data
this._adConfig = data
this._setConfig(data)
this._callbacks.forEach(({ adpid, success, fail }) => {
this._doCallback(adpid, success, fail)
})
} else {
this._callbacks.forEach((i) => {
i.fail({ errCode: rd.ret, errMsg: rd.msg })
})
}
this._callbacks = []
},
fail: (err) => {
this._callbacks.forEach((i) => {
i.fail(err)
})
this._callbacks = []
},
complete: (c) => {
this._isLoading = false
}
})
}
_getConfig () {
if (!navigator.cookieEnabled || !window.localStorage) {
return null
}
var data = localStorage.getItem(this.KEY)
return data ? JSON.parse(data) : null
}
_setConfig (data) {
if (!navigator.cookieEnabled || !window.localStorage) {
return null
}
localStorage.setItem(this.KEY, JSON.stringify({
last: Date.now(),
data: data
}))
}
}
Object.assign(AdConfig.prototype, {
URL: 'https://hac1.dcloud.net.cn/ah5',
KEY: 'uni_app_ad_config',
CACHE_TIME: 1000 * 60 * 10,
ERROR_INVALID_ADPID: {
'-5002': 'invalid adpid'
}
})
class AdScript {
static get instance () {
if (this._instance == null) {
this._instance = new AdScript()
}
return this._instance
}
constructor () {
this._instance = null
this._callback = {}
this._cache = {}
}
load (provider, script, success, fail) {
if (this._cache[provider] === undefined) {
this.loadScript(provider, script)
}
if (this._cache[provider] === 1) {
success()
} else {
if (!this._callback[provider]) {
this._callback[provider] = []
}
this._callback[provider].push({
success,
fail
})
}
}
loadScript (provider, script) {
this._cache[provider] = 0
var ads = document.createElement('script')
ads.setAttribute('id', 'uniad_provider' + provider)
for (const var1 in script) {
ads.setAttribute(var1, script[var1])
}
ads.onload = () => {
this._cache[provider] = 1
this._callback[provider].forEach(({ success }) => {
success()
})
this._callback[provider].length = 0
}
ads.onerror = (err) => {
this._cache[provider] = undefined
this._callback[provider].forEach(({ fail }) => {
fail(err)
})
this._callback[provider].length = 0
}
document.body.append(ads)
}
}
+39
View File
@@ -0,0 +1,39 @@
<template>
<view @click="_onclick">
<slot :options="options" :loading="loading" :error="errorMessage" />
<!-- #ifdef MP-WEIXIN -->
<uniad-plugin class="uniad-plugin" data-com-type="wx" :adpid="adpid" :unit-id="unitId" @load="_onmpload" @close="_onmpclose" @error="_onmperror" @nextChannel="_onnextchannel"></uniad-plugin>
<uniad-plugin-wx v-if="wxchannel" class="uniad-plugin-wx" data-com-type="wx" @load="_onmpload" @close="_onmpclose" @error="_onwxchannelerror"></uniad-plugin-wx>
<!-- #endif -->
<!-- #ifdef MP-ALIPAY -->
<uniad-plugin class="uniad-plugin" :adpid="adpid" @create="_handleAdRef" @load="_onmpload" @close="_onmpclose" @error="_onmperror"></uniad-plugin>
<!-- #endif -->
</view>
</template>
<script>
// #ifdef APP
import adMixin from "./ad.mixin.app.js"
// #endif
// #ifdef H5
import adMixin from "./ad.mixin.web.js"
// #endif
// #ifdef MP-WEIXIN
import adMixin from "./ad.mixin.mp-weixin.js"
// #endif
// #ifdef MP-ALIPAY
import adMixin from "./ad.mixin.mp-alipay.js"
// #endif
export default {
name: 'AdRewardedVideo',
mixins: [adMixin],
props: {
adType: {
type: String,
default: 'RewardedVideo'
}
},
methods: {}
}
</script>
+556
View File
@@ -0,0 +1,556 @@
const ADType = {
RewardedVideo: 'RewardedVideo',
FullScreenVideo: 'FullScreenVideo',
Interstitial: 'Interstitial'
}
const EventType = {
Load: 'load',
Close: 'close',
Error: 'error'
}
const EXPIRED_TIME = 1000 * 60 * 30
const ProviderType = {
CSJ: 'csj',
GDT: 'gdt'
}
const RETRY_COUNT = 1
class AdBase {
constructor (adInstance, options = {}) {
this._isLoad = false
this._isLoading = false
this._isPlaying = false
this._lastLoadTime = 0
this._lastError = null
this._retryCount = 0
if (options.retry !== undefined) {
this._retry = options.retry
} else {
this._retry = true
}
this._loadCallback = null
this._closeCallback = null
this._errorCallback = null
const ad = this._ad = adInstance
ad.onLoad((e) => {
this._isLoading = false
this._isLoad = true
this._lastLoadTime = Date.now()
this.onLoad()
})
ad.onClose((e) => {
this._isLoad = false
this._isPlaying = false
this.onClose(e)
})
ad.onVerify && ad.onVerify((e) => {
// e.isValid
})
ad.onError(({
code,
message,
detail
}) => {
this._isLoading = false
const data = {
code: code,
errMsg: message,
detail: detail
}
if (code === -5008 && this._retry && this._retryCount < RETRY_COUNT) {
this._retryCount += 1
this._loadAd()
return
}
this._lastError = data
this.onError(data)
})
}
get isExpired () {
return (this._lastLoadTime !== 0 && (Math.abs(Date.now() - this._lastLoadTime) > EXPIRED_TIME))
}
get isLoad () {
return this._isLoad
}
get isLoading () {
return this._isLoading
}
getProvider () {
return this._ad.getProvider()
}
load (onload, onerror) {
this._loadCallback = onload
this._errorCallback = onerror
if (this._isPlaying) {
onerror && onerror()
return
}
if (this._isLoading) {
return
}
if (this._isLoad) {
this.onLoad()
return
}
this._retryCount = 0
this._loadAd()
}
show (onclose, onshow) {
this._closeCallback = onclose
if (this._isLoading || this._isPlaying || !this._isLoad) {
return
}
if (this._lastError !== null) {
this.onError(this._lastError)
return
}
const provider = this.getProvider()
if (provider === ProviderType.CSJ && this.isExpired) {
if (this._retry) {
this._loadAd()
} else {
this.onError(this._lastError)
}
return
}
this._isPlaying = true
this._ad.show()
onshow && onshow()
}
onLoad (e) {
if (this._loadCallback != null) {
this._loadCallback()
}
}
onClose (e) {
if (this._closeCallback != null) {
this._closeCallback({
isEnded: e.isEnded
})
}
}
onError (e) {
if (this._errorCallback != null) {
this._errorCallback(e)
}
}
destroy () {
this._ad.destroy()
}
_loadAd () {
this._isLoad = false
this._isLoading = true
this._lastError = null
this._ad.load()
}
}
class RewardedVideo extends AdBase {
constructor (options = {}) {
super(plus.ad.createRewardedVideoAd(options), options)
}
}
class FullScreenVideo extends AdBase {
constructor (options = {}) {
super(plus.ad.createFullScreenVideoAd(options), options)
}
}
class Interstitial extends AdBase {
constructor (options = {}) {
super(plus.ad.createInterstitialAd(options), options)
}
}
class AdHelper {
constructor (adType) {
this._ads = {}
this._adType = adType
this._lastWaterfallIndex = -1
}
load (options, onload, onerror) {
if (!options.adpid || this.isBusy(options.adpid)) {
return
}
this.get(options).load(onload, onerror)
}
show (options, onload, onerror, onclose, onshow) {
const ad = this.get(options)
if (ad.isLoad) {
this._lastWaterfallIndex = -1
ad.show((e) => {
onclose && onclose(e)
}, () => {
onshow && onshow()
})
} else {
ad.load(() => {
this._lastWaterfallIndex = -1
onload && onload()
ad.show((e) => {
onclose && onclose(e)
}, () => {
onshow && onshow()
})
}, (err) => {
onerror && onerror(err)
})
}
}
// 底价预载逻辑
loadWaterfall (options, onload, onfail, index = 0) {
const {
adpid,
urlCallback
} = options
if (!Array.isArray(adpid)) {
return
}
const options2 = {
adpid: adpid[index],
urlCallback,
retry: false
}
console.log('ad.loadWaterfall::index=' + index)
this.load(options2, (res) => {
this._lastWaterfallIndex = index
onload(options2)
}, (err) => {
index++
if (index >= adpid.length) {
onfail(err)
} else {
this.loadWaterfall(options, onload, onfail, index)
}
})
}
// 底价逻辑,失败后下一个,无重试机制
showWaterfall (options, onload, onfail, onclose, onshow, index = 0) {
const {
adpid,
urlCallback
} = options
if (!Array.isArray(adpid)) {
return
}
if (this._lastWaterfallIndex > -1) {
index = this._lastWaterfallIndex
}
const options2 = {
adpid: adpid[index],
urlCallback,
retry: false
}
console.log('ad.showWaterfall::index=' + index)
this.show(options2, () => {
onload()
}, (err) => {
index++
if (index >= adpid.length) {
onfail(err)
} else {
this.showWaterfall(options, onload, onfail, onclose, onshow, index)
}
}, (res) => {
onclose(res)
}, () => {
onshow()
})
}
// 预载底价瀑布流
preloadWaterfall (options, index = 0, step = 1) {
if (step === 1) {
this.loadWaterfall(options, (res) => {
console.log('preloadWaterfall.success::', res)
}, (err) => {
console.log('loadWaterfall.fail', err)
})
return
}
const {
adpid,
urlCallback
} = options
for (let i = 0; i < step; i++) {
if (index < adpid.length) {
const options2 = {
adpid: adpid[index],
urlCallback
}
this.loadWaterfall(options2, (res) => {
console.log('preloadWaterfall.success::', res)
}, (err) => {
console.log('loadWaterfall.fail', err)
this.preloadWaterfall(options, index, step)
})
index++
} else {
break
}
}
}
isBusy (adpid) {
return (this._ads[adpid] && this._ads[adpid].isLoading)
}
get (options) {
const {
adpid
} = options
if (!this._ads[adpid]) {
this._ads[adpid] = this._createInstance(options)
}
return this._ads[adpid]
}
getProvider (adpid) {
if (this._ads[adpid]) {
return this._ads[adpid].getProvider()
}
return null
}
remove (adpid) {
if (this._ads[adpid]) {
this._ads[adpid].destroy()
delete this._ads[adpid]
}
}
_createInstance (options) {
const adType = options.adType || this._adType
delete options.adType
let ad = null
if (adType === ADType.RewardedVideo) {
ad = new RewardedVideo(options)
} else if (adType === ADType.FullScreenVideo) {
ad = new FullScreenVideo(options)
} else if (adType === ADType.Interstitial) {
ad = new Interstitial(options, true)
}
return ad
}
}
export default {
props: {
options: {
type: [Object, Array],
default () {
return {}
}
},
disabled: {
type: [Boolean, String],
default: false
},
adpid: {
type: [Number, String, Array],
default: ''
},
preload: {
type: [Boolean, String],
default: true
},
loadnext: {
type: [Boolean, String],
default: false
},
urlCallback: {
type: Object,
default () {
return {}
}
}
},
data () {
return {
loading: false,
errorMessage: null
}
},
watch: {
adpid (newValue, oldValue) {
this._removeInstance(oldValue)
if (this.preload) {
this._loadAd()
}
},
// 服务器回调透传参数,仅在创建广告实例时可传递参数,如果发生变化需要重新创建广告实例
urlCallback: {
deep: true,
handler () {
this._removeInstance()
}
}
},
created () {
this._adHelper = new AdHelper(this.adType)
setTimeout(() => {
if (this.preload) {
this._loadAd()
}
}, 100)
},
methods: {
load () {
if (this.isLoading) {
return
}
this._startLoading()
const invoke = this._isWaterfall() ? 'loadWaterfall' : 'load'
this._adHelper[invoke](this._getAdOptions(), () => {
this._onLoad()
}, (err) => {
this._onLoadFail(err)
})
},
show () {
if (this.isLoading) {
return
}
this._startLoading()
const invoke = this._isWaterfall() ? 'showWaterfall' : 'show'
this._adHelper[invoke](this._getAdOptions(), () => {
this._onLoad()
}, (err) => {
this._onLoadFail(err)
}, (res) => {
this._dispatchEvent(EventType.Close, res)
if (this.loadnext) {
this.load()
}
}, () => {
// show
this.loading = false
})
},
getProvider () {
if (Array.isArray(this.adpid)) {
return null
}
return this._adHelper.getProvider(this.adpid)
},
_loadAd () {
if (this._canCreateAd()) {
this.load()
}
},
_onclick () {
if (!this.disabled) {
this.show()
}
},
_getAdOptions () {
return {
adpid: this.adpid,
urlCallback: this.urlCallback
}
},
_isWaterfall () {
return (Array.isArray(this.adpid) && this.adpid.length > 0)
},
_canCreateAd () {
let result = false
if (Array.isArray(this.adpid) && this.adpid.length > 0) {
result = true
} else if (typeof this.adpid === 'string' && this.adpid.length > 0) {
result = true
} else if (typeof this.adpid === 'number') {
result = true
}
return result
},
_removeInstance (adpid) {
const id = adpid || this.adpid
if (Array.isArray(id)) {
id.forEach((item) => {
this._adHelper.remove(item)
})
} else if (id) {
this._adHelper.remove(id)
}
},
_startLoading () {
this.loading = true
this.errorMessage = null
},
_onLoad () {
this.loading = false
this._dispatchEvent(EventType.Load, {})
},
_onLoadFail (err) {
this.loading = false
this.errorMessage = JSON.stringify(err)
this._dispatchEvent(EventType.Error, err)
},
_dispatchEvent (type, data) {
this.$emit(type, {
detail: data
})
}
}
}
+111
View File
@@ -0,0 +1,111 @@
const EventType = {
Load: 'load',
Close: 'close',
Error: 'error'
}
export default {
props: {
options: {
type: [Object, Array],
default () {
return {}
}
},
adpid: {
type: [Number, String],
default: ''
},
unitId: {
type: [Number, String],
default: ''
},
preload: {
type: [Boolean, String],
default: true
},
loadnext: {
type: [Boolean, String],
default: false
},
urlCallback: {
type: Object,
default () {
return {}
}
}
},
data () {
return {
loading: false,
errorMessage: null
}
},
created () {
this._ad = null
},
methods: {
load () {
if (this.loading) {
return
}
this._startLoading()
},
show () {
this.errorMessage = null
this._refAdPlugin.show()
},
_handleAdRef (c) {
// this._refAdPlugin = c
this._refAdPlugin = c.detail.__args__[0]
if (this.preload && this._canCreateAd()) {
this._startLoading()
}
},
_onclick () {
this.show()
},
_startLoading () {
this.loading = true
this.errorMessage = null
this._refAdPlugin.load()
},
_canCreateAd () {
let result = false
if (typeof this.adpid === 'string' && this.adpid.length > 0) {
result = true
} else if (typeof this.adpid === 'number') {
result = true
}
return result
},
_hasCallback () {
return (typeof this.urlCallback === 'object' && Object.keys(this.urlCallback).length > 0)
},
_onmpload (e) {
this.loading = false
this._dispatchEvent(EventType.Load, {})
},
_onmpclose (e) {
this._dispatchEvent(EventType.Close, e)
},
_onmperror (e) {
this.loading = false
this.errorMessage = JSON.stringify(e)
this._dispatchEvent(EventType.Error, e)
},
_dispatchEvent (type, data) {
this.$emit(type, data)
}
}
}
+389
View File
@@ -0,0 +1,389 @@
/* eslint-disable no-undef */
const adPlugin = requirePlugin('uni-ad')
const EventType = {
Load: 'load',
Close: 'close',
Error: 'error'
}
const AdType = {
Banner: 'banner',
RewardedVideo: 'rewardedVideo',
Interstitial: 'interstitial'
}
const ProviderType = {
WeChat: 10018,
UserWeChat: 10017,
ShanHu: 10020
}
export default {
props: {
options: {
type: [Object, Array],
default () {
return {}
}
},
adpid: {
type: [Number, String],
default: ''
},
unitId: {
type: [Number, String],
default: ''
},
preload: {
type: [Boolean, String],
default: true
},
loadnext: {
type: [Boolean, String],
default: false
},
urlCallback: {
type: Object,
default () {
return {}
}
}
},
data () {
return {
loading: false,
userwx: false,
userUnitId: '',
customFullscreen: '',
wxchannel: false,
errorMessage: null
}
},
created () {
this._ad = null
this._loading = false
this._wxRewardedAd = null
this._wxInterstitialAd = null
this._userInvokeShowFlag = false
this._providerType = ProviderType.ShanHu
if (this.preload && this._canCreateAd()) {
this.load()
}
},
methods: {
load () {
if (this.loading) {
return
}
this._startLoading()
if (this._providerType === ProviderType.ShanHu) {
} else if (this._providerType === ProviderType.WeChat) {
this.selectComponent('.uniad-plugin-wx').load()
} else if (this._providerType === ProviderType.UserWeChat) {
this._loadWxAd()
}
},
show (e) {
this.errorMessage = null
if (this.loading) {
this._userInvokeShowFlag = true
return
}
if (this._providerType === ProviderType.ShanHu) {
this._showAdInPlugin(this.selectComponent('.uniad-plugin'))
} else if (this._providerType === ProviderType.WeChat) {
this._showAdInPlugin(this.selectComponent('.uniad-plugin-wx'))
} else if (this._providerType === ProviderType.UserWeChat) {
this._showWxAd(e)
}
},
_onclick () {
this.show()
},
_startLoading () {
this.loading = true
this.errorMessage = null
},
_canCreateAd () {
let result = false
if (typeof this.adpid === 'string' && this.adpid.length > 0) {
result = true
} else if (typeof this.adpid === 'number') {
result = true
}
return result
},
_hasCallback () {
return (typeof this.urlCallback === 'object' && Object.keys(this.urlCallback).length > 0)
},
_onmpload (e) {
this.loading = false
this._dispatchEvent(EventType.Load, {})
if (this._userInvokeShowFlag) {
this._userInvokeShowFlag = false
setTimeout(() => {
this.show()
}, 1)
}
},
_onmpclose (e) {
const detail = e.detail || e
this._dispatchEvent(EventType.Close, detail)
if (detail.adsdata) {
const adv = detail.adv
const adsdata = detail.adsdata
const version = detail.version
/* eslint-disable no-undef */
uniCloud.callFunction({
name: 'uniAdCallback',
data: {
adv: adv,
adsdata: adsdata,
version: version
},
secretType: 'both',
success: (res) => {
},
fail: (err) => {
this._dispatchEvent(EventType.Error, err)
}
})
delete detail.adv
delete detail.adsdata
delete detail.version
}
},
_onmperror (e) {
this.loading = false
this.errorMessage = JSON.stringify(e.detail)
this._dispatchEvent(EventType.Error, e.detail)
},
_onnextchannel (e) {
this.wxchannel = true
const adData = e.detail[0]
this.$nextTick(() => {
if (adData.provider === 10017) {
this._providerType = ProviderType.UserWeChat
switch (adData._nt_) {
case 4:
this.wxAdType = AdType.Banner
this.userwx = true
this.userUnitId = adData.posid
if (adData.tmpl_type === 24) {
this.customFullscreen = 'uni-ad-custom-fullscreen'
}
break
case 9:
this.wxAdType = AdType.RewardedVideo
this._createRewardedAd(adData.posid)
break
case 15:
this.wxAdType = AdType.Interstitial
this._createInterstitialAd(adData.posid)
break
}
} else if (adData.provider === 10018) {
this._providerType = ProviderType.WeChat
if (adData.tmpl_type === 24) {
this.customFullscreen = 'uni-ad-custom-fullscreen'
}
this.loading = true
this.selectComponent('.uniad-plugin-wx').setConfig(adData)
}
})
},
_onwxchannelerror (e) {
this._dispatchEvent(EventType.Error, e.detail)
},
_dispatchEvent (type, data) {
this.$emit(type, {
detail: data
})
},
_showAdInPlugin (adComponent) {
if (this._hasCallback()) {
const userCryptoManager = wx.getUserCryptoManager()
userCryptoManager.getLatestUserKey({
success: ({
encryptKey,
iv,
version,
expireTime
}) => {
adComponent.show({
userId: this.urlCallback.userId || '',
extra: this.urlCallback.extra || '',
encryptKey,
iv,
version,
expireTime
})
},
fail: (err) => {
this._dispatchEvent(EventType.Error, err)
}
})
} else {
adComponent.show({
userId: this.urlCallback.userId || '',
extra: this.urlCallback.extra || ''
})
}
},
_loadWxAd () {
switch (this.wxAdType) {
case AdType.RewardedVideo:
if (this._wxRewardedAd) {
this._wxRewardedAd.load()
}
break
case AdType.Interstitial:
if (this._wxInterstitialAd) {
this._wxInterstitialAd.load()
}
break
}
},
// 加载/显示广告
_showWxAd (options) {
this._urlCallback = options || this.urlCallback
if (this.loading === true) {
this._userInvokeShowFlag = true
return
}
switch (this.wxAdType) {
case AdType.RewardedVideo:
if (!this._wxRewardedAd) {
return
}
// eslint-disable-next-line handle-callback-err
this._wxRewardedAd.show().catch((err) => {
this._wxRewardedAd.load().then(() => {
this._wxRewardedAd.show()
}).catch((err) => {
this._dispatchEvent(EventType.Error, err)
})
})
break
case AdType.Interstitial:
if (!this._wxInterstitialAd) {
return
}
// eslint-disable-next-line handle-callback-err
this._wxInterstitialAd.show().catch((err) => {
this._wxInterstitialAd.load().then(() => {
this._wxInterstitialAd.show()
}).catch((err) => {
this._dispatchEvent(EventType.Error, err)
})
})
break
}
},
// 微信激励视频
_createRewardedAd (adUnitId) {
if (this._wxRewardedAd) {
return
}
this._wxRewardedAd = wx.createRewardedVideoAd({ adUnitId: adUnitId, multiton: true })
this._wxRewardedAd.onLoad(() => {
this.loading = false
this._dispatchEvent(EventType.Load, {})
if (this._userInvokeShowFlag) {
this._userInvokeShowFlag = false
this._wxRewardedAd.show()
}
})
this._wxRewardedAd.onError(err => {
this.loading = false
this._dispatchEvent(EventType.Error, err)
})
this._wxRewardedAd.onClose(res => {
this._dispatchEvent(EventType.Close, res)
if (res.isEnded && this._hasCallback()) {
this._callServer()
}
})
this._wxRewardedAd.load().then(() => { }).catch((_) => { })
this.loading = true
},
// 微信插屏
_createInterstitialAd (adUnitId) {
if (this._wxInterstitialAd) {
return
}
this._wxInterstitialAd = wx.createInterstitialAd({ adUnitId: adUnitId })
this._wxInterstitialAd.onLoad(() => {
this.loading = false
this._dispatchEvent(EventType.Load, {})
if (this._userInvokeShowFlag) {
this._userInvokeShowFlag = false
this._wxInterstitialAd.show()
}
})
this._wxInterstitialAd.onError(err => {
this.loading = false
this._dispatchEvent(EventType.Error, err)
})
this._wxInterstitialAd.onClose(res => {
this._dispatchEvent(EventType.Close, res)
})
this._wxInterstitialAd.load().then(() => { }).catch((_) => { })
this.loading = true
},
_callServer () {
const userCryptoManager = wx.getUserCryptoManager()
userCryptoManager.getLatestUserKey({
success: (encryptConfig) => {
const callbackData = adPlugin.buildCallbackData(this.adpid, this.urlCallback, {}, encryptConfig)
uniCloud.callFunction({
name: 'uniAdCallback',
data: callbackData,
secretType: 'both',
success: (res) => {
this._dispatchEvent(EventType.Close, res)
},
fail: (err) => {
this._dispatchEvent(EventType.Error, err)
}
})
},
fail: (err) => {
this._dispatchEvent(EventType.Error, err)
}
})
}
}
}
+173
View File
@@ -0,0 +1,173 @@
const AD_SERVER_URL = 'https://hac1.dcloud.net.cn/h5/gs'
const EventType = {
Load: 'load',
Close: 'close',
Error: 'error'
}
const ProviderType = 'wm'
class Process {
static Start (cmd, args) {
return new Process().openScheme(cmd)
}
constructor () {
this._a = null
}
openScheme (url) {
if (this._a == null) {
this._a = document.createElement('a')
}
this._a.href = url
this._a.click()
}
}
export default {
props: {
options: {
type: [Object, Array],
default () {
return {}
}
},
adpid: {
type: [Number, String],
default: ''
},
preload: {
type: [Boolean, String],
default: true
},
loadnext: {
type: [Boolean, String],
default: false
},
urlCallback: {
type: Object,
default () {
return {}
}
}
},
data () {
return {
adData: null,
loading: false,
showModel: false,
errorMessage: null
}
},
created () {
this._loading = false
this.adConfigData = null
},
methods: {
load () {
setTimeout(() => {
this._onmpload()
}, 200)
},
show (options) {
if (!this._isMobile()) {
this._dispatchEvent(EventType.Error, {
errCode: -1,
errMsg: '当前设备环境无效'
})
return
}
this.errorMessage = null
if (this._loading) {
return
}
this._loading = true
this._requestScheme(options)
},
getProvider () {
return ProviderType
},
_onclick () {
if (this.disabled) {
return
}
this.show()
},
_requestScheme (options = {}) {
const urlCallback = options.urlCallback || this.urlCallback
uni.request({
url: AD_SERVER_URL,
method: 'POST',
data: {
adpid: this.adpid,
userId: urlCallback.userId,
extra: urlCallback.extra
},
timeout: 5000,
dataType: 'json',
success: (res) => {
if (res.statusCode !== 200) {
this._dispatchEvent(EventType.Error, {
errCode: res.statusCode,
errMsg: res.statusCode
})
return
}
const responseData = res.data
if (responseData.ret === 0) {
Process.Start(responseData.data.openlink)
} else {
this._dispatchEvent(EventType.Error, {
errCode: responseData.ret,
errMsg: responseData.msg
})
}
},
fail: (err) => {
this.$emit(EventType.Error, {
errCode: '',
errMsg: err.errMsg
})
},
complete: () => {
this.loading = false
}
})
},
_isMobile () {
return /android|iphone/i.test(navigator.userAgent.toLowerCase())
},
_onmpload (e) {
this.loading = false
this._dispatchEvent(EventType.Load, {})
},
_onmpclose (e) {
this._dispatchEvent(EventType.Close, e.detail)
},
_onmperror (e) {
this.loading = false
this.errorMessage = JSON.stringify(e.detail)
this._dispatchEvent(EventType.Error, e.detail)
},
_dispatchEvent (type, data) {
this.$emit(type, {
detail: data
})
}
}
}
+8
View File
@@ -0,0 +1,8 @@
{
"uniCloud.component.add.success": "Success",
"uniCloud.component.update.success": "Success",
"uniCloud.component.update.showModal.title": "Tips",
"uniCloud.component.update.showModal.content": "是否更新该数据",
"uniCloud.component.remove.showModal.title": "Tips",
"uniCloud.component.remove.showModal.content": "是否删除该数据"
}
+8
View File
@@ -0,0 +1,8 @@
{
"uniCloud.component.add.success": "新增成功",
"uniCloud.component.update.success": "修改成功",
"uniCloud.component.update.showModal.title": "提示",
"uniCloud.component.update.showModal.content": "是否更新该数据",
"uniCloud.component.remove.showModal.title": "提示",
"uniCloud.component.remove.showModal.content": "是否删除该数据"
}
+8
View File
@@ -0,0 +1,8 @@
{
"uniCloud.component.add.success": "新增成功",
"uniCloud.component.update.success": "修改成功",
"uniCloud.component.update.showModal.title": "提示",
"uniCloud.component.update.showModal.content": "是否更新该数据",
"uniCloud.component.remove.showModal.title": "提示",
"uniCloud.component.remove.showModal.content": "是否删除该数据"
}
+12
View File
@@ -0,0 +1,12 @@
import en from './en.json'
import es from './es.json'
import fr from './fr.json'
import zhHans from './zh-Hans.json'
import zhHant from './zh-Hant.json'
export default {
en,
es,
fr,
'zh-Hans': zhHans,
'zh-Hant': zhHant
}
+8
View File
@@ -0,0 +1,8 @@
{
"uniCloud.component.add.success": "新增成功",
"uniCloud.component.update.success": "修改成功",
"uniCloud.component.update.showModal.title": "提示",
"uniCloud.component.update.showModal.content": "是否更新该数据",
"uniCloud.component.remove.showModal.title": "提示",
"uniCloud.component.remove.showModal.content": "是否删除该数据"
}
+8
View File
@@ -0,0 +1,8 @@
{
"uniCloud.component.add.success": "新增成功",
"uniCloud.component.update.success": "修改成功",
"uniCloud.component.update.showModal.title": "提示",
"uniCloud.component.update.showModal.content": "是否更新该数据",
"uniCloud.component.remove.showModal.title": "提示",
"uniCloud.component.remove.showModal.content": "是否刪除數據"
}
+165
View File
@@ -0,0 +1,165 @@
<template>
<view style="display: none;" />
</template>
<script>
const attrs = [
'titleIcon',
'titleIconRadius',
'subtitleText',
'subtitleSize',
'subtitleColor',
'subtitleOverflow',
'titleAlign',
'backgroundImage',
'backgroundRepeat',
'blurEffect'
]
export default {
props: {
title: {
type: String,
default: ''
},
titleIcon: {
type: String,
default: ''
},
titleIconRadius: {
type: String,
default: ''
},
subtitleText: {
type: String,
default: ''
},
subtitleSize: {
type: String,
default: ''
},
subtitleColor: {
type: String,
default: ''
},
subtitleOverflow: {
type: String,
default: ''
},
titleAlign: {
type: String,
default: ''
},
backgroundImage: {
type: String,
default: ''
},
backgroundRepeat: {
type: String,
default: ''
},
blurEffect: {
type: String,
default: ''
},
loading: {
type: Boolean,
default: false
},
frontColor: {
type: String,
default: '#ffffff'
},
backgroundColor: {
type: String,
default: '#000000'
},
colorAnimationDuration: {
type: Number,
default: 0
},
colorAnimationTimingFunc: {
type: String,
default: 'linear'
}
},
created () {
const pages = getCurrentPages()
const page = pages[pages.length - 1]
this.__$page = page
this.$watch('title', () => {
this.setNavigationBarTitle()
})
this.$watch('loading', () => {
this.setNavigationBarLoading()
})
this.$watch(() => [
this.frontColor,
this.backgroundColor,
this.colorAnimationDuration,
this.colorAnimationTimingFunc
],
() => {
this.setNavigationBarColor()
})
// #ifdef APP-PLUS
this.__$webview = page.$getAppWebview()
attrs.forEach(key => {
const titleNView = {}
if (this[key] || this[key].length > 0) {
titleNView[key] = this[key]
}
this.setTitleNView(titleNView)
this.$watch(key, (val) => {
const titleStyle = {}
titleStyle[key] = val
this.setTitleNView(titleStyle)
})
})
// #endif
},
beforeMount () {
this.title && this.setNavigationBarTitle()
this.setNavigationBarLoading()
this.setNavigationBarColor()
},
methods: {
setNavigationBarTitle () {
uni.setNavigationBarTitle({
// #ifndef MP
__page__: this.__$page,
// #endif
title: this.title
})
},
setNavigationBarLoading () {
uni[(this.loading ? 'show' : 'hide') + 'NavigationBarLoading']({
// #ifndef MP
__page__: this.__$page
// #endif
})
},
setNavigationBarColor () {
uni.setNavigationBarColor({
// #ifndef MP
__page__: this.__$page,
// #endif
frontColor: this.frontColor,
backgroundColor: this.backgroundColor,
animation: {
duration: this.colorAnimationDuration,
timingFunc: this.colorAnimationTimingFunc
}
})
},
setTitleNView (titleNView) {
const webview = this.__$webview
const style = webview.getStyle()
if (style && style.titleNView) {
webview.setStyle({
titleNView: titleNView
})
}
}
}
}
</script>
+192
View File
@@ -0,0 +1,192 @@
<template>
<view style="display: none;">
<slot />
</view>
</template>
<script>
const scrolldoneEvent = {
type: 'scrolldone',
target: {
id: '',
offsetLeft: 0,
offsetTop: 0,
dataset: {}
},
currentTarget: {
id: '',
offsetLeft: 0,
offsetTop: 0,
dataset: {}
},
detail: {}
}
export default {
props: {
backgroundTextStyle: {
type: String,
default: 'dark',
validator (value) {
return ['dark', 'light'].indexOf(value) !== -1
}
},
backgroundColor: {
type: String,
default: '#ffffff'
},
backgroundColorTop: {
type: String,
default: '#ffffff'
},
backgroundColorBottom: {
type: String,
default: '#ffffff'
},
scrollTop: {
type: String,
default: ''
},
scrollDuration: {
type: Number,
default: 300
},
pageStyle: {
type: String,
default: ''
},
enablePullDownRefresh: {
type: [Boolean, String],
default: false
},
rootFontSize: {
type: String,
default: ''
}
},
created () {
const page = getCurrentPages()[0]
this.$pageVm = page.$vm || page
// event
// h5 暂不支持生命周期 onResize,补充后,可以移除该条件编译
// #ifdef H5
uni.onWindowResize(evt => {
this.$emit('resize', evt)
})
// #endif
// #ifndef H5
this.$pageVm.$on('hook:onResize', evt => {
this.$emit('resize', evt)
})
// #endif
// 父节点一定是 page
this.$pageVm.$on('hook:onPageScroll', evt => {
this.$emit('scroll', evt)
})
// #ifdef APP-PLUS
this._currentWebview = page.$getAppWebview()
if (this.enablePullDownRefresh) {
this.setPullDownRefresh(this._currentWebview, true)
}
this.$watch('enablePullDownRefresh', (val) => {
this.setPullDownRefresh(this._currentWebview, val)
})
// #endif
// props
this.$watch('backgroundTextStyle', () => {
this.setBackgroundTextStyle()
})
this.$watch(() => [
this.rootFontSize,
this.pageStyle
], () => {
this.setPageMeta()
})
this.$watch(() => [
this.backgroundColor,
this.backgroundColorTop,
this.backgroundColorBottom
], () => {
this.setBackgroundColor()
})
this.$watch(() => [
this.scrollTop,
this.scrollDuration
], () => {
this.pageScrollTo()
})
},
beforeMount () {
this.setBackgroundColor()
if (this.rootFontSize || this.pageStyle) {
this.setPageMeta()
}
this.backgroundTextStyle && this.setBackgroundTextStyle()
},
mounted () {
this.scrollTop && this.pageScrollTo()
},
methods: {
setPullDownRefresh (webview, enabled) {
webview.setStyle({
pullToRefresh: {
support: enabled,
style: plus.os.name === 'Android' ? 'circle' : 'default'
}
})
},
setPageMeta () {
// h5 和 app-plus 设置 rootFontSize
// #ifdef H5 || APP-PLUS
uni.setPageMeta({
pageStyle: this.pageStyle,
rootFontSize: this.rootFontSize
})
// #endif
},
setBackgroundTextStyle () {
// TODO h5 app-plus 暂不支持
// #ifdef MP
uni.setBackgroundTextStyle && uni.setBackgroundTextStyle({
textStyle: this.backgroundTextStyle
})
// #endif
},
setBackgroundColor () {
// TODO h5 app-plus 暂不支持
// #ifdef MP
uni.setBackgroundColor && uni.setBackgroundColor({
backgroundColor: this.backgroundColor,
backgroundColorTop: this.backgroundColorTop,
backgroundColorBottom: this.backgroundColorBottom
})
// #endif
},
pageScrollTo () {
let scrollTop = String(this.scrollTop)
if (scrollTop.indexOf('rpx') !== -1) {
scrollTop = uni.upx2px(scrollTop.replace('rpx', ''))
}
scrollTop = parseFloat(scrollTop)
if (isNaN(scrollTop)) {
return
}
const pageScrollDone = (evt) => {
if (evt.scrollTop === scrollTop) {
this.$pageVm.$off('hook:onPageScroll', pageScrollDone)
this.$emit('scrolldone', scrolldoneEvent)
}
}
uni.pageScrollTo({
scrollTop,
duration: this.scrollDuration,
success: () => {
this.$pageVm.$on('hook:onPageScroll', pageScrollDone)
}
})
}
}
}
</script>
+73
View File
@@ -0,0 +1,73 @@
<template>
<view v-show="matches">
<slot />
</view>
</template>
<script>
let mediaQueryObserver
export default {
name: 'UniMatchMedia',
props: {
width: {
type: [Number, String],
default: ''
},
minWidth: {
type: [Number, String],
default: ''
},
maxWidth: {
type: [Number, String],
default: ''
},
height: {
type: [Number, String],
default: ''
},
minHeight: {
type: [Number, String],
default: ''
},
maxHeight: {
type: [Number, String],
default: ''
},
orientation: {
type: String,
default: ''
}
},
data () {
return {
matches: true
}
},
mounted () {
mediaQueryObserver = uni.createMediaQueryObserver(this)
mediaQueryObserver.observe({
width: this.width,
maxWidth: this.maxWidth,
minWidth: this.minWidth,
height: this.height,
minHeight: this.minHeight,
maxHeight: this.maxHeight,
orientation: this.orientation
}, matches => {
this.matches = matches
})
},
destroyed () {
mediaQueryObserver.disconnect()
}
}
</script>
<style>
view {
display: block;
}
</style>
+40
View File
@@ -0,0 +1,40 @@
<template>
<view @click="onclick">
<uniad-plugin
class="uniad-plugin"
:adpid="adpid"
@load="_onmpload"
@close="_onmpclose"
@error="_onmperror"
@nextChannel="_onnextchannel"
/>
<!-- #ifdef MP-WEIXIN -->
<ad-custom v-if="userwx" :unit-id="userUnitId" class="uni-ad-custom" data-com-type="wx" :class="[customFullscreen]" @load="_onmpload" @error="_onmperror"></ad-custom>
<uniad-plugin-wx v-if="wxchannel" class="uniad-plugin-wx" :class="[customFullscreen]" data-com-type="wx" @load="_onmpload" @error="_onwxchannelerror"></uniad-plugin-wx>
<!-- #endif -->
</view>
</template>
<script>
// #ifdef MP-WEIXIN
import adMixin from "./ad.mixin.mp-weixin.js"
// #endif
// #ifdef MP-ALIPAY
import adMixin from "./ad.mixin.mp-alipay.js"
// #endif
export default {
name: 'Uniad',
mixins: [adMixin],
props: {
},
methods: {
}
}
</script>
<style>
.uni-ad-custom-fullscreen {
display: flex;
height: 100vh;
}
</style>
+668
View File
@@ -0,0 +1,668 @@
<template>
<view>
<slot :options="options" :data="dataList" :pagination="paginationInternal" :loading="loading" :hasMore="hasMore"
:error="errorMessage" />
</view>
</template>
<script>
import {
initVueI18n
} from '@dcloudio/uni-i18n'
import messages from './i18n/index'
const {
t
} = initVueI18n(messages)
const events = {
load: 'load',
error: 'error'
}
const pageMode = {
add: 'add',
replace: 'replace'
}
const loadMode = {
auto: 'auto',
onready: 'onready',
manual: 'manual'
}
const attrs = [
'pageCurrent',
'pageSize',
'spaceInfo',
'collection',
'action',
'field',
'getcount',
'orderby',
'where',
'groupby',
'groupField',
'distinct'
]
export default {
name: 'UniClouddb',
props: {
options: {
type: [Object, Array],
default () {
return {}
}
},
spaceInfo: {
type: Object,
default () {
return {}
}
},
collection: {
type: [String, Array],
default: ''
},
action: {
type: String,
default: ''
},
field: {
type: String,
default: ''
},
orderby: {
type: String,
default: ''
},
where: {
type: [String, Object],
default: ''
},
pageData: {
type: String,
default: 'add'
},
pageCurrent: {
type: Number,
default: 1
},
pageSize: {
type: Number,
default: 20
},
getcount: {
type: [Boolean, String],
default: false
},
getone: {
type: [Boolean, String],
default: false
},
gettree: {
type: [Boolean, String, Object],
default: false
},
gettreepath: {
type: [Boolean, String],
default: false
},
startwith: {
type: String,
default: ''
},
limitlevel: {
type: Number,
default: 10
},
groupby: {
type: String,
default: ''
},
groupField: {
type: String,
default: ''
},
distinct: {
type: [Boolean, String],
default: false
},
pageIndistinct: {
type: [Boolean, String],
default: false
},
foreignKey: {
type: String,
default: ''
},
loadtime: {
type: String,
default: 'auto'
},
manual: {
type: Boolean,
default: false
}
},
data() {
return {
loading: false,
hasMore: false,
dataList: this.getone ? undefined : [],
paginationInternal: {},
errorMessage: ''
}
},
computed: {
collectionArgs() {
return Array.isArray(this.collection) ? this.collection : [this.collection]
},
isLookup() {
return (Array.isArray(this.collection) && this.collection.length > 1) || (typeof this.collection === 'string' &&
this.collection.indexOf(',') > -1)
}
},
created() {
this._isEnded = false
this.paginationInternal = {
current: this.pageCurrent,
size: this.pageSize,
count: 0
}
this.$watch(() => {
var al = []
attrs.forEach(key => {
al.push(this[key])
})
return al
}, (newValue, oldValue) => {
this.paginationInternal.size = this.pageSize
if (newValue[0] !== oldValue[0]) {
this.paginationInternal.current = this.pageCurrent
}
if (this.loadtime === loadMode.manual) {
return
}
let needReset = false
for (let i = 2; i < newValue.length; i++) {
if (newValue[i] !== oldValue[i]) {
needReset = true
break
}
}
if (needReset) {
this.clear()
this.reset()
}
this._execLoadData()
})
// #ifdef H5
if (process.env.NODE_ENV === 'development') {
this._debugDataList = []
if (!window.unidev) {
window.unidev = {
clientDB: {
data: []
}
}
}
window.unidev.clientDB.data.push(this._debugDataList)
}
// #endif
// #ifdef MP-TOUTIAO
let changeName
const events = this.$scope.dataset.eventOpts || []
for (var i = 0; i < events.length; i++) {
const event = events[i]
if (event[0].includes('^load')) {
changeName = event[1][0][0]
}
}
if (changeName) {
let parent = this.$parent
let maxDepth = 16
this._changeDataFunction = null
while (parent && maxDepth > 0) {
const fun = parent[changeName]
if (fun && typeof fun === 'function') {
this._changeDataFunction = fun
maxDepth = 0
break
}
parent = parent.$parent
maxDepth--
}
}
// #endif
if (!this.manual && this.loadtime === loadMode.auto) {
this.loadData()
}
},
// #ifdef H5
beforeDestroy() {
if (process.env.NODE_ENV === 'development' && window.unidev) {
var cd = this._debugDataList
var dl = window.unidev.clientDB.data
for (var i = dl.length - 1; i >= 0; i--) {
if (dl[i] === cd) {
dl.splice(i, 1)
break
}
}
}
},
// #endif
methods: {
loadData(args1, args2) {
let callback = null
let clear = false
if (typeof args1 === 'object') {
if (args1.clear) {
if (this.pageData === pageMode.replace) {
this.clear()
} else {
clear = args1.clear
}
this.reset()
}
if (args1.current !== undefined) {
this.paginationInternal.current = args1.current
}
if (typeof args2 === 'function') {
callback = args2
}
} else if (typeof args1 === 'function') {
callback = args1
}
this._execLoadData(callback, clear)
},
loadMore() {
if (this._isEnded || this.loading) {
return
}
if (this.pageData === pageMode.add) {
this.paginationInternal.current++
}
this._execLoadData()
},
refresh() {
this.clear()
this._execLoadData()
},
clear() {
this._isEnded = false
this.dataList = []
},
reset() {
this.paginationInternal.current = 1
},
add(value, {
action,
showToast = true,
toastTitle,
success,
fail,
complete,
needConfirm = true,
needLoading = true,
loadingTitle = ''
} = {}) {
if (needLoading) {
uni.showLoading({
title: loadingTitle
})
}
/* eslint-disable no-undef */
let db = uniCloud.database(this.spaceInfo)
if (action) {
db = db.action(action)
}
db.collection(this.getMainCollection()).add(value).then((res) => {
success && success(res)
if (showToast) {
uni.showToast({
title: toastTitle || t('uniCloud.component.add.success')
})
}
}).catch((err) => {
fail && fail(err)
if (needConfirm) {
uni.showModal({
content: err.message,
showCancel: false
})
}
}).finally(() => {
if (needLoading) {
uni.hideLoading()
}
complete && complete()
})
},
remove(id, {
action,
success,
fail,
complete,
confirmTitle,
confirmContent,
needConfirm = true,
needLoading = true,
loadingTitle = ''
} = {}) {
if (!id || !id.length) {
return
}
if (!needConfirm) {
this._execRemove(id, action, success, fail, complete, needConfirm, needLoading, loadingTitle)
return
}
uni.showModal({
title: confirmTitle || t('uniCloud.component.remove.showModal.title'),
content: confirmContent || t('uniCloud.component.remove.showModal.content'),
showCancel: true,
success: (res) => {
if (!res.confirm) {
return
}
this._execRemove(id, action, success, fail, complete, needConfirm, needLoading, loadingTitle)
}
})
},
update(id, value, options = {}) {
const fixOptions = Object.assign({
action: null,
showToast: true,
toastTitle: null,
success: null,
fail: null,
complete: null,
confirmTitle: null,
confirmContent: null,
needConfirm: true,
needLoading: true,
loadingTitle: ''
}, options);
if (options.needConfirm) {
uni.showModal({
title: options.confirmTitle || t('uniCloud.component.update.showModal.title'),
content: options.confirmContent || t('uniCloud.component.update.showModal.content'),
showCancel: true,
success: (res) => {
if (res.confirm) {
this._doUpdate(id, value, fixOptions)
}
}
})
} else {
this._doUpdate(id, value, fixOptions)
}
},
_doUpdate(id, value, options) {
const {
action,
success,
fail,
complete,
showToast,
toastTitle,
needConfirm,
needLoading,
loadingTitle
} = options
if (needLoading) {
uni.showLoading({
title: loadingTitle
})
}
/* eslint-disable no-undef */
let db = uniCloud.database(this.spaceInfo)
if (action) {
db = db.action(action)
}
db.collection(this.getMainCollection()).doc(id).update(value).then((res) => {
success && success(res)
if (showToast) {
uni.showToast({
title: toastTitle || t('uniCloud.component.update.success')
})
}
}).catch((err) => {
fail && fail(err)
if (needConfirm) {
uni.showModal({
content: err.message,
showCancel: false
})
}
}).finally(() => {
if (needLoading) {
uni.hideLoading()
}
complete && complete()
})
},
getMainCollection() {
if (typeof this.collection === 'string') {
return this.collection.split(',')[0]
}
const mainQuery = JSON.parse(JSON.stringify(this.collection[0]))
return mainQuery.$db[0].$param[0]
},
getTemp(isTemp = true) {
/* eslint-disable no-undef */
let db = uniCloud.database(this.spaceInfo)
if (this.action) {
db = db.action(this.action)
}
db = db.collection(...this.collectionArgs)
if (this.foreignKey) {
db = db.foreignKey(this.foreignKey)
}
if (!(!this.where || !Object.keys(this.where).length)) {
db = db.where(this.where)
}
if (this.field) {
db = db.field(this.field)
}
if (this.groupby) {
db = db.groupBy(this.groupby)
}
if (this.groupField) {
db = db.groupField(this.groupField)
}
if (this.distinct === true) {
db = db.distinct()
}
if (this.orderby) {
db = db.orderBy(this.orderby)
}
const {
current,
size
} = this.paginationInternal
const getOptions = {}
if (this.getcount) {
getOptions.getCount = this.getcount
}
const treeOptions = {
limitLevel: this.limitlevel,
startWith: this.startwith
}
if (this.gettree) {
getOptions.getTree = treeOptions
}
if (this.gettreepath) {
getOptions.getTreePath = treeOptions
}
db = db.skip(size * (current - 1)).limit(size)
if (isTemp) {
db = db.getTemp(getOptions)
db.udb = this
} else {
db = db.get(getOptions)
}
return db
},
setResult(result) {
if (result.code === 0) {
this._execLoadDataSuccess(result)
} else {
this._execLoadDataFail(new Error(result.message))
}
},
_execLoadData(callback, clear) {
if (this.loading) {
return
}
this.loading = true
this.errorMessage = ''
this._getExec().then((res) => {
this.loading = false
this._execLoadDataSuccess(res.result, callback, clear)
// #ifdef H5
if (process.env.NODE_ENV === 'development') {
this._debugDataList.length = 0
const formatData = JSON.parse(JSON.stringify(this.dataList))
if (Array.isArray(this.dataList)) {
this._debugDataList.push(...formatData)
} else {
this._debugDataList.push(formatData)
}
}
// #endif
}).catch((err) => {
this.loading = false
this._execLoadDataFail(err, callback)
})
},
_execLoadDataSuccess(result, callback, clear) {
const {
data,
count
} = result
this._isEnded = count !== undefined ? (this.paginationInternal.current * this.paginationInternal.size >=
count) : (data.length < this.pageSize)
this.hasMore = !this._isEnded
const data2 = this.getone ? (data.length ? data[0] : undefined) : data
if (this.getcount) {
this.paginationInternal.count = count
}
callback && callback(data2, this._isEnded, this.paginationInternal)
this._dispatchEvent(events.load, data2)
if (this.getone || this.pageData === pageMode.replace) {
this.dataList = data2
} else {
if (clear) {
this.dataList = data2
} else {
this.dataList.push(...data2)
}
}
},
_execLoadDataFail(err, callback) {
this.errorMessage = err
callback && callback()
this.$emit(events.error, err)
if (process.env.NODE_ENV === 'development') {
console.error(err)
}
},
_getExec() {
return this.getTemp(false)
},
_execRemove(id, action, success, fail, complete, needConfirm, needLoading, loadingTitle) {
if (!this.collection || !id) {
return
}
const ids = Array.isArray(id) ? id : [id]
if (!ids.length) {
return
}
if (needLoading) {
uni.showLoading({
mask: true,
title: loadingTitle
})
}
/* eslint-disable no-undef */
const db = uniCloud.database(this.spaceInfo)
const dbCmd = db.command
let exec = db
if (action) {
exec = exec.action(action)
}
exec.collection(this.getMainCollection()).where({
_id: dbCmd.in(ids)
}).remove().then((res) => {
success && success(res.result)
if (this.pageData === pageMode.replace) {
this.refresh()
} else {
this.removeData(ids)
}
}).catch((err) => {
fail && fail(err)
if (needConfirm) {
uni.showModal({
content: err.message,
showCancel: false
})
}
}).finally(() => {
if (needLoading) {
uni.hideLoading()
}
complete && complete()
})
},
removeData(ids) {
const il = ids.slice(0)
const dl = this.dataList
for (let i = dl.length - 1; i >= 0; i--) {
const index = il.indexOf(dl[i]._id)
if (index >= 0) {
dl.splice(i, 1)
il.splice(index, 1)
}
}
},
_dispatchEvent(type, data) {
if (this._changeDataFunction) {
this._changeDataFunction(data, this._isEnded, this.paginationInternal)
} else {
this.$emit(type, data, this._isEnded, this.paginationInternal)
}
}
}
}
</script>
+1
View File
@@ -0,0 +1 @@
{'cs_common':{},'cs_':{'cs_1':'','cs_2':'','cs_3':'','cs_4':''}}
+23
View File
@@ -0,0 +1,23 @@
function parseApis (modules, test) {
return modules.reduce(function (apis, module) {
const apiList = module.apiList
apiList && Object.keys(apiList).forEach(name => {
if (test(name, apiList[name])) {
apis.add(name.replace('uni.', ''))
}
})
return apis
}, new Set())
}
module.exports = {
parseUserApis (configModules = [], allModules = []) {
const blackboxApis = parseApis(configModules, function (name, value) {
return value === false
})
const allApis = parseApis(allModules, function () {
return true
})
return [...allApis].filter(name => !blackboxApis.has(name))
}
}
+389
View File
@@ -0,0 +1,389 @@
const fs = require('fs')
const path = require('path')
const crypto = require('crypto')
const {
isNormalPage
} = require('./util')
/**
* 1.page-loader 缓存基础的 app.json page.json project.config.json
* 2.main-loader 缓存 app.json 中的 usingComponents 节点
* 3.script-loader 修改缓存 usingComponents 节点
* 5.webpack plugin 中获取被修改的 page.json,component.json 并 emitFile
*/
let jsonFileMap = new Map()
const changedJsonFileSet = new Set()
let componentSet = new Set()
let pageSet = new Set()
let globalUsingComponents = Object.create(null)
let appJsonUsingComponents = Object.create(null)
let componentSpecialMethods = Object.create(null)
function getPagesJson () {
if (process.env.UNI_PLATFORM === 'h5') {
return process.UNI_H5_PAGES_JSON
}
const pagesJson = {
pages: {}
}
for (const name of pageSet.values()) {
const style = JSON.parse(getJsonFile(name) || '{}')
delete style.customUsingComponents
pagesJson.pages[name] = style
}
const appJson = JSON.parse(getJsonFile('app') || '{}')
pagesJson.globalStyle = appJson.window || {}
return pagesJson
}
function updateJsonFile (name, jsonStr) {
changedJsonFileSet.add(name)
if (typeof jsonStr !== 'string') {
jsonStr = JSON.stringify(jsonStr, null, 2)
}
jsonFileMap.set(name, jsonStr)
}
function getJsonFile (name) {
return jsonFileMap.get(name)
}
function getChangedJsonFileMap (clear = true) {
const changedJsonFileMap = new Map()
for (const name of changedJsonFileSet.values()) {
if (isNormalPage(name)) {
changedJsonFileMap.set(name + '.json', jsonFileMap.get(name))
}
}
clear && changedJsonFileSet.clear()
return changedJsonFileMap
}
function updateAppJson (name, jsonObj) {
updateComponentJson(name, jsonObj, true, 'App')
}
function updatePageJson (name, jsonObj) {
pageSet.add(name)
updateComponentJson(name, jsonObj, true, 'Page')
}
function updateProjectJson (name, jsonObj) {
updateComponentJson(name, jsonObj, false, 'Project')
}
const supportGlobalUsingComponents = process.env.UNI_PLATFORM === 'mp-weixin' || process.env.UNI_PLATFORM === 'mp-qq'
function updateComponentJson (name, jsonObj, usingComponents = true, type = 'Component') {
if (type === 'Component') {
jsonObj.component = true
if (process.env.UNI_PLATFORM === 'mp-alipay') {
const manifestConfig = process.UNI_MANIFEST
const alipayConfig = manifestConfig['mp-alipay'] || {}
jsonObj.styleIsolation = alipayConfig.styleIsolation || 'apply-shared'
}
} else if (type === 'Page') {
if (process.env.UNI_PLATFORM === 'mp-baidu') {
jsonObj.component = true
}
}
const oldJsonStr = getJsonFile(name)
if (oldJsonStr) { // update
if (usingComponents) { // merge usingComponents
// 其实直接拿新的 merge 到旧的应该就行
const oldJsonObj = JSON.parse(oldJsonStr)
jsonObj.usingComponents = oldJsonObj.usingComponents || {}
jsonObj.usingAutoImportComponents = oldJsonObj.usingAutoImportComponents || {}
if (oldJsonObj.genericComponents) {
jsonObj.genericComponents = oldJsonObj.genericComponents
}
if (oldJsonObj.usingGlobalComponents) { // 复制 global components(针对不支持全局 usingComponents 的平台)
jsonObj.usingGlobalComponents = oldJsonObj.usingGlobalComponents
}
}
const newJsonStr = JSON.stringify(jsonObj, null, 2)
if (newJsonStr !== oldJsonStr) {
updateJsonFile(name, newJsonStr)
}
} else { // add
updateJsonFile(name, jsonObj)
}
}
function updateUsingGlobalComponents (name, usingGlobalComponents) {
const manifestConfig = process.UNI_MANIFEST
const weixinConfig = manifestConfig['mp-weixin']
const independentSwitch = !!weixinConfig.independent
if (!independentSwitch && supportGlobalUsingComponents) {
return
}
const oldJsonStr = getJsonFile(name)
if (oldJsonStr) { // update
const jsonObj = JSON.parse(oldJsonStr)
jsonObj.usingGlobalComponents = usingGlobalComponents
const newJsonStr = JSON.stringify(jsonObj, null, 2)
if (newJsonStr !== oldJsonStr) {
updateJsonFile(name, newJsonStr)
}
} else { // add
const jsonObj = {
usingGlobalComponents
}
updateJsonFile(name, jsonObj)
}
}
function updateUsingAutoImportComponents (name, usingAutoImportComponents) {
const oldJsonStr = getJsonFile(name)
if (oldJsonStr) { // update
const jsonObj = JSON.parse(oldJsonStr)
jsonObj.usingAutoImportComponents = usingAutoImportComponents
const newJsonStr = JSON.stringify(jsonObj, null, 2)
if (newJsonStr !== oldJsonStr) {
updateJsonFile(name, newJsonStr)
}
} else { // add
updateJsonFile(name, {
usingAutoImportComponents
})
}
}
const styleIsolationRE =
/export\s+default\s+[\s\S]*?styleIsolation\s*:\s*['|"](isolated|apply-shared|shared)['|"]/
function parseComponentStyleIsolation (content) {
const matches = content.match(styleIsolationRE)
if (matches) {
return matches[1]
}
}
function updateUsingComponents (name, usingComponents, type, content = '') {
if (type === 'Component') {
componentSet.add(name)
}
if (type === 'App') { // 记录全局组件
globalUsingComponents = usingComponents
}
const oldJsonStr = getJsonFile(name)
const jsonObj = oldJsonStr ? JSON.parse(oldJsonStr) : {
usingComponents
}
if (type === 'Component') {
jsonObj.component = true
if (process.env.UNI_PLATFORM === 'mp-alipay') {
const alipayConfig = process.UNI_MANIFEST['mp-alipay'] || {}
jsonObj.styleIsolation =
parseComponentStyleIsolation(content) ||
alipayConfig.styleIsolation ||
'apply-shared'
}
// 微信小程序json文件中的styleIsolation优先级比options中的高,为了兼容旧版本,不能设置默认值,并且只有在manifest.json中配置styleIsolation才会静态分析组件的styleIsolation
if (process.env.UNI_PLATFORM === 'mp-weixin') {
const weixinConfig = process.UNI_MANIFEST['mp-weixin'] || {}
if (weixinConfig.styleIsolation) {
jsonObj.styleIsolation =
parseComponentStyleIsolation(content) ||
weixinConfig.styleIsolation
}
}
} else if (type === 'Page') {
if (process.env.UNI_PLATFORM === 'mp-baidu') {
jsonObj.component = true
}
}
if (oldJsonStr) { // update
jsonObj.usingComponents = usingComponents
const newJsonStr = JSON.stringify(jsonObj, null, 2)
if (newJsonStr !== oldJsonStr) {
updateJsonFile(name, newJsonStr)
}
} else { // add
updateJsonFile(name, jsonObj)
}
}
function updateComponentGenerics (name, componentGenerics) {
const oldJsonStr = getJsonFile(name)
if (oldJsonStr) { // update
const jsonObj = JSON.parse(oldJsonStr)
jsonObj.componentGenerics = componentGenerics
const newJsonStr = JSON.stringify(jsonObj, null, 2)
if (newJsonStr !== oldJsonStr) {
updateJsonFile(name, newJsonStr)
}
} else { // add
const jsonObj = {
componentGenerics
}
updateJsonFile(name, jsonObj)
}
}
function updateGenericComponents (name, genericComponents) {
const oldJsonStr = getJsonFile(name)
if (oldJsonStr) { // update
const jsonObj = JSON.parse(oldJsonStr)
jsonObj.genericComponents = genericComponents
const newJsonStr = JSON.stringify(jsonObj, null, 2)
if (newJsonStr !== oldJsonStr) {
updateJsonFile(name, newJsonStr)
}
} else { // add
const jsonObj = {
genericComponents
}
updateJsonFile(name, jsonObj)
}
}
function updateAppJsonUsingComponents (usingComponents) {
appJsonUsingComponents = usingComponents
}
function getComponentSet () {
return componentSet
}
function getGlobalUsingComponents () {
// 合并 app.json main.js 全局组件
return Object.assign({}, appJsonUsingComponents, globalUsingComponents)
}
function getWXComponents (name) {
const oldJsonStr = getJsonFile(name)
if (oldJsonStr) {
const jsonObj = JSON.parse(oldJsonStr)
if (jsonObj.customUsingComponents) {
return Object.assign({}, appJsonUsingComponents, jsonObj.customUsingComponents)
}
}
return Object.assign({}, appJsonUsingComponents)
}
function updateSpecialMethods (name, specialMethods) {
if (specialMethods.length) {
componentSpecialMethods[name] = specialMethods
} else {
delete componentSpecialMethods[name]
}
}
function getSpecialMethods (name) {
if (!name) {
return componentSpecialMethods
}
return componentSpecialMethods[name] || []
}
const cacheTypes = ['babel-loader', 'css-loader', 'uni-template-compiler', 'vue-loader']
function clearCache () {
const fsExtra = require('fs-extra')
cacheTypes.forEach(cacheType => {
fsExtra.emptyDirSync(path.resolve(
process.env.UNI_CLI_CONTEXT,
'node_modules/.cache/' + cacheType + '/' + process.env.UNI_PLATFORM
))
})
}
function digest (str) {
return crypto
.createHash('md5')
.update(str)
.digest('hex')
}
module.exports = {
getPageSet () {
return pageSet
},
getJsonFileMap () {
return jsonFileMap
},
// 先简单处理,该方案不好,
// 后续为 pages-loader 增加 cache-loader,
// 然后其他修改 json 的地方也要定制 cache-loader
store () {
const pagesJsonPath = path.resolve(process.env.UNI_INPUT_DIR, 'pages.json')
const filepath = path.resolve(
process.env.UNI_CLI_CONTEXT,
'node_modules/.cache/uni-pages-loader/' + process.env.UNI_PLATFORM,
digest(process.env.UNI_INPUT_DIR) + '.json'
)
const files = Array.from(jsonFileMap.entries())
const pages = Array.from(pageSet)
const components = Array.from(componentSet)
const methods = componentSpecialMethods
fs.writeFileSync(filepath, JSON.stringify({
mtimeMs: fs.statSync(pagesJsonPath).mtimeMs,
files,
pages,
components,
methods,
globalUsingComponents,
appJsonUsingComponents
}))
},
restore () {
const filepath = path.resolve(
process.env.UNI_CLI_CONTEXT,
'node_modules/.cache/uni-pages-loader/' + process.env.UNI_PLATFORM,
digest(process.env.UNI_INPUT_DIR) + '.json'
)
if (!fs.existsSync(filepath)) {
try {
clearCache()
} catch (e) { }
return
}
const pagesJsonPath = path.resolve(process.env.UNI_INPUT_DIR, 'pages.json')
const mtimeMs = fs.statSync(pagesJsonPath).mtimeMs
const jsonCache = require(filepath)
if (jsonCache.mtimeMs !== mtimeMs) {
try {
clearCache()
} catch (e) { }
return
}
jsonFileMap = new Map(jsonCache.files)
pageSet = new Set(jsonCache.pages)
componentSet = new Set(jsonCache.components)
componentSpecialMethods = jsonCache.methods
globalUsingComponents = jsonCache.globalUsingComponents
appJsonUsingComponents = jsonCache.appJsonUsingComponents
// restore 时,所有 file 均触发 change
for (const name of jsonFileMap.keys()) {
changedJsonFileSet.add(name)
}
return true
},
getJsonFile,
getPagesJson,
getComponentSet,
getWXComponents,
getGlobalUsingComponents,
updateAppJson,
updateJsonFile,
updatePageJson,
updateProjectJson,
updateComponentJson,
updateSpecialMethods,
updateUsingComponents,
updateUsingGlobalComponents,
updateAppJsonUsingComponents,
updateUsingAutoImportComponents,
updateComponentGenerics,
updateGenericComponents,
getChangedJsonFileMap,
getSpecialMethods,
supportGlobalUsingComponents
}
+38
View File
@@ -0,0 +1,38 @@
const path = require('path')
const webpack = require('webpack')
const {
normalizePath
// normalizeNodeModules
} = require('./util')
let inputDir
const uniModulesStaticRe = /uni_modules\/[^/]+\/static\//
module.exports = {
loader: 'file-loader',
options: {
name (resourcePath, resourceQuery) {
if (!inputDir) {
inputDir = normalizePath(process.env.UNI_INPUT_DIR)
}
resourcePath = normalizePath(resourcePath)
if (resourcePath.startsWith(inputDir)) {
const relativePath = normalizePath(path.relative(inputDir,
resourcePath))
const subPackageStatic = Object.keys(process.UNI_SUBPACKAGES || {}).map(root => normalizePath(path.join(root,
'static')) + '/')
if (relativePath.startsWith('static/') || uniModulesStaticRe.test(relativePath) ||
subPackageStatic.some(s => relativePath.startsWith(s))) {
return relativePath
}
}
return `assets/[name].[hash:8]${webpack.version[0] > 4 ? '' : '.'}[ext]`
}
// publicPath (url, resourcePath, context) {
// return '/' + normalizeNodeModules(path.relative(process.env.UNI_INPUT_DIR, resourcePath))
// },
// outputPath (url, resourcePath, context) {
// return normalizeNodeModules(path.relative(process.env.UNI_INPUT_DIR, resourcePath))
// }
}
}
+99
View File
@@ -0,0 +1,99 @@
const fs = require('fs')
const path = require('path')
const {
parseJson
} = require('./json')
const {
getManifestJson
} = require('./manifest')
const delimiters = ['%', '%']
function initI18nOptions (
platform,
inputDir,
warning = false,
withMessages = true
) {
const locales = initLocales(path.resolve(inputDir, 'locale'), withMessages)
if (!Object.keys(locales).length) {
return
}
const manifestJson = getManifestJson()
const fallbackLocale = manifestJson.fallbackLocale || manifestJson.locale
const locale = resolveI18nLocale(
platform,
Object.keys(locales),
fallbackLocale
)
if (warning) {
if (!fallbackLocale) {
console.warn()
} else if (locale !== fallbackLocale) {
console.warn()
}
}
return {
locale,
locales,
delimiters
}
}
const localeJsonRE = /uni-app.*.json/
function isUniAppLocaleFile (filepath) {
if (!filepath) {
return false
}
return localeJsonRE.test(path.basename(filepath))
}
function parseLocaleJson (filepath) {
let jsonObj = parseJson(fs.readFileSync(filepath, 'utf8'))
if (isUniAppLocaleFile(filepath)) {
jsonObj = jsonObj.common || {}
}
return jsonObj
}
function initLocales (dir, withMessages = true) {
if (!fs.existsSync(dir)) {
return {}
}
return fs.readdirSync(dir).reduce((res, filename) => {
if (path.extname(filename) === '.json') {
const locale = path
.basename(filename)
.replace(/(uni-app.)?(.*).json/, '$2')
if (withMessages) {
Object.assign(
res[locale] || (res[locale] = {}),
parseLocaleJson(path.join(dir, filename))
)
} else {
res[locale] = {}
}
}
return res
}, {})
}
function resolveI18nLocale (platfrom, locales, locale) {
if (locale && locales.includes(locale)) {
return locale
}
const defaultLocales = ['zh-Hans', 'zh-Hant']
if (platfrom === 'app-plus' || platfrom === 'h5') {
defaultLocales.unshift('en')
} else {
// 小程序
defaultLocales.push('en')
}
return defaultLocales.find(locale => locales.includes(locale)) || locales[0]
}
module.exports = {
initLocales,
initI18nOptions
}
+134
View File
@@ -0,0 +1,134 @@
const tags = require('./tags')
const {
getJson,
parseJson
} = require('./json')
const {
getH5Options,
getManifestJson,
getNetworkTimeout,
parseManifestJson
} = require('./manifest.js')
const {
getMainEntry,
getNVueMainEntry,
parseEntry,
parsePages,
getPagesJson,
parsePagesJson
} = require('./pages')
const {
md5,
hasOwn,
hasModule,
hashify,
camelize,
hyphenate,
removeExt,
normalizePath,
getComponentName,
convertStaticStyle,
getTemplatePath,
createSource,
deleteAsset,
showRunPrompt
} = require('./util')
const {
getFlexDirection,
getPlatformProject,
isSupportSubPackages,
getPlatforms,
getPlatformScss,
getPlatformSass,
runByHBuilderX,
isInHBuilderX,
isInHBuilderXAlpha,
getPlatformExts,
getPlatformTarget,
getShadowCss,
getPlatformCssVars,
getPlatformCssnano,
getShadowTemplate,
jsPreprocessOptions,
cssPreprocessOptions,
htmlPreprocessOptions,
nvueJsPreprocessOptions,
nvueCssPreprocessOptions,
nvueHtmlPreprocessOptions,
getPlatformGlobal,
getPlatformStat,
getPlatformPush,
getPlatformUniCloud,
getDevUniConsoleCode
} = require('./platform')
const uts = require('./uts')
const {
parseTheme,
initTheme
} = require('./theme')
module.exports = {
uts,
md5,
tags,
hasOwn,
getJson,
parseJson,
hashify,
hasModule,
camelize,
hyphenate,
removeExt,
normalizePath,
parseEntry,
parsePages,
getH5Options,
getMainEntry,
getNVueMainEntry,
getPagesJson,
getManifestJson,
getNetworkTimeout,
runByHBuilderX,
isInHBuilderX,
isInHBuilderXAlpha,
isSupportSubPackages,
getPlatforms,
getFlexDirection,
getPlatformScss,
getPlatformSass,
getPlatformExts,
getPlatformTarget,
getPlatformProject,
getShadowCss,
getPlatformCssVars,
getPlatformCssnano,
getShadowTemplate,
parsePagesJson,
parseManifestJson,
getComponentName,
convertStaticStyle,
getTemplatePath,
createSource,
deleteAsset,
showRunPrompt,
jsPreprocessOptions,
cssPreprocessOptions,
htmlPreprocessOptions,
nvueJsPreprocessOptions,
nvueCssPreprocessOptions,
nvueHtmlPreprocessOptions,
getPlatformGlobal,
getPlatformStat,
getPlatformPush,
getPlatformUniCloud,
parseTheme,
initTheme,
getDevUniConsoleCode
}
+42
View File
@@ -0,0 +1,42 @@
const fs = require('fs')
const path = require('path')
const stripJsonComments = require('strip-json-comments')
const uniI18n = require('@dcloudio/uni-cli-i18n')
function parseJson (content, preprocess = false) {
if (typeof content === 'string') {
if (preprocess) {
const preprocessor = require('@dcloudio/vue-cli-plugin-uni/packages/webpack-preprocess-loader/preprocess')
const {
jsPreprocessOptions
} = require('./platform')
content = preprocessor.preprocess(content, jsPreprocessOptions.context, {
type: jsPreprocessOptions.type
})
}
content = JSON.parse(stripJsonComments(content))
}
content = JSON.stringify(content)
.replace(/\u2028/g, '\\u2028')
.replace(/\u2029/g, '\\u2029')
return JSON.parse(content)
}
function getJson (jsonFileName, preprocess = false) {
const jsonFilePath = path.resolve(process.env.UNI_INPUT_DIR, jsonFileName)
if (!fs.existsSync(jsonFilePath)) {
throw new Error(jsonFilePath + ' ' + uniI18n.__('cliShared.doesNotExist'))
}
try {
return parseJson(fs.readFileSync(jsonFilePath, 'utf8'), preprocess)
} catch (e) {
throw new Error(jsonFileName + uniI18n.__('cliShared.parseJsonFailed') + '\n' + e.message)
}
}
module.exports = {
getJson,
parseJson
}
+189
View File
@@ -0,0 +1,189 @@
const path = require('path')
const {
hasOwn
} = require('./util')
const {
getJson,
parseJson
} = require('./json')
const defaultRouter = {
mode: 'hash',
base: '/'
}
const defaultAsync = {
loading: 'AsyncLoading',
error: 'AsyncError',
delay: 200,
timeout: 60000
}
const networkTimeout = {
request: 60000,
connectSocket: 60000,
uploadFile: 60000,
downloadFile: 60000
}
function getManifestJson () {
return getJson('manifest.json')
}
function parseManifestJson (content) {
return parseJson(content)
}
function getNetworkTimeout (manifestJson) {
if (!manifestJson) {
manifestJson = getManifestJson()
}
return Object.assign({}, networkTimeout, manifestJson.networkTimeout || {})
}
function getH5Options (manifestJson) {
if (!manifestJson) {
manifestJson = getManifestJson()
}
let h5 = {}
if (process.env.UNI_SUB_PLATFORM) {
h5 = manifestJson[process.env.UNI_SUB_PLATFORM] || {}
} else {
if (process.env.UNI_PLATFORM === 'h5') {
h5 = manifestJson.web || manifestJson.h5 || {}
} else {
h5 = manifestJson[process.env.UNI_PLATFORM] || {}
}
}
h5.appid = (manifestJson.appid || '').replace('__UNI__', '')
h5.title = h5.title || manifestJson.name || ''
h5.router = Object.assign({}, defaultRouter, h5.router || {})
h5.async = Object.assign({}, defaultAsync, h5.async || {})
let base = h5.router.base
if (!base.startsWith('/') && !base.startsWith('./')) {
base = '/' + base
}
if (!base.endsWith('/')) {
base = base + '/'
}
// 相对路径仅支持 hash 模式
if (base.startsWith('./')) {
h5.router.mode = defaultRouter.mode
}
h5.router.base = base
if (process.env.NODE_ENV === 'production') { // 生产模式,启用 publicPath
h5.publicPath = h5.publicPath || base
if (!h5.publicPath.endsWith('/')) {
h5.publicPath = h5.publicPath + '/'
}
} else { // 其他模式,启用 base
if (base.startsWith('./')) {
// 在开发模式, publicPath 如果为 './' webpack-dev-server 匹配文件时会失败
h5.publicPath = base.substr(1)
} else {
h5.publicPath = base
}
}
/* eslint-disable no-mixed-operators */
h5.template = h5.template && path.resolve(process.env.UNI_INPUT_DIR, h5.template) || path.resolve(require('./util')
.getCLIContext(), 'public/index.html')
h5.devServer = h5.devServer || {}
// 插件修改 h5Options
global.uniPlugin.configureH5.forEach(configureH5 => {
configureH5(h5)
})
return h5
}
function isEnableUniPushV1 (manifestJson, platform) {
if (!manifestJson) {
manifestJson = getManifestJson()
}
if (isEnableUniPushV2(manifestJson, platform)) {
return false
}
if (platform === 'app-plus') {
const platformOptions = manifestJson[platform]
const sdkConfigs = platformOptions && platformOptions.distribute && platformOptions.distribute.sdkConfigs
const push = sdkConfigs && sdkConfigs.push
if (push && hasOwn(push, 'unipush')) {
return true
}
}
return false
}
function isEnableUniPushV2 (manifestJson, platform) {
if (!manifestJson) {
manifestJson = getManifestJson()
}
const platformOptions = manifestJson[platform]
if (platform === 'app-plus') {
const sdkConfigs = platformOptions && platformOptions.distribute && platformOptions.distribute.sdkConfigs
const unipush = sdkConfigs && sdkConfigs.push && sdkConfigs.push.unipush
return (
/* eslint-disable eqeqeq */
unipush && unipush.version == '2'
)
}
return platformOptions && platformOptions.unipush && platformOptions.unipush.enable === true
}
function isEnableSecureNetwork (manifestJson, platform) {
if (!manifestJson) {
manifestJson = getManifestJson()
}
const platformOptions = manifestJson[platform]
if (platform === 'app-plus') {
return !!(
platformOptions && platformOptions.modules && platformOptions.modules.SecureNetwork
)
}
return platformOptions && platformOptions.secureNetwork && platformOptions.secureNetwork.enable === true
}
function isUniPushOffline (manifestJson) {
if (!manifestJson) {
manifestJson = getManifestJson()
}
const platformOptions = manifestJson['app-plus']
const sdkConfigs = platformOptions && platformOptions.distribute && platformOptions.distribute.sdkConfigs
const unipush = sdkConfigs && sdkConfigs.push && sdkConfigs.push.unipush
return unipush && unipush.offline === true
}
function hasPushModule (manifestJson) {
if (!manifestJson) {
manifestJson = getManifestJson()
}
const platformOptions = manifestJson['app-plus']
return platformOptions && platformOptions.modules && platformOptions.modules.Push
}
module.exports = {
getManifestJson,
parseManifestJson,
getNetworkTimeout,
getH5Options,
isEnableUniPushV1,
isEnableUniPushV2,
isUniPushOffline,
hasPushModule,
isEnableSecureNetwork
}
+21
View File
@@ -0,0 +1,21 @@
function mergeWith (objects, customizer) {
const [first, ...rest] = objects
let ret = first
rest.forEach(a => {
ret = mergeTo(ret, a, customizer)
})
return ret
}
function mergeTo (a, b, customizer) {
const ret = {}
Object.keys(a)
.concat(Object.keys(b))
.forEach(k => {
const v = customizer(a[k], b[k], k)
ret[k] = typeof v === 'undefined' ? a[k] : v
})
return ret
}
module.exports = mergeWith
+57
View File
@@ -0,0 +1,57 @@
const uniI18n = require('@dcloudio/uni-cli-i18n')
function isPlainObject (a) {
if (a === null) {
return false
}
return typeof a === 'object'
}
module.exports = {
initCustomScript (name, pkgPath) {
const pkg = require(pkgPath)
const uniAppOptions = pkg['uni-app']
let scriptOptions = false
if (uniAppOptions && uniAppOptions.scripts) {
scriptOptions = uniAppOptions.scripts[name]
}
if (!scriptOptions) {
console.error(`package.json->uni-app->scripts->${name} ${uniI18n.__('cliShared.doesNotExist')}`)
process.exit(0)
}
if (!scriptOptions.env || !scriptOptions.env.UNI_PLATFORM) {
console.error(uniI18n.__('cliShared.requireConfigUniPlatform', {
0: `package.json->uni-app->scripts->${name}->env `
}))
process.exit(0)
}
if (isPlainObject(scriptOptions.define)) {
Object.keys(uniAppOptions.scripts).forEach(scriptName => {
if (scriptName !== name) {
const define = uniAppOptions.scripts[scriptName].define || {}
Object.keys(define).forEach(name => {
if (typeof scriptOptions.define[name] !== 'undefined') {
delete define[name]
} else {
define[name] = false
}
})
scriptOptions.define = Object.assign({}, define, scriptOptions.define)
}
})
}
process.env.UNI_PLATFORM = scriptOptions.env.UNI_PLATFORM
process.env.UNI_SCRIPT = name
process.UNI_SCRIPT_ENV = scriptOptions.env || {}
process.UNI_SCRIPT_DEFINE = scriptOptions.define || {}
return scriptOptions
}
}
+83
View File
@@ -0,0 +1,83 @@
'use strict'
Object.defineProperty(exports, '__esModule', {
value: true
})
const isArray = Array.isArray
function isPlainObject (a) {
if (a === null) {
return false
}
return typeof a === 'object'
}
function mergeWith (objects, customizer) {
const [first, ...rest] = objects
let ret = first
rest.forEach(a => {
ret = mergeTo(ret, a, customizer)
})
return ret
}
function mergeTo (a, b, customizer) {
const ret = {}
Object.keys(a)
.concat(Object.keys(b))
.forEach(k => {
const v = customizer(a[k], b[k], k)
ret[k] = typeof v === 'undefined' ? a[k] : v
})
return ret
}
function mergeWithRule (a, b, k, matchField) {
if (!isArray(a)) {
return a
}
const bMatchItems = []
const ret = a.map(aItem => {
if (!matchField) {
return aItem
}
// 暂不考虑重复
const bMatchItem = b.find(bItem => aItem[matchField] === bItem[matchField])
if (bMatchItem) {
bMatchItems.push(bMatchItem)
return mergeWith([aItem, bMatchItem], createCustomizer(k))
}
return aItem
})
return ret.concat(b.filter(bItem => !bMatchItems.includes(bItem)))
}
function customizeArray (a, b, k) {
if (k === 'pages' || k === 'subPackages.pages') {
return mergeWithRule(a, b, k, 'path')
} else if (k === 'subPackages') {
return mergeWithRule(a, b, k, 'root')
}
return b
}
function customizeObject (a, b, k) {
return mergeWith([a, b], createCustomizer(k))
}
function createCustomizer (key) {
return function customizer (a, b, k) {
const newKey = key ? `${key}.${k}` : k
if (isArray(a) && isArray(b)) {
return customizeArray(a, b, newKey)
}
if (isPlainObject(a) && isPlainObject(b)) {
return customizeObject(a, b, newKey)
}
return b
}
}
function merge (pagesJsons) {
return mergeWith(pagesJsons, createCustomizer())
}
exports.default = merge
+589
View File
@@ -0,0 +1,589 @@
const fs = require('fs')
const path = require('path')
const uniI18n = require('@dcloudio/uni-cli-i18n')
const {
removeExt,
normalizePath,
camelize,
capitalize,
isNormalPage
} = require('./util')
const {
getJson,
parseJson
} = require('./json')
let mainEntry = ''
let nvueMainEntry = ''
function getMainEntry () {
if (!mainEntry) {
mainEntry = fs.existsSync(path.resolve(process.env.UNI_INPUT_DIR, 'main.ts')) ? 'main.ts' : 'main.js'
}
return mainEntry
}
function getNVueMainEntry () {
if (!nvueMainEntry) {
nvueMainEntry = fs.existsSync(path.resolve(process.env.UNI_INPUT_DIR, 'main.js')) ? 'main.js' : '.main.js'
if (nvueMainEntry === '.main.js') {
fs.writeFileSync(path.resolve(process.env.UNI_INPUT_DIR, '.main.js'), '')
}
}
return nvueMainEntry
}
function getPagesJson () {
return processPagesJson(getJson('pages.json', true))
}
function parsePagesJson (content, loader) {
return processPagesJson(parseJson(content, true), loader)
}
function filterPages (pages = [], root) {
for (let i = pages.length - 1; i >= 0; i--) {
const page = pages[i]
if (!isValidPage(page, root)) {
pages.splice(i, 1)
}
}
}
const pagesJsonJsFileName = 'pages.js'
function processPagesJson (pagesJson, loader = {
addDependency: function () {}
}) {
const pagesJsonJsPath = path.resolve(process.env.UNI_INPUT_DIR, pagesJsonJsFileName)
if (fs.existsSync(pagesJsonJsPath)) {
delete require.cache[pagesJsonJsPath]
const pagesJsonJsFn = require(pagesJsonJsPath)
if (typeof pagesJsonJsFn === 'function') {
pagesJson = pagesJsonJsFn(pagesJson, loader)
if (!pagesJson) {
console.error(`${pagesJsonJsFileName} ${uniI18n.__('cliShared.requireReturnJsonObject')}`)
}
} else {
console.error(`${pagesJsonJsFileName} ${uniI18n.__('cliShared.requireExportFunction')}`)
}
}
// 将 subpackages 转换成 subPackages
if (pagesJson.subpackages && !pagesJson.subPackages) {
pagesJson.subPackages = pagesJson.subpackages
delete pagesJson.subpackages
}
let uniNVueEntryPagePath
if (pagesJson.pages && pagesJson.pages.length) { // 如果首页是 nvue
if (isNVuePage(pagesJson.pages[0])) {
uniNVueEntryPagePath = pagesJson.pages[0].path
}
}
// pages
filterPages(pagesJson.pages)
// subPackages
if (Array.isArray(pagesJson.subPackages) && pagesJson.subPackages.length) {
pagesJson.subPackages.forEach(subPackage => {
filterPages(subPackage.pages, subPackage.root)
})
}
if (uniNVuePages.length) { // 直接挂在 pagesJson 上
pagesJson.nvue = {
pages: uniNVuePages.reverse()
}
if (uniNVueEntryPagePath) {
pagesJson.nvue.entryPagePath = uniNVueEntryPagePath
}
}
return pagesJson
}
function isNVuePage (page, root = '') {
if (process.env.UNI_PLATFORM === 'app-plus') {
const pagePath = path.join(root, page.path)
if (fs.existsSync(path.resolve(process.env.UNI_INPUT_DIR, pagePath + '.nvue'))) { // cache一下结果?如果文件被删除,cache 就会出现错误
return true
}
}
return false
}
function isValidPage (page, root = '') {
if (typeof page === 'string' || !page.path) { // 不合法的配置
console.warn(uniI18n.__('cliShared.pagesJsonError', {
0: 'https://uniapp.dcloud.io/collocation/pages?id=pages'
}))
return false
}
let pagePath = page.path
if (pagePath.indexOf('platforms') === 0) { // 平台相关
if (process.env.UNI_PLATFORM === 'h5' || process.env.UNI_PLATFORM === 'web') {
if (!(pagePath.indexOf('platforms/h5/') === 0 || pagePath.indexOf('platforms/web/') === 0)) {
return false
}
} else if (process.env.UNI_PLATFORM === 'app-plus' || process.env.UNI_PLATFORM === 'app') {
if (!(pagePath.indexOf('platforms/app-plus/') === 0 || pagePath.indexOf('platforms/app/') === 0)) {
return false
}
} else if (pagePath.indexOf('platforms/' + process.env.UNI_PLATFORM) === -1) { // 非本平台
return false
}
}
if (
process.env.UNI_PLATFORM === 'app-plus' &&
page.style
) {
const subNVues = page.style.subNVues || (page.style['app-plus'] && page.style['app-plus'].subNVues)
if (Array.isArray(subNVues)) {
subNVues.forEach(subNVue => {
let subNVuePath = subNVue.path
if (subNVuePath) {
subNVuePath = subNVue.path.split('?')[0]
const subNVuePagePath = removeExt(path.join(root, subNVuePath))
process.UNI_NVUE_ENTRY[subNVuePagePath] = getNVueMainJsPath(subNVuePagePath)
}
})
}
} else {
page.style && (delete page.style.subNVues)
}
if (isNVuePage(page, root)) {
// 存储 nvue 相关信息
pagePath = normalizePath(path.join(root, pagePath))
process.UNI_NVUE_ENTRY[pagePath] = getNVueMainJsPath(pagePath)
if (process.env.UNI_USING_V3 || process.env.UNI_USING_V3_NATIVE) { // 不移除
page.nvue = true
return true
} else {
uniNVuePages.push({
path: pagePath + '.html',
style: page.style || {}
})
return false
}
}
return true
}
function getMainJsPath (page) {
return path.resolve(process.env.UNI_INPUT_DIR, getMainEntry() + '?' + JSON.stringify({
page: encodeURIComponent(page)
}))
}
function getNVueMainJsPath (page) {
return path.resolve(process.env.UNI_INPUT_DIR, getNVueMainEntry() + '?' + JSON.stringify({
page: encodeURIComponent(page)
}))
}
process.UNI_ENTRY = {}
process.UNI_NVUE_ENTRY = {}
const uniNVuePages = []
function parsePages (pagesJson, pageCallback, subPageCallback) {
if (!pagesJson) {
pagesJson = getPagesJson()
}
// pages
pagesJson.pages.forEach(page => {
pageCallback && pageCallback(page)
})
// subPackages
if (Array.isArray(pagesJson.subPackages) && pagesJson.subPackages.length) {
pagesJson.subPackages.forEach((subPackage) => {
const {
root,
pages
} = subPackage
pages.forEach(page => {
root && subPageCallback && subPageCallback(root, page, subPackage)
})
})
}
}
function parseEntry (pagesJson) {
const mainJsPath = path.resolve(process.env.UNI_INPUT_DIR, getMainEntry())
process.UNI_ENTRY = {
'common/main': mainJsPath
}
const manifestConfig = process.UNI_MANIFEST
const weixinConfig = manifestConfig['mp-weixin'] || {}
const independentSwitch = !!weixinConfig.independent
if (independentSwitch) {
Object.values(process.UNI_SUBPACKAGES).forEach(({
root,
independent = false
}) => {
if (root && independent) {
const pkgRootMainJsKey = `${root}/common/main`
// const pkgRootMainJsPath = `${process.env.UNI_INPUT_DIR}/${root}/main.js`;
process.UNI_ENTRY[pkgRootMainJsKey] = mainJsPath
}
})
}
process.UNI_SUB_PACKAGES_ROOT = {}
process.UNI_NVUE_ENTRY = {}
if (process.env.UNI_USING_NATIVE || process.env.UNI_USING_V3_NATIVE) {
process.UNI_NVUE_ENTRY['app-config'] = path.resolve(process.env.UNI_INPUT_DIR, 'pages.json')
process.UNI_NVUE_ENTRY['app-service'] = path.resolve(process.env.UNI_INPUT_DIR, getMainEntry())
}
uniNVuePages.length = 0
if (!pagesJson) {
pagesJson = getPagesJson() // 会检测修改 nvue entry
}
// pages
pagesJson.pages.forEach(page => {
if (isNormalPage(page.path)) {
process.UNI_ENTRY[page.path] = getMainJsPath(page.path)
}
})
// subPackages
if (Array.isArray(pagesJson.subPackages) && pagesJson.subPackages.length) {
pagesJson.subPackages.forEach(({
root,
pages
}) => {
Array.isArray(pages) && pages.forEach(page => {
if (root) {
const pagePath = normalizePath(path.join(root, page.path))
process.UNI_ENTRY[pagePath] = getMainJsPath(pagePath)
process.UNI_SUB_PACKAGES_ROOT[pagePath] = root
}
})
})
}
}
function parseUsingComponents (usingComponents = {}) {
const components = []
Object.keys(usingComponents).forEach(name => {
const identifier = capitalize(camelize(name))
let source = usingComponents[name]
if (source.indexOf('/') === 0) { // 绝对路径
source = '@' + source
} else if (source.indexOf('.') !== 0) { // 相对路径
source = './' + source
}
components.push({
name,
identifier,
source
})
})
return components
}
function generateUsingComponentsCode (usingComponents) {
const components = parseUsingComponents(usingComponents)
const importCode = []
const componentsCode = []
components.forEach(({
name,
identifier,
source
}) => {
importCode.push(`import ${identifier} from '${source}.vue'`)
componentsCode.push(`'${name}':${identifier}`)
})
if (!importCode.length) {
return ''
}
return `;${importCode.join(';')};exports.default.components=Object.assign({${componentsCode.join(',')}},exports.default.components||{});`
}
function generateGlobalUsingComponentsCode (usingComponents) {
const components = parseUsingComponents(usingComponents)
const importCode = []
const componentsCode = []
components.forEach(({
name,
identifier,
source
}) => {
importCode.push(`import ${identifier} from '${source}.vue'`)
componentsCode.push(`Vue.component('${name}',${identifier})`)
})
if (!importCode.length) {
return ''
}
return `${importCode.join(';')};${componentsCode.join(';')};`
}
function getGlobalUsingComponentsCode () {
const pagesJson = getPagesJson()
const usingComponents = pagesJson.globalStyle && pagesJson.globalStyle.usingComponents
if (!usingComponents) {
return ''
}
return generateGlobalUsingComponentsCode(usingComponents)
}
function getUsingComponentsCode (pagePath) {
const usingComponents = usingComponentsPages[pagePath]
if (!usingComponents) {
return ''
}
return generateUsingComponentsCode(usingComponents)
}
const usingComponentsPages = Object.create(null)
function addPageUsingComponents (pagePath, usingComponents) {
if (usingComponents && Object.keys(usingComponents).length) {
usingComponentsPages[pagePath] = usingComponents
}
}
// 存储自动组件
const autoComponentMap = {}
let lastUsingAutoImportComponentsJson = ''
let uniAutoImportComponents = []
let uniAutoImportScanComponents = []
let uniQuickAppAutoImportScanComponents = false
const isDirectory = source => fs.lstatSync(source).isDirectory()
function getAutoComponentsByDir (componentsPath, absolute = false) {
const components = {}
try {
if (fs.existsSync(componentsPath)) {
let importComponentsDir = '@/components'
const uniModulesDir = path.resolve(process.env.UNI_INPUT_DIR, 'uni_modules')
if (!absolute && componentsPath.includes(uniModulesDir)) {
importComponentsDir = `@/uni_modules/${path.basename(path.dirname(componentsPath))}/components`
}
fs.readdirSync(componentsPath).forEach(name => {
const folder = path.resolve(componentsPath, name)
if (!isDirectory(folder)) {
return
}
const importDir = absolute ? normalizePath(folder) : `${importComponentsDir}/${name}`
// 读取文件夹文件列表,比对文件名(fs.existsSync在大小写不敏感的系统会匹配不准确)
const files = fs.readdirSync(folder)
if (files.includes(name + '.vue')) {
components[`^${name}$`] = `${importDir}/${name}.vue`
} else if (files.includes(name + '.nvue')) {
components[`^${name}$`] = `${importDir}/${name}.nvue`
}
})
}
} catch (e) {
console.log(e)
}
return components
}
function initAutoComponents () {
const allComponents = {}
const componentsDirs = [path.resolve(process.env.UNI_INPUT_DIR, 'components')]
global.uniModules.forEach(module => {
componentsDirs.push(path.resolve(process.env.UNI_INPUT_DIR, 'uni_modules', module, 'components'))
})
componentsDirs.forEach((componentsDir) => {
// 根目录 components 使用相对路径,uni_modules 使用绝对路径
const currentComponents = getAutoComponentsByDir(componentsDir, false)
Object.keys(currentComponents).forEach(name => {
(allComponents[name] || (allComponents[name] = [])).push(currentComponents[name])
})
})
const components = {}
const conflictFiles = []
Object.keys(allComponents).forEach(name => {
const files = allComponents[name]
components[name] = files[0]
if (files.length > 1) {
conflictFiles.push(files)
}
})
if (conflictFiles.length > 0) {
conflictFiles.forEach(files => {
console.warn(uniI18n.__('cliShared.easycomConflict', {
0: '[' + files.map((file, index) => {
return file
}).join(',') + ']'
}))
console.log('\n')
})
}
return components
}
function initAutoImportScanComponents () {
const components = initAutoComponents()
const {
initUTSComponents
} = require('./uts/uts.js')
initUTSComponents(process.env.UNI_INPUT_DIR, process.env.UNI_PLATFORM).forEach((item) => {
components[item.pattern.source] = item.replacement.replace('\0', '').replace('?uts-proxy',
'/package.json?uts-proxy')
})
if (process.env.UNI_PLATFORM === 'quickapp-native') {
if (!uniQuickAppAutoImportScanComponents) {
uniQuickAppAutoImportScanComponents = getAutoComponentsByDir(
path.resolve(require.resolve('@dcloudio/uni-quickapp-native'), '../../components'),
true
)
}
// 平台内置组件优先级高
Object.assign(components, uniQuickAppAutoImportScanComponents)
}
uniAutoImportScanComponents = parseUsingAutoImportComponents(components)
refreshAutoComponentMap()
}
const _toString = Object.prototype.toString
function isPlainObject (obj) {
return _toString.call(obj) === '[object Object]'
}
function initBuiltInEasycom (components, usingAutoImportComponents) {
components.forEach(name => {
const easycomName = `^${name}$`
if (!usingAutoImportComponents[easycomName]) {
usingAutoImportComponents[easycomName] =
'@dcloudio/uni-cli-shared/components/' + name + '.vue'
}
})
}
function initAutoImportComponents (easycom = {}) {
let usingAutoImportComponents = easycom.custom || easycom || {}
if (!isPlainObject(usingAutoImportComponents)) {
usingAutoImportComponents = {}
}
initBuiltInEasycom(BUILT_IN_EASYCOMS, usingAutoImportComponents)
// 目前仅 mp-weixin 内置支持 page-meta 等组件
if (process.env.UNI_PLATFORM === 'mp-weixin') {} else if (process.env.UNI_PLATFORM === 'mp-alipay') {
initBuiltInEasycom(BUILT_IN_COMPONENTS_ALIPAY, usingAutoImportComponents)
} else {
initBuiltInEasycom(BUILT_IN_COMPONENTS, usingAutoImportComponents)
}
const newUsingAutoImportComponentsJson = JSON.stringify(usingAutoImportComponents)
if (newUsingAutoImportComponentsJson !== lastUsingAutoImportComponentsJson) {
lastUsingAutoImportComponentsJson = newUsingAutoImportComponentsJson
uniAutoImportComponents = parseUsingAutoImportComponents(usingAutoImportComponents)
refreshAutoComponentMap()
}
}
/**
* UNI_AUTO_COMPONENTS 被更新,重新刷新 map
*/
function refreshAutoComponentMap () {
Object.keys(autoComponentMap).forEach(name => {
addAutoComponent(name)
})
}
function addAutoComponent (name) {
let opt = uniAutoImportComponents.find(opt => opt.pattern.test(name))
if (!opt) {
opt = uniAutoImportScanComponents.find(opt => opt.pattern.test(name))
}
if (!opt) { // 不匹配
return (autoComponentMap[name] = true) // cache
}
return (autoComponentMap[name] = {
name,
identifier: capitalize(camelize(name + '-auto-import')),
source: name.replace(opt.pattern, opt.replacement)
})
}
function getAutoComponents (autoComponents) {
const components = []
autoComponents.forEach(name => {
let autoComponent = autoComponentMap[name]
if (!autoComponent) {
autoComponent = addAutoComponent(name)
}
if (autoComponent !== true) {
components.push(autoComponent)
}
})
return components
}
function parseUsingAutoImportComponents (usingAutoImportComponents) {
const autoImportComponents = []
if (usingAutoImportComponents) {
Object.keys(usingAutoImportComponents).forEach(pattern => {
const replacement = usingAutoImportComponents[pattern]
if (replacement && typeof replacement === 'string') {
autoImportComponents.push({
pattern: new RegExp(pattern),
replacement: replacement
})
}
})
}
return autoImportComponents
}
const BUILT_IN_COMPONENTS = ['page-meta', 'navigation-bar', 'uni-match-media']
const BUILT_IN_COMPONENTS_ALIPAY = ['navigation-bar']
const BUILT_IN_EASYCOMS = ['unicloud-db', 'uniad', 'ad-rewarded-video', 'ad-fullscreen-video', 'ad-interstitial',
'ad-interactive'
]
function isBuiltInComponent (name) { // uni-template-compiler/lib/util.js 识别微信内置组件
return BUILT_IN_COMPONENTS.includes(name)
}
function isBuiltInComponentPath (modulePath) { // 内置的 easycom 类组件
if (BUILT_IN_EASYCOMS.find(name => modulePath.includes(name))) {
return true
}
return !!BUILT_IN_COMPONENTS.find(name => modulePath.includes(name))
}
module.exports = {
isBuiltInComponent,
isBuiltInComponentPath,
getMainEntry,
getNVueMainEntry,
parsePages,
parseEntry,
getPagesJson,
parsePagesJson,
pagesJsonJsFileName,
getAutoComponents,
initAutoImportComponents,
initAutoImportScanComponents,
addPageUsingComponents,
getUsingComponentsCode,
generateUsingComponentsCode,
getGlobalUsingComponentsCode,
parseUsingAutoImportComponents,
generateGlobalUsingComponentsCode
}
+260
View File
@@ -0,0 +1,260 @@
const fs = require('fs')
const path = require('path')
const {
getManifestJson
} = require('./manifest')
const {
isInHBuilderX,
isInHBuilderXAlpha,
normalizeNodeModules
} = require('./util')
const {
SCSS,
SASS
} = require('./scss')
function getShadowCss () {
let tagName = 'page'
if (process.env.UNI_PLATFORM === 'h5') {
tagName = 'body'
}
const url = createShadowImageUrl(getShadowCdn(), 'grey')
return `${tagName}::after{position:fixed;content:'';left:-1000px;top:-1000px;-webkit-animation:shadow-preload .1s;-webkit-animation-delay:3s;animation:shadow-preload .1s;animation-delay:3s}@-webkit-keyframes shadow-preload{0%{background-image:url(${url})}100%{background-image:url(${url})}}@keyframes shadow-preload{0%{background-image:url(${url})}100%{background-image:url(${url})}}`
}
const cdns = {
h5: '',
web: '',
'mp-weixin': 1,
'mp-alipay': 2,
'mp-baidu': 3,
'mp-toutiao': 4,
'mp-qq': 5,
'mp-360': 7,
'mp-dingtalk': 8,
'mp-kuaishou': 9,
'mp-lark': 10,
'mp-jd': 11,
'mp-xhs': 12,
'quickapp-webview-huawei': 200,
'mp-harmony': 200,
'quickapp-webview-union': 201
}
function getShadowCdn () {
return cdns[process.env.UNI_SUB_PLATFORM || process.env.UNI_PLATFORM] || ''
}
let appid
let platformAppId
function createIdent (platform) {
if (process.env.UNI_INPUT_DIR) {
if (typeof appid === 'undefined') {
const manifestJson = getManifestJson()
appid = manifestJson.appid || ''
platformAppId = manifestJson[platform]?.appid
}
let id = appid.replace('__UNI__', '')
if (platformAppId) {
id += '%%' + platformAppId
}
if (id) {
return Buffer.from(Buffer.from(id).toString('base64')).toString('hex')
}
}
return ''
}
function createShadowImageUrl (cdn, type = 'grey') {
let identStr = ''
if (process.env.UNI_PLATFORM !== 'h5' && process.env.UNI_PLATFORM !== 'web') {
const ident = createIdent(process.env.UNI_PLATFORM)
identStr = ident ? `${ident}/` : ''
}
return `https://cdn${cdn || ''}.dcloud.net.cn/${identStr}img/shadow-${type}.png`
}
function isEnableConsole () {
return !!(
process.env.NODE_ENV === 'development' &&
process.env.UNI_SOCKET_HOSTS &&
process.env.UNI_SOCKET_PORT &&
process.env.UNI_SOCKET_ID
)
}
// 解决 vue-cli-service lint 时 UNI_PLATFORM 不存在
process.env.UNI_PLATFORM = process.env.UNI_PLATFORM || 'h5'
const uniPluginOptions = global.uniPlugin.options || {}
const {
vueContext: preprocessContext,
nvueContext: nvuePreprocessContext
} = global.uniPlugin.preprocess
// TODO 暂时保留原有导出,减少影响,后续再整理一下
module.exports = {
normalizeNodeModules,
isInHBuilderX,
isInHBuilderXAlpha,
runByHBuilderX: isInHBuilderX || fs.existsSync(path.resolve(process.env.UNI_HBUILDERX_PLUGINS || '',
'weapp-tools')),
getFlexDirection (json) {
let flexDir = 'column'
if (json && json.nvue && json.nvue['flex-direction']) {
flexDir = json.nvue['flex-direction']
const flexDirs = ['row', 'row-reverse', 'column', 'column-reverse']
if (flexDirs.indexOf(flexDir) === -1) {
flexDir = 'column'
}
}
return flexDir
},
jsPreprocessOptions: {
type: 'js',
context: preprocessContext
},
cssPreprocessOptions: {
type: 'css',
context: preprocessContext
},
htmlPreprocessOptions: {
type: 'html',
context: preprocessContext
},
nvueCssPreprocessOptions: {
type: 'css',
context: nvuePreprocessContext
},
nvueJsPreprocessOptions: {
type: 'js',
context: nvuePreprocessContext
},
nvueHtmlPreprocessOptions: {
type: 'html',
context: nvuePreprocessContext
},
isSupportSubPackages () {
return !!uniPluginOptions.subPackages
},
getPlatforms () {
return global.uniPlugin.platforms
},
getPlatformGlobal () { // 目前仅mp-alipay有用
return uniPluginOptions.global
},
getPlatformExts () { // 小程序扩展名
return uniPluginOptions.extnames
},
getPlatformProject () { // 开发工具项目配置名
return uniPluginOptions.project
},
getPlatformFilterTag () {
return uniPluginOptions.filterTag
},
getMPRuntimePath () {
if (process.env.UNI_USING_VUE3) {
try {
return require.resolve('@dcloudio/uni-' + process.env.UNI_PLATFORM + '/dist/uni.mp.esm.js')
} catch (error) {
throw new Error('Vue3 项目暂不支持当前小程序')
}
}
return require.resolve('@dcloudio/uni-' + process.env.UNI_PLATFORM)
},
getPlatformVue (vueOptions) {
if (uniPluginOptions.vue) {
return uniPluginOptions.vue
}
if (process.env.UNI_USING_VUE3) {
return '@dcloudio/uni-mp-vue'
}
return '@dcloudio/vue-cli-plugin-uni/packages/mp-vue'
},
getPlatformCssVars () {
return uniPluginOptions.cssVars || {}
},
getPlatformCssnano () {
return {
calc: false,
orderedValues: false,
mergeLonghand: false,
mergeRules: false,
cssDeclarationSorter: false,
uniqueSelectors: false, // 标签排序影响头条小程序
minifySelectors: false, // 标签排序影响头条小程序
discardComments: false,
discardDuplicates: false // 条件编译会导致重复
}
},
createShadowImageUrl,
getShadowCss,
getShadowTemplate (colorType = 'grey') {
let tagName = 'cover-image'
if (process.env.UNI_PLATFORM === 'mp-toutiao' || process.env.UNI_PLATFORM === 'mp-lark' || process.env
.UNI_PLATFORM === 'mp-xhs') {
tagName = 'image'
}
return `<${tagName} src="${createShadowImageUrl(getShadowCdn(), colorType)}" style="z-index:998;position:fixed;left:0;top:0;width:100%;height:3px;"/>`
},
getPlatformScss () {
return SCSS
},
getPlatformSass () {
return SASS
},
getPlatformStat () {
if (!process.env.UNI_USING_STAT) {
return ''
}
return process.env.UNI_USING_STAT === '2' ? 'import \'@dcloudio/uni-stat/dist/uni-cloud-stat.es.js\';'
: 'import \'@dcloudio/uni-stat/dist/uni-stat.es.js\';'
},
getPlatformPush () {
if (process.env.UNI_PUSH_V1) {
if (process.env.UNI_PUSH_MODULE) {
return ';import \'@dcloudio/vue-cli-plugin-uni/packages/uni-push/dist/uni-push-v1.plus.es.js\';'
}
} else if (process.env.UNI_PUSH_V2_OFFLINE) {
if (process.env.UNI_PUSH_MODULE) {
return ';import \'@dcloudio/vue-cli-plugin-uni/packages/uni-push/dist/uni-push.plus.es.js\';'
}
} else if (process.env.UNI_PUSH_V2) {
return ';import \'@dcloudio/vue-cli-plugin-uni/packages/uni-push/dist/uni-push.es.js\';'
}
return ''
},
getPlatformUniCloud () {
if (JSON.parse(process.env.UNI_CLOUD_PROVIDER || '[]').length) {
const uniCloudLibPath = '@dcloudio/vue-cli-plugin-uni/packages/uni-cloud/dist/index.js'
return `import '${uniCloudLibPath}';`
}
return ''
},
getBabelParserOptions () {
return {
sourceType: 'module',
plugins: [
['pipelineOperator', {
proposal: 'minimal'
}],
'doExpressions',
'optionalChaining',
'typescript',
['decorators', {
decoratorsBeforeExport: true
}],
'classProperties'
]
}
},
isEnableConsole,
getDevUniConsoleCode () {
if (isEnableConsole()) {
return 'import \'@dcloudio/uni-console\';\n'
}
return ''
}
}
+122
View File
@@ -0,0 +1,122 @@
const path = require('path')
const initPreprocessContext = require('./preprocess')
const uniI18n = require('@dcloudio/uni-cli-i18n')
const Plugin = {
options: {},
// 初步校验相关配置是否正确
validate: [], // (platformOptions, manifestJson) {},
configureEnv: [], // (){},
// 以 H5 为基准的平台特殊配置
configureH5: [], // (h5Options) {},
configurePages: [], // (pagesJson,manifestJson,loader) {},
// 链式修改 webpack config
chainWebpack: [], // (config, vueOptions, api) {},
// 修改 webpack config
configureWebpack: [], // (config, vueOptions, api) {},
// 配置额外的资源拷贝
copyWebpackOptions: [] // (platformOptions, vueOptions) {}
}
const PLUGIN_KEYS = Object.keys(Plugin)
function initPlugin (plugin) {
let pluginApi
try {
pluginApi = require(path.join(plugin.id, (plugin.config.main || '/lib/uni.config.js')))
} catch (e) {
console.warn(uniI18n.__('cliShared.missingUniConfig', { 0: plugin.id }))
}
pluginApi && PLUGIN_KEYS.forEach(name => {
if (pluginApi[name]) {
if (Array.isArray(Plugin[name])) { // hooks
Plugin[name].push(pluginApi[name])
} else { // options
Object.assign(Plugin[name], pluginApi[name])
}
}
})
}
const pluginRE = /^(uni-|@[\w-]+(\.)?[\w-]+\/uni-)/
function resolvePlugins () {
const pkg = require(path.resolve(process.env.UNI_CLI_CONTEXT, 'package.json'))
return Object.keys(pkg.devDependencies || {})
.concat(Object.keys(pkg.dependencies || {}))
.map(id => {
if (!pluginRE.test(id)) {
return
}
try {
const pluginPkg = require(id + '/package.json')
const config = pluginPkg['uni-app']
if (!config) {
return
}
if (!config.name) {
return console.warn(uniI18n.__('cliShared.missingNameAttribute', { 0: `${id}/package.json->uni-app` }))
}
return {
id,
name: config.name,
config
}
} catch (e) {}
}).filter(Boolean)
}
function initExtends (name, plugin, plugins) {
const extendsPlatform = plugin.config.extends
if (extendsPlatform) {
if (extendsPlatform !== 'h5') {
console.error(uniI18n.__('cliShared.extendOnlySupportH5'))
process.exit(0)
}
if (!plugin) {
console.error(uniI18n.__('cliShared.noFoundPlatformPlugin', { 0: extendsPlatform }))
process.exit(0)
}
const extendsPlugin = plugins.find(plugin => plugin.name === extendsPlatform)
process.env.UNI_SUB_PLATFORM = name
process.env.UNI_PLATFORM = extendsPlatform
initPlugin(extendsPlugin)
}
}
module.exports = {
init () {
// compatible with vue-cli-service lint
process.env.UNI_PLATFORM = process.env.UNI_PLATFORM || 'h5'
// hack
if (
process.env.UNI_PLATFORM === 'quickapp-webview-huawei' ||
process.env.UNI_PLATFORM === 'quickapp-webview-union'
) {
process.env.UNI_SUB_PLATFORM = process.env.UNI_PLATFORM
process.env.UNI_PLATFORM = 'quickapp-webview'
}
const plugins = resolvePlugins()
const plugin = plugins.find(plugin => plugin.name === process.env.UNI_PLATFORM)
if (!plugin) {
console.error(uniI18n.__('cliShared.noFoundPlatformPlugin', { 0: process.env.UNI_PLATFORM }))
process.exit(0)
}
const name = plugin.name
initExtends(name, plugin, plugins)
initPlugin(plugin)
Plugin.name = name
Plugin.id = plugin.id
Plugin.config = plugin.config
Plugin.platforms = plugins.map(plugin => plugin.name)
Plugin.preprocess = initPreprocessContext(name, Plugin.platforms, process.UNI_SCRIPT_DEFINE)
return Plugin
}
}
+102
View File
@@ -0,0 +1,102 @@
const DEFAULT_KEYS = [
'UNI-APP-X',
'VUE2',
'VUE3',
'MP',
'APP',
'APP-PLUS-NVUE',
'APP-VUE',
'APP-NVUE',
'APP-ANDROID',
'APP-IOS',
'APP-HARMONY',
'MP-HARMONY',
'WEB'
]
function normalize (name) {
return name.replace(/-/g, '_').toUpperCase()
}
module.exports = function initPreprocess (name, platforms, userDefines = {}) {
const vueContext = {} // vue 值为true的条件编译
const nvueContext = {} // nvue 值为true的条件编译
const defaultContext = {}
defaultContext.uniVersion = parseFloat(process.env.UNI_COMPILER_VERSION) || 0
const userDefineKeys = Object.keys(userDefines)
platforms
.concat(DEFAULT_KEYS)
.concat(userDefineKeys)
.forEach(name => {
defaultContext[normalize(name)] = false
})
if (process.env.UNI_USING_VUE3) {
defaultContext.VUE3 = true
} else {
defaultContext.VUE2 = true
}
// nvue 只支持vue2
nvueContext.VUE2 = true
nvueContext.VUE3 = false
vueContext[normalize(name)] = true
if (name === 'app-plus') {
vueContext.APP_VUE = true
nvueContext.APP_PLUS = true
nvueContext.APP_NVUE = true
nvueContext.APP_PLUS_NVUE = true
// if (process.env.UNI_APP_PLATFORM === 'android') {
// defaultContext.APP_ANDROID = true
// } else if (process.env.UNI_APP_PLATFORM === 'ios') {
// defaultContext.APP_IOS = true
// } else {
// defaultContext.APP_ANDROID = true
// defaultContext.APP_IOS = true
// }
}
if (name === 'h5') {
defaultContext.WEB = true
}
if (name.startsWith('mp-')) {
vueContext.MP = true
}
if (name.startsWith('app-')) {
vueContext.APP = true
nvueContext.APP = true
}
if (name === 'quickapp-webview') {
vueContext.QUICKAPP_WEBVIEW_HUAWEI = true
vueContext.QUICKAPP_WEBVIEW_UNION = true
if (process.env.UNI_SUB_PLATFORM === 'quickapp-webview-huawei') {
vueContext.QUICKAPP_WEBVIEW_UNION = false
} else if (process.env.UNI_SUB_PLATFORM === 'quickapp-webview-union') {
vueContext.QUICKAPP_WEBVIEW_HUAWEI = false
}
}
userDefineKeys.forEach(name => {
const key = normalize(name)
vueContext[key] = nvueContext[key] = !!userDefines[name]
})
return {
vueContext: {
...defaultContext,
...vueContext
},
nvueContext: {
...defaultContext,
...nvueContext
}
}
}
+61
View File
@@ -0,0 +1,61 @@
function resolveNativeBinding () {
const { platform, arch } = process
let nativeBinding = ''
switch (platform) {
case 'win32':
switch (arch) {
case 'x64':
nativeBinding = 'preprocessor-windows-x86_64'
break
default:
throw new Error(`Unsupported architecture on Windows: ${arch}`)
}
break
case 'darwin':
switch (arch) {
case 'x64':
nativeBinding = 'preprocessor-macos-x86_64'
break
case 'arm64':
nativeBinding = 'preprocessor-macos-arm64'
break
default:
throw new Error(`Unsupported architecture on macOS: ${arch}`)
}
break
default:
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
}
return require('./' + nativeBinding)
}
async function runProcess (vue3 = false) {
try {
/* eslint-disable no-undef */
globalThis.preprocessor_require = require
await resolveNativeBinding().process(vue3)
} catch (error) {
}
}
class PreprocessorWebpackPlugin {
apply (compiler) {
compiler.hooks.afterEmit.tapPromise('d', (params) => {
return runProcess(false)
})
}
}
function PreprocessorVitePlugin () {
return {
name: 'preprocessor',
async writeBundle (_) {
await runProcess(true)
}
}
}
module.exports = {
PreprocessorWebpackPlugin,
PreprocessorVitePlugin
}
+115
View File
@@ -0,0 +1,115 @@
const semver = require('semver')
let sassLoaderVersion
try {
sassLoaderVersion = semver.major(require('sass-loader/package.json').version)
} catch (e) {}
const SCSS =
`
$uni-color-primary: #007aff;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;
$uni-text-color: #333;//基本色
$uni-text-color-inverse: #fff;//反色
$uni-text-color-grey: #999;//辅助灰色,如加载更多的提示信息
$uni-text-color-placeholder: #808080;
$uni-text-color-disable: #c0c0c0;
$uni-bg-color: #ffffff;
$uni-bg-color-grey: #f8f8f8;
$uni-bg-color-hover: #f1f1f1;//点击状态颜色
$uni-bg-color-mask: rgba(0, 0, 0, 0.4);//遮罩颜色
$uni-border-color: #c8c7cc;
$uni-font-size-sm: 24rpx;
$uni-font-size-base: 28rpx;
$uni-font-size-lg: 32rpx;
$uni-img-size-sm: 40rpx;
$uni-img-size-base: 52rpx;
$uni-img-size-lg: 80rpx;
$uni-border-radius-sm: 4rpx;
$uni-border-radius-base: 6rpx;
$uni-border-radius-lg: 12rpx;
$uni-border-radius-circle: 50%;
$uni-spacing-row-sm: 10px;
$uni-spacing-row-base: 20rpx;
$uni-spacing-row-lg: 30rpx;
$uni-spacing-col-sm: 8rpx;
$uni-spacing-col-base: 16rpx;
$uni-spacing-col-lg: 24rpx;
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
$uni-color-title: #2C405A; // 文章标题颜色
$uni-font-size-title: 40rpx;
$uni-color-subtitle: #555555; // 二级标题颜色
$uni-font-size-subtitle: 36rpx;
$uni-color-paragraph: #3F536E; // 文章段落颜色
$uni-font-size-paragraph: 30rpx;
`
const SASS =
`
$uni-color-primary: #007aff
$uni-color-success: #4cd964
$uni-color-warning: #f0ad4e
$uni-color-error: #dd524d
$uni-text-color: #333//基本色
$uni-text-color-inverse: #fff//反色
$uni-text-color-grey: #999//辅助灰色,如加载更多的提示信息
$uni-text-color-placeholder: #808080
$uni-text-color-disable: #c0c0c0
$uni-bg-color: #ffffff
$uni-bg-color-grey: #f8f8f8
$uni-bg-color-hover: #f1f1f1//点击状态颜色
$uni-bg-color-mask: rgba(0, 0, 0, 0.4)//遮罩颜色
$uni-border-color: #c8c7cc
$uni-font-size-sm: 24rpx
$uni-font-size-base: 28rpx
$uni-font-size-lg: 32rpx
$uni-img-size-sm: 40rpx
$uni-img-size-base: 52rpx
$uni-img-size-lg: 80rpx
$uni-border-radius-sm: 4rpx
$uni-border-radius-base: 6rpx
$uni-border-radius-lg: 12rpx
$uni-border-radius-circle: 50%
$uni-spacing-row-sm: 10px
$uni-spacing-row-base: 20rpx
$uni-spacing-row-lg: 30rpx
$uni-spacing-col-sm: 8rpx
$uni-spacing-col-base: 16rpx
$uni-spacing-col-lg: 24rpx
$uni-opacity-disabled: 0.3 // 组件禁用态的透明度
$uni-color-title: #2C405A // 文章标题颜色
$uni-font-size-title: 40rpx
$uni-color-subtitle: #555555 // 二级标题颜色
$uni-font-size-subtitle: 36rpx
$uni-color-paragraph: #3F536E // 文章段落颜色
$uni-font-size-paragraph: 30rpx
`
module.exports = {
SCSS,
SASS,
sassLoaderVersion
}
+62
View File
@@ -0,0 +1,62 @@
const path = require('path')
const webpack = require('webpack')
const {
normalizePath,
pathToRegexp,
isInHBuilderX
} = require('@dcloudio/uni-cli-shared/lib/util')
let sourceRoot = false
function getSourceRoot () {
if (!sourceRoot) {
if (isInHBuilderX) {
sourceRoot = normalizePath(process.env.UNI_INPUT_DIR)
} else {
sourceRoot = normalizePath(process.env.UNI_CLI_CONTEXT)
}
}
return sourceRoot
}
function moduleFilenameTemplate (info) {
if (
info.resourcePath &&
(
!info.allLoaders ||
info.query.includes('type=script&lang=ts') ||
info.resourcePath.endsWith('.ts')
)
) {
const filepath = normalizePath(path.relative(getSourceRoot(), info.absoluteResourcePath))
if (filepath.indexOf('../') === 0) {
return
}
return `uni-app:///${filepath}`
}
}
const exclude = [/pages\.json/, /node_modules/, /vue&type=template/, /vue&type=style/]
module.exports = {
createSourceMapDevToolPlugin (filename = false, args) {
const options = {
test: [/\.js$/],
exclude,
moduleFilenameTemplate,
...args
}
if (filename) {
options.filename = '../.sourcemap/' + process.env.UNI_PLATFORM + '/[file].map'
}
return new webpack.SourceMapDevToolPlugin(options)
},
createEvalSourceMapDevToolPlugin () {
return new webpack.EvalSourceMapDevToolPlugin({
test: pathToRegexp(process.env.UNI_INPUT_DIR, { start: true }),
exclude,
moduleFilenameTemplate
})
}
}
+44
View File
@@ -0,0 +1,44 @@
module.exports = {
'resize-sensor': ['h5'],
ad: ['mp-weixin'],
audio: ['app-plus', 'mp-weixin', 'h5'],
button: ['app-plus', 'mp-weixin', 'h5'],
camera: ['mp-weixin'],
canvas: ['app-plus', 'mp-weixin'],
checkbox: ['app-plus', 'mp-weixin', 'h5'],
'checkbox-group': ['app-plus', 'mp-weixin', 'h5'],
'cover-image': ['app-plus', 'mp-weixin'],
'cover-view': ['app-plus', 'mp-weixin'],
editor: ['app-plus', 'mp-weixin', 'h5'],
form: ['app-plus', 'mp-weixin', 'h5'],
'functional-page-navigator': ['mp-weixin'],
icon: ['app-plus', 'mp-weixin'],
image: ['app-plus', 'mp-weixin', 'h5'],
input: ['app-plus', 'mp-weixin', 'h5'],
label: ['app-plus', 'mp-weixin', 'h5'],
'live-player': ['mp-weixin'],
'live-pusher': ['mp-weixin'],
map: ['app-plus', 'mp-weixin', 'h5'],
'movable-area': ['app-plus', 'mp-weixin'],
'movable-view': ['app-plus', 'mp-weixin'],
navigator: ['app-plus', 'mp-weixin', 'h5'],
'official-account': ['mp-weixin'],
'open-data': ['mp-weixin'],
picker: ['app-plus', 'mp-weixin', 'h5'],
'picker-view': ['app-plus', 'mp-weixin', 'h5'],
'picker-view-column': ['app-plus', 'mp-weixin', 'h5'],
progress: ['app-plus', 'mp-weixin', 'h5'],
radio: ['app-plus', 'mp-weixin', 'h5'],
'radio-group': ['app-plus', 'mp-weixin', 'h5'],
'rich-text': ['app-plus', 'mp-weixin', 'h5'],
'scroll-view': ['app-plus', 'mp-weixin', 'h5'],
slider: ['app-plus', 'mp-weixin', 'h5'],
swiper: ['app-plus', 'mp-weixin', 'h5'],
'swiper-item': ['app-plus', 'mp-weixin', 'h5'],
switch: ['app-plus', 'mp-weixin', 'h5'],
text: ['app-plus', 'mp-weixin', 'h5'],
textarea: ['app-plus', 'mp-weixin', 'h5'],
video: ['app-plus', 'mp-weixin', 'h5'],
view: ['app-plus', 'mp-weixin', 'h5'],
'web-view': ['app-plus', 'mp-weixin']
}
+73
View File
@@ -0,0 +1,73 @@
const fs = require('fs')
const path = require('path')
const { parseJson, getJson } = require('./json')
let themeConfig = {}
function parseThemeByJsonStr (jsonStr, keys, theme) {
if (jsonStr.indexOf('@') === -1) {
return jsonStr
}
keys.forEach(key => {
jsonStr = jsonStr.replace(new RegExp('@' + key, 'g'), $1 => {
return theme[key] || $1
})
})
return jsonStr
}
function hasTheme (themeLocation = 'theme.json') {
const themeJsonPath = path.join(process.env.UNI_INPUT_DIR, themeLocation)
return fs.existsSync(themeJsonPath)
}
function darkmode () {
return !!(global.uniPlugin.options || {}).darkmode
}
module.exports = {
getTheme: () => themeConfig,
darkmode,
hasTheme,
initTheme (manifestJson = {}) {
const platform = process.env.UNI_PLATFORM
const themeLocation = (manifestJson[platform] || {}).themeLocation || 'theme.json'
if (!hasTheme(themeLocation)) {
return
}
if (darkmode()) {
return
}
try {
themeConfig = Object.keys(themeConfig).length ? themeConfig : getJson(themeLocation, true)
global.uniPlugin.defaultTheme = themeConfig.light
} catch (e) {
console.error(e)
}
},
parseTheme (json, _theme) {
const theme = themeConfig[_theme] || global.uniPlugin.defaultTheme
if (!theme) {
return json
}
const keys = Object.keys(theme)
if (!keys.length) {
return json
}
if (typeof json === 'string') {
return parseThemeByJsonStr(json, keys, theme)
}
return JSON.parse(parseThemeByJsonStr(JSON.stringify(json), keys, theme))
},
copyMiniProgramThemeJson (platformOptions, vueOptions) {
const themeLocation = platformOptions.themeLocation || 'theme.json'
if (hasTheme(themeLocation)) {
platformOptions.themeLocation = themeLocation
return {
from: path.resolve(process.env.UNI_INPUT_DIR, platformOptions.themeLocation),
to: path.resolve(process.env.UNI_OUTPUT_DIR, platformOptions.themeLocation),
transform: content => JSON.stringify(parseJson(content.toString(), true))
}
}
}
}
+29
View File
@@ -0,0 +1,29 @@
if (typeof Promise !== 'undefined' && !Promise.prototype.finally) {
Promise.prototype.finally = function (callback) {
var promise = this.constructor
return this.then(function (value) {
return promise.resolve(callback()).then(function () {
return value
})
}, function (reason) {
return promise.resolve(callback()).then(function () {
throw reason
})
})
}
}
if (typeof uni !== 'undefined' && uni && uni.requireGlobal) {
const global = uni.requireGlobal()
ArrayBuffer = global.ArrayBuffer
Int8Array = global.Int8Array
Uint8Array = global.Uint8Array
Uint8ClampedArray = global.Uint8ClampedArray
Int16Array = global.Int16Array
Uint16Array = global.Uint16Array
Int32Array = global.Int32Array
Uint32Array = global.Uint32Array
Float32Array = global.Float32Array
Float64Array = global.Float64Array
BigInt64Array = global.BigInt64Array
BigUint64Array = global.BigUint64Array
}
+65
View File
@@ -0,0 +1,65 @@
const fs = require('fs')
const path = require('path')
const {
parseJson
} = require('./json')
const merge = require('./pages-json').default
function normalizeUniModulesPagesJson (pagesJson, pluginId) {
if (Array.isArray(pagesJson.pages)) {
pagesJson.pages.forEach(page => {
page.path = 'uni_modules/' + pluginId + '/' + page.path
})
}
if (Array.isArray(pagesJson.subPackages)) {
pagesJson.subPackages.forEach(subPackage => {
subPackage.root = 'uni_modules/' + pluginId + '/' + subPackage.root
})
}
return pagesJson
}
function initUniModules () {
global.uniModules = []
try {
global.uniModules = fs
.readdirSync(path.resolve(process.env.UNI_INPUT_DIR, 'uni_modules'))
.filter(module =>
fs.existsSync(
path.resolve(process.env.UNI_INPUT_DIR, 'uni_modules', module, 'package.json')
)
)
} catch (e) {}
}
module.exports = {
initUniModules,
getPagesJson (content) {
const uniModulesDir = path.resolve(process.env.UNI_INPUT_DIR, 'uni_modules')
const pluginPagesJsons = []
global.uniModules.forEach(plugin => {
const pagesJsonPath = path.resolve(uniModulesDir, plugin, 'pages.json')
if (fs.existsSync(pagesJsonPath)) {
pluginPagesJsons.push(
normalizeUniModulesPagesJson(parseJson(fs.readFileSync(pagesJsonPath).toString(), true), plugin)
)
}
})
content = content || fs.readFileSync(path.resolve(process.env.UNI_INPUT_DIR, 'pages.json'), 'utf8')
const mainPagesJson = parseJson(content, true)
if (pluginPagesJsons.length) {
const pagesJson = merge(pluginPagesJsons.concat(mainPagesJson))
if (Array.isArray(mainPagesJson.pages)) { // entry page
const entryPagePath = mainPagesJson.pages[0].path
const index = pagesJson.pages.findIndex(page => page.path === entryPagePath)
const entryPage = pagesJson.pages[index]
pagesJson.pages.splice(index, 1)
pagesJson.pages.unshift(entryPage)
}
return pagesJson
}
return mainPagesJson
}
}
+55
View File
@@ -0,0 +1,55 @@
const fileLoader = require('./file-loader.js')
const defaultOptions = {
limit: -1,
fallback: fileLoader
}
const inlineLimit =
process.env.UNI_PLATFORM === 'mp-weixin' ||
process.env.UNI_PLATFORM === 'mp-qq' ||
process.env.UNI_PLATFORM === 'mp-toutiao' ||
process.env.UNI_PLATFORM === 'mp-kuaishou' ||
process.env.UNI_PLATFORM === 'mp-lark' ||
process.env.UNI_PLATFORM === 'mp-jd' ||
process.env.UNI_PLATFORM === 'mp-xhs' ||
process.env.UNI_PLATFORM === 'app-plus' // v2需要base64,v3需要rewriteUrl
// mp-weixin,mp-qq,app-plus 非v3(即:需要base64的平台)
// 将/static/logo.png转换为~@/static/logo.png
// @import,src,background,background-image
const rewriteUrl = inlineLimit ? require('postcss-urlrewrite')({
imports: true,
properties: ['src', 'background', 'background-image'],
rules: [{
from: /^@\//,
to: '~@/'
}, {
from: /^\/([^/])/,
to: '~@/$1'
}]
}) : () => {}
module.exports = {
loader: 'url-loader',
options () {
if (process.env.UNI_PLATFORM === 'h5') {
// h5平台,不对 url-loader 作调整,默认limit:4096,也不修改file-loader输出路径(已做处理)
return {
...defaultOptions,
limit: 4096
}
}
if (inlineLimit) {
return {
...defaultOptions,
limit: process.env.UNI_USING_V3 ? -1 : 40960 // (主要用于background-image
}
}
return {
...defaultOptions
}
},
rewriteUrl
}
+255
View File
@@ -0,0 +1,255 @@
const path = require('path')
const fs = require('fs')
const hash = require('hash-sum')
const crypto = require('crypto')
const escapeStringRegexp = require('escape-string-regexp')
const escapeGlob = require('glob-escape')
const webpack = require('webpack')
const uniI18n = require('@dcloudio/uni-cli-i18n')
const isWin = /^win/.test(process.platform)
const normalizePath = path => (isWin ? path.replace(/\\/g, '/') : path)
let aboutPkg
try {
aboutPkg = require(path.resolve(__dirname, '../../../../../about/package.json'))
} catch (e) {}
const isInHBuilderX = !!aboutPkg
const isInHBuilderXAlpha = !!(isInHBuilderX && aboutPkg.alpha)
function getCLIContext () {
var context = path.resolve(__dirname, '../../../../')
// const isInHBuilderX = fs.existsSync(path.resolve(context, 'bin/uniapp-cli.js'))
if (isInHBuilderX) {
return context
}
const pnpmFind = __dirname.match(/.+?[/\\].pnpm[/\\]/)
if (pnpmFind) {
const pnpm = pnpmFind[0]
context = path.resolve(pnpm, '../../')
}
const isInCLI = fs.existsSync(path.resolve(context, './src'))
if (isInCLI) {
return context
}
return process.cwd()
}
function removeExt (str, ext) {
if (ext) {
const reg = new RegExp(ext.replace(/\./, '\\.') + '$')
return normalizePath(str.replace(reg, ''))
}
return normalizePath(str.replace(/\.\w+$/g, ''))
}
function hashify (filepath) {
const relativePath = removeExt(path.relative(process.env.UNI_INPUT_DIR, filepath))
return hash(relativePath)
}
function md5 (str) {
const hash = crypto.createHash('md5')
hash.update(str)
return hash.digest('hex')
}
function cached (fn) {
const cache = Object.create(null)
return function cachedFn (str) {
const hit = cache[str]
return hit || (cache[str] = fn(str))
}
}
const camelizeRE = /-(\w)/g
const camelize = cached((str) => {
return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '')
})
function capitalize (str) {
return str.charAt(0).toUpperCase() + str.slice(1)
}
const hyphenateRE = /\B([A-Z])/g
const hyphenate = cached((str) => {
return str.replace(hyphenateRE, '-$1').toLowerCase()
})
const REGEX_PX = /(:|\s|\(|\/)[+-]?\d+(\.\d+)?u?px/g
const REGEX_UPX = /(:|\s|\(|\/)[+-]?\d+(\.\d+)?upx/g
function convertStaticStyle (styleStr) {
if (typeof styleStr === 'string') {
let matches = styleStr.match(REGEX_UPX)
if (matches && matches.length) {
matches.forEach(function (match) {
styleStr = styleStr.replace(match, match.substr(0, match.length - 3) + 'rpx')
})
}
// TODO 不应该再支持 px 转 rpx
if (process.UNI_TRANSFORM_PX) { // 需要转换 px
matches = styleStr.match(REGEX_PX)
if (matches && matches.length) {
matches.forEach(function (match) {
styleStr = styleStr.replace(match, match.substr(0, match.length - 2) + 'rpx')
})
}
}
}
return styleStr
}
function hasModule (name) {
try {
return !!require.resolve(name)
} catch (e) {}
return false
}
const NODE_MODULES_REGEX = /(\.\.\/)?node_modules/g
function normalizeNodeModules (str) {
str = normalizePath(str).replace(NODE_MODULES_REGEX, 'node-modules')
// HBuilderX 内置模块路径转换
str = str.replace(/.*\/plugins\/uniapp-cli\/node[-_]modules/, 'node-modules')
if (process.env.UNI_PLATFORM === 'mp-alipay') {
str = str.replace('node-modules/@', 'node-modules/npm-scope-')
}
return str
}
const _hasOwnProperty = Object.prototype.hasOwnProperty
/**
* pathToRegexp
* @param {string} pathString
* @param {{start:?boolean,end:?boolean,global:?boolean}?} options
* @returns {RegExp}
*/
function pathToRegexp (pathString, options = {}) {
return new RegExp((options.start ? '^' : '') + escapeStringRegexp(pathString) + (options.end ? '$' : ''), 'i' + (options.global ? 'g' : ''))
}
/**
* pathToGlob
* @param {string} pathString
* @param {string} glob
* @param {{windows:?boolean,escape:?boolean}?} options
* @returns {string}
*/
function pathToGlob (pathString, glob, options = {}) {
const isWindows = 'windows' in options ? options.windows : /^win/.test(process.platform)
const useEscape = options.escape
const str = isWindows ? pathString.replace(/\\/g, '/') : pathString
let safeStr = escapeGlob(str)
if (isWindows || !useEscape) {
safeStr = safeStr.replace(/\\(.)/g, '[$1]')
}
return path.posix.join(safeStr, glob)
}
/**
* 字节跳动小程序可以配置 ext:// 开头的插件页面模板,如 ext://microapp-trade-plugin/order-confirm
* @param pagePath
* @returns
*/
function isNormalPage (pagePath) {
return !pagePath.startsWith('ext://')
}
function createSource (content) {
return webpack.version[0] > 4 ? new webpack.sources.RawSource(content) : {
size () {
return Buffer.byteLength(content, 'utf8')
},
source () {
return content
}
}
}
function deleteAsset (compilation, name) {
if ('deleteAsset' in compilation) {
compilation.deleteAsset(name)
} else {
delete compilation.assets[name]
}
}
/**
* cli 项目增加运行方式提示 https://ask.dcloud.net.cn/question/165071
* App 端存在多次编译问题(vue 2 nvue 3),故做防抖处理
* @param delay
* @returns
*/
let runPromptTimer = null
function showRunPrompt (delay = 300) {
if (runPromptTimer) {
clearTimeout(runPromptTimer)
}
runPromptTimer = setTimeout(() => {
const { runByHBuilderX } = require('./platform')
if (!runByHBuilderX) {
const chalk = require('chalk')
const outputDir = path.relative(
process.env.UNI_CLI_CONTEXT,
process.env.UNI_OUTPUT_DIR
)
const platform = process.env.UNI_PLATFORM.startsWith('quickapp-webview') && process.env.UNI_SUB_PLATFORM ? process.env.UNI_SUB_PLATFORM : process.env.UNI_PLATFORM
console.log(uniI18n.__('prompt.run.message', {
devtools: uniI18n.__(`prompt.run.devtools.${platform}`),
outputDir: chalk.cyan(outputDir)
}))
}
runPromptTimer = null
}, delay)
}
module.exports = {
isNormalPage,
isInHBuilderX,
isInHBuilderXAlpha,
getCLIContext,
normalizeNodeModules,
md5,
hasOwn (obj, key) {
return _hasOwnProperty.call(obj, key)
},
hasModule,
parseStyle (style = {}) {
Object.keys(style).forEach(name => {
if (global.uniPlugin.platforms.includes(name)) {
if (name === process.env.UNI_PLATFORM) {
Object.assign(style, style[name] || {})
}
delete style[name]
}
})
return style
},
hashify,
removeExt,
camelize,
capitalize,
hyphenate,
normalizePath,
convertStaticStyle,
pathToRegexp,
pathToGlob,
getComponentName: cached((str) => {
if (str.indexOf('wx-') === 0) {
return str.replace('wx-', 'weixin-')
}
return str
}),
getTemplatePath () {
return path.join(__dirname, '../template')
},
createSource,
deleteAsset,
showRunPrompt
}
+154
View File
@@ -0,0 +1,154 @@
const reservedWords =
'break case class catch const continue debugger default delete do else export extends finally for function if import in instanceof let new return super switch this throw try typeof var void while with yield enum await implements package protected static interface private public'
const builtins =
'arguments Infinity NaN undefined null true false eval uneval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Symbol Error EvalError InternalError RangeError ReferenceError SyntaxError TypeError URIError Number Math Date String RegExp Array Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array Map Set WeakMap WeakSet SIMD ArrayBuffer DataView JSON Promise Generator GeneratorFunction Reflect Proxy Intl'
const forbiddenIdentifiers = new Set(`${reservedWords} ${builtins}`.split(' '))
forbiddenIdentifiers.add('')
const makeLegalIdentifier = function makeLegalIdentifier (str) {
let identifier = str
.replace(/-(\w)/g, (_, letter) => letter.toUpperCase())
.replace(/[^$_a-zA-Z0-9]/g, '_')
if (/\d/.test(identifier[0]) || forbiddenIdentifiers.has(identifier)) {
identifier = `_${identifier}`
}
return identifier || '_'
}
function stringify (obj) {
return (JSON.stringify(obj) || 'undefined').replace(/[\u2028\u2029]/g, (char) =>
`\\u${`000${char.charCodeAt(0).toString(16)}`.slice(-4)}`)
}
function serializeArray (arr, indent, baseIndent) {
let output = '['
const separator = indent ? `\n${baseIndent}${indent}` : ''
for (let i = 0; i < arr.length; i++) {
const key = arr[i]
output += `${i > 0 ? ',' : ''}${separator}${serialize(key, indent, baseIndent + indent)}`
}
return `${output}${indent ? `\n${baseIndent}` : ''}]`
}
function serializeObject (obj, indent, baseIndent) {
let output = '{'
const separator = indent ? `\n${baseIndent}${indent}` : ''
const entries = Object.entries(obj)
for (let i = 0; i < entries.length; i++) {
const [key, value] = entries[i]
const stringKey = makeLegalIdentifier(key) === key ? key : stringify(key)
output +=
`${i > 0 ? ',' : ''}${separator}${stringKey}:${indent ? ' ' : ''}${serialize(value, indent, baseIndent + indent)}`
}
return `${output}${indent ? `\n${baseIndent}` : ''}}`
}
function serialize (obj, indent, baseIndent) {
if (typeof obj === 'object' && obj !== null) {
if (Array.isArray(obj)) {
return serializeArray(obj, indent, baseIndent)
}
if (obj instanceof Date) {
return `new Date(${obj.getTime()})`
}
if (obj instanceof RegExp) {
return obj.toString()
}
return serializeObject(obj, indent, baseIndent)
}
if (typeof obj === 'number') {
if (obj === Infinity) {
return 'Infinity'
}
if (obj === -Infinity) {
return '-Infinity'
}
if (obj === 0) {
return 1 / obj === Infinity ? '0' : '-0'
}
if (isNaN(obj)) {
return 'NaN'
}
}
if (typeof obj === 'symbol') {
const key = Symbol.keyFor(obj)
// eslint-disable-next-line no-undefined
if (key !== undefined) {
return `Symbol.for(${stringify(key)})`
}
}
if (typeof obj === 'bigint') {
return `${obj}n`
}
return stringify(obj)
}
// isWellFormed exists from Node.js 20
const hasStringIsWellFormed = 'isWellFormed' in String.prototype
function isWellFormedString (input) {
// @ts-expect-error String::isWellFormed exists from ES2024. tsconfig lib is set to ES6
if (hasStringIsWellFormed) {
return input.isWellFormed()
}
// https://github.com/tc39/proposal-is-usv-string/blob/main/README.md#algorithm
return !/\p{Surrogate}/u.test(input)
}
function dataToEsm (data, options = {}) {
var _a, _b
const t = options.compact ? '' : 'indent' in options ? options.indent : '\t'
const _ = options.compact ? '' : ' '
const n = options.compact ? '' : '\n'
const declarationType = options.preferConst ? 'const' : 'var'
if (options.namedExports === false ||
typeof data !== 'object' ||
Array.isArray(data) ||
data instanceof Date ||
data instanceof RegExp ||
data === null) {
const code = serialize(data, options.compact ? null : t, '')
const magic = _ || (/^[{[\-\/]/.test(code) ? '' : ' ') // eslint-disable-line no-useless-escape
return `export default${magic}${code};`
}
let maxUnderbarPrefixLength = 0
for (const key of Object.keys(data)) {
const underbarPrefixLength = (_b = (_a = key.match(/^(_+)/)) === null || _a === undefined ? undefined : _a[0]
.length) !==
null && _b !== undefined ? _b : 0
if (underbarPrefixLength > maxUnderbarPrefixLength) {
maxUnderbarPrefixLength = underbarPrefixLength
}
}
const arbitraryNamePrefix = `${'_'.repeat(maxUnderbarPrefixLength + 1)}arbitrary`
let namedExportCode = ''
const defaultExportRows = []
const arbitraryNameExportRows = []
for (const [key, value] of Object.entries(data)) {
if (key === makeLegalIdentifier(key)) {
if (options.objectShorthand) {
defaultExportRows.push(key)
} else {
defaultExportRows.push(`${key}:${_}${key}`)
}
namedExportCode +=
`export ${declarationType} ${key}${_}=${_}${serialize(value, options.compact ? null : t, '')};${n}`
} else {
defaultExportRows.push(`${stringify(key)}:${_}${serialize(value, options.compact ? null : t, '')}`)
if (options.includeArbitraryNames && isWellFormedString(key)) {
const variableName = `${arbitraryNamePrefix}${arbitraryNameExportRows.length}`
namedExportCode +=
`${declarationType} ${variableName}${_}=${_}${serialize(value, options.compact ? null : t, '')};${n}`
arbitraryNameExportRows.push(`${variableName} as ${JSON.stringify(key)}`)
}
}
}
const arbitraryExportCode = arbitraryNameExportRows.length > 0
? `export${_}{${n}${t}${arbitraryNameExportRows.join(`,${n}${t}`)}${n}};${n}`
: ''
const defaultExportCode = `export default${_}{${n}${t}${defaultExportRows.join(`,${n}${t}`)}${n}};${n}`
return `${namedExportCode}${arbitraryExportCode}${defaultExportCode}`
};
module.exports = {
dataToEsm
}
+8
View File
@@ -0,0 +1,8 @@
const {
isInHBuilderX
} = require('../util')
module.exports = {
isInHBuilderX () {
return isInHBuilderX
}
}
+5
View File
@@ -0,0 +1,5 @@
const UTSResolverPlugin = require('./resolver')
const uts = require('./uts')
module.exports = Object.assign({
UTSResolverPlugin
}, uts)
+29
View File
@@ -0,0 +1,29 @@
const path = require('path')
const {
resolveUTSModule
} = require('./uts')
class UTSResolverPlugin {
apply (resolver) {
resolver.hooks.resolve.tapAsync('UTSResolverPlugin', (request, resolveContext, callback) => {
let utsModulePath = ''
if (request.request.startsWith('@/uni_modules/')) {
utsModulePath = path.resolve(process.env.UNI_INPUT_DIR, request.request.replace('@/', ''))
} else if (request.request.includes('uni_modules')) {
utsModulePath = path.resolve(request.path, request.request)
}
if (utsModulePath) {
const utsModule = resolveUTSModule(utsModulePath)
if (utsModule) {
if (process.env.UNI_PLATFORM === 'app-plus') {
request.request = utsModule + '/package.json?uts-proxy'
} else {
request.request = utsModule
}
}
}
callback()
})
}
}
module.exports = UTSResolverPlugin
+279
View File
@@ -0,0 +1,279 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseUTSModuleDeps = exports.capitalize = exports.camelize = exports.parseInjects = exports.parseUniExtApi = exports.parseUniExtApis = exports.getUniExtApiProviderRegisters = exports.formatExtApiProviderName = exports.getUniExtApiPlugins = exports.getUniExtApiProviders = void 0;
// 重要:此文件编译后的js,需同步至 vue2 编译器中 uni-cli-shared/lib/uts/uni_modules.js
const path_1 = __importDefault(require("path"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const extApiProviders = [];
const extApiPlugins = new Set();
function getUniExtApiProviders() {
return extApiProviders;
}
exports.getUniExtApiProviders = getUniExtApiProviders;
function getUniExtApiPlugins() {
return [...extApiPlugins].map((plugin) => {
return { plugin };
});
}
exports.getUniExtApiPlugins = getUniExtApiPlugins;
function formatExtApiProviderName(service, name) {
if (service === 'oauth') {
service = 'OAuth';
}
return `Uni${(0, exports.capitalize)((0, exports.camelize)(service))}${(0, exports.capitalize)((0, exports.camelize)(name))}ProviderImpl`;
}
exports.formatExtApiProviderName = formatExtApiProviderName;
function getUniExtApiProviderRegisters() {
const result = [];
extApiProviders.forEach((provider) => {
if (provider.name && provider.service) {
result.push({
name: provider.name,
plugin: provider.plugin,
service: provider.service,
class: `uts.sdk.modules.${(0, exports.camelize)(provider.plugin)}.${formatExtApiProviderName(provider.service, provider.name)}`,
});
}
});
return result;
}
exports.getUniExtApiProviderRegisters = getUniExtApiProviderRegisters;
function parseUniExtApis(vite = true, platform, language = 'javascript') {
if (!process.env.UNI_INPUT_DIR) {
return {};
}
const uniModulesDir = path_1.default.resolve(process.env.UNI_INPUT_DIR, 'uni_modules');
if (!fs_extra_1.default.existsSync(uniModulesDir)) {
return {};
}
const injects = {};
extApiProviders.length = 0;
extApiPlugins.clear();
fs_extra_1.default.readdirSync(uniModulesDir).forEach((uniModuleDir) => {
// 必须以 uni- 开头
if (!uniModuleDir.startsWith('uni-')) {
return;
}
const uniModuleRootDir = path_1.default.resolve(uniModulesDir, uniModuleDir);
const pkgPath = path_1.default.resolve(uniModuleRootDir, 'package.json');
if (!fs_extra_1.default.existsSync(pkgPath)) {
return;
}
try {
let exports;
const pkg = JSON.parse(fs_extra_1.default.readFileSync(pkgPath, 'utf8'));
if (pkg && pkg.uni_modules && pkg.uni_modules['uni-ext-api']) {
exports = pkg.uni_modules['uni-ext-api'];
}
if (exports) {
const provider = exports.provider;
if (provider && provider.service) {
provider.plugin = uniModuleDir;
extApiProviders.push(provider);
}
extApiPlugins.add(uniModuleDir);
const curInjects = parseInjects(vite, platform, language, `@/uni_modules/${uniModuleDir}`, uniModuleRootDir, exports);
Object.assign(injects, curInjects);
}
}
catch (e) { }
});
return injects;
}
exports.parseUniExtApis = parseUniExtApis;
function parseUniExtApi(pluginDir, pluginId, vite = true, platform, language = 'javascript') {
const pkgPath = path_1.default.resolve(pluginDir, 'package.json');
if (!fs_extra_1.default.existsSync(pkgPath)) {
return;
}
let exports;
const pkg = JSON.parse(fs_extra_1.default.readFileSync(pkgPath, 'utf8'));
if (pkg && pkg.uni_modules && pkg.uni_modules['uni-ext-api']) {
exports = pkg.uni_modules['uni-ext-api'];
}
if (exports) {
return parseInjects(vite, platform, language, `@/uni_modules/${pluginId}`, pluginDir, exports);
}
}
exports.parseUniExtApi = parseUniExtApi;
/**
* uni:'getBatteryInfo'
* import getBatteryInfo from '..'
*
* uni:['getBatteryInfo']
* import { getBatteryInfo } from '..'
*
* uni:['openLocation','chooseLocation']
* import { openLocation, chooseLocation } from '..'
*
* uni:{
* onUserCaptureScreen: "onCaptureScreen"
* offUserCaptureScreen: "offCaptureScreen"
* }
*
* uni.getBatteryInfo = getBatteryInfo
* @param source
* @param globalObject
* @param define
* @returns
*/
function parseInjects(vite = true, platform, language, source, uniModuleRootDir, exports = {}) {
if (platform === 'app-plus') {
platform = 'app';
}
let rootDefines = {};
Object.keys(exports).forEach((name) => {
if (name.startsWith('uni')) {
rootDefines[name] = exports[name];
}
});
const injects = {};
if (Object.keys(rootDefines).length) {
const platformIndexFileName = path_1.default.resolve(uniModuleRootDir, 'utssdk', platform);
const rootIndexFileName = path_1.default.resolve(uniModuleRootDir, 'utssdk', 'index.uts');
let hasPlatformFile = uniModuleRootDir
? fs_extra_1.default.existsSync(rootIndexFileName) || fs_extra_1.default.existsSync(platformIndexFileName)
: true;
if (!hasPlatformFile) {
if (platform === 'app') {
hasPlatformFile =
fs_extra_1.default.existsSync(path_1.default.resolve(uniModuleRootDir, 'utssdk', 'app-android')) ||
fs_extra_1.default.existsSync(path_1.default.resolve(uniModuleRootDir, 'utssdk', 'app-ios')) ||
fs_extra_1.default.existsSync(path_1.default.resolve(uniModuleRootDir, 'utssdk', 'app-harmony'));
}
}
// 其他平台修改source,直接指向目标文件,否则 uts2js 找不到类型信息
if (platform !== 'app' &&
platform !== 'app-android' &&
platform !== 'app-ios' &&
platform !== 'app-harmony') {
if (fs_extra_1.default.existsSync(platformIndexFileName)) {
source = `${source}/utssdk/${platform}/index.uts`;
}
else if (fs_extra_1.default.existsSync(rootIndexFileName)) {
source = `${source}/utssdk/index.uts`;
}
}
else if (process.env.UNI_APP_X_UVUE_SCRIPT_ENGINE === 'js') {
if (fs_extra_1.default.existsSync(path_1.default.resolve(uniModuleRootDir, 'utssdk', 'app-js', 'index.uts'))) {
source = `${source}/utssdk/app-js/index.uts`;
}
}
for (const key in rootDefines) {
Object.assign(injects, parseInject(vite, platform, language, source, 'uni', rootDefines[key], hasPlatformFile));
}
}
return injects;
}
exports.parseInjects = parseInjects;
function parseInject(vite = true, platform, language, source, globalObject, define, hasPlatformFile) {
const injects = {};
if (define === false) {
}
else if (typeof define === 'string') {
// {'uni.getBatteryInfo' : '@dcloudio/uni-getbatteryinfo'}
if (hasPlatformFile) {
injects[globalObject + '.' + define] = vite ? source : [source, 'default'];
}
}
else if (Array.isArray(define)) {
// {'uni.getBatteryInfo' : ['@dcloudio/uni-getbatteryinfo','getBatteryInfo]}
if (hasPlatformFile) {
define.forEach((d) => {
injects[globalObject + '.' + d] = [source, d];
});
}
}
else {
const keys = Object.keys(define);
keys.forEach((d) => {
if (typeof define[d] === 'string') {
if (hasPlatformFile) {
injects[globalObject + '.' + d] = [source, define[d]];
}
}
else {
const defineOptions = define[d];
const p = platform === 'app-android' ||
platform === 'app-ios' ||
platform === 'app-harmony'
? 'app'
: platform;
if (!(p in defineOptions)) {
if (hasPlatformFile) {
injects[globalObject + '.' + d] = [source, defineOptions.name || d];
}
}
else {
if (defineOptions[p] !== false) {
if (p === 'app') {
const appOptions = defineOptions.app;
if (isPlainObject(appOptions)) {
// js engine 下且存在 app-js,不检查
const skipCheck = process.env.UNI_APP_X_UVUE_SCRIPT_ENGINE === 'js' &&
source.includes('app-js');
if (!skipCheck) {
const targetLanguage = language === 'javascript' ? 'js' : language;
if (targetLanguage && appOptions[targetLanguage] === false) {
return;
}
}
}
injects[globalObject + '.' + d] = [
source,
defineOptions.name || d,
defineOptions.app,
];
}
else {
injects[globalObject + '.' + d] = [
source,
defineOptions.name || d,
];
}
}
}
}
});
}
return injects;
}
const objectToString = Object.prototype.toString;
const toTypeString = (value) => objectToString.call(value);
function isPlainObject(val) {
return toTypeString(val) === '[object Object]';
}
const cacheStringFunction = (fn) => {
const cache = Object.create(null);
return ((str) => {
const hit = cache[str];
return hit || (cache[str] = fn(str));
});
};
const camelizeRE = /-(\w)/g;
/**
* @private
*/
exports.camelize = cacheStringFunction((str) => {
return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ''));
});
/**
* @private
*/
exports.capitalize = cacheStringFunction((str) => str.charAt(0).toUpperCase() + str.slice(1));
/**
* 解析 UTS 类型的模块依赖列表
* @param deps
* @param inputDir
* @returns
*/
function parseUTSModuleDeps(deps, inputDir) {
const modulesDir = path_1.default.resolve(inputDir, 'uni_modules');
return deps.filter((dep) => {
return fs_extra_1.default.existsSync(path_1.default.resolve(modulesDir, dep, 'utssdk'));
});
}
exports.parseUTSModuleDeps = parseUTSModuleDeps;
+43
View File
@@ -0,0 +1,43 @@
const fs = require('fs')
const path = require('path')
const {
normalizePath,
camelize,
capitalize
} = require('../util')
function hasProjectYarn (cwd) {
return fs.existsSync(path.join(cwd, 'yarn.lock'))
}
function hasProjectPnpm (cwd) {
return fs.existsSync(path.join(cwd, 'pnpm-lock.yaml'))
}
function getInstallCommand (cwd) {
return hasProjectYarn(cwd)
? 'yarn add'
: hasProjectPnpm(cwd)
? 'pnpm i'
: 'npm i'
}
function installDepTips (
type,
module,
version
) {
const command =
`${getInstallCommand(process.cwd())} ${module + (version ? '@' + version : '')}${type === 'devDependencies' ? ' -D' : ''}`
return `Cannot find module: ${module}
Please run \`${command}\` and try again.`
}
module.exports = {
version: require('../../package.json').version,
normalizePath,
installDepTips,
camelize,
capitalize,
isArray: Array.isArray
}
+205
View File
@@ -0,0 +1,205 @@
const path = require('path')
const {
resolveUTSCompiler,
parseUniExtApiNamespacesOnce
} = require('./uts')
const {
parseUTSModuleDeps
} = require('./uni_modules')
const {
dataToEsm
} = require('./dataToEsm')
const {
getUniXKotlinCompiler,
getUniXSwiftCompiler,
getChangedFiles,
getUTSPlugins
} = require('./uts-webpack-plugin')
function createUniModulesSyncFilePreprocessor (
platform,
utsPlatform
) {
const initPreprocessContext = require('../preprocess')
const {
vueContext: preContext
} = initPreprocessContext(
platform,
global.uniPlugin.platforms
)
if (utsPlatform === 'app-android') {
preContext.APP_ANDROID = true
}
if (utsPlatform === 'app-ios') {
preContext.APP_IOS = true
}
const {
preprocess
} = require('@dcloudio/vue-cli-plugin-uni/packages/webpack-preprocess-loader/preprocess/lib/preprocess')
function preJs (jsCode) {
return preprocess(jsCode, preContext, {
type: 'js'
})
}
function preHtml (htmlCode) {
return preprocess(htmlCode, preContext, {
type: 'html'
})
}
return async (content, fileName) => {
const extname = path.extname(fileName)
if (extname === '.json') {
return dataToEsm(JSON.parse(preJs(content)), {
namedExports: true,
preferConst: true
})
} else if (extname === '.uts' || extname === '.ts') {
return preJs(content)
} else if (extname === '.uvue' || extname === '.vue') {
return preJs(preHtml(content))
}
return content
}
}
function once (fn, ctx = null) {
let res
return (...args) => {
if (fn) {
res = fn.apply(ctx, args)
fn = null
}
return res
}
}
const createAppAndroidUniModulesSyncFilePreprocessorOnce = once(
() => {
return createUniModulesSyncFilePreprocessor('app', 'app-android')
}
)
const createAppIosUniModulesSyncFilePreprocessorOnce = once(
() => {
return createUniModulesSyncFilePreprocessor('app', 'app-ios')
}
)
module.exports = async function (content) {
const callback = this.async()
const uniXKotlinCompiler = getUniXKotlinCompiler()
const uniXSwiftCompiler = getUniXSwiftCompiler()
const {
syncUniModuleFilesByCompiler,
resolveTscUniModuleIndexFileName
} = resolveUTSCompiler()
const compilePlugin = async (pluginDir) => {
const pluginId = path.basename(pluginDir)
const utsPlugins = getUTSPlugins()
const changedFiles = getChangedFiles()
if (uniXKotlinCompiler) {
await uniXKotlinCompiler.init()
await syncUniModuleFilesByCompiler(
'app-android',
uniXKotlinCompiler,
pluginDir,
createAppAndroidUniModulesSyncFilePreprocessorOnce()
)
}
if (uniXSwiftCompiler) {
await uniXSwiftCompiler.init()
await syncUniModuleFilesByCompiler(
'app-ios',
uniXSwiftCompiler,
pluginDir,
createAppIosUniModulesSyncFilePreprocessorOnce()
)
}
if (!utsPlugins.has(pluginId)) {
utsPlugins.add(pluginId)
if (uniXKotlinCompiler) {
const indexFileName = resolveTscUniModuleIndexFileName(
'app-android',
pluginDir
)
if (indexFileName) {
await uniXKotlinCompiler.addRootFile(indexFileName)
}
}
if (uniXSwiftCompiler) {
const indexFileName = resolveTscUniModuleIndexFileName(
'app-ios',
pluginDir
)
if (indexFileName) {
await uniXSwiftCompiler.addRootFile(indexFileName)
}
}
}
// 处理uni_modules中的文件变更
const files = changedFiles.get(pluginId)
if (files) {
// 仅限watch模式是会生效
changedFiles.delete(pluginId)
if (uniXKotlinCompiler) {
await uniXKotlinCompiler.invalidate(files)
}
if (uniXSwiftCompiler) {
await uniXSwiftCompiler.invalidate(files)
}
}
const pkgJson = require(path.join(pluginDir, 'package.json'))
const compiler = resolveUTSCompiler()
// 处理依赖的 uts 插件
const deps = parseUTSModuleDeps(
pkgJson.uni_modules?.dependencies || [],
process.env.UNI_INPUT_DIR
)
if (deps.length) {
for (const dep of deps) {
await compilePlugin(
path.resolve(process.env.UNI_INPUT_DIR, 'uni_modules', dep)
)
}
}
return compiler.compile(pluginDir, {
isX: false,
isPlugin: true,
extApis: parseUniExtApiNamespacesOnce(
process.env.UNI_UTS_PLATFORM,
process.env.UNI_UTS_TARGET_LANGUAGE
),
sourceMap: process.env.NODE_ENV === 'development',
uni_modules: deps
// 暂不提供
// async kotlinAutoImports() {}
// async swiftAutoImports() {}
})
}
const pluginDir = path.dirname(this.resourcePath)
compilePlugin(pluginDir).then(result => {
if (result) {
result.deps.forEach((dep) => {
this.addDependency(dep)
})
callback(null, result.code)
} else {
callback(null, '')
}
}).catch(err => {
callback(err)
})
}
+138
View File
@@ -0,0 +1,138 @@
const path = require('path')
const fs = require('fs-extra')
const {
resolveUTSCompiler
} = require('./uts')
const {
normalizePath
} = require('../util')
const {
runByHBuilderX
} = require('../platform')
class WebpackUTSPlugin {
apply (compiler) {
compiler.hooks.watchRun.tapAsync('WatchRun', (comp, done) => {
let changedFileNames = []
if (comp.modifiedFiles) { // webpack5
changedFileNames = Array.from(comp.modifiedFiles)
} else if (comp.watchFileSystem?.watcher?.mtimes) { // webpack4
changedFileNames = Object.keys(comp.watchFileSystem.watcher.mtimes)
}
if (changedFileNames.length) {
// console.log('====================================')
// console.log('NEW BUILD FILES CHANGED:', changedFileNames)
// console.log('====================================')
const uniModulesDir = normalizePath(path.resolve(process.env.UNI_INPUT_DIR, 'uni_modules'))
changedFileNames.forEach(fileName => {
fileName = normalizePath(fileName)
if (fileName.startsWith(uniModulesDir)) {
// 仅处理uni_modules中的文件
const plugin = fileName.slice(uniModulesDir.length + 1).split('/')[0]
if (utsPlugins.has(plugin)) {
const changeFile = {
fileName,
event: 'update' // 写死 update
}
if (!changedFiles.has(plugin)) {
changedFiles.set(plugin, [changeFile])
} else {
changedFiles.get(plugin).push(changeFile)
}
}
}
})
}
return done()
})
compiler.hooks.done.tapPromise('webpack-uts-done', async () => {
if (process.env.NODE_ENV !== 'development') {
if (uniXKotlinCompiler) {
await uniXKotlinCompiler.close()
}
if (uniXSwiftCompiler) {
await uniXSwiftCompiler.close()
}
}
})
}
}
let uniXKotlinCompiler = null
let uniXSwiftCompiler = null
const utsPlugins = new Set()
const changedFiles = new Map()
function getUTSPlugins () {
return utsPlugins
}
function getChangedFiles () {
return changedFiles
}
function getUniXKotlinCompiler () {
if (uniXKotlinCompiler) {
return uniXKotlinCompiler
}
const {
createUniXKotlinCompilerOnce
} = resolveUTSCompiler()
uniXKotlinCompiler = runByHBuilderX && process.env.UNI_APP_X_TSC === 'true' &&
(process.env.UNI_UTS_PLATFORM === 'app-android' ||
process.env.UNI_UTS_PLATFORM === 'app' ||
process.env.UNI_UTS_PLATFORM === 'app-plus')
? createUniXKotlinCompilerOnce()
: null
if (uniXKotlinCompiler) {
const tscDir = path.resolve(process.env.UNI_OUTPUT_DIR, '../.tsc/app-android')
const uvueDir = path.resolve(process.env.UNI_OUTPUT_DIR, '../.uvue/app-android')
try {
if (fs.existsSync(tscDir)) {
fs.emptyDirSync(tscDir)
}
if (fs.existsSync(uvueDir)) {
fs.emptyDirSync(uvueDir)
}
} catch (e) {}
}
return uniXKotlinCompiler
}
function getUniXSwiftCompiler () {
if (uniXSwiftCompiler) {
return uniXSwiftCompiler
}
const {
createUniXSwiftCompilerOnce
} = resolveUTSCompiler()
uniXSwiftCompiler =
runByHBuilderX && process.env.UNI_APP_X_TSC === 'true' &&
(process.env.UNI_UTS_PLATFORM === 'app-ios' ||
process.env.UNI_UTS_PLATFORM === 'app' ||
process.env.UNI_UTS_PLATFORM === 'app-plus')
? createUniXSwiftCompilerOnce()
: null
if (uniXSwiftCompiler) {
const tscDir = path.resolve(process.env.UNI_OUTPUT_DIR, '../.tsc/app-ios')
const uvueDir = path.resolve(process.env.UNI_OUTPUT_DIR, '../.uvue/app-ios')
try {
if (fs.existsSync(tscDir)) {
fs.emptyDirSync(tscDir)
}
if (fs.existsSync(uvueDir)) {
fs.emptyDirSync(uvueDir)
}
} catch (e) {}
}
return uniXSwiftCompiler
}
module.exports = {
getUTSPlugins,
getChangedFiles,
getUniXKotlinCompiler,
getUniXSwiftCompiler,
WebpackUTSPlugin
}
+464
View File
@@ -0,0 +1,464 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.isUniHelpers = exports.isUTSProxy = exports.tscOutDir = exports.uvueOutDir = exports.genUniExtApiDeclarationFileOnce = exports.initUTSSwiftAutoImportsOnce = exports.initUTSKotlinAutoImportsOnce = exports.resolveUniTypeScript = exports.parseUniExtApiNamespacesJsOnce = exports.parseUniExtApiNamespacesOnce = exports.parseSwiftPackageWithPluginId = exports.parseKotlinPackageWithPluginId = exports.initUTSComponents = exports.parseUTSComponent = exports.getUTSComponentAutoImports = exports.isUTSComponent = exports.resolveUTSCompilerVersion = exports.resolveUTSCompiler = exports.resolveUTSModule = exports.resolveUTSAppModule = void 0;
// 重要,该文件编译后的 js 需要同步到 vue2 编译器 uni-cli-shared/lib/uts
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_1 = __importDefault(require("path"));
const fast_glob_1 = __importDefault(require("fast-glob"));
const hbx_1 = require("./hbx");
const utils_1 = require("./utils");
const uni_modules_1 = require("./uni_modules");
function once(fn, ctx = null) {
let res;
return ((...args) => {
if (fn) {
res = fn.apply(ctx, args);
fn = null;
}
return res;
});
}
/**
* 解析 app 平台的 uts 插件,任意平台(android|ios)存在即可
* @param id
* @param importer
* @returns
*/
function resolveUTSAppModule(platform, id, importer, includeUTSSDK = true) {
id = path_1.default.resolve(importer, id);
if (id.includes('uni_modules') || (includeUTSSDK && id.includes('utssdk'))) {
const parts = (0, utils_1.normalizePath)(id).split('/');
const parentDir = parts[parts.length - 2];
if (parentDir === 'uni_modules' ||
(includeUTSSDK && parentDir === 'utssdk')) {
const basedir = parentDir === 'uni_modules' ? 'utssdk' : '';
if (process.env.UNI_APP_X_UVUE_SCRIPT_ENGINE === 'js') {
// js engine
if (parentDir === 'uni_modules') {
const appJsIndex = path_1.default.resolve(id, basedir, 'app-js', 'index.uts');
if (fs_extra_1.default.existsSync(appJsIndex)) {
return appJsIndex;
}
}
}
if (fs_extra_1.default.existsSync(path_1.default.resolve(id, basedir, 'index.uts'))) {
return id;
}
const fileName = id.split('?')[0];
const resolvePlatformDir = (p) => {
return path_1.default.resolve(fileName, basedir, p);
};
const extname = ['.uts', '.vue', '.uvue'];
if (platform === 'app-harmony') {
if (resolveUTSFile(resolvePlatformDir(platform), extname)) {
return id;
}
return;
}
if (resolveUTSFile(resolvePlatformDir('app-android'), extname)) {
return id;
}
if (resolveUTSFile(resolvePlatformDir('app-ios'), extname)) {
return id;
}
}
}
}
exports.resolveUTSAppModule = resolveUTSAppModule;
// 仅限 root/uni_modules/test-plugin | root/utssdk/test-plugin 格式
function resolveUTSModule(id, importer, includeUTSSDK = true) {
if (process.env.UNI_PLATFORM === 'app' ||
process.env.UNI_PLATFORM === 'app-plus' ||
process.env.UNI_PLATFORM === 'app-harmony') {
return resolveUTSAppModule(process.env.UNI_UTS_PLATFORM, id, importer);
}
id = path_1.default.resolve(importer, id);
if (id.includes('uni_modules') || (includeUTSSDK && id.includes('utssdk'))) {
const parts = (0, utils_1.normalizePath)(id).split('/');
const parentDir = parts[parts.length - 2];
if (parentDir === 'uni_modules' ||
(includeUTSSDK && parentDir === 'utssdk')) {
const basedir = parentDir === 'uni_modules' ? 'utssdk' : '';
const resolvePlatformDir = (p) => {
return path_1.default.resolve(id, basedir, p);
};
let index = resolveUTSFile(resolvePlatformDir(process.env.UNI_UTS_PLATFORM));
if (index) {
return index;
}
index = path_1.default.resolve(id, basedir, 'index.uts');
if (fs_extra_1.default.existsSync(index)) {
return index;
}
}
}
}
exports.resolveUTSModule = resolveUTSModule;
function resolveUTSFile(dir, extensions = ['.uts', '.ts', '.js']) {
for (let i = 0; i < extensions.length; i++) {
const indexFile = path_1.default.join(dir, 'index' + extensions[i]);
if (fs_extra_1.default.existsSync(indexFile)) {
return indexFile;
}
}
}
function resolveUTSCompiler(throwError = false) {
let compilerPath = '';
if (process.env.UNI_COMPILE_TARGET === 'ext-api' &&
process.env.UNI_APP_NEXT_WORKSPACE) {
return require(path_1.default.resolve(process.env.UNI_APP_NEXT_WORKSPACE, 'packages/uni-uts-v1'));
}
if ((0, hbx_1.isInHBuilderX)()) {
try {
compilerPath = require.resolve(path_1.default.resolve(process.env.UNI_HBUILDERX_PLUGINS, 'uniapp-uts-v1'));
}
catch (e) { }
}
if (!compilerPath) {
try {
compilerPath = require.resolve('@dcloudio/uni-uts-v1', {
paths: [process.env.UNI_CLI_CONTEXT || process.cwd()],
});
}
catch (e) {
if (throwError) {
throw `Error: Cannot find module '@dcloudio/uni-uts-v1'`;
}
console.error((0, utils_1.installDepTips)('devDependencies', '@dcloudio/uni-uts-v1', resolveUTSCompilerVersion()));
process.exit(0);
}
}
return require(compilerPath);
}
exports.resolveUTSCompiler = resolveUTSCompiler;
function resolveUTSCompilerVersion() {
let utsCompilerVersion = '';
try {
utsCompilerVersion = require('../package.json').version;
}
catch (e) {
try {
// vue2
utsCompilerVersion = require('../../package.json').version;
}
catch (e) { }
}
if (utsCompilerVersion.startsWith('2.0.')) {
utsCompilerVersion = '^3.0.0-alpha-3060920221117001';
}
return utsCompilerVersion;
}
exports.resolveUTSCompilerVersion = resolveUTSCompilerVersion;
const utsComponents = new Map();
function isUTSComponent(name) {
return utsComponents.has(name);
}
exports.isUTSComponent = isUTSComponent;
function getUTSComponentAutoImports(language) {
const utsComponentAutoImports = {};
utsComponents.forEach(({ kotlinPackage, swiftModule }, name) => {
const source = language === 'kotlin' ? kotlinPackage : swiftModule;
const className = (0, utils_1.capitalize)((0, utils_1.camelize)(name)) + 'Element';
if (!utsComponentAutoImports[source]) {
utsComponentAutoImports[source] = [[className]];
}
else {
if (!utsComponentAutoImports[source].find((item) => item[0] === className)) {
utsComponentAutoImports[source].push([className]);
}
}
});
return utsComponentAutoImports;
}
exports.getUTSComponentAutoImports = getUTSComponentAutoImports;
function parseUTSComponent(name, type) {
const meta = utsComponents.get(name);
if (meta) {
const namespace = meta[type === 'swift' ? 'swiftModule' : 'kotlinPackage'] || '';
const className = (0, utils_1.capitalize)((0, utils_1.camelize)(name)) + 'Component';
return {
className,
namespace,
source: meta.source,
};
}
}
exports.parseUTSComponent = parseUTSComponent;
function initUTSComponents(inputDir, platform) {
utsComponents.clear();
const components = [];
const isApp = platform === 'app' || platform === 'app-plus';
const easycomsObj = {};
const dirs = resolveUTSComponentDirs(inputDir);
dirs.forEach((dir) => {
const is_uni_modules_utssdk = dir.endsWith('utssdk');
const is_ussdk = !is_uni_modules_utssdk && path_1.default.dirname(dir).endsWith('utssdk');
const pluginId = is_uni_modules_utssdk
? path_1.default.basename(path_1.default.dirname(dir))
: path_1.default.basename(dir);
if (is_uni_modules_utssdk || is_ussdk) {
// dir 是 uni_modules/test-plugin/utssdk 或者 utssdk/test-plugin
// 需要分平台解析,不能直接解析 utssdk 目录下的文件,因为 utssdk 目录下可能存在多个平台的文件
const cwd = isApp
? dir
: path_1.default.join(dir, platform === 'h5' ? 'web' : platform);
fast_glob_1.default
.sync('**/*.vue', {
cwd,
absolute: true,
})
.forEach((file) => {
let name = parseVueComponentName(file);
if (!name) {
if (file.endsWith('index.vue')) {
name = path_1.default.basename(is_uni_modules_utssdk ? path_1.default.dirname(dir) : dir);
}
}
if (name) {
const source = '@/' +
(0, utils_1.normalizePath)(isApp
? path_1.default.relative(inputDir, is_uni_modules_utssdk ? path_1.default.dirname(dir) : dir)
: path_1.default.relative(inputDir, file));
easycomsObj[`^${name}$`] = {
source: isApp ? `${source}?uts-proxy` : source,
kotlinPackage: parseKotlinPackageWithPluginId(pluginId, is_uni_modules_utssdk),
swiftModule: parseSwiftPackageWithPluginId(pluginId, is_uni_modules_utssdk),
};
}
});
}
});
Object.keys(easycomsObj).forEach((name) => {
const obj = easycomsObj[name];
const componentName = name.slice(1, -1);
components.push({
name: componentName,
pattern: new RegExp(name),
replacement: obj.source,
});
utsComponents.set(componentName, {
source: obj.source,
kotlinPackage: obj.kotlinPackage,
swiftModule: obj.swiftModule,
});
});
return components;
}
exports.initUTSComponents = initUTSComponents;
function resolveUTSComponentDirs(inputDir) {
const utssdkDir = path_1.default.resolve(inputDir, 'utssdk');
const uniModulesDir = path_1.default.resolve(inputDir, 'uni_modules');
return (fs_extra_1.default.existsSync(utssdkDir)
? fast_glob_1.default.sync('*', {
cwd: utssdkDir,
absolute: true,
onlyDirectories: true,
})
: []).concat(fs_extra_1.default.existsSync(uniModulesDir)
? fast_glob_1.default.sync('*/utssdk', {
cwd: uniModulesDir,
absolute: true,
onlyDirectories: true,
})
: []);
}
const nameRE = /name\s*:\s*['|"](.*)['|"]/;
function parseVueComponentName(file) {
const content = fs_extra_1.default.readFileSync(file, 'utf8');
const matches = content.match(nameRE);
if (matches) {
return matches[1];
}
}
function prefix(id) {
if (process.env.UNI_UTS_MODULE_PREFIX &&
!id.startsWith(process.env.UNI_UTS_MODULE_PREFIX)) {
return process.env.UNI_UTS_MODULE_PREFIX + '-' + id;
}
return id;
}
function parseKotlinPackageWithPluginId(id, is_uni_modules) {
return 'uts.sdk.' + (is_uni_modules ? 'modules.' : '') + (0, utils_1.camelize)(prefix(id));
}
exports.parseKotlinPackageWithPluginId = parseKotlinPackageWithPluginId;
function parseSwiftPackageWithPluginId(id, is_uni_modules) {
return ('UTSSDK' +
(is_uni_modules ? 'Modules' : '') +
(0, utils_1.capitalize)((0, utils_1.camelize)(prefix(id))));
}
exports.parseSwiftPackageWithPluginId = parseSwiftPackageWithPluginId;
async function parseUniExtApiAutoImports(uniExtApiAutoImports, extApis, parseSource) {
if (Object.keys(extApis).length) {
const { parseExportIdentifiers } = resolveUTSCompiler();
for (const name in extApis) {
const options = extApis[name];
if ((0, utils_1.isArray)(options) && options.length >= 2) {
const pluginId = path_1.default.basename(options[0]);
const source = parseSource(pluginId);
if (uniExtApiAutoImports[source]) {
continue;
}
uniExtApiAutoImports[source] = [];
const filename = `uni_modules/${pluginId}/utssdk/interface.uts`;
const interfaceFileName = path_1.default.resolve(process.env.UNI_INPUT_DIR, filename);
if (fs_extra_1.default.existsSync(interfaceFileName)) {
const ids = await parseExportIdentifiers(interfaceFileName);
ids
// 过滤掉 Uni
.filter((id) => id !== 'Uni')
.forEach((id) => {
uniExtApiAutoImports[source].push([id]);
});
}
}
}
}
return uniExtApiAutoImports;
}
let uniExtApiKotlinAutoImports = null;
async function parseUniExtApiKotlinAutoImportsOnce(extApis) {
if (uniExtApiKotlinAutoImports) {
return uniExtApiKotlinAutoImports;
}
uniExtApiKotlinAutoImports = {};
return parseUniExtApiAutoImports(uniExtApiKotlinAutoImports, extApis, (pluginId) => {
return parseKotlinPackageWithPluginId(pluginId, true);
});
}
let uniExtApiSwiftAutoImports = null;
async function parseUniExtApiSwiftAutoImportsOnce(extApis) {
if (uniExtApiSwiftAutoImports) {
return uniExtApiSwiftAutoImports;
}
uniExtApiSwiftAutoImports = {};
return parseUniExtApiAutoImports(uniExtApiSwiftAutoImports, extApis, (pluginId) => {
return parseSwiftPackageWithPluginId(pluginId, true);
});
}
exports.parseUniExtApiNamespacesOnce = once((platform, language) => {
const extApis = (0, exports.parseUniExtApiNamespacesJsOnce)(platform, language);
const namespaces = {};
Object.keys(extApis).forEach((name) => {
const options = extApis[name];
let source = options[0];
const pluginId = path_1.default.basename(options[0]);
if (language === 'kotlin') {
source = parseKotlinPackageWithPluginId(pluginId, true);
}
else if (language === 'swift') {
source = parseSwiftPackageWithPluginId(pluginId, true);
}
namespaces[name] = [source, options[1]];
});
return namespaces;
});
exports.parseUniExtApiNamespacesJsOnce = once((platform, language) => {
const extApis = (0, uni_modules_1.parseUniExtApis)(true, platform, language);
const namespaces = {};
Object.keys(extApis).forEach((name) => {
const options = extApis[name];
if ((0, utils_1.isArray)(options) && options.length >= 2) {
namespaces[name.replace('uni.', '')] = [options[0], options[1]];
}
});
return namespaces;
});
function resolveUniTypeScript() {
if ((0, hbx_1.isInHBuilderX)()) {
return require(path_1.default.resolve(process.env.UNI_HBUILDERX_PLUGINS, 'uniapp-uts-v1', 'node_modules', '@dcloudio', 'uni-uts-v1', 'lib', 'typescript'));
}
return require('@dcloudio/uni-uts-v1/lib/typescript');
}
exports.resolveUniTypeScript = resolveUniTypeScript;
async function initUTSAutoImports(autoImports, platform, language) {
const utsComponents = getUTSComponentAutoImports(language);
Object.keys(utsComponents).forEach((source) => {
if (autoImports[source]) {
autoImports[source].push(...utsComponents[source]);
}
else {
autoImports[source] = utsComponents[source];
}
});
const extApis = (0, uni_modules_1.parseUniExtApis)(true, platform, language);
const extApiImports = await (language === 'kotlin'
? parseUniExtApiKotlinAutoImportsOnce
: parseUniExtApiSwiftAutoImportsOnce)(extApis);
Object.keys(extApiImports).forEach((source) => {
if (autoImports[source]) {
autoImports[source].push(...extApiImports[source]);
}
else {
autoImports[source] = extApiImports[source];
}
});
return autoImports;
}
let autoKotlinImports = null;
async function initUTSKotlinAutoImportsOnce() {
if (autoKotlinImports) {
return autoKotlinImports;
}
autoKotlinImports = {};
return initUTSAutoImports(autoKotlinImports, 'app-android', 'kotlin');
}
exports.initUTSKotlinAutoImportsOnce = initUTSKotlinAutoImportsOnce;
let autoSwiftImports = null;
async function initUTSSwiftAutoImportsOnce() {
if (autoSwiftImports) {
return autoSwiftImports;
}
autoSwiftImports = {};
return initUTSAutoImports(autoSwiftImports, 'app-ios', 'swift');
}
exports.initUTSSwiftAutoImportsOnce = initUTSSwiftAutoImportsOnce;
exports.genUniExtApiDeclarationFileOnce = once((tscInputDir) => {
const extApis = (0, uni_modules_1.parseUniExtApis)(true, 'app-android', 'kotlin');
// 之所以往上一级写,是因为 tscInputDir 会被 empty,目前时机有问题,比如先生成了d.ts,又被empty
const fileName = path_1.default.resolve(tscInputDir, '../uni-ext-api.d.ts');
if (fs_extra_1.default.existsSync(fileName)) {
try {
// 先删除
fs_extra_1.default.unlinkSync(fileName);
}
catch (e) { }
}
if (Object.keys(extApis).length) {
const apis = [];
for (const name in extApis) {
const options = extApis[name];
if ((0, utils_1.isArray)(options) && options.length >= 2) {
const api = name.replace('uni.', '');
apis.push(' ' + api + `: typeof import("${options[0]}")["${options[1]}"]`);
}
}
if (apis.length) {
fs_extra_1.default.outputFileSync(fileName, `
interface Uni {
${apis.join('\n')}
}
`);
}
}
});
function uvueOutDir(platform) {
return path_1.default.join(process.env.UNI_APP_X_UVUE_DIR, platform);
}
exports.uvueOutDir = uvueOutDir;
function tscOutDir(platform) {
return path_1.default.join(process.env.UNI_APP_X_TSC_DIR, platform);
}
exports.tscOutDir = tscOutDir;
const UTSProxyRE = /\?uts-proxy$/;
const UniHelpersRE = /\?uni_helpers$/;
function isUTSProxy(id) {
return UTSProxyRE.test(id);
}
exports.isUTSProxy = isUTSProxy;
function isUniHelpers(id) {
return UniHelpersRE.test(id);
}
exports.isUniHelpers = isUniHelpers;
+26
View File
@@ -0,0 +1,26 @@
const compiler = require('@dcloudio/uni-template-compiler')
const defaultOptions = {
compiler,
hotReload: false,
cacheDirectory: false,
cacheIdentifier: false,
transformAssetUrls: false // 禁用,由 uni-template-compiler 自行实现 transformAssetUrls
}
const defaultCompilerOptions = {
preserveWhitespace: false
}
module.exports = {
test: [/\.vue$/, /\.nvue$/],
loader: require.resolve('@dcloudio/vue-cli-plugin-uni/packages/vue-loader'),
options (options = {}, compilerOptions = {}) {
return Object.assign({},
defaultOptions,
options, {
compilerOptions: Object.assign({}, defaultCompilerOptions, compilerOptions)
})
},
compiler
}
+1
View File
@@ -0,0 +1 @@
[https://dcloud.io/license/uni-app.html](https://dcloud.io/license/uni-app.html)
+31
View File
@@ -0,0 +1,31 @@
{
"name": "@dcloudio/uni-cli-shared",
"version": "2.0.2-4070620250821001",
"description": "uni-cli-shared",
"main": "lib/index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/dcloudio/uni-app.git",
"directory": "packages/uni-cli-shared"
},
"files": [
"lib",
"template",
"components"
],
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "fxy060608",
"license": "Apache-2.0",
"dependencies": {
"escape-string-regexp": "^4.0.0",
"fast-glob": "^3.2.11",
"fs-extra": "^10.0.0",
"glob-escape": "^0.0.2",
"hash-sum": "^1.0.2",
"postcss-urlrewrite": "^0.2.2",
"strip-json-comments": "^2.0.1"
},
"gitHead": "83322ec9f7cc592b2052ff78370e12f4689f5966"
}
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

+25
View File
@@ -0,0 +1,25 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<script>
var __UniViewStartTime__ = Date.now();
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
CSS.supports('top: constant(a)'))
document.write(
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<title>View</title>
<link rel="stylesheet" href="view.css" />
</head>
<body>
<div id="app"></div>
<script src="__uniappes6.js"></script>
<script src="view.umd.min.js"></script>
<script src="app-view.js"></script>
</body>
</html>
@@ -0,0 +1,678 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)'))
document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<title></title>
<style>
html,
body {
margin: 0;
padding: 0;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background: #ffffff;
}
* {
margin: 0;
padding: 0;
}
button,
input,
input[type=button],
input[type=reset],
input[type=search],
input[type=submit],
select {
outline: none;
-webkit-tap-highlight-color: transparent;
-webkit-appearance: none;
font-family: inherit;
border: none;
}
.hide {
display: none;
}
.search-wrap {
position: absolute;
left: 0;
right: 0;
top: 0;
padding: 8px 60px 8px 15px;
background-color: #fff;
border-bottom: 1px solid #d3d3d3;
z-index: 100;
}
.search-wrap.init-status {
padding-right: 15px;
}
.search-wrap .search-bar {
display: block;
height: 30px;
background-color: #ebebeb;
padding-left: 10px;
padding-right: 10px;
color: #b4b4b4;
font-size: 15px;
line-height: 31px;
border-radius: 5px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.search-wrap .cancel,
.search-wrap .submit {
position: absolute;
top: 0;
right: 0;
width: 55px;
height: 46px;
line-height: 46px;
text-align: center;
font-size: 16px;
color: #0079ff;
background-color: #fff;
}
.search-wrap .clear-input {
top: 11px;
right: 60px;
width: 34px;
height: 26px;
line-height: 26px;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAPFBMVEUAAACZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZlr8OySAAAAE3RSTlMANO/H574Jw5g/soF2LxKbQCgmvcJ4rgAAAKFJREFUOMu9k1sSgyAMRcNLwbfe/e+1HZLa0DKTP8+PztwTDRDoWa4lRSCm5erGZcTNWP7iIaMhD22+BfwQtqae89bQ39jRYVf9ocu3U+5/cp4D7yZeCwkrKo7Y8O8XVFYRZilkgx+VWYQEZagcSYQIZagcUQRAGZwLpmD+wmzSXKa5UdZWW4d10E1Gh2wPjD1y9tBqSlDlB/U4PxfnpEd5AeZAIGebfob2AAAAAElFTkSuQmCC) no-repeat center center;
background-color: #ededed;
background-size: 18px 18px;
position: absolute;
padding: 0;
border: 0;
font-size: 14px;
border-radius: 4px;
text-align: center;
z-index: 2;
}
.search-wrap.init-status .cancel,
.search-wrap.init-status .clear-input,
.search-wrap.init-status .submit {
display: none;
}
.search-wrap .search-bar .keyword {
display: block;
width: 100%;
padding-top: 6px;
padding-bottom: 6px;
border: 0;
font-size: 14px;
line-height: 18px;
background: 0 0;
}
.search-wrap.init-status .search-bar .keyword {
text-align: left;
}
.search-wrap .search-bar .keyword::-webkit-input-placeholder {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAAgCAMAAACioYPHAAAAaVBMVEUAAACAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICxWbJ4AAAAInRSTlMAv39AEB/f758wYFDQj3CvDPflh9qpJBYEyEc3sn1om1t4LqRQpwAABAhJREFUWMPtlumS0zAQhD26TzvXsiwsC/T7PySK5Fi+Q2Cpoij6R2w5lvSpPTNS86+Jc1kbLbfrb7WxXT4U44Y1jK/1tI3cmPnwzYTT6dK1chcQCLVB2ABk8GtdXW1IKLHWk9Ct452PuOlJ7gLexk1shGYLcGFPfbujLs0Aut+z6vMJuJw/2Q+8JeD4tg0YyizCE0gQGs+TvCjIRIZlEW43RAvAmJx8ENAfofwQBQScNwEJZQ4gdDI1kNXHJ6AoSyFQFoAFYGLYAzTspki29++I10NT9QVo9wEZ2r4h82XPh0cBAw3qRzkovH6cJiFg7wDy2vgtQPsTPc9Qh9mjJ7yswUXGFBgzloEvHYyR3USjD2XcNWn7lLJyBCi8UbgPeNDLmvB8XLMARKRBpDhDEl2npBqDBLpJ0aAAluftxQZARYDSPwH4DZcly1d8vRODnPtrw3LOw/xLO7Ba2fM9d9fXeLpcO7MYAN21dtSnMzPvzS1IzVrOfoJ6IAZngBHKiTFg7So86xSArgVNF0WYqu4IL2tV/wAcfhFQ0A3JRzEHtABULgFLwEVA9TdqNWM15CZgmzwKVAKyXIpxlKm04gU0Ako2kvExQvR5dX8SUBJc7NhVCv12MbzLCZ0ocahB/m6ZIboPGPBpyfEREBuAWrdbg0qNKkoY7wL4hO8rmzNOq3xOwyRyMR1UDL7TtRZ6pqFcalr/HoBva0X5jKflQ9kqACspx6ZHRsp4+TX3DoDPwOe94l35rigB2UimFe/loEfRIJzKeKUR4OaAYgwoQJtlpv5l8PJxYeBleFQVOjks1NfqUddiXQdow3nLskwA3ATQEauAjnQ1P4BPVSuxPOI8L9Np0qXEtBqXV1qYuoFUBUrqGNPaVsCogbYCCmgzmE803/QSex34y4TvuIzAZahQntohDHNIYi3ndrKj8v5oL/yVrnOi/zMbZJsdCTY5AL7KevoHcPpwF1AE7ZrY81Wx7sZgcyw6eUVXAEIrapJIxqYVIBdNx/NWFEvkmTrq2xFH458THT9rwIRKuASshAhzPkmA6Rm8wlDBg4py/cBCUZSYprSkkjkKmTOMj82WkHTUSLr45jkTbgPWmHPTk66GkQODYEMFkmOPx50kIPocyb+2hEVm0pOVfI4XJJ2efMrfQrgP6Agwk/3MKSg+MclWE6ssgpc9nlMwJdW6UcYZuOKqFtP9TcrDcGS9rBIKjTywT2ggmZ1X0dsCgyhmX1EQ9CIVIkYikZkLioQuF9XUMNyQvEDNFs+INFQOkiRTGFwAyjix2Cc6otHHMWZlbM+yPOclxYd9QYGXTrIsTza7hGFmH6BMqSKdq+bbGMo0ohqUUvkR8VtJ8fKBXvJly2Cx3882//UX6QfMclqph21gcgAAAABJRU5ErkJggg==);
background-repeat: no-repeat;
background-position: left center;
background-size: 80px 16px;
color: gray
}
.search-wrap.init-status .search-bar .keyword::-webkit-input-placeholder {
background-position: center center;
}
.suggestion-wrap {
position: absolute;
top: 46px;
bottom: 0;
z-index: 7;
width: 100%;
background: #f6f6f6;
overflow: scroll;
-webkit-overflow-scrolling: touch;
}
.map-wrap {
height: 220px;
position: relative;
top: 46px;
width: 100%;
}
.list-wrap {
width: 100%;
position: absolute;
background-color: #fff;
z-index: 1;
bottom: 0;
left: 0;
overflow: hidden;
border-top: 1px solid #d3d3d3;
overflow-y: scroll;
padding-bottom: 0;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
-webkit-overflow-scrolling: touch;
}
.poi-list ul {
list-style: none;
width: 100%;
text-align: left;
padding: 0 0 65px;
}
.suggestion-wrap li,
.active-pos,
.poi-list li {
position: relative;
display: block;
padding-left: 15px;
border: none;
height: 58px;
padding-top: 6px;
margin: 0;
}
.poi-list li * {
pointer-events: none;
}
.poi-list li p,
.active-pos div p {
padding-bottom: 10px;
border-bottom: 1px solid #d3d3d3;
}
.poi-title {
font-size: 14px;
line-height: 27px;
color: #333;
font-weight: 400;
display: block;
width: 92%;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.poi-address {
font-size: 12px;
color: gray;
height: 20px;
line-height: 20px;
margin: 0;
width: 92%;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
display: block;
}
.poi-city,
.poi-latlng {
line-height: 22px;
display: none;
}
.no-more-results,
.no-results {
color: gray;
padding: 20px 0;
line-height: 24px;
text-align: center;
}
.no-more-results p,
.no-results p {
padding: 0;
margin: 0;
}
.list-wrap i {
width: 16px;
height: 16px;
display: none;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAaVBMVEUAAAAAef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef8Aef84EEEWAAAAInRSTlMA+QQY6izG8NO6TphC3JReWSMoDLOfgXajf29lZEs7Hcep1l5DEAAAAPxJREFUOMuFU9cSgyAQBDSUgCVgSS/8/0cGc8E5FQdeOGaXud0rBB9mzdFYRtKnGDkVkktB+VgkYE27poCw6aheUxpxPqHn6SyaRe66NKsfpqyRll6+Njlfsp/jS1WkRFeXf/QUh6Stg3iCAHndMX6VPxltlaiMNdPXqp1iftviR+qHcN34ZJm6FO4/4XY0FOeuknhpp0jdCamHJA7GhjqQ2n2ctCpofPw8K+22OHm8I+HjvXIYj4SYYvSBwTAeU0SROjA6hnEQCTYjg2McbEKhZgbGoVC41HqJQ6lxs1iP8blZuN3WrdudG5jcyGWHNj/2+cXJr15+ebPr/wWbNBG/n/A0GgAAAABJRU5ErkJggg==) no-repeat right center;
background-size: 16px 16px;
position: absolute;
right: 15px;
top: 50%;
margin-top: -8px;
}
.list-wrap i.active {
right: 30px;
display: inline-block;
}
</style>
</head>
<body>
<div class="search-wrap init-status">
<div class="search-bar">
<form name="poi-search" id="poiSearch" onsubmit="return false;">
<input type="search" class="keyword" id="searchword" placeholder=" ">
<button type="reset" class="clear-input hide"></button>
<button type="submit" class="submit hide">搜索</button>
</form>
<a class="cancel">取消</a>
</div>
</div>
<div class="suggestion-wrap hide">
<div class="poi-list">
<ul>
</ul>
</div>
<div class="no-results hide">
<p>对不起,没有搜索到相关数据!</p>
</div>
<div class="no-more-results hide">
<p>亲,没有更多了~</p>
</div>
</div>
<div id="map" class="map-wrap"></div>
<div class="list-wrap">
<div class="active-pos">
</div>
<div class="poi-list">
<ul>
</ul>
<div class="no-results hide">
<p>对不起,没有搜索到相关数据!</p>
</div>
</div>
</div>
<script>
var loc;
var serviceWebview;
var back = function (cancel) {
if (cancel) {
plus.webview.postMessageToUniNView({
type: 'chooseLocation',
args: {
errMsg: 'cancel'
}
}, '__uniapp__service');
}
var webview = plus.webview.currentWebview()
if (webview.__uniapp_statusbar_style === 'dark') {
plus.navigator.setStatusBarStyle('dark')
}
webview.close('auto');
};
window.__chooseLocationConfirm__ = function () {
if (!loc) {
plus.nativeUI.alert('您尚未选择位置!');
return;
}
plus.webview.postMessageToUniNView({
type: 'chooseLocation',
args: loc
}, '__uniapp__service');
back();
}
var searchWrapElem = document.querySelector('.search-wrap');
var searchWordElem = document.getElementById('searchword');
var resetElem = document.querySelector('[type="reset"]');
var cancelElem = document.querySelector('.cancel');
var suggestionWrapElem = document.querySelector('.suggestion-wrap');
var mapElem = document.getElementById('map');
var listWrapElem = document.querySelector('.list-wrap');
var suggestionPoiListElem = suggestionWrapElem.querySelector('.poi-list ul');
var suggestionPoiNoResultsElem = suggestionWrapElem.querySelector('.no-results');
var suggestionPoiNoMoreResultsElem = suggestionWrapElem.querySelector(
'.no-more-results');
var activePosElem = document.querySelector('.active-pos');
var nearbyPoiListElem = listWrapElem.querySelector('.poi-list ul');
var nearbyPoiNoResultsElem = listWrapElem.querySelector('.no-results');
listWrapElem.style.top = mapElem.offsetHeight + 47 + 'px';
var debounce = function (func, wait, immediate) {
var timeout, result;
return function () {
var context = this,
args = arguments,
later, callNow;
later = function () {
timeout = null;
if (!immediate) {
result = func.apply(context, args);
}
};
callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) {
result = func.apply(context, args);
}
return result;
};
};
var plusReady = function (callback) {
if (window.plus) {
callback()
} else {
document.addEventListener('plusready', callback)
}
}
var ZOOM = 13
window.__chooseLocation__ = function (params) {
if (params && params.keyword) {
searchWordElem.value = params.keyword;
}
plusReady(function () {
serviceWebview = plus.webview.getWebviewById('__W2A_CONTEXT_') ||
plus.webview
.getLaunchWebview();
plus.key.addEventListener('backbutton', function () {
back(true);
});
var nativeMarker = false;
var nativeMap = new plus.maps.Map('map', {
zoom: ZOOM
});
var centerPoint = false
var reverseGeocode = debounce(function (point) {
plus.maps.Map.reverseGeocode(point, {}, function (res) {
activePosElem.innerHTML =
'<div data-name="' + (res.address || '') +
'" data-address="' + (res.address || '') +
'" data-lat="' + res.coord.getLat() +
'" data-lng="' + res.coord.getLng() +
'"><h2 class="poi-title">地图位置</h2><p><span class="poi-address">' +
(res.address ||
'') +
'</span><span class="poi-latlng">' +
res.coord
.getLat() +
',' + res.coord.getLng() +
'</span><i></i></p></div>';
}, function (err) {
console.log(err);
});
searchNearbyPoi.poiSearchNearBy(searchWordElem.value || '', point, 1000);
}, 10)
nativeMap.getUserLocation(function (state, point) { //获取当前用户坐标
if (state === 0) {
nativeMarker = new plus.maps.Marker(point);
nativeMarker.setIcon('__uniappmarker@3x.png');
nativeMap.addOverlay(nativeMarker);
//centerPoint = point;
nativeMap.showUserLocation(true);
if (plus.os.name !== 'Android') {
nativeMap.setCenter(point);
}
// reverseGeocode(centerPoint);
} else {
console.log('获取用户坐标失败');
}
});
nativeMap.onstatuschanged = function (evt) { //切换坐标中心
// if (!centerPoint) {
// return;
// }
if (centerPoint && evt.center) {
if (centerPoint.latitude === evt.center.latitude &&
centerPoint.longitude === evt.center.longitude) {
return;
}
}
centerPoint = evt.center
if (nativeMarker) {
nativeMarker.setPoint(centerPoint);
}
reverseGeocode(centerPoint);
};
var searchPoi = new plus.maps.Search(nativeMap);
var searchNearbyPoi = new plus.maps.Search(nativeMap);
var showMap = function (centerPoint) {
nativeMap.show();
if (centerPoint) {
if (nativeMarker) {
nativeMarker.setPoint(centerPoint);
}
nativeMap.setCenter(centerPoint);
// setTimeout(function() {
// nativeMap.setZoom(ZOOM);
// }, 150);
// reverseGeocode(centerPoint);
}
searchWordElem.value = '';
cancelElem.className = 'cancel hide';
searchWrapElem.className = 'search-wrap init-status';
suggestionWrapElem.className = 'suggestion-wrap hide';
resetSuggestionPoiList();
}
var resetSuggestionPoiList = function () {
suggestionPoiListElem.innerHTML = '';
suggestionPoiNoResultsElem.className = 'no-results hide';
suggestionPoiNoMoreResultsElem.className =
'no-more-results hide';
}
var showSuggestionPoiList = function () {
nativeMap.hide();
resetSuggestionPoiList();
}
var showSuggestionPoiNoResults = function () {
suggestionPoiListElem.innerHTML = '';
suggestionPoiNoResultsElem.className = 'no-results';
suggestionPoiNoMoreResultsElem.className =
'no-more-results hide';
}
var renderPoiResults = function (poiList) {
var html = [];
for (var i = 0; i < poiList.length; i++) {
var poi = poiList[i];
if (poi.point) {
html.push('<li data-name="' + (poi.name || '') +
'" data-address="' + (poi.address || '') +
'" data-lat="' + poi.point.getLat() +
'" data-lng="' + poi.point.getLng() +
'"><p><span class="poi-title">' + poi.name +
'</span><span class="poi-address">' + (poi.address ||
'') +
'</span><span class="poi-latlng">' + poi.point
.getLat() +
',' + poi.point.getLng() +
'</span><span class="poi-city">' + poi.city +
'</span></p><i></i></li>');
}
}
return html.join('');
}
var showNearbyPoiNoResults = function () {
nearbyPoiListElem.innerHTML = '';
nearbyPoiNoResultsElem.className = 'no-results';
}
var showNearbyPoiResults = function (poiList) {
var html = renderPoiResults(poiList);
if (html) {
nearbyPoiListElem.innerHTML = html;
nearbyPoiNoResultsElem.className = 'no-results hide';
} else {
showNearbyPoiNoResults();
}
}
var showSuggestionPoiResults = function (poiList) {
var html = renderPoiResults(poiList);
if (html) {
suggestionPoiListElem.innerHTML = html;
suggestionPoiNoResultsElem.className =
'no-results hide';
suggestionPoiNoMoreResultsElem.className =
'no-more-results';
} else {
showSuggestionPoiNoResults();
}
}
searchPoi.onPoiSearchComplete = function (state, res) {
if (state === 0) {
if (res.poiList.length) {
showSuggestionPoiResults(res.poiList);
} else {
showSuggestionPoiNoResults();
}
} else {
showSuggestionPoiNoResults();
}
};
searchNearbyPoi.onPoiSearchComplete = function (state, res) {
if (state === 0) {
if (res.poiList.length) {
showNearbyPoiResults(res.poiList);
} else {
showNearbyPoiNoResults();
}
} else {
showNearbyPoiNoResults();
}
};
var getSuggestion = debounce(function (q) {
if (q.trim()) {
searchPoi.poiSearchNearBy(q, centerPoint, 50000)
} else { }
}, 10);
suggestionPoiListElem.addEventListener('click', function (evt) {
var target = evt.target;
for (; target && target !== suggestionPoiListElem; target =
target.parentNode) {
if (target && target.tagName === 'LI') {
var laglng = target.querySelector('.poi-latlng')
.innerText
.split(',');
centerPoint = new plus.maps.Point(Number(laglng[1]), Number(laglng[
0]));
showMap(centerPoint);
reverseGeocode(centerPoint);
break;
}
}
});
searchWordElem.addEventListener('click', function () {
searchWrapElem.className = 'search-wrap';
suggestionWrapElem.className = 'suggestion-wrap';
cancelElem.className = 'cancel';
showSuggestionPoiList();
});
var oldHasValue = false;
var setInputState = function (hasValue) {
if (hasValue !== oldHasValue) {
if (hasValue) {
resetElem.className = 'clear-input'
} else {
resetElem.className = 'clear-input hide'
}
oldHasValue = hasValue;
}
}
searchWordElem.addEventListener('input', function () {
var value = this.value.replace(/^\s+|\s+$/g, '');
setInputState(!!value);
getSuggestion(value);
});
resetElem.addEventListener('click', function (e) {
setInputState(false);
setTimeout(function () {
searchWordElem.focus();
}, 0);
});
cancelElem.addEventListener('click', function () {
showMap();
});
listWrapElem.addEventListener('click', function (e) {
var target = e.target;
for (; target && target !== listWrapElem; target =
target.parentNode) {
if (target.className === 'active-pos' || target.tagName ===
'LI') {
var lastActiveElem = listWrapElem.querySelector(
'i.active');
if (lastActiveElem) {
lastActiveElem.className = '';
}
if (target.className === 'active-pos') {
target = target.children[0]
}
target.querySelector('i').className = 'active';
loc = {
poiname: target.getAttribute('data-name'),
poiaddress: target.getAttribute(
'data-address'),
latlng: {
lat: target.getAttribute(
'data-lat'),
lng: target.getAttribute(
'data-lng'),
}
}
if (nativeMarker) {
nativeMarker.setPoint(new plus.maps.Point(
loc.latlng.lng, loc.latlng.lat));
}
break;
}
}
})
});
};
</script>
</body>
</html>
@@ -0,0 +1,284 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)'))
document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<title></title>
<style>
html,
body,
.container {
margin: 0;
padding: 0;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background: #ffffff;
}
#map {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 80px;
bottom: calc(80px + constant(safe-area-inset-bottom));
bottom: calc(80px + env(safe-area-inset-bottom));
}
#poi {
position: absolute;
left: 0;
right: 0;
bottom: 0;
bottom: constant(safe-area-inset-bottom);
bottom: env(safe-area-inset-bottom);
height: 80px;
background: #FFFFFF;
}
.poi-info {
width: 100%;
padding: 23px 16px 23px 18px;
box-sizing: border-box;
background: #FFFFFF;
}
.poi-name {
font-size: 17px;
line-height: 17px;
color: #111111;
display: block;
margin-right: 70px;
word-wrap: break-word;
}
.poi-addr {
font-size: 13px;
line-height: 13px;
color: #666666;
display: block;
margin-top: 4px;
margin-right: 70px;
word-wrap: break-word;
}
.poi-nav {
display: block;
position: absolute;
top: 10px;
right: 16px;
width: 60px;
height: 60px;
border-radius: 60px;
overflow: hidden;
}
.poi-nav i,
.poi-nav span {
position: absolute;
top: 0;
width: 100%;
height: 100%;
display: inline-block;
border-radius: 60px;
}
.poi-nav i {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAMAAAAOusbgAAACnVBMVEUAAAA9avA+avA9avA/bPE8afA+avM9afA9avA9au9Ac/I+bPQ9avA8a/E8au8+avY9avA9avBAgP88avA9au9AbfFAgP89avA9avBJbf89au88afA8ae88afA8ae9AbO88afA/avE9ae88avBHcfFCcfY+a/H///89afE8afA8avA9afA8afA9a/E9afA9avA8avA8avA9ae////88ae8/a+/+/v77/P5Cbu9jh/I9au9Te/CIo/XY4fuasfbH1PpJc/Dl6/xHce9Cbe9Eb+9FcO/3+f5SevC0xfjh6PygtvdLdPD4+f7e5fytwPj9/f7y9f1agPG6yvlsjvNIcvC8y/lXfvFNdvBZf/HR3PtBbe+DoPTT3fvg5/xWffGyxPh/nPTo7f32+P65yfnBz/n6+/6xw/i+zfmwwvj5+v6Np/WetPdPd/BMdfBOd/BdgvGkufdGce9ghfKnu/deg/F4l/NqjPKAnfS3x/lAbO+KpfVPePBmifKqvviZsPait/fS3PtUe/F6mfT8/f7s8P2Xr/bX4PuWrvbI1fqdtPfq7/3t8f3E0vqCn/RRefCzxPjK1vpwkfPP2vtVfPHR2/tDbu+BnvTr8P3G0/qLpvXW3/uOqPXL1/rf5vyht/eDn/Rzk/OPqfWQqfXZ4vuGovX19/67y/nm7Pymuvc+au9hhfKluvfU3vt3lvO3yPlpjPJykvN2lfNQePB7mfSsv/ju8v18mvTO2fvv8/22x/nr7/2cs/aMpvXn7P3D0fp+nPR5mPTE0frj6fyftfdcgfFfhPHN2Prx9P1ihvJ2lvO/zvm9zPl0lPOHo/VsjvKovPeQqvX09v6TrPZ1lfOUrfZnivKVrfbM2PrAzvmuwfi1xvjC0Pri6fzz9v59m/T8d63OAAAAM3RSTlMA7GNUSf4p38bFFC3nN7Id75oI/eI4BIv7B9Kl9fnCQLs1ossSG2sBS/p7rJlYuLmYrcSkuUTkAAAGJElEQVR4XsWbVXvbShBAJbumJE0abp0mbdI23KS9M4YgM0ORmZmZmZkZLjMzMzPDb7m2NvJnx8p6pVjd86J18nA+raSFmVlBNXGRxtyMApvdIqamiha7rSAj1xgZJ+iLOTPPEo8KxFvyMs06SSMMKVFIJSrFEBFu6zBjdA4ykBNtHBZGbfq4IcjMkHHpYdKOGIkqGTkiDNpBNtSAbdAAtYNHoUZGDRa0MzrWhJoxxY7WqM0yiDggREOWFm9MGg6YtBj13mwRw4CYrVKblGzCsGBKTlLjHWPFsGEdw+41J2AYSWCePRJFDCtiIuNYNRzDzHCmcWzsUAw7Q8cy3C/xhtsc8p4T1fbz7TUXmXo7xHM2i6iSb2Hus8iAaKZ+vwmoXgzwYQnLV0X5npOsqEkM9QcdGBJr/2NYMmoUA9zswZAk9zsvmLSJCc+txBCYspW9MSIORAyd7xQjHVFxlsxKQ+1iwrUipJOmtDIw4IDF0PFKNVIxKKyvWDu68vbEQ2+5OnxAAAc2Iw0xeB0Wi0zsnb8f6NyYghRig9axJmSguHkhhGRh8zTKm9131cu0fq6uAAY6tyGFUX3mJGTAXQYMvLkSqQTOUzZk4GsGbdsmDMEjAfsyZGAbEFrbz253FMuUgh/zDjOM2f47Opb9YO1xIqjY3u93vKABGRgp+EhHBnYRQWMx9iN+/EVkI90nzkcG2iTBMw5UFi+85UZG8mXvMJb9/iQi2IHK4s+6kJkhcrTCyD4mlyn//fglVINRIEQjA29L4t1K4o72CaiKaOKNyEEGlkjibQriQ0WokpwIFfNhtyQOnnteXkaZ/umzY4pWsXZSJHHUwxdHeb1mfPhiNHvEmTzEmR7xeB7iPI/YwkNsEYS4eB7i+DghEnmIMVIw8hEbhVw+4lwhg484QyjkIy4UrHzEVsHOR2wXLHzEFkHkIxaFVD7iVG5i5q4u2ujlpfB1tQW5YBHsyAW7YEMu2IQC5EKBkIFcyBBykQu5ghG5YGRZ+qzasmUV+uFYhzJfrrmKmohkWexNAfAPmk17b+kHcns9fIQ+znf2ZSVlsSdY1IonnIP9pUjY4f+vWdCXyZTlrZBHCeQRugC6epuSYOt8gIO4eo6Hza2waI6XvUTcs8FDBVR4L99QxHnULcwmCOIplGiEN1YsB3+mS2Ji6oZulH9StjBmDeInZ3+K12fKuODyzI3E9HyXhytwxXt5gSI2U7epdUWEfQD7eptuDKbLCatVPuMosjFnerkUOLq8mAQp2lAWz3vUgwtc3ku9JKZszA0qxa894WEZ4kaAI5WILa1QTsTsz9ggB19UiWeDh6mIeM8F7xZhObhKVIpzIqjhpi0ze6kCqJLbpxHn7Nx5RhJjz6uwdNkBaEefuPyehzIo814+7lccTQ+wvQ4KnJEU04kYG8oAoH6V2gHESA8p/lwq0Q7QXOrjToAY3XsA7tcgYfJjhLkwt7dVTQ8p0oOoe4jk7NNICBAf7gCAG7XoQ37GNMYxhY3fJ4HTdU54ECSumQ8w9SjADHJnjl4mwkS5SQsb0wPllcdgsdRYBPWfBIpr71YBLK7BcoD7LYhYAsGUUALl9NTAYmidJDUuNkGb21+863MAkPq/GeDmCnbxCJZkyF3w9fAXLliChOLZ0LT1N3B+tU6elafWITom9XICTshNhb62saR/TjrhNBIcpxrB+R1pLgCAc5O/X40yP9Sxv1yDQie8HGuc8OPVn3YvWnChqRO8NEk5tFuwtLwKqn75taFyba17Wk1ddcupLqy8RyADiMxa5YQXPcW3AvyY9/i1iv2wHBF7OuABVl6AAI7hFFDifFCKjyWpeeT3PxrXl18/eaeoQXqv/oS/EHHD5QrvlHzp73/+dYJMN5bMUGI7JanJnsZt+Y8MjbNQZqu7du0ELzXIhDiakrjWEwMlVa8naVmU4gQdEWMo5Rg6YsqmFKDoSTKt5EZHrEnUIiPdSBjDUFalA6KZoZBMB4Yn8iqd41UsyKs8kldBKK8SWF5Fv7zKnHkVdvMvZedfvM//uAL/Axr8j6TwP4RDSM9Xc+woP53TQStOR8v0wZw5XvfDdPTjg4VW+figtVDb8cH/AZ+Eg+9jqX0NAAAAAElFTkSuQmCC) no-repeat;
background-size: 100%;
}
</style>
</head>
<body>
<div id="container" class="container">
<div id="map"></div>
<div id="poi">
<div class="poi-info">
<span class="poi-name"></span>
<span class="poi-addr"></span>
<div class="poi-nav">
<i></i>
<span></span>
</div>
</div>
</div>
</div>
<script>
var loc;
var serviceWebview;
var back = function() {
var webview = plus.webview.currentWebview()
if (webview.__uniapp_statusbar_style === 'light') {
plus.navigator.setStatusBarStyle('light')
}
webview.close('auto');
};
var isIos = !!navigator.userAgent.match(/iPhone|iPad|iPod/i);
document.addEventListener('plusready', function() {
serviceWebview = plus.webview.getWebviewById('__W2A_CONTEXT_') || plus.webview.getLaunchWebview();
plus.key.addEventListener('backbutton', back);
})
/**
* 调用系统第三方程序进行导航
*/
function openSysMap(lat, lng, title) {
/**
* 网页版地图源
*/
var mapsSourceWeb = [
{
title: '腾讯地图网页版',
getUrl: function() {
var url
url = 'https://apis.map.qq.com/uri/v1/routeplan?type=drive' + '&to=' +
encodeURIComponent(title) + '&tocoord=' + encodeURIComponent(lat + ',' + lng) +
'&referer=APP'
return url
}
}
]
/**
* APP版地图源
*/
var mapsSource = [
{
title: '高德地图',
pname: 'com.autonavi.minimap',
action: !isIos ? 'amapuri://' : 'iosamap://',
getUrl: function() {
var url
if (!isIos) {
url = 'amapuri://route/plan/'
} else {
url = 'iosamap://path'
}
url += '?sourceApplication=APP&dname=' + encodeURIComponent(title) + '&dlat=' + lat +
'&dlon=' + lng + '&dev=0'
return url
}
},
{
title: '百度地图',
pname: 'com.baidu.BaiduMap',
action: 'baidumap://',
getUrl: function() {
var url = 'baidumap://map/direction?destination=' + encodeURIComponent('latlng:' + lat +
',' + lng + '|name:' + title) + '&mode=driving&src=APP&coord_type=gcj02'
return url
}
},
{
title: '腾讯地图',
pname: 'com.tencent.map',
action: 'qqmap://',
getUrl: function() {
var url
url = 'qqmap://map/routeplan?type=drive' + (isIos ? ('&from=' + encodeURIComponent(
'我的位置')) : '') + '&to=' + encodeURIComponent(title) + '&tocoord=' +
encodeURIComponent(lat + ',' + lng) + '&referer=APP'
return url
}
}
]
var maps = []
mapsSource.forEach(function(mapsSource) {
var installed = plus.runtime.isApplicationExist({
pname: mapsSource.pname,
action: mapsSource.action,
})
if (installed) {
maps.push(mapsSource)
}
})
if (isIos) {
maps.unshift({
title: 'Apple 地图',
getUrl: function() {
var url
url = 'https://maps.apple.com/?daddr=' + encodeURIComponent(title) + '&sll=' +
encodeURIComponent(lat + ',' + lng)
return url
}
})
}
if (maps.length === 0) {
maps = maps.concat(mapsSourceWeb)
}
plus.nativeUI.actionSheet({
title: '导航方式',
cancel: '取消',
buttons: maps,
}, function(res) {
var index = res.index
var map
if (index > 0) {
map = maps[index - 1]
plus.runtime.openURL(map.getUrl(), function() { }, map.pname)
}
})
}
var ZOOM = 13
window.__openLocation__ = function(params) {
var mapElem = document.getElementById('map');
var poiNameElem = document.querySelector('.poi-name');
var poiAddrElem = document.querySelector('.poi-addr');
var poiNavElem = document.querySelector('.poi-nav');
var latitude = params.latitude;
var longitude = params.longitude;
var scale = params.scale;
var name = params.name;
var address = params.address;
var point = new plus.maps.Point(longitude, latitude);
var map = plus.maps.create('map', {
center: point,
zoom: scale || ZOOM,
top: 0,
left: 0,
width: mapElem.offsetWidth,
height: mapElem.offsetHeight
});
var marker = new plus.maps.Marker(point);
marker.setIcon('__uniappmarker@3x.png');
if (name) {
poiNameElem.innerText = name;
// marker.setLabel(name);
}
if (address) {
poiAddrElem.innerText = address;
// var bubble = new plus.maps.Bubble(address);
// marker.setBubble(bubble);
}
map.addOverlay(marker);
plus.webview.currentWebview().append(map);
var userPoint = false
map.getUserLocation(function(state, point) {
if (state) {
plus.nativeUI.toast('定位失败!');
} else {
userPoint = point;
}
})
poiNavElem.addEventListener('click', function() {
openSysMap(latitude, longitude, name)
});
}
</script>
</body>
</html>
File diff suppressed because one or more lines are too long
+149
View File
@@ -0,0 +1,149 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
CSS.supports(
'top: constant(a)'))
document.write(
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<title>Scan code</title>
<style>
html,
body,
.container {
margin: 0;
padding: 0;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background: #000000;
}
</style>
</head>
<body>
<div id="scan" class="container">
</div>
<script>
var scan;
var lightImg;
var lightView;
var back = function(cancel) {
if (cancel) {
plus.webview.postMessageToUniNView({
type: 'scanCode',
args: {
errMsg: 'cancel'
}
}, '__uniapp__service');
}
lightImg && lightImg.clear();
lightView && lightView.clear();
scan && scan.close();
var webview = plus.webview.currentWebview();
if (webview.__uniapp_dark) {
plus.navigator.setStatusBarStyle('dark');
}
webview.close('auto');
}
/**
* 绘制照亮开关
*/
function drawLight() {
var offImg =
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAABjklEQVRoQ+1ZbVHEQAx9TwE4ABTcOQAknANQAKcAUAAOAAXgAHAACsDCKQiTmbYDzJZtNt2bFrJ/m6+Xl2yyU2LmhzOPH/8PgIjcADirxNyapNoffMwMiMgzgMPBHmyCLySPLCoBwJKtAbJbYaBmD1yRvBwAtBMxl5DF+DZkiwCIyBLAzsgBbki+Wm2WAlCaL6zOMvKnJO+sNksB7ALQbO1ZHfbIv5FUVs2nCIB6EZETALdmj2mFY5I6X8ynGEADQllYmL1+VzBfnV/VvQB0aj45ARyQ/Ci14QLQsOBZLe5JaikWnzEA7AN4L4hgA2Dpyb76dANwsOCq/TZhASAYKGie0a7R1lDPI0ebtF0NUi+4yfdAtxr3PEMnD6BbD0QkNfACQO05EAwMuaBqDrIVycdmTpwDuP4R0OR7QFftVRP0g+49cwOQq4DJMxAAchmofY3m/EcJBQOZbTRKKJeBKKEoIePvpFRJ1VzmciUccyCa+C81cerBkuuB7sGTE/zt+yhN7AnAqxsAvBn06n8CkyPwMZKwm+UAAAAASUVORK5CYII=';
var onImg =
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAB4klEQVRoQ+1ZQU7CUBCdaWVBLFETqUtxB7iQG4hH4AZ4AvUE4gnkBuoJ9AbiDXAhZadby4IQICaS9psqJBVLy5/fkhKHbefPzPvzZv6bgLDmP1zz/OH/ARjZpSYAniVSORQXRt5qyviWrsDQLrUQ8FgmyLK2AsRTzrSqy9p7dgxA5raibFdSgSR7QAi4yu11GlFA/d+lKSTjfBW2JAAj+7Cio7MVZ4KO0AeG+dKW9UkCMHwvNxDhUjZYuL17apjdW1mfJACiX9gef2bbgLgvG3CB/bNhdioUXyQAXqCRXawDaDeUoPNnBLonuXy3RfFFBvADouxx9ogSeHaGMjpjm0LDXrGKQntUAaBn3IPsTveN6kOpAl5QNWkh7gzTqlOTJ0mJ+WAf/WLBmWivskkIEIONjKio3H4sAKhVUOX+7MKUKcQAZLk3Z88VWEQhr0kRYCoN/m5wqe8BvzQOkuDpB+CTB0EPHgOYNnNiTewXaFyBkFGbWAVQE7XNXevhW7X2Sucg8NqfR+p7AADaesateUk7E+0eAH4tLOsAIPSNZQBJT6EoicMV4Ar4OEJZK5lCTCGmkPy/MUGjOTEtxO9A1A1wE3MTp6iJgxaWKAr7F54o27DvsUwhlQRUzzIA1RtUPf8FRKRYQOI+9hQAAAAASUVORK5CYII=';
var webview = plus.webview.currentWebview();
var en = webview.__uniapp_locale && webview.__uniapp_locale.indexOf('zh') < 0
var onText = en ? '' : '轻触照亮';
var offText = en ? '' : '轻触关闭';
var on = false;
var viewWidth = 48;
var fontSize = 10;
var imgWidth = 26;
function changeType() {
lightView.reset();
lightImg.loadBase64Data(on ? onImg : offImg, function() {
lightView.drawBitmap(lightImg, {}, {
top: 0,
left: (viewWidth - imgWidth) / 2 + 'px',
width: imgWidth + 'px',
height: imgWidth + 'px'
});
});
lightView.drawText(on ? offText : onText, {
top: imgWidth + 'px',
left: '0px',
width: '100%',
height: (fontSize + 2) + 'px'
}, {
color: '#ffffff',
size: fontSize + 'px'
});
scan.setFlash(on);
on = !on;
}
lightImg = new plus.nativeObj.Bitmap('lightImg');
lightView = new plus.nativeObj.View('lightView', {
width: viewWidth + 'px',
height: viewWidth + 'px',
top: window.innerHeight / 2 + 50 + 'px',
left: (window.innerWidth - viewWidth) / 2 + 'px',
position: 'static'
});
lightView.addEventListener('click', function() {
changeType();
});
plus.webview.currentWebview().append(lightView);
changeType();
}
document.addEventListener('plusready', function() {
var serviceWebview = plus.webview.getWebviewById('__W2A_CONTEXT_') || plus.webview.getLaunchWebview();
plus.key.addEventListener('backbutton', function() {
back(true);
});
setTimeout(function() {
var webview = plus.webview.currentWebview();
scan = new plus.barcode.Barcode('scan', webview.__uniapp_scan_type, {
frameColor: '#118CE9',
scanbarColor: '#118CE9'
}, webview.__uniapp_auto_decode_char_set);
scan.onmarked = function(type, code, file, charSet) {
var res = {
type: type,
code: code,
charSet: charSet
};
back()
plus.webview.postMessageToUniNView({
type: 'scanCode',
args: res
}, '__uniapp__service');
};
scan.onerror = function(error) {
back()
plus.webview.postMessageToUniNView({
type: 'scanCode',
args: {
errMsg: error.message + ' error code:' + error.code
}
}, '__uniapp__service');
};
scan.start();
drawLight();
}, 500)
})
</script>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB