Skip to content

Commit 2298532

Browse files
authored
Merge pull request #1818 from didi/feat-mini-capture-event
Feat mini capture event
2 parents 9f647c6 + ff96094 commit 2298532

3 files changed

Lines changed: 137 additions & 90 deletions

File tree

packages/core/src/platform/builtInMixins/proxyEventMixin.js

Lines changed: 74 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -4,70 +4,85 @@ import contextMap from '../../dynamic/vnode/context'
44

55
function logCallbackNotFound (context, callbackName) {
66
const location = context.__mpxProxy && context.__mpxProxy.options.mpxFileResource
7-
error(`Instance property [${callbackName}] is not function, please check.`, location)
7+
error(
8+
`Instance property [${callbackName}] is not function, please check.`,
9+
location
10+
)
11+
}
12+
13+
function handleEvent (context, $event, isCapture) {
14+
if (typeof Mpx.config.proxyEventHandler === 'function') {
15+
try {
16+
Mpx.config.proxyEventHandler($event, context)
17+
} catch (e) {
18+
}
19+
}
20+
const location = context.__mpxProxy.options.mpxFileResource
21+
const type = $event.type
22+
// thanos 平台特殊事件标识
23+
const emitMode = $event.detail && $event.detail.mpxEmit
24+
if (!type) {
25+
error('Event object must have [type] property!', location)
26+
return
27+
}
28+
let fallbackType = ''
29+
if (type === 'begin' || type === 'end') {
30+
// 地图的 regionchange 事件会派发 e.type 为 begin 和 end 的事件
31+
fallbackType = __mpx_mode__ === 'ali' ? 'regionChange' : 'regionchange'
32+
} else if (/-([a-z])/.test(type)) {
33+
fallbackType = dash2hump(type)
34+
} else if (__mpx_mode__ === 'ali') {
35+
fallbackType = type.replace(/^./, i => i.toLowerCase())
36+
}
37+
const target = $event.currentTarget || $event.target
38+
if (!target) {
39+
error(`[${type}] event object must have [currentTarget/target] property!`, location)
40+
return
41+
}
42+
const mode = isCapture ? 'capture' : 'bubble'
43+
const eventConfigs = target.dataset.eventconfigs?.[mode] || {}
44+
45+
const curEventConfig = eventConfigs[type] || eventConfigs[fallbackType] || []
46+
// 如果有 mpxuid 说明是运行时组件,那么需要设置对应的上下文
47+
const rootRuntimeContext = contextMap.get(target.dataset.mpxuid)
48+
const runtimeContext = rootRuntimeContext || context
49+
let returnedValue
50+
curEventConfig.forEach((item) => {
51+
const callbackName = item[0]
52+
if (emitMode) {
53+
// thanos 平台特殊事件标识处理
54+
$event = $event.detail.data
55+
}
56+
if (callbackName) {
57+
const params = item.length > 1
58+
? item.slice(1).map(item => {
59+
if (item === '__mpx_event__') {
60+
return $event
61+
} else {
62+
return item
63+
}
64+
})
65+
: [$event]
66+
if (typeof runtimeContext[callbackName] === 'function') {
67+
returnedValue = runtimeContext[callbackName].apply(
68+
runtimeContext,
69+
params
70+
)
71+
} else {
72+
logCallbackNotFound(runtimeContext, callbackName)
73+
}
74+
}
75+
})
76+
return returnedValue
877
}
978

