diff --git a/lib/apis.js b/lib/apis.js
index 79ae1fbecb5749f7d4d1434ea7bf8db5eaaf6a87..d9e6d7188cae1934fc979274d88fe101c9215225 100644
--- a/lib/apis.js
+++ b/lib/apis.js
@@ -240,7 +240,8 @@ const third = [
const ad = [
'createRewardedVideoAd',
- 'createFullScreenVideoAd'
+ 'createFullScreenVideoAd',
+ 'createInterstitialAd'
]
const apis = [
diff --git a/lib/modules.json b/lib/modules.json
index 333c9e6ffed97c9653b4d006caf0de19dceb9898..dd0c32dfd69472c0f4d767d69f8a42c0777aa519 100644
--- a/lib/modules.json
+++ b/lib/modules.json
@@ -223,6 +223,7 @@
"title": "广告",
"apiList": {
"uni.createRewardedVideoAd": true,
- "uni.createFullScreenVideoAd": true
+ "uni.createFullScreenVideoAd": true,
+ "uni.'createInterstitialAd'": true
}
}]
diff --git a/packages/uni-template-compiler/__tests__/compiler-extra.spec.js b/packages/uni-template-compiler/__tests__/compiler-extra.spec.js
index a75db7311f33c24d715f3d1c9313defb0e2d3c8d..052e92b38a9649d4290f72e93edf20cfc338c171 100644
--- a/packages/uni-template-compiler/__tests__/compiler-extra.spec.js
+++ b/packages/uni-template-compiler/__tests__/compiler-extra.spec.js
@@ -237,16 +237,28 @@ describe('mp:compiler-extra', () => {
assertCodegen(
'text',
- 'text'
+ 'text'
)
assertCodegen(
'text123213',
- 'text123213'
+ 'text123213'
)
assertCodegen(
'',
- ''
+ ''
+ )
+ assertCodegen(
+ 'view1view2',
+ 'view1view2'
+ )
+ assertCodegen(
+ 'view1view2',
+ 'view1view2'
+ )
+ assertCodegen(
+ 'view1view2',
+ 'view1view2'
)
assertCodegen(
`
@@ -258,7 +270,7 @@ describe('mp:compiler-extra', () => {
Here's some contact info
`,
- 'Here might be a page titleHere\'s some contact infoA paragraph for the main content.'
+ 'Here might be a page titleHere\'s some contact infoA paragraph for the main content.'
)
})
diff --git a/packages/uni-template-compiler/__tests__/compiler-mp-alipay.spec.js b/packages/uni-template-compiler/__tests__/compiler-mp-alipay.spec.js
index d31ab3f31a3c02ab9fed5cadffc4918c6e0d6f7c..4541914ab2e6454da178ee28c06e45d8465d609c 100644
--- a/packages/uni-template-compiler/__tests__/compiler-mp-alipay.spec.js
+++ b/packages/uni-template-compiler/__tests__/compiler-mp-alipay.spec.js
@@ -55,6 +55,12 @@ describe('mp:compiler-mp-alipay', () => {
}
)
})
+ it('generate slot fallback content', () => {
+ assertCodegen(
+ 'slot',
+ 'slot'
+ )
+ })
it('generate default slot', () => {
assertCodegen(
'text',
diff --git a/packages/uni-template-compiler/__tests__/compiler-mp-weixin.spec.js b/packages/uni-template-compiler/__tests__/compiler-mp-weixin.spec.js
index b60fcb8de74b0321b0c417eff551ca5aef648d2f..efa48612dac830a7185da76f0c784b2316f40554 100644
--- a/packages/uni-template-compiler/__tests__/compiler-mp-weixin.spec.js
+++ b/packages/uni-template-compiler/__tests__/compiler-mp-weixin.spec.js
@@ -82,6 +82,41 @@ describe('mp:compiler-mp-weixin', () => {
)
})
+ it('generate scoped slot with filter', () => {
+ assertCodegen(
+ '{{getValue(item)}}',
+ '{{$root.m1}}',
+ 'with(this){var m0=$hasScopedSlotsParams("551070e6-1");var m1=m0?getValue($getScopedSlotsParams("551070e6-1","default","item")):null;$mp.data=Object.assign({},{$root:{m0:m0,m1:m1}})}',
+ {
+ betterScopedSlots: true
+ }
+ )
+ assertCodegen(
+ '{{getValue(item.text)}}',
+ '{{$root.m1}}',
+ 'with(this){var m0=$hasScopedSlotsParams("551070e6-1");var m1=m0?getValue($getScopedSlotsParams("551070e6-1","default").text):null;$mp.data=Object.assign({},{$root:{m0:m0,m1:m1}})}',
+ {
+ betterScopedSlots: true
+ }
+ )
+ assertCodegen(
+ '',
+ '',
+ 'with(this){$setScopedSlotsParams("default",{"item":item})}',
+ {
+ betterScopedSlots: true
+ }
+ )
+ assertCodegen(
+ '',
+ '',
+ 'with(this){$setScopedSlotsParams("default",object)}',
+ {
+ betterScopedSlots: true
+ }
+ )
+ })
+
it('generate scoped slot', () => {
assertCodegen(
'',
@@ -158,4 +193,4 @@ describe('mp:compiler-mp-weixin', () => {
'hello world'
)
})
-})
+})
diff --git a/packages/uni-template-compiler/lib/constants.js b/packages/uni-template-compiler/lib/constants.js
index 9c68613a9d6ab982cd9943038582f368ec54f831..af0ea8ca2eaf74fd42d77df105d5a8313aedc318 100644
--- a/packages/uni-template-compiler/lib/constants.js
+++ b/packages/uni-template-compiler/lib/constants.js
@@ -106,6 +106,9 @@ module.exports = {
METHOD_TO_STRING,
METHOD_RENDER_LIST,
METHOD_RESOLVE_FILTER,
+ METHOD_RENDER_SLOT,
+ METHOD_CREATE_EMPTY_VNODE,
+ METHOD_RESOLVE_SCOPED_SLOTS,
PREFIX_GLOBAL: 'g',
PREFIX_ATTR: 'a',
PREFIX_METHOD: 'm',
diff --git a/packages/uni-template-compiler/lib/script/traverse/index.js b/packages/uni-template-compiler/lib/script/traverse/index.js
index 64325f4b97eef4f3bcd3e7e10d68fb1d0b7e6c05..c293ca116e86808a17ef7e9c7d50d6a3ff1e4814 100644
--- a/packages/uni-template-compiler/lib/script/traverse/index.js
+++ b/packages/uni-template-compiler/lib/script/traverse/index.js
@@ -90,6 +90,7 @@ module.exports = function traverse (ast, state) {
const blockStatementBody = []
const objectPropertyArray = []
const initExpressionStatementArray = []
+ const renderSlotStatementArray = []
// TODO 待重构,至少 filter,method 等实现方式要调整
babelTraverse(ast, visitor, undefined, {
scoped: [],
@@ -100,7 +101,8 @@ module.exports = function traverse (ast, state) {
identifierArray: identifierArray,
propertyArray: objectPropertyArray,
declarationArray: blockStatementBody,
- initExpressionStatementArray: initExpressionStatementArray
+ initExpressionStatementArray: initExpressionStatementArray,
+ renderSlotStatementArray
})
if (initExpressionStatementArray.length) {
@@ -111,10 +113,14 @@ module.exports = function traverse (ast, state) {
blockStatementBody.push(getDataExpressionStatement(objectPropertyArray))
}
+ if (renderSlotStatementArray.length) {
+ blockStatementBody.push(...renderSlotStatementArray)
+ }
+
reIdentifier(identifierArray)
return t.withStatement(
t.thisExpression(),
t.blockStatement(blockStatementBody)
)
-}
+}
diff --git a/packages/uni-template-compiler/lib/script/traverse/render-slot.js b/packages/uni-template-compiler/lib/script/traverse/render-slot.js
new file mode 100644
index 0000000000000000000000000000000000000000..d02dcce3a5d7f8eb03211060b1b97e826b462226
--- /dev/null
+++ b/packages/uni-template-compiler/lib/script/traverse/render-slot.js
@@ -0,0 +1,34 @@
+const t = require('@babel/types')
+
+module.exports = function getRenderSlot (path, state) {
+ const name = path.get('arguments.0')
+ const arg2 = path.get('arguments.2')
+ const arg3 = path.get('arguments.3')
+ let valueNode
+ if (arg3) {
+ // v-bind:object
+ valueNode = arg3.node
+ } else if (arg2 && !arg2.isNullLiteral()) {
+ if (arg2.isObjectExpression()) {
+ const propertiesPath = arg2.get('properties')
+ const oldProperties = []
+ const newProperties = []
+ propertiesPath.forEach(path => {
+ const properties = path.get('key').isStringLiteral({ value: 'SLOT_DEFAULT' }) ? oldProperties : newProperties
+ properties.push(path.node)
+ })
+ if (!newProperties.length) {
+ return
+ }
+ valueNode = t.objectExpression(newProperties)
+ arg2.replaceWith(t.objectExpression(oldProperties))
+ } else {
+ valueNode = arg2.node
+ }
+ }
+ if (valueNode) {
+ state.renderSlotStatementArray.push(t.expressionStatement(t.callExpression(t.identifier('$setScopedSlotsParams'), [t.stringLiteral(name.node.value), valueNode])))
+ }
+ // TODO 组件嵌套
+ path.skip()
+}
diff --git a/packages/uni-template-compiler/lib/script/traverse/resolve-scoped-slots.js b/packages/uni-template-compiler/lib/script/traverse/resolve-scoped-slots.js
new file mode 100644
index 0000000000000000000000000000000000000000..632e810a34c0fe71f30f4199729b9e191b55f8b0
--- /dev/null
+++ b/packages/uni-template-compiler/lib/script/traverse/resolve-scoped-slots.js
@@ -0,0 +1,54 @@
+const t = require('@babel/types')
+
+const {
+ METHOD_CREATE_EMPTY_VNODE
+} = require('../../constants')
+
+function replaceId (path, ids) {
+ let replaced
+ path.traverse({
+ noScope: true,
+ Identifier (path) {
+ const name = path.node.name
+ if (name in ids && path.key !== 'key' && (path.key !== 'property' || path.parent.computed)) {
+ path.replaceWith(ids[name])
+ replaced = true
+ }
+ }
+ })
+ return replaced
+}
+
+module.exports = function getResolveScopedSlots (parent, state) {
+ const properties = parent.get('arguments.0.elements.0.properties')
+ const fn = properties.find(path => path.get('key').isIdentifier({ name: 'fn' }))
+ const params = fn.get('value.params.0')
+ if (!params) {
+ return
+ }
+ const vueId = parent.parentPath.parentPath.get('properties').find(path => path.get('key').isIdentifier({ name: 'attrs' })).get('value').get('properties').find(path => path.get('key').isStringLiteral({ value: 'vue-id' })).get('value').node.value
+ const slot = properties.find(path => path.get('key').isIdentifier({ name: 'key' })).get('value').node.value
+ const ids = {}
+ function updateIds (vueId, slot, value, key) {
+ const array = [t.stringLiteral(vueId), t.stringLiteral(slot)]
+ if (key) {
+ array.push(t.stringLiteral(key))
+ }
+ ids[value] = t.callExpression(t.identifier('$getScopedSlotsParams'), array)
+ }
+ if (params.isObjectPattern()) {
+ params.get('properties').forEach(prop => {
+ updateIds(vueId, slot, prop.get('value').node.name, prop.get('key').node.name)
+ })
+ } else if (params.isIdentifier()) {
+ updateIds(vueId, slot, params.node.name)
+ }
+ const fnBody = fn.get('value.body')
+ if (replaceId(fnBody, ids)) {
+ const orgin = fnBody.get('body.0.argument')
+ const elements = orgin.get('elements')
+ const node = (elements.length === 1 ? elements[0] : orgin).node
+ const test = t.callExpression(t.identifier('$hasScopedSlotsParams'), [t.stringLiteral(vueId)])
+ orgin.replaceWith(t.arrayExpression([t.conditionalExpression(test, node, t.callExpression(t.identifier(METHOD_CREATE_EMPTY_VNODE), []))]))
+ }
+}
diff --git a/packages/uni-template-compiler/lib/script/traverse/visitor.js b/packages/uni-template-compiler/lib/script/traverse/visitor.js
index 15e7c14e6f9d84f1540c8e61dc8e5148858a7473..721cd334060aebe60236d4f02e10baa77090c30c 100644
--- a/packages/uni-template-compiler/lib/script/traverse/visitor.js
+++ b/packages/uni-template-compiler/lib/script/traverse/visitor.js
@@ -6,6 +6,8 @@ const {
METHOD_RENDER_LIST,
METHOD_BUILT_IN,
METHOD_RESOLVE_FILTER,
+ METHOD_RENDER_SLOT,
+ METHOD_RESOLVE_SCOPED_SLOTS,
IDENTIFIER_FILTER,
IDENTIFIER_METHOD,
IDENTIFIER_GLOBAL
@@ -26,6 +28,8 @@ const traverseData = require('./data')
const traverseRenderList = require('./render-list')
const getMemberExpr = require('./member-expr')
+const getRenderSlot = require('./render-slot')
+const getResolveScopedSlots = require('./resolve-scoped-slots')
function addStaticClass (path, staticClass) {
const dataPath = path.get('arguments.1')
@@ -217,6 +221,12 @@ module.exports = {
this
)
)
+ } else if (this.options.betterScopedSlots) {
+ if (methodName === METHOD_RESOLVE_SCOPED_SLOTS) {
+ getResolveScopedSlots(path, this)
+ } else if (methodName === METHOD_RENDER_SLOT) {
+ getRenderSlot(path, this)
+ }
}
break
}
diff --git a/packages/uni-template-compiler/lib/template/generate.js b/packages/uni-template-compiler/lib/template/generate.js
index df216600c1a9a8717293f9e4e47bc5caa9af62e6..6c0b34db0351d3742448ae1c5ec7e485f0dd64ec 100644
--- a/packages/uni-template-compiler/lib/template/generate.js
+++ b/packages/uni-template-compiler/lib/template/generate.js
@@ -48,12 +48,17 @@ function processElement (ast, state, isRoot) {
const slots = []
for (let i = children.length - 1; i >= 0; i--) {
const childElement = children[i]
- // =>
+ /**
+ * 仅百度、字节支持使用 block 作为命名插槽根节点
+ * 此处为了统一仅忽略默认插槽
+ * =>
+ */
if (typeof childElement !== 'string' && childElement.attr.slot) {
- if (childElement.type === 'block') {
+ const slot = childElement.attr.slot
+ if (slot && slot !== 'default' && childElement.type === 'block') {
childElement.type = 'view'
}
- slots.push(childElement.attr.slot)
+ slots.push(slot)
} else {
defaultSlot = true
}
@@ -78,7 +83,7 @@ function processElement (ast, state, isRoot) {
if (ast.attr.id && ast.attr.id.indexOf('{{') === 0) {
state.tips.add(`id 作为属性保留名,不允许在自定义组件 ${ast.type} 中定义为 props`)
}
- if (hasOwn(ast.attr, 'data') && platformName !== 'mp-toutiao') { // 百度中会出现异常情况
+ if (hasOwn(ast.attr, 'data') && platformName !== 'mp-toutiao') { // 百度中会出现异常情况
// TODO 暂不输出
// state.tips.add(`data 作为属性保留名,不允许在自定义组件 ${ast.type} 中定义为 props`)
}
diff --git a/packages/uni-template-compiler/lib/template/traverse.js b/packages/uni-template-compiler/lib/template/traverse.js
index 4107551fe64d867f83c8a2b49224dff549745a13..fd700937121dc4a6358e0aae943677e71cbb0c66 100644
--- a/packages/uni-template-compiler/lib/template/traverse.js
+++ b/packages/uni-template-compiler/lib/template/traverse.js
@@ -273,6 +273,10 @@ function genSlotNode (slotName, slotNode, fallbackNodes, state) {
if (!fallbackNodes || t.isNullLiteral(fallbackNodes)) {
return slotNode
}
+ // 支付宝小程序默认插槽为 $default
+ if (state.options.platform.name === 'mp-alipay') {
+ slotName = slotName === 'default' ? '$default' : slotName
+ }
const prefix = state.options.platform.directive
return [{
type: 'block',
@@ -300,7 +304,7 @@ function traverseRenderSlot (callExprNode, state) {
const slotName = callExprNode.arguments[0].value
let deleteSlotName = false // 标记是否组件 slot 手动指定了 name="default"
- if (callExprNode.arguments.length > 2) { // 作用域插槽
+ if (!state.options.betterScopedSlots && callExprNode.arguments.length > 2) { // 作用域插槽
const props = {}
callExprNode.arguments[2].properties.forEach(property => {
props[property.key.value] = genCode(property.value)
@@ -333,6 +337,20 @@ function traverseRenderSlot (callExprNode, state) {
}
function traverseResolveScopedSlots (callExprNode, state) {
+ function single (children, slotName, ignore) {
+ if (Array.isArray(children) && children.length === 1) {
+ const child = children[0]
+ if (!child.type) {
+ return
+ }
+ if (ignore.includes(child.type)) {
+ return single(child.children, slotName, ignore)
+ }
+ child.attr = child.attr || {}
+ child.attr.slot = slotName
+ return true
+ }
+ }
return callExprNode.arguments[0].elements.map(slotNode => {
let keyProperty = false
let fnProperty = false
@@ -351,7 +369,7 @@ function traverseResolveScopedSlots (callExprNode, state) {
})
const slotName = keyProperty.value.value
const returnExprNodes = fnProperty.value.body.body[0].argument
- if (!proxyProperty) {
+ if (!state.options.betterScopedSlots && !proxyProperty) {
const resourcePath = state.options.resourcePath
const ownerName = path.basename(resourcePath, path.extname(resourcePath))
@@ -379,14 +397,18 @@ function traverseResolveScopedSlots (callExprNode, state) {
state
)
}
- const node = {
- type: 'view',
+ const children = normalizeChildren(traverseExpr(returnExprNodes, state))
+ // 除百度、字节外其他小程序仅默认插槽可以支持多个节点
+ if (single(children, slotName, ['template', 'block'])) {
+ return children[0]
+ }
+ return {
+ type: 'block',
attr: {
slot: slotName
},
- children: normalizeChildren(traverseExpr(returnExprNodes, state))
+ children
}
- return node
})
}
@@ -488,4 +510,4 @@ function traverseCreateTextVNode (callExprNode, state) {
function traverseCreateEmptyVNode (callExprNode, state) {
return ''
-}
+}
diff --git a/packages/vue-cli-plugin-uni/lib/commands/custom.js b/packages/vue-cli-plugin-uni/lib/commands/custom.js
index 2d4b20bdefe8dd380e1aa0b733db848f98f6f9d6..e18ca26403b0e7131e5e8640cc1f653053d10a23 100644
--- a/packages/vue-cli-plugin-uni/lib/commands/custom.js
+++ b/packages/vue-cli-plugin-uni/lib/commands/custom.js
@@ -30,9 +30,11 @@ module.exports = function custom (argv) {
service.run(command, {
watch: process.env.NODE_ENV === 'development',
minimize: process.env.UNI_MINIMIZE === 'true',
- clean: false
+ clean: false,
+ subpackage: argv.subpackage,
+ plugin: argv.plugin
}).catch(err => {
console.error(err)
process.exit(1)
- })
+ })
}
diff --git a/packages/vue-cli-plugin-uni/lib/env.js b/packages/vue-cli-plugin-uni/lib/env.js
index 9c87845314e624983842c74fccd245153b6b30a5..3b7c6d6cd2d083e76e79069fbd0104d896b36e43 100644
--- a/packages/vue-cli-plugin-uni/lib/env.js
+++ b/packages/vue-cli-plugin-uni/lib/env.js
@@ -258,6 +258,10 @@ if (platformOptions.usingComponents === true) {
}
}
+if (platformOptions.betterScopedSlots) {
+ process.env.BETTER_SCOPED_SLOTS = true
+}
+
if (
process.env.UNI_USING_COMPONENTS ||
process.env.UNI_PLATFORM === 'h5'
diff --git a/packages/vue-cli-plugin-uni/lib/error-reporting.js b/packages/vue-cli-plugin-uni/lib/error-reporting.js
index f053334ea72ea869671c722722c756be9b2b0f74..91752b5a95a3d6319277290cd52011083ec48f2e 100644
--- a/packages/vue-cli-plugin-uni/lib/error-reporting.js
+++ b/packages/vue-cli-plugin-uni/lib/error-reporting.js
@@ -36,12 +36,12 @@ class ErrorReport {
return this._https
}
- report (type, err) {
+ report (type, err = '') {
if (!this._shouldReport(err)) {
return
}
- err = normalizePath(err)
+ err = normalizePath(err) || ''
err = err.replace(this._UNI_INPUT_DIR_REG, 'UNI_INPUT_DIR')
err = err.replace(this._UNI_CLI_CONTEXT_REG, 'UNI_CLI_CONTEXT')
diff --git a/packages/webpack-uni-mp-loader/lib/template.js b/packages/webpack-uni-mp-loader/lib/template.js
index 6539148f7129fdbf3d2f7b47460bd93505ec345c..11ff5b8298fb6c98e04ea274c8f81f1b2ea36ef8 100644
--- a/packages/webpack-uni-mp-loader/lib/template.js
+++ b/packages/webpack-uni-mp-loader/lib/template.js
@@ -65,7 +65,8 @@ module.exports = function (content, map) {
const filterModules = parseFilterModules(params && params['filter-modules'])
Object.assign(vueLoaderOptions.options.compilerOptions, {
mp: {
- platform: process.env.UNI_PLATFORM
+ platform: process.env.UNI_PLATFORM,
+ betterScopedSlots: process.env.BETTER_SCOPED_SLOTS
},
filterModules,
filterTagName,
@@ -84,4 +85,4 @@ module.exports = function (content, map) {
throw new Error('vue-loader-options parse error')
}
this.callback(null, content, map)
-}
+}
diff --git a/src/core/view/mixins/field.js b/src/core/view/mixins/field.js
index 1645a729a731a70e6fc9770015763d10bb5f47d6..2baa91f83e43dee694c91e6e6b7a42f0ad2fbc67 100644
--- a/src/core/view/mixins/field.js
+++ b/src/core/view/mixins/field.js
@@ -4,6 +4,7 @@ import {
} from 'uni-shared'
import emitter from './emitter'
import keyboard from './keyboard'
+import interact from './interact'
UniViewJSBridge.subscribe('getSelectedTextRange', function ({ pageId, callbackId }) {
const activeElement = document.activeElement
@@ -29,7 +30,7 @@ let startTime
export default {
name: 'Field',
- mixins: [emitter, keyboard],
+ mixins: [emitter, keyboard, interact],
model: {
prop: 'value',
event: 'update:value'
@@ -167,7 +168,10 @@ export default {
return
}
field.focus()
- plus.key.showSoftKeybord()
+ // 无用户交互的 webview 需主动显示键盘(安卓)
+ if (!this.userInteract) {
+ plus.key.showSoftKeybord()
+ }
}
},
_blur () {
diff --git a/src/platforms/app-plus/service/api/ad/interstitial-ad.js b/src/platforms/app-plus/service/api/ad/interstitial-ad.js
new file mode 100644
index 0000000000000000000000000000000000000000..27425744935172b5b24764db024135dc183c4a62
--- /dev/null
+++ b/src/platforms/app-plus/service/api/ad/interstitial-ad.js
@@ -0,0 +1,115 @@
+const eventNames = [
+ 'load',
+ 'close',
+ 'error',
+ 'adClicked'
+]
+
+class InterstitialAd {
+ constructor (options = {}) {
+ const _callbacks = this._callbacks = {}
+ eventNames.forEach(item => {
+ _callbacks[item] = []
+ const name = item[0].toUpperCase() + item.substr(1)
+ this[`on${name}`] = function (callback) {
+ _callbacks[item].push(callback)
+ }
+ })
+
+ this._isLoad = false
+ this._isLoading = false
+ this._adError = ''
+ this._loadPromiseResolve = null
+ this._loadPromiseReject = null
+
+ const ad = this._ad = plus.ad.createInterstitialAd(options)
+ ad.onLoad((e) => {
+ this._isLoad = true
+ this._isLoading = false
+ this._dispatchEvent('load', {})
+
+ if (this._loadPromiseResolve != null) {
+ this._loadPromiseResolve()
+ this._loadPromiseResolve = null
+ }
+ })
+ ad.onClose((e) => {
+ this._isLoad = false
+ this._isLoading = false
+ this._dispatchEvent('close', {})
+ })
+ ad.onError((e) => {
+ this._isLoading = false
+
+ const { code, message } = e
+ const data = { code: code, errMsg: message }
+ this._adError = message
+
+ this._dispatchEvent('error', data)
+
+ if (this._loadPromiseReject != null) {
+ this._loadPromiseReject(data)
+ this._loadPromiseReject = null
+ }
+ })
+ ad.onAdClicked((e) => {
+ this._dispatchEvent('adClicked', {})
+ })
+ }
+
+ load () {
+ return new Promise((resolve, reject) => {
+ this._loadPromiseResolve = resolve
+ this._loadPromiseReject = reject
+ if (this._isLoading) {
+ return
+ }
+ if (this._isLoad) {
+ resolve()
+ return
+ }
+ this._loadAd()
+ })
+ }
+
+ show () {
+ return new Promise((resolve, reject) => {
+ if (this._isLoading) {
+ return
+ }
+
+ if (this._isLoad) {
+ this._ad.show()
+ resolve()
+ } else {
+ reject(new Error(this._adError))
+ }
+ })
+ }
+
+ getProvider () {
+ return this._ad.getProvider()
+ }
+
+ destroy () {
+ this._ad.destroy()
+ }
+
+ _loadAd () {
+ this._isLoad = false
+ this._isLoading = true
+ this._ad.load()
+ }
+
+ _dispatchEvent (name, data) {
+ this._callbacks[name].forEach(callback => {
+ if (typeof callback === 'function') {
+ callback(data || {})
+ }
+ })
+ }
+}
+
+export function createInterstitialAd (options) {
+ return new InterstitialAd(options)
+}
diff --git a/src/platforms/app-plus/service/api/ad/rewarded-video-ad.js b/src/platforms/app-plus/service/api/ad/rewarded-video-ad.js
index a6a3ea032a26b8b4655f54c9c183ad36777afd92..eb0008c5aaed4a110006256f86983fd6a717769e 100644
--- a/src/platforms/app-plus/service/api/ad/rewarded-video-ad.js
+++ b/src/platforms/app-plus/service/api/ad/rewarded-video-ad.js
@@ -24,6 +24,7 @@ class RewardedVideoAd {
this._preload = options.preload !== undefined ? options.preload : true
this._isLoad = false
+ this._isLoading = false
this._adError = ''
this._loadPromiseResolve = null
this._loadPromiseReject = null
@@ -32,6 +33,7 @@ class RewardedVideoAd {
const rewardAd = this._rewardAd = plus.ad.createRewardedVideoAd(options)
rewardAd.onLoad((e) => {
this._isLoad = true
+ this._isLoading = false
this._lastLoadTime = Date.now()
this._dispatchEvent('load', {})
@@ -41,6 +43,8 @@ class RewardedVideoAd {
}
})
rewardAd.onClose((e) => {
+ this._isLoad = false
+ this._isLoading = false
if (this._preload) {
this._loadAd()
}
@@ -50,6 +54,7 @@ class RewardedVideoAd {
this._dispatchEvent('verify', { isValid: e.isValid })
})
rewardAd.onError((e) => {
+ this._isLoading = false
const { code, message } = e
const data = { code: code, errMsg: message }
this._adError = message
@@ -78,18 +83,25 @@ class RewardedVideoAd {
load () {
return new Promise((resolve, reject) => {
+ this._loadPromiseResolve = resolve
+ this._loadPromiseReject = reject
+ if (this._isLoading) {
+ return
+ }
if (this._isLoad) {
resolve()
return
}
- this._loadPromiseResolve = resolve
- this._loadPromiseReject = reject
this._loadAd()
})
}
show () {
return new Promise((resolve, reject) => {
+ if (this._isLoading) {
+ return
+ }
+
const provider = this.getProvider()
if (provider === ProviderType.CSJ && this.isExpired) {
this._isLoad = false
@@ -118,6 +130,7 @@ class RewardedVideoAd {
_loadAd () {
this._isLoad = false
+ this._isLoading = true
this._rewardAd.load()
}
diff --git a/src/platforms/app-plus/service/api/index.js b/src/platforms/app-plus/service/api/index.js
index 495d35af303bb8aa2aa2683b90b2c497633eb88c..6d650abbe9a456aa1b31d6cff6d74469c9d30ade 100644
--- a/src/platforms/app-plus/service/api/index.js
+++ b/src/platforms/app-plus/service/api/index.js
@@ -81,3 +81,4 @@ export * from './ui/request-component-info'
export * from './ad/ad'
export * from './ad/rewarded-video-ad'
export * from './ad/full-screen-video-ad'
+export * from './ad/interstitial-ad'
diff --git a/src/platforms/app-plus/service/api/storage/storage.js b/src/platforms/app-plus/service/api/storage/storage.js
index b7e9b1590e130980d3499c30996b9de478356ead..e3e2fd7a9e6e75a5b6087a81110f7e08168ccfdd 100644
--- a/src/platforms/app-plus/service/api/storage/storage.js
+++ b/src/platforms/app-plus/service/api/storage/storage.js
@@ -185,7 +185,7 @@ export function getStorageInfo () {
let currentSize = 0
for (let index = 0; index < length; index++) {
const key = plus.storage.key(index)
- if (key !== STORAGE_KEYS && key.indexOf(STORAGE_DATA_TYPE) + STORAGE_DATA_TYPE.length !== key.length) {
+ if (key !== STORAGE_KEYS && (key.indexOf(STORAGE_DATA_TYPE) < 0 || key.indexOf(STORAGE_DATA_TYPE) + STORAGE_DATA_TYPE.length !== key.length)) {
const value = plus.storage.getItem(key)
currentSize += key.length + value.length
keys.push(key)
diff --git a/src/platforms/app-plus/service/framework/app.js b/src/platforms/app-plus/service/framework/app.js
index 79b605dfad2907d2dbc4b8b1992bf145eb072eaa..20de4d5d22425a56a2cfeee512e9eae65e596eaa 100644
--- a/src/platforms/app-plus/service/framework/app.js
+++ b/src/platforms/app-plus/service/framework/app.js
@@ -93,10 +93,15 @@ function initGlobalListeners () {
})
})
+ let keyboardHeightChange = 0
plus.globalEvent.addEventListener('KeyboardHeightChange', function (event) {
- publish('onKeyboardHeightChange', {
- height: event.height
- })
+ // 安卓设备首次获取高度为 0
+ if (keyboardHeightChange !== event.height) {
+ keyboardHeightChange = event.height
+ publish('onKeyboardHeightChange', {
+ height: keyboardHeightChange
+ })
+ }
})
globalEvent.addEventListener('uistylechange', function (event) {
diff --git a/src/platforms/h5/service/api/media/MIMEType.js b/src/platforms/h5/service/api/media/MIMEType.js
new file mode 100644
index 0000000000000000000000000000000000000000..bbbf163a73fbf1070323a0816b4b5777ed1dc590
--- /dev/null
+++ b/src/platforms/h5/service/api/media/MIMEType.js
@@ -0,0 +1,53 @@
+export default {
+ /**
+ * 关于图片常见的MIME类型
+ */
+ image: {
+ jpg: 'jpeg',
+ jpe: 'jpeg',
+ pbm: 'x-portable-bitmap',
+ pgm: 'x-portable-graymap',
+ pnm: 'x-portable-anymap',
+ ppm: 'x-portable-pixmap',
+ psd: 'vnd.adobe.photoshop',
+ pic: 'x-pict',
+ rgb: 'x-rgb',
+ svg: 'svg+xml',
+ svgz: 'svg+xml',
+ tif: 'tiff',
+ xif: 'vnd.xiff',
+ wbmp: 'vnd.wap.wbmp',
+ wdp: 'vnd.ms-photo',
+ xbm: 'x-xbitmap',
+ ico: 'x-icon'
+ },
+ /**
+ * 关于视频常见的MIME类型
+ */
+ video: {
+ '3g2': '3gpp2',
+ '3gp': '3gpp',
+ avi: 'x-msvideo',
+ f4v: 'x-f4v',
+ flv: 'x-flv',
+ jpgm: 'jpm',
+ jpgv: 'jpeg',
+ m1v: 'mpeg',
+ m2v: 'mpeg',
+ mpe: 'mpeg',
+ mpg: 'mpeg',
+ mpg4: 'mpeg',
+ m4v: 'x-m4v',
+ mkv: 'x-matroska',
+ mov: 'quicktime',
+ qt: 'quicktime',
+ movie: 'x-sgi-movie',
+ mp4v: 'mp4',
+ ogv: 'ogg',
+ smv: 'x-smv',
+ wm: 'x-ms-wm',
+ wmv: 'x-ms-wmv',
+ wmx: 'x-ms-wmx',
+ wvx: 'x-ms-wvx'
+ }
+}
diff --git a/src/platforms/h5/service/api/media/create_input.js b/src/platforms/h5/service/api/media/create_input.js
index d261c10c565d633351b84e304877c1765b7f3018..50e9bd669423073a5b01b931615e5090dbad10af 100644
--- a/src/platforms/h5/service/api/media/create_input.js
+++ b/src/platforms/h5/service/api/media/create_input.js
@@ -1,4 +1,5 @@
import { updateElementStyle } from 'uni-shared'
+import MIMEType from './MIMEType'
const ALL = '*'
function isWXEnv () {
@@ -24,16 +25,20 @@ export default function ({ count, sourceType, type, extension }) {
left: 0
})
+ /**
+ * 选择文件
+ * chooseFile 使用后缀名
+ * chooseImage、chooseVideo 使用MIME类型
+ */
inputEl.accept = extension.map(item => {
if (type !== ALL) {
- // 剔除.拼接在type后
- return `${type}/${item.replace('.', '')}`
+ const MIMEKey = item.replace('.', '')
+ return `${type}/${MIMEType[type][MIMEKey] || MIMEKey}`
} else {
// 在微信环境里,'.jpeg,.png' 会提示没有应用可执行此操作
if (isWXEnv()) {
return '.'
}
- // 在后缀前方加上.
return item.indexOf('.') === 0 ? item : `.${item}`
}
}).join(',')
diff --git a/src/platforms/mp-baidu/runtime/wrapper/component-parser.js b/src/platforms/mp-baidu/runtime/wrapper/component-parser.js
index f2c7037af6be1cad50e716086764851833986fb5..ab57a3f8f20dd4146ff09bedf844bb7ce26841fc 100644
--- a/src/platforms/mp-baidu/runtime/wrapper/component-parser.js
+++ b/src/platforms/mp-baidu/runtime/wrapper/component-parser.js
@@ -8,9 +8,14 @@ import {
import {
isPage,
- initRelation
+ initRelation,
+ mocks
} from './util'
+import {
+ initMocks
+} from 'uni-wrapper/util'
+
import parseBaseComponent from '../../../mp-weixin/runtime/wrapper/component-base-parser'
const newLifecycle = swan.canIUse('lifecycle-2-0')
@@ -52,6 +57,7 @@ export default function parseComponent (vueOptions) {
if (!this.$vm) {
oldAttached.call(this)
} else {
+ initMocks(this.$vm, mocks)
this.__fixInitData && this.__fixInitData()
}
if (isPage.call(this)) { // 百度 onLoad 在 attached 之前触发(基础库小于 3.70)
diff --git a/src/platforms/mp-weixin/runtime/wrapper/app-base-parser.js b/src/platforms/mp-weixin/runtime/wrapper/app-base-parser.js
index 5d1ee7632e3cf305036df437568f82fc82f3a858..aa346c27edc92e6c7e9b059dbb6ee2f0b4693da8 100644
--- a/src/platforms/mp-weixin/runtime/wrapper/app-base-parser.js
+++ b/src/platforms/mp-weixin/runtime/wrapper/app-base-parser.js
@@ -41,11 +41,63 @@ function initEventChannel () {
}
}
+function initScopedSlotsParams () {
+ const center = {}
+ const parents = {}
+
+ Vue.prototype.$hasScopedSlotsParams = function (vueId) {
+ const has = center[vueId]
+ if (!has) {
+ parents[vueId] = this
+ this.$on('hook:destory', () => {
+ delete parents[vueId]
+ })
+ }
+ return has
+ }
+
+ Vue.prototype.$getScopedSlotsParams = function (vueId, name, key) {
+ const data = center[vueId]
+ if (data) {
+ const object = data[name] || {}
+ return key ? object[key] : object
+ } else {
+ parents[vueId] = this
+ this.$on('hook:destory', () => {
+ delete parents[vueId]
+ })
+ }
+ }
+
+ Vue.prototype.$setScopedSlotsParams = function (name, value) {
+ const vueId = this.$options.propsData.vueId
+ const object = center[vueId] = center[vueId] || {}
+ object[name] = value
+ if (parents[vueId]) {
+ parents[vueId].$forceUpdate()
+ }
+ }
+
+ Vue.mixin({
+ destroyed () {
+ const propsData = this.$options.propsData
+ const vueId = propsData && propsData.vueId
+ if (vueId) {
+ delete center[vueId]
+ delete parents[vueId]
+ }
+ }
+ })
+}
+
export default function parseBaseApp (vm, {
mocks,
initRefs
}) {
initEventChannel()
+ if (__PLATFORM__ === 'mp-weixin' || __PLATFORM__ === 'mp-qq' || __PLATFORM__ === 'mp-toutiao' || __PLATFORM__ === 'mp-kuaishou' || __PLATFORM__ === 'mp-alipay' || __PLATFORM__ === 'mp-baidu') {
+ initScopedSlotsParams()
+ }
if (vm.$options.store) {
Vue.prototype.$store = vm.$options.store
}