+ ${labelOpt.content}
+
`
+ marker.setLabel({
+ content,
+ direction: 'bottom-right'
+ })
+ } else {
+ // google
+ const className = this.updateMarkerLabelStyle(this.idString, labelStyle)
+ marker.setLabel({
+ text: labelOpt.content,
+ color: labelStyle.color,
+ fontSize: labelStyle.fontSize,
+ className
+ })
+ }
}
}
const calloutOpt = option.callout || {}
@@ -210,6 +253,8 @@ export default {
position,
map,
top,
+ // handle AMap callout offset
+ offsetY: -option.height / 2,
content: calloutOpt.content,
color: calloutOpt.color,
fontSize: calloutOpt.fontSize,
@@ -223,26 +268,43 @@ export default {
position,
map,
top,
+ offsetY: -option.height / 2,
content: title,
boxShadow: boxShadow
}
if (callout) {
callout.setOption(calloutStyle)
} else {
- callout = marker.callout = new maps.Callout(calloutStyle)
- callout.div.onclick = ($event) => {
- if (this.idString) {
- this.$parent.$trigger('callouttap', $event, {
- markerId: Number(this.idString)
- })
+ if (IS_AMAP) {
+ const callback = ($event, self) => {
+ if (self.idString) {
+ self.$parent.$trigger('callouttap', $event, {
+ markerId: Number(self.idString)
+ })
+ }
+ }
+ callout = marker.callout = new maps.Callout(calloutStyle, callback, this)
+ } else {
+ callout = marker.callout = new maps.Callout(calloutStyle)
+ callout.div.onclick = ($event) => {
+ if (this.idString) {
+ this.$parent.$trigger('callouttap', $event, {
+ markerId: Number(this.idString)
+ })
+ }
+ $event.stopPropagation()
+ $event.preventDefault()
+ }
+ // The mobile terminal prevent google map callout click trigger map click
+ if (getMapInfo().type === MapType.GOOGLE) {
+ callout.div.onpointerdown = (e) => { e.stopPropagation() }
+ callout.div.ontouchstart = (e) => { e.stopPropagation() }
}
- $event.stopPropagation()
- $event.preventDefault()
}
}
} else {
if (callout) {
- callout.setMap(null)
+ this.removeMarkerCallout(marker.callout)
delete marker.callout
}
}
@@ -253,6 +315,25 @@ export default {
console.error('Marker.iconPath is required.')
}
},
+ handleAMapMarkerClick (e, marker) {
+ const callout = marker.callout
+ if (callout && !callout.alwaysVisible) {
+ callout.visible = !callout.visible
+ if (callout.visible) {
+ marker.callout.createAMapText()
+ } else {
+ marker.callout.removeAMapText()
+ }
+ }
+ if (this.idString) {
+ this.$parent.$trigger('markertap', e, {
+ markerId: Number(this.idString),
+ latitude: marker._position.lat,
+ longitude: marker._position.lng
+ })
+ }
+ e.stopPropagation()
+ },
updateMarkerLabelStyle (id, style) {
const className = 'uni-map-marker-label-' + id
let styleEl = document.getElementById(className)
@@ -276,6 +357,23 @@ export default {
styleEl.innerText = `.${className}{${div.getAttribute('style')}}`
return className
},
+ getMarkerLatitudeLongitude (e) {
+ const mapInfo = getMapInfo()
+ let latitude
+ let longitude
+
+ if (IS_AMAP) {
+ latitude = e.lnglat.lat
+ longitude = e.lnglat.lng
+ } else if (mapInfo.type === MapType.QQ) {
+ latitude = e.latLng.lat
+ longitude = e.latLng.lng
+ } else if (mapInfo.type === MapType.GOOGLE) {
+ latitude = e.latLng.lat()
+ longitude = e.latLng.lng()
+ }
+ return { latitude, longitude }
+ },
removeMarker () {
const marker = this._marker
if (marker) {
@@ -283,12 +381,19 @@ export default {
marker.label.setMap(null)
}
if (marker.callout) {
- marker.callout.setMap(null)
+ this.removeMarkerCallout(marker.callout)
}
marker.setMap(null)
}
delete this.$parent._markers[this.idString]
this._marker = null
+ },
+ removeMarkerCallout (callout) {
+ if (IS_AMAP) {
+ callout.removeAMapText()
+ } else {
+ callout.setMap(null)
+ }
}
},
render () {
diff --git a/src/platforms/h5/view/components/map/map-polygon.js b/src/platforms/h5/view/components/map/map-polygon.js
index e0a7494ba8288efb16e2f53feed294c84be576ce..4b86a703d6d6ea6a1888d5a8229b80962a93c2fe 100644
--- a/src/platforms/h5/view/components/map/map-polygon.js
+++ b/src/platforms/h5/view/components/map/map-polygon.js
@@ -1,8 +1,9 @@
import { hexToRgba } from 'uni-shared'
+import { IS_AMAP } from '../../../helpers/location'
export default {
props: {
- // 边框虚线,腾讯地图支持,google 地图不支持,默认值为[0, 0] 为实线,非 [0, 0] 为虚线,H5 端无法像微信小程序一样控制虚线的间隔像素大小
+ // 边框虚线,腾讯地图支持,google 高德 地图不支持,默认值为[0, 0] 为实线,非 [0, 0] 为虚线,H5 端无法像微信小程序一样控制虚线的间隔像素大小
dashArray: {
type: Array,
default: () => [0, 0]
@@ -65,7 +66,7 @@ export default {
const path = points.map(item => {
const { latitude, longitude } = item
- return new _maps.LatLng(latitude, longitude)
+ return IS_AMAP ? [longitude, latitude] : new _maps.LatLng(latitude, longitude)
})
const { r: fcR, g: fcG, b: fcB, a: fcA } = hexToRgba(fillColor)
diff --git a/src/platforms/h5/view/components/map/maps/callout.js b/src/platforms/h5/view/components/map/maps/callout.js
index 5d7a8fa54e4d2ba0346b81090d55ed01b82eade6..545e2f97d8996c9546b8b254ad6b2ee940cb9461 100644
--- a/src/platforms/h5/view/components/map/maps/callout.js
+++ b/src/platforms/h5/view/components/map/maps/callout.js
@@ -1,5 +1,6 @@
+import { IS_AMAP } from '../../../../helpers/location'
+
export function createCallout (maps) {
- const overlay = new (maps.OverlayView || maps.Overlay)()
function onAdd () {
const div = this.div
const panes = this.getPanes()
@@ -12,6 +13,47 @@ export function createCallout (maps) {
}
}
+ function createAMapText () {
+ const option = this.option
+ this.Text = new maps.Text({
+ text: option.content,
+ anchor: 'bottom-center', // 设置文本标记锚点
+ offset: new maps.Pixel(0, option.offsetY - 16),
+ style: {
+ padding: (option.padding || 8) + 'px',
+ 'line-height': (option.fontSize || 14) + 'px',
+ 'border-radius': (option.borderRadius || 0) + 'px',
+ 'border-color': `${option.bgColor || '#fff'} transparent transparent`,
+ 'background-color': option.bgColor || '#fff',
+ 'box-shadow': '0 2px 6px 0 rgba(114, 124, 245, .5)',
+ 'text-align': 'center',
+ 'font-size': (option.fontSize || 14) + 'px',
+ color: option.color || '#000'
+ },
+ position: option.position
+ })
+ // 不通过 addListener 方式绑定事件,为了规避高德地图覆盖物点击触发map点击问题
+ this.Text.dom.addEventListener('click', e => {
+ handleAMapTextClick(this, e)
+ })
+ this.Text.dom.addEventListener('touchend', e => {
+ handleAMapTextClick(this, e)
+ })
+
+ this.Text.setMap(option.map)
+ }
+
+ function handleAMapTextClick (self, e) {
+ self.callback(e, self.parent)
+ e.stopPropagation()
+ }
+
+ function removeAMapText () {
+ if (this.Text) {
+ this.option.map.remove(this.Text)
+ }
+ }
+
class Callout {
option
position
@@ -20,6 +62,9 @@ export function createCallout (maps) {
alwaysVisible
div
triangle
+ callback
+ parent
+ Text
set onclick (callback) {
this.div.onclick = callback
@@ -29,43 +74,60 @@ export function createCallout (maps) {
return this.div.onclick
}
- constructor (option = {}) {
+ constructor (option = {}, callback, parent) {
this.option = option || {}
- const map = option.map
- this.position = option.position
- this.index = 1
- const visible = (this.visible = this.alwaysVisible = option.display === 'ALWAYS')
- const div = (this.div = document.createElement('div'))
- const divStyle = div.style
- divStyle.position = 'absolute'
- divStyle.whiteSpace = 'nowrap'
- divStyle.transform = 'translateX(-50%) translateY(-100%)'
- divStyle.zIndex = '1'
- divStyle.boxShadow = option.boxShadow || 'none'
- divStyle.display = visible ? 'block' : 'none'
- const triangle = (this.triangle = document.createElement('div'))
- triangle.setAttribute(
- 'style',
- 'position: absolute;white-space: nowrap;border-width: 4px;border-style: solid;border-color: #fff transparent transparent;border-image: initial;font-size: 12px;padding: 0px;background-color: transparent;width: 0px;height: 0px;transform: translate(-50%, 100%);left: 50%;bottom: 0;'
- )
- this.setStyle(option)
- div.appendChild(triangle)
- if (map) {
- this.setMap(map)
+ this.visible = this.alwaysVisible = option.display === 'ALWAYS'
+ if (IS_AMAP) {
+ this.callback = callback
+ this.parent = parent
+ if (this.visible) {
+ this.createAMapText()
+ }
+ } else {
+ const map = option.map
+ this.position = option.position
+ this.index = 1
+ const div = (this.div = document.createElement('div'))
+ const divStyle = div.style
+ divStyle.position = 'absolute'
+ divStyle.whiteSpace = 'nowrap'
+ divStyle.transform = 'translateX(-50%) translateY(-100%)'
+ divStyle.zIndex = '1'
+ divStyle.boxShadow = option.boxShadow || 'none'
+ divStyle.display = this.visible ? 'block' : 'none'
+ const triangle = (this.triangle = document.createElement('div'))
+ triangle.setAttribute(
+ 'style',
+ 'position: absolute;white-space: nowrap;border-width: 4px;border-style: solid;border-color: #fff transparent transparent;border-image: initial;font-size: 12px;padding: 0px;background-color: transparent;width: 0px;height: 0px;transform: translate(-50%, 100%);left: 50%;bottom: 0;'
+ )
+ this.setStyle(option)
+ div.appendChild(triangle)
+ if (map) {
+ this.setMap(map)
+ }
}
}
+ createAMapText = createAMapText
+ removeAMapText = removeAMapText
+
onAdd = onAdd
construct = onAdd
setOption (option) {
this.option = option
- this.setPosition(option.position)
if (option.display === 'ALWAYS') {
this.alwaysVisible = this.visible = true
} else {
this.alwaysVisible = false
}
- this.setStyle(option)
+ if (IS_AMAP) {
+ if (this.visible) {
+ this.createAMapText()
+ }
+ } else {
+ this.setPosition(option.position)
+ this.setStyle(option)
+ }
}
setStyle (option) {
@@ -107,11 +169,15 @@ export function createCallout (maps) {
destroy = onRemove
}
- const prototype = Callout.prototype
- for (const key in overlay) {
- if (!(key in prototype)) {
- prototype[key] = overlay[key]
+ if (!IS_AMAP) {
+ const prototype = Callout.prototype
+ const overlay = new (maps.OverlayView || maps.Overlay)()
+ for (const key in overlay) {
+ if (!(key in prototype)) {
+ prototype[key] = overlay[key]
+ }
}
}
+
return Callout
}
diff --git a/src/platforms/h5/view/components/map/maps/index.js b/src/platforms/h5/view/components/map/maps/index.js
index b284ee4c4c5805d54e020b0ebc330c1dd7c7c144..ad01257081bad6d3972d59bcc9a75ad91787c986 100644
--- a/src/platforms/h5/view/components/map/maps/index.js
+++ b/src/platforms/h5/view/components/map/maps/index.js
@@ -1,6 +1,7 @@
import {
MapType,
- getMapInfo
+ getMapInfo,
+ IS_AMAP
} from '../../../../helpers/location'
import { createCallout } from './callout'
@@ -21,7 +22,7 @@ export function loadMaps (libraries, callback) {
window[mapInfo.type] &&
window[mapInfo.type].maps
) {
- maps = window[mapInfo.type].maps
+ maps = IS_AMAP ? window[mapInfo.type] : window[mapInfo.type].maps
maps.Callout = maps.Callout || createCallout(maps)
callback(maps)
} else if (callbacks.length) {
@@ -32,20 +33,24 @@ export function loadMaps (libraries, callback) {
const callbackName = GOOGLE_MAP_CALLBACKNAME + mapInfo.type
globalExt[callbackName] = function () {
delete globalExt[callbackName]
- maps = window[mapInfo.type].maps
+ maps = IS_AMAP ? window[mapInfo.type] : window[mapInfo.type].maps
maps.Callout = createCallout(maps)
callbacks.forEach((callback) => callback(maps))
callbacks.length = 0
}
const script = document.createElement('script')
- let src =
- mapInfo.type === MapType.GOOGLE ? 'https://maps.googleapis.com/maps/api/js?' : 'https://map.qq.com/api/js?v=2.exp&'
+ let src = getScriptBaseUrl(mapInfo.type)
+
if (mapInfo.type === MapType.QQ) {
libraries.push('geometry')
}
if (libraries.length) {
src += `libraries=${libraries.join('%2C')}&`
}
+
+ if (IS_AMAP) {
+ handleAMapSecurityPolicy(mapInfo)
+ }
script.src = `${src}key=${mapInfo.key}&callback=${callbackName}`
script.onerror = function () {
console.error('Map load failed.')
@@ -53,3 +58,20 @@ export function loadMaps (libraries, callback) {
document.body.appendChild(script)
}
}
+
+function getScriptBaseUrl (mapType) {
+ const urlMap = {
+ qq: 'https://map.qq.com/api/js?v=2.exp&',
+ google: 'https://maps.googleapis.com/maps/api/js?',
+ AMap: 'https://webapi.amap.com/maps?v=2.0&'
+ }
+
+ return urlMap[mapType]
+}
+
+function handleAMapSecurityPolicy (mapInfo) {
+ window._AMapSecurityConfig = {
+ securityJsCode: mapInfo.securityJsCode || '',
+ serviceHost: mapInfo.serviceHost || ''
+ }
+}
diff --git a/src/platforms/h5/view/components/web-view/index.vue b/src/platforms/h5/view/components/web-view/index.vue
index 7510c3af900390e770bbfa92d020e8d236a24e76..8368beecf9ca0979e6ba1293f419a6504953f99b 100644
--- a/src/platforms/h5/view/components/web-view/index.vue
+++ b/src/platforms/h5/view/components/web-view/index.vue
@@ -1,11 +1,16 @@
-
+
+
diff --git a/src/platforms/mp-alipay/runtime/api/protocols.js b/src/platforms/mp-alipay/runtime/api/protocols.js
index 7bf23a3d1ed7fdb37b0c9c55792ad57e06433d53..12079c02447e36807618477dec1eabdbf30768a5 100644
--- a/src/platforms/mp-alipay/runtime/api/protocols.js
+++ b/src/platforms/mp-alipay/runtime/api/protocols.js
@@ -177,7 +177,6 @@ const protocols = { // 需要做转换的 API 列表
const args = {
title: 'content',
icon: 'type',
- duration: false,
image: false,
mask: false
}
@@ -204,8 +203,7 @@ const protocols = { // 需要做转换的 API 列表
},
showLoading: {
args: {
- title: 'content',
- mask: false
+ title: 'content'
}
},
uploadFile: {
@@ -466,12 +464,6 @@ const protocols = { // 需要做转换的 API 列表
hideHomeButton: {
name: 'hideBackHome'
},
- saveImageToPhotosAlbum: {
- name: 'saveImage',
- args: {
- filePath: 'url'
- }
- },
saveVideoToPhotosAlbum: {
args: {
filePath: 'src'
diff --git a/src/platforms/mp-alipay/runtime/wrapper/app-parser.js b/src/platforms/mp-alipay/runtime/wrapper/app-parser.js
index db1dc35db11b95d69cb2f917fb283623b3503182..56bfb3984eee324fc0d7f682b70f7fa029ee92e0 100644
--- a/src/platforms/mp-alipay/runtime/wrapper/app-parser.js
+++ b/src/platforms/mp-alipay/runtime/wrapper/app-parser.js
@@ -8,23 +8,6 @@ import {
} from './util'
export default function parseApp (vm) {
- Object.defineProperty(Vue.prototype, '$slots', {
- get () {
- return this.$scope && this.$scope.props.$slots
- },
- set () {
-
- }
- })
- Object.defineProperty(Vue.prototype, '$scopedSlots', {
- get () {
- return this.$scope && this.$scope.props.$scopedSlots
- },
- set () {
-
- }
- })
-
Vue.prototype.$onAliGetAuthorize = function onAliGetAuthorize (method, $event) {
my.getPhoneNumber({
success: (res) => {
diff --git a/src/platforms/mp-alipay/runtime/wrapper/component-parser.js b/src/platforms/mp-alipay/runtime/wrapper/component-parser.js
index 5dc4c94cf2be066c55a47a34e7cbacf02e95d0dc..9cc232f0bd9166f5441309fb218b7170eff65a56 100644
--- a/src/platforms/mp-alipay/runtime/wrapper/component-parser.js
+++ b/src/platforms/mp-alipay/runtime/wrapper/component-parser.js
@@ -22,6 +22,29 @@ import {
initSpecialMethods
} from './util'
+function initSlots (vm, vueSlots) {
+ const $slots = Object.create(null)
+ // 未启用小程序基础库 2.0 时,组件实例支持支持访问 $slots、$scopedSlots
+ Object.defineProperty(vm, '$slots', {
+ get () {
+ const $scope = this.$scope
+ return ($scope && $scope.props.$slots) || ($scope && $scope.props.$scopedSlots ? {} : $slots)
+ }
+ })
+ Object.defineProperty(vm, '$scopedSlots', {
+ get () {
+ const $scope = this.$scope
+ return ($scope && $scope.props.$scopedSlots) || ($scope && $scope.props.$slots ? {} : $slots)
+ }
+ })
+ // 处理$slots,$scopedSlots(暂不支持动态变化$slots)
+ if (Array.isArray(vueSlots) && vueSlots.length) {
+ vueSlots.forEach(slotName => {
+ $slots[slotName] = true
+ })
+ }
+}
+
function initVm (VueComponent) {
if (this.$vm) {
return
@@ -46,6 +69,8 @@ function initVm (VueComponent) {
// 初始化 vue 实例
this.$vm = new VueComponent(options)
+ initSlots(this.$vm, properties.vueSlots)
+
// 触发首次 setData
this.$vm.$mount()
} else {
@@ -61,6 +86,9 @@ function initVm (VueComponent) {
// 初始化 vue 实例
this.$vm = new VueComponent(options)
handleRef.call(options.parent.$scope, this)
+
+ initSlots(this.$vm, properties.vueSlots)
+
// 触发首次 setData
this.$vm.$mount()
@@ -83,9 +111,7 @@ export default function parseComponent (vueComponentOptions) {
}
Object.keys(properties).forEach(key => {
- if (key !== 'vueSlots') {
- props[key] = properties[key].value
- }
+ props[key] = properties[key].value
})
const componentOptions = {
diff --git a/src/platforms/mp-alipay/runtime/wrapper/page-parser.js b/src/platforms/mp-alipay/runtime/wrapper/page-parser.js
index 756a6534f70efff0de49b47d20ccf4bf3ddbd910..11c0fe59194f8412fc89fb5284e8449907a7b10e 100644
--- a/src/platforms/mp-alipay/runtime/wrapper/page-parser.js
+++ b/src/platforms/mp-alipay/runtime/wrapper/page-parser.js
@@ -7,6 +7,7 @@ import {
import {
initData,
initHooks,
+ initUnknownHooks,
handleEvent,
initBehaviors,
initVueComponent,
@@ -93,6 +94,7 @@ export default function parsePage (vuePageOptions) {
}
initHooks(pageOptions, hooks, vuePageOptions)
+ initUnknownHooks(pageOptions, vuePageOptions, ['onReady'])
if (Array.isArray(vueOptions.wxsCallMethods)) {
vueOptions.wxsCallMethods.forEach(callMethod => {
diff --git a/src/platforms/mp-alipay/runtime/wrapper/util.js b/src/platforms/mp-alipay/runtime/wrapper/util.js
index aa5d034b1e2bf3aeedbbf3831604328354a660cd..1b3e3e9f1c54e0968c49d94a9d381b720932e544 100644
--- a/src/platforms/mp-alipay/runtime/wrapper/util.js
+++ b/src/platforms/mp-alipay/runtime/wrapper/util.js
@@ -111,7 +111,7 @@ export function initChildVues (mpInstance) {
function handleProps (ref) {
const eventProps = {}
let refProps = ref.props
- const eventList = refProps['data-event-list'].split(',')
+ const eventList = (refProps['data-event-list'] || '').split(',')
// 初始化支付宝小程序组件事件
Object.keys(refProps).forEach(key => {
if (eventList.includes(key)) {
@@ -227,7 +227,7 @@ export const handleLink = (function () {
export const handleWrap = function (mp, destory) {
const vueId = mp.props.vueId
- const list = mp.props['data-event-list'].split(',')
+ const list = (mp.props['data-event-list'] || '').split(',')
list.forEach(eventName => {
const key = `${eventName}${vueId}`
if (destory) {
diff --git a/src/platforms/mp-toutiao/runtime/wrapper/component-parser.js b/src/platforms/mp-toutiao/runtime/wrapper/component-parser.js
index 97dc705635c8df50c2130f5ae21cf649b0f05629..be28d0313c4a1bd90f0080bc117656caad8a4bd8 100644
--- a/src/platforms/mp-toutiao/runtime/wrapper/component-parser.js
+++ b/src/platforms/mp-toutiao/runtime/wrapper/component-parser.js
@@ -1,7 +1,8 @@
import {
isPage,
initRelation,
- handleLink
+ handleLink,
+ components
} from './util'
import {
@@ -11,17 +12,26 @@ import {
import parseBaseComponent from '../../../mp-weixin/runtime/wrapper/component-base-parser'
-const components = []
+function currentComponents (mpInstance, callback) {
+ const webviewId = mpInstance.__webviewId__
+ const currentComponents = components[webviewId]
+ if (currentComponents) {
+ callback(currentComponents)
+ }
+}
export default function parseComponent (vueOptions) {
const [componentOptions, VueComponent] = parseBaseComponent(vueOptions)
+ const lifetimes = componentOptions.lifetimes
// 基础库 2.0 以上 attached 顺序错乱,按照 created 顺序强制纠正
- componentOptions.lifetimes.created = function created () {
- components.push(this)
+ lifetimes.created = function created () {
+ currentComponents(this, components => {
+ components.push(this)
+ })
}
- componentOptions.lifetimes.attached = function attached () {
+ lifetimes.attached = function attached () {
this.__lifetimes_attached = function () {
const properties = this.properties
@@ -48,17 +58,32 @@ export default function parseComponent (vueOptions) {
// 触发首次 setData
this.$vm.$mount()
}
- let component = this
- while (component && component.__lifetimes_attached && components[0] && component === components[0]) {
- components.shift()
- component.__lifetimes_attached()
- delete component.__lifetimes_attached
- component = components[0]
+ currentComponents(this, components => {
+ let component = this
+ while (component && component.__lifetimes_attached && components[0] && component === components[0]) {
+ components.shift()
+ component.__lifetimes_attached()
+ delete component.__lifetimes_attached
+ component = components[0]
+ }
+ })
+ }
+
+ const oldDetached = lifetimes.detached
+ lifetimes.detached = function detached () {
+ if (typeof oldDetached === 'function') {
+ oldDetached.call(this)
}
+ currentComponents(this, components => {
+ const index = components.indexOf(this)
+ if (index >= 0) {
+ components.splice(index, 1)
+ }
+ })
}
// ready 比 handleLink 还早,初始化逻辑放到 handleLink 中
- delete componentOptions.lifetimes.ready
+ delete lifetimes.ready
componentOptions.methods.__l = handleLink
diff --git a/src/platforms/mp-toutiao/runtime/wrapper/page-parser.js b/src/platforms/mp-toutiao/runtime/wrapper/page-parser.js
index 6598851b0a2982bd538f235064b7cd82f9db1f8b..4776891a4cb033286997ed247d77e4f96069e7d0 100644
--- a/src/platforms/mp-toutiao/runtime/wrapper/page-parser.js
+++ b/src/platforms/mp-toutiao/runtime/wrapper/page-parser.js
@@ -1,6 +1,7 @@
import {
- isPage,
+ isPage,
instances,
+ components,
initRelation
} from './util'
@@ -11,8 +12,17 @@ export default function parsePage (vuePageOptions) {
isPage,
initRelation
})
+ const lifetimes = pageOptions.lifetimes
+ const oldCreated = lifetimes.created
+ lifetimes.created = function created () {
+ const webviewId = this.__webviewId__
+ components[webviewId] = []
+ if (typeof oldCreated === 'function') {
+ oldCreated.call(this)
+ }
+ }
// 页面需要在 ready 中触发,其他组件是在 handleLink 中触发
- pageOptions.lifetimes.ready = function ready () {
+ lifetimes.ready = function ready () {
if (this.$vm && this.$vm.mpType === 'page') {
this.$vm.__call_hook('created')
this.$vm.__call_hook('beforeMount')
@@ -22,18 +32,21 @@ export default function parsePage (vuePageOptions) {
} else {
this.is && console.warn(this.is + ' is not ready')
}
- }
-
- pageOptions.lifetimes.detached = function detached () {
- this.$vm && this.$vm.$destroy()
- // 清理
- const webviewId = this.__webviewId__
- webviewId && Object.keys(instances).forEach(key => {
- if (key.indexOf(webviewId + '_') === 0) {
- delete instances[key]
- }
- })
+ }
+ const oldDetached = lifetimes.detached
+ lifetimes.detached = function detached () {
+ if (typeof oldDetached === 'function') {
+ oldDetached.call(this)
+ }
+ // 清理
+ const webviewId = this.__webviewId__
+ webviewId && Object.keys(instances).forEach(key => {
+ if (key.indexOf(webviewId + '_') === 0) {
+ delete instances[key]
+ }
+ })
+ delete components[webviewId]
}
return pageOptions
-}
+}
diff --git a/src/platforms/mp-toutiao/runtime/wrapper/util.js b/src/platforms/mp-toutiao/runtime/wrapper/util.js
index 01980a0cca5b251dca285b3133c0f62b16eb6afe..44aadf0c4227c8747508e1fc689b9e82ade0e31c 100644
--- a/src/platforms/mp-toutiao/runtime/wrapper/util.js
+++ b/src/platforms/mp-toutiao/runtime/wrapper/util.js
@@ -16,12 +16,13 @@ export function initRefs (vm) {
Object.defineProperty(vm, '$refs', {
get () {
const $refs = {}
- const components = mpInstance.selectAllComponents('.vue-ref')
+ // mpInstance 销毁后 selectAllComponents 取值为 null
+ const components = mpInstance.selectAllComponents('.vue-ref') || []
components.forEach(component => {
const ref = component.dataset.ref
$refs[ref] = component.$vm || component
})
- const forComponents = mpInstance.selectAllComponents('.vue-ref-in-for')
+ const forComponents = mpInstance.selectAllComponents('.vue-ref-in-for') || []
forComponents.forEach(component => {
const ref = component.dataset.ref
if (!$refs[ref]) {
@@ -52,6 +53,7 @@ export function initRefs (vm) {
}
export const instances = Object.create(null)
+export const components = Object.create(null)
export function initRelation ({
vuePid,
@@ -101,4 +103,4 @@ export function handleLink ({
vm._isMounted = true
vm.__call_hook('mounted')
vm.__call_hook('onReady')
-}
+}
diff --git a/src/platforms/mp-weixin/runtime/index.js b/src/platforms/mp-weixin/runtime/index.js
index ed11b5f932f6f793f67b25a1c33f8a906c649514..4012f0b42221f00a0cfdfedc7d1a3e4ee9af0055 100644
--- a/src/platforms/mp-weixin/runtime/index.js
+++ b/src/platforms/mp-weixin/runtime/index.js
@@ -15,7 +15,17 @@ const customize = cached((str) => {
function initTriggerEvent (mpInstance) {
const oldTriggerEvent = mpInstance.triggerEvent
const newTriggerEvent = function (event, ...args) {
- return oldTriggerEvent.apply(mpInstance, [customize(event), ...args])
+ // 事件名统一转驼峰格式,仅处理:当前组件为 vue 组件、当前组件为 vue 组件子组件
+ if (this.$vm || (this.dataset && this.dataset.comType)) {
+ event = customize(event)
+ } else if (__PLATFORM__ === 'mp-weixin' || __PLATFORM__ === 'mp-qq') {
+ // 针对微信/QQ小程序单独补充驼峰格式事件,以兼容历史项目
+ const newEvent = customize(event)
+ if (newEvent !== event) {
+ oldTriggerEvent.apply(this, [newEvent, ...args])
+ }
+ }
+ return oldTriggerEvent.apply(this, [event, ...args])
}
try {
// 京东小程序 triggerEvent 为只读
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 d8659b99c9ec7066767febbb5a8d4676c948ac6d..762c3c740ab7aa5a40bf76bad5398abf44459112 100644
--- a/src/platforms/mp-weixin/runtime/wrapper/app-base-parser.js
+++ b/src/platforms/mp-weixin/runtime/wrapper/app-base-parser.js
@@ -2,6 +2,7 @@ import Vue from 'vue'
import {
initHooks,
+ initUnknownHooks,
initMocks
} from 'uni-wrapper/util'
@@ -190,6 +191,7 @@ export default function parseBaseApp (vm, {
initAppLocale(Vue, vm, normalizeLocale(__GLOBAL__.getSystemInfoSync().language) || LOCALE_EN)
initHooks(appOptions, hooks)
+ initUnknownHooks(appOptions, vm.$options)
return appOptions
}
diff --git a/src/platforms/mp-weixin/runtime/wrapper/page-base-parser.js b/src/platforms/mp-weixin/runtime/wrapper/page-base-parser.js
index 7d908d9f0ebfa11e8c0b15d63183b589235a0ded..e8fe85ef6f34a4af97629f5cade06b259bc5ff5d 100644
--- a/src/platforms/mp-weixin/runtime/wrapper/page-base-parser.js
+++ b/src/platforms/mp-weixin/runtime/wrapper/page-base-parser.js
@@ -4,6 +4,7 @@ import {
import {
initHooks,
+ initUnknownHooks,
PAGE_EVENT_HOOKS
} from 'uni-wrapper/util'
@@ -38,6 +39,11 @@ export default function parseBasePage (vuePageOptions, {
this.$vm.$mp.query = query // 兼容 mpvue
this.$vm.__call_hook('onLoad', query)
}
+ if (__PLATFORM__ === 'mp-baidu') {
+ initUnknownHooks(pageOptions.methods, vuePageOptions, ['onInit', 'onReady'])
+ } else {
+ initUnknownHooks(pageOptions.methods, vuePageOptions, ['onReady'])
+ }
return pageOptions
-}
+}
diff --git a/src/platforms/mp-xhs/runtime/wrapper/page-parser.js b/src/platforms/mp-xhs/runtime/wrapper/page-parser.js
index f60f8f69ed1d9bf8e4da26d2a59ee44640e8f3cb..f206ca955fbea1bbaf4e771249e6f4c88595322a 100644
--- a/src/platforms/mp-xhs/runtime/wrapper/page-parser.js
+++ b/src/platforms/mp-xhs/runtime/wrapper/page-parser.js
@@ -7,6 +7,7 @@ import {
import {
initData,
initHooks,
+ initUnknownHooks,
handleEvent,
initBehaviors,
initVueComponent,
@@ -80,6 +81,7 @@ export default function parsePage (vuePageOptions) {
}
initHooks(pageOptions, hooks, vuePageOptions)
+ initUnknownHooks(pageOptions, vuePageOptions, ['onReady'])
if (Array.isArray(vueOptions.wxsCallMethods)) {
vueOptions.wxsCallMethods.forEach(callMethod => {
diff --git a/src/platforms/mp-xhs/runtime/wrapper/util.js b/src/platforms/mp-xhs/runtime/wrapper/util.js
index b9eb54824b496de5116231f7b7488b27369cc6c4..5565a5fe0c067e7829b99fcea75c67678f5f759f 100644
--- a/src/platforms/mp-xhs/runtime/wrapper/util.js
+++ b/src/platforms/mp-xhs/runtime/wrapper/util.js
@@ -1,52 +1,52 @@
-import {
- isFn,
- hasOwn
-} from 'uni-shared'
-
-export const isComponent2 = xhs.canIUse('component2')
-
-export const mocks = ['$id']
-
-export function initSpecialMethods (mpInstance) {
- if (!mpInstance.$vm) {
- return
- }
- let path = mpInstance.is || mpInstance.route
- if (!path) {
- return
- }
- if (path.indexOf('/') === 0) {
- path = path.substr(1)
- }
- const specialMethods = xhs.specialMethods && xhs.specialMethods[path]
- if (specialMethods) {
- specialMethods.forEach(method => {
- if (isFn(mpInstance.$vm[method])) {
- mpInstance[method] = function (event) {
- if (hasOwn(event, 'markerId')) {
- event.detail = typeof event.detail === 'object' ? event.detail : {}
- event.detail.markerId = event.markerId
- }
- // TODO normalizeEvent
- mpInstance.$vm[method](event)
- }
- }
- })
- }
-}
-
-export const handleWrap = function (mp, destory) {
- const vueId = mp.props.vueId
- const list = mp.props['data-event-list'].split(',')
- list.forEach(eventName => {
- const key = `${eventName}${vueId}`
- if (destory) {
- delete this[key]
- } else {
- // TODO remove handleRef
- this[key] = function () {
- mp.props[eventName].apply(this, arguments)
- }
- }
- })
-}
+import {
+ isFn,
+ hasOwn
+} from 'uni-shared'
+
+export const isComponent2 = xhs.canIUse('component2')
+
+export const mocks = ['$id']
+
+export function initSpecialMethods (mpInstance) {
+ if (!mpInstance.$vm) {
+ return
+ }
+ let path = mpInstance.is || mpInstance.route
+ if (!path) {
+ return
+ }
+ if (path.indexOf('/') === 0) {
+ path = path.substr(1)
+ }
+ const specialMethods = xhs.specialMethods && xhs.specialMethods[path]
+ if (specialMethods) {
+ specialMethods.forEach(method => {
+ if (isFn(mpInstance.$vm[method])) {
+ mpInstance[method] = function (event) {
+ if (hasOwn(event, 'markerId')) {
+ event.detail = typeof event.detail === 'object' ? event.detail : {}
+ event.detail.markerId = event.markerId
+ }
+ // TODO normalizeEvent
+ mpInstance.$vm[method](event)
+ }
+ }
+ })
+ }
+}
+
+export const handleWrap = function (mp, destory) {
+ const vueId = mp.props.vueId
+ const list = (mp.props['data-event-list'] || '').split(',')
+ list.forEach(eventName => {
+ const key = `${eventName}${vueId}`
+ if (destory) {
+ delete this[key]
+ } else {
+ // TODO remove handleRef
+ this[key] = function () {
+ mp.props[eventName].apply(this, arguments)
+ }
+ }
+ })
+}
diff --git a/yarn.lock b/yarn.lock
index 35eedd6d3adbceb0cefae6bdd964e7b5cc05d985..26f33ccc41a8248ffe4eeb05997b3838d45dfd0c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3433,6 +3433,11 @@ escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1
version "1.0.5"
resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+escape-string-regexp@4:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
+ integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
+
escodegen@^1.11.1, escodegen@^1.14.1:
version "1.14.1"
resolved "https://registry.npmjs.org/escodegen/-/escodegen-1.14.1.tgz#ba01d0c8278b5e95a9a45350142026659027a457"
@@ -4215,6 +4220,11 @@ getpass@^0.1.1:
dependencies:
assert-plus "^1.0.0"
+glob-escape@^0.0.2:
+ version "0.0.2"
+ resolved "https://registry.yarnpkg.com/glob-escape/-/glob-escape-0.0.2.tgz#9c27f7821ed1c1377582f3efd9558e3f675628ed"
+ integrity sha512-L/cXYz8x7qer1HAyUQ+mbjcUsJVdpRxpAf7CwqHoNBs9vTpABlGfNN4tzkDxt+u3Z7ZncVyKlCNPtzb0R/7WbA==
+
glob-parent@5.1.0:
version "5.1.0"
resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2"