1079
export default function proxyEventMixin () {
1180
const methods = {
1281
__invoke ($event) {
13-
if (typeof Mpx.config.proxyEventHandler === 'function') {
14-
try {
15-
Mpx.config.proxyEventHandler($event, this)
16-
} catch (e) {
17-
}
18-
}
19-
const location = this.__mpxProxy.options.mpxFileResource
20-
const type = $event.type
21-
// thanos 平台特殊事件标识
22-
const emitMode = $event.detail && $event.detail.mpxEmit
23-
if (!type) {
24-
error('Event object must have [type] property!', location)
25-
return
26-
}
27-
let fallbackType = ''
28-
if (type === 'begin' || type === 'end') {
29-
// 地图的 regionchange 事件会派发 e.type 为 begin 和 end 的事件
30-
fallbackType = __mpx_mode__ === 'ali' ? 'regionChange' : 'regionchange'
31-
} else if (/-([a-z])/.test(type)) {
32-
fallbackType = dash2hump(type)
33-
} else if (__mpx_mode__ === 'ali') {
34-
fallbackType = type.replace(/^./, i => i.toLowerCase())
35-
}
36-
const target = $event.currentTarget || $event.target
37-
if (!target) {
38-
error(`[${type}] event object must have [currentTarget/target] property!`, location)
39-
return
40-
}
41-
const eventConfigs = target.dataset.eventconfigs || {}
42-
const curEventConfig = eventConfigs[type] || eventConfigs[fallbackType] || []
43-
// 如果有 mpxuid 说明是运行时组件,那么需要设置对应的上下文
44-
const rootRuntimeContext = contextMap.get(target.dataset.mpxuid)
45-
const context = rootRuntimeContext || this
46-
let returnedValue
47-
curEventConfig.forEach((item) => {
48-
const callbackName = item[0]
49-
if (emitMode) {
50-
// thanos 平台特殊事件标识处理
51-
$event = $event.detail.data
52-
}
53-
if (callbackName) {
54-
const params = item.length > 1
55-
? item.slice(1).map(item => {
56-
if (item === '__mpx_event__') {
57-
return $event
58-
} else {
59-
return item
60-
}
61-
})
62-
: [$event]
63-
if (typeof context[callbackName] === 'function') {
64-
returnedValue = context[callbackName].apply(context, params)
65-
} else {
66-
logCallbackNotFound(context, callbackName)
67-
}
68-
}
69-
})
70-
return returnedValue
82+
return handleEvent(this, $event, false)
83+
},
84+
__captureInvoke ($event) {
85+
return handleEvent(this, $event, true)
7186
},
7287
__model (expr, $event, valuePath = ['value'], filterMethod) {
7388
const innerFilter = {

packages/webpack-plugin/lib/platform/template/wx/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,9 @@ module.exports = function getSpec ({ warn, error }) {
463463
ali (prefix) {
464464
const prefixMap = {
465465
bind: 'on',
466-
catch: 'catch'
466+
catch: 'catch',
467+
'capture-catch': 'capture-catch',
468+
'capture-bind': 'capture-on'
467469
}
468470
if (!prefixMap[prefix]) {
469471
error(`Ali environment does not support [${prefix}] event handling!`)

packages/webpack-plugin/lib/template-compiler/compiler.js

Lines changed: 60 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,8 +1333,35 @@ function processEventReact (el, options) {
13331333
// }
13341334
}
13351335

1336+
function isNeedBind (configs, isProxy) {
1337+
if (isProxy) return true
1338+
if (configs.length > 1) return true
1339+
if (configs.length === 1) return configs[0].hasArgs
1340+
return false
1341+
}
1342+
1343+
function processEventBinding (el, configs) {
1344+
let resultName
1345+
configs.forEach(({ name }) => {
1346+
if (name) {
1347+
// 清空原始事件绑定
1348+
let has
1349+
do {
1350+
has = getAndRemoveAttr(el, name).has
1351+
} while (has)
1352+
1353+
if (!resultName) {
1354+
// 清除修饰符
1355+
resultName = name.replace(/\..*/, '')
1356+
}
1357+
}
1358+
})
1359+
return { resultName }
1360+
}
1361+
13361362
function processEvent (el, options) {
13371363
const eventConfigMap = {}
1364+
const finalEventsMap = {}
13381365
el.attrsList.forEach(function ({ name, value }) {
13391366
const parsedEvent = config[mode].event.parseEvent(name)
13401367

@@ -1346,12 +1373,15 @@ function processEvent (el, options) {
13461373
const extraStr = runtimeCompile && prefix === 'catch' ? `, "__mpx_${prefix}"` : ''
13471374
const parsedFunc = parseFuncStr(value, extraStr)
13481375
if (parsedFunc) {
1376+
const isCapture = /^capture/.test(prefix)
13491377
if (!eventConfigMap[type]) {
13501378
eventConfigMap[type] = {
1351-
configs: []
1379+
configs: [],
1380+
captureConfigs: []
13521381
}
13531382
}
1354-
eventConfigMap[type].configs.push(Object.assign({ name }, parsedFunc))
1383+
const targetConfigs = isCapture ? eventConfigMap[type].captureConfigs : eventConfigMap[type].configs
1384+
targetConfigs.push(Object.assign({ name }, parsedFunc))
13551385
if (modifiers.indexOf('proxy') > -1 || options.forceProxyEvent) {
13561386
eventConfigMap[type].proxy = true
13571387
}
@@ -1393,57 +1423,57 @@ function processEvent (el, options) {
13931423
}
13941424

13951425
for (const type in eventConfigMap) {
1396-
let needBind = false
1397-
const { configs, proxy } = eventConfigMap[type]
1398-
delete eventConfigMap[type]
1399-
if (proxy) {
1400-
needBind = true
1401-
} else if (configs.length > 1) {
1402-
needBind = true
1403-
} else if (configs.length === 1) {
1404-
needBind = !!configs[0].hasArgs
1405-
}
1426+
const { configs = [], captureConfigs = [], proxy } = eventConfigMap[type]
1427+
1428+
let needBubblingBind = isNeedBind(configs, proxy)
1429+
let needCaptureBind = isNeedBind(captureConfigs, proxy)
14061430

14071431
const escapedType = dash2hump(type)
14081432
// 排除特殊情况
14091433
if (!isValidIdentifierStr(escapedType)) {
14101434
warn$1(`EventName ${type} which need be framework proxy processed must be a valid identifier!`)
1411-
needBind = false
1435+
needBubblingBind = false
1436+
needCaptureBind = false
14121437
}
14131438

1414-
if (needBind) {
1415-
let resultName
1416-
configs.forEach(({ name }) => {
1417-
if (name) {
1418-
// 清空原始事件绑定
1419-
let has
1420-
do {
1421-
has = getAndRemoveAttr(el, name).has
1422-
} while (has)
1439+
if (needBubblingBind) {
1440+
const { resultName } = processEventBinding(el, configs)
14231441

1424-
if (!resultName) {
1425-
// 清除修饰符
1426-
resultName = name.replace(/\..*/, '')
1427-
}
1442+
addAttrs(el, [
1443+
{
1444+
name: resultName || config[mode].event.getEvent(type),
1445+
value: '__invoke'
14281446
}
1447+
])
1448+
if (!finalEventsMap.bubble) {
1449+
finalEventsMap.bubble = {}
1450+
}
1451+
finalEventsMap.bubble[escapedType] = configs.map((item) => {
1452+
return item.expStr
14291453
})
1454+
}
14301455

1456+
if (needCaptureBind) {
1457+
const { resultName } = processEventBinding(el, captureConfigs)
14311458
addAttrs(el, [
14321459
{
14331460
name: resultName || config[mode].event.getEvent(type),
1434-
value: '__invoke'
1461+
value: '__captureInvoke'
14351462
}
14361463
])
1437-
eventConfigMap[escapedType] = configs.map((item) => {
1464+
if (!finalEventsMap.capture) {
1465+
finalEventsMap.capture = {}
1466+
}
1467+
finalEventsMap.capture[escapedType] = captureConfigs.map((item) => {
14381468
return item.expStr
14391469
})
14401470
}
14411471
}
14421472

1443-
if (!isEmptyObject(eventConfigMap)) {
1473+
if (!isEmptyObject(finalEventsMap)) {
14441474
addAttrs(el, [{
14451475
name: 'data-eventconfigs',
1446-
value: `{{${shallowStringify(eventConfigMap, true)}}}`
1476+
value: `{{${shallowStringify(finalEventsMap, true)}}}`
14471477
}])
14481478
}
14491479
}

0 commit comments

Comments
 (0)