Skip to content

Commit

Permalink
Merge pull request #1797 from didi/fix-dataset-web
Browse files Browse the repository at this point in the history
Fix dataset web
  • Loading branch information
hiyuki authored Jan 14, 2025
2 parents c38c57a + 55fa49f commit 9647bac
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 57 deletions.
58 changes: 53 additions & 5 deletions packages/core/src/platform/builtInMixins/proxyEventMixin.web.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { setByPath } from '@mpxjs/utils'
import { setByPath, error, parseDataset } from '@mpxjs/utils'
import Mpx from '../../index'

export default function proxyEventMixin () {
return {
Expand All @@ -19,11 +20,58 @@ export default function proxyEventMixin () {
const value = filterMethod ? (innerFilter[filterMethod] ? innerFilter[filterMethod](originValue) : typeof this[filterMethod] === 'function' && this[filterMethod]) : originValue
setByPath(this, expr, value)
},
__invokeHandler (eventName, $event) {
const handler = this[eventName]
if (handler && typeof handler === 'function') {
handler.call(this, $event)
__invoke (rawEvent, eventConfig = []) {
if (typeof Mpx.config.proxyEventHandler === 'function') {
try {
Mpx.config.proxyEventHandler(rawEvent)
} catch (e) {}
}
const location = this.__mpxProxy.options.mpxFileResource

if (rawEvent.target && !rawEvent.target._datasetProcessed) {
const originalDataset = rawEvent.target.dataset
Object.defineProperty(rawEvent.target, 'dataset', {
get: () => parseDataset(originalDataset),
configurable: true,
enumerable: true
})
rawEvent.target._datasetProcessed = true
}
if (rawEvent.currentTarget && !rawEvent.currentTarget._datasetProcessed) {
const originalDataset = rawEvent.currentTarget.dataset
Object.defineProperty(rawEvent.currentTarget, 'dataset', {
get: () => parseDataset(originalDataset),
configurable: true,
enumerable: true
})
rawEvent.currentTarget._datasetProcessed = true
}

let returnedValue
eventConfig.forEach((item) => {
const callbackName = item[0]
if (callbackName) {
const params =
item.length > 1
? item.slice(1).map((item) => {
if (item === '__mpx_event__') {
return rawEvent
} else {
return item
}
})
: [rawEvent]
if (typeof this[callbackName] === 'function') {
returnedValue = this[callbackName].apply(this, params)
} else {
error(
`Instance property [${callbackName}] is not function, please check.`,
location
)
}
}
})
return returnedValue
}
}
}
Expand Down
91 changes: 44 additions & 47 deletions packages/core/src/platform/env/event.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,57 +11,60 @@ function extendEvent (e, extendObj = {}) {
})
}

function MpxEvent (layer) {
this.targetElement = null
this.touches = []
this.touchStartX = 0
this.touchStartY = 0
this.startTimer = null
this.needTap = true
this.isTouchDevice = document && ('ontouchstart' in document.documentElement)
function createMpxEvent (layer) {
let startTimer = null
let needTap = true
let touchStartX = 0
let touchStartY = 0
let targetElement = null
const isTouchDevice = document && 'ontouchstart' in document.documentElement

this.onTouchStart = (event) => {
const onTouchStart = (event) => {
if (event.targetTouches?.length > 1) {
return true
}
this.touches = event.targetTouches
this.targetElement = event.target
this.needTap = true
this.startTimer = null
this.touchStartX = this.touches[0].pageX
this.touchStartY = this.touches[0].pageY
this.startTimer = setTimeout(() => {
this.needTap = false
this.sendEvent(this.targetElement, 'longpress', event)
this.sendEvent(this.targetElement, 'longtap', event)
const touches = event.targetTouches
targetElement = event.target
needTap = true
startTimer = null
touchStartX = touches[0].pageX
touchStartY = touches[0].pageY
startTimer = setTimeout(() => {
needTap = false
sendEvent(targetElement, 'longpress', event)
sendEvent(targetElement, 'longtap', event)
}, 350)
}

this.onTouchMove = (event) => {
const onTouchMove = (event) => {
const touch = event.changedTouches[0]
if (Math.abs(touch.pageX - this.touchStartX) > 1 || Math.abs(touch.pageY - this.touchStartY) > 1) {
this.needTap = false
this.startTimer && clearTimeout(this.startTimer)
this.startTimer = null
if (
Math.abs(touch.pageX - touchStartX) > 1 ||
Math.abs(touch.pageY - touchStartY) > 1
) {
needTap = false
startTimer && clearTimeout(startTimer)
startTimer = null
}
}

this.onTouchEnd = (event) => {
const onTouchEnd = (event) => {
if (event.targetTouches?.length > 1) {
return true
}
this.startTimer && clearTimeout(this.startTimer)
this.startTimer = null
if (this.needTap) {
this.sendEvent(this.targetElement, 'tap', event)
startTimer && clearTimeout(startTimer)
startTimer = null
if (needTap) {
sendEvent(targetElement, 'tap', event)
}
}

this.onClick = (event) => {
this.targetElement = event.target
this.sendEvent(this.targetElement, 'tap', event)
const onClick = (event) => {
targetElement = event.target
sendEvent(targetElement, 'tap', event)
}
this.sendEvent = (targetElement, type, event) => {

const sendEvent = (targetElement, type, event) => {
const touchEvent = new CustomEvent(type, {
bubbles: true,
cancelable: true
Expand All @@ -72,36 +75,30 @@ function MpxEvent (layer) {
changedTouches,
touches: changedTouches,
detail: {
// pc端点击事件可能没有changedTouches,所以直接从 event中取
x: changedTouches[0]?.pageX || event.pageX || 0,
y: changedTouches[0]?.pageY || event.pageY || 0
}
})
targetElement && targetElement.dispatchEvent(touchEvent)
}

this.addListener = () => {
if (this.isTouchDevice) {
layer.addEventListener('touchstart', this.onTouchStart, true)
layer.addEventListener('touchmove', this.onTouchMove, true)
layer.addEventListener('touchend', this.onTouchEnd, true)
} else {
layer.addEventListener('click', this.onClick, true)
}
if (isTouchDevice) {
layer.addEventListener('touchstart', onTouchStart, true)
layer.addEventListener('touchmove', onTouchMove, true)
layer.addEventListener('touchend', onTouchEnd, true)
} else {
layer.addEventListener('click', onClick, true)
}
this.addListener()
}

export function initEvent () {
if (isBrowser && !global.__mpxCreatedEvent) {
global.__mpxCreatedEvent = true
if (document.readyState === 'complete' || document.readyState === 'interactive') {
// eslint-disable-next-line no-new
new MpxEvent(document.body)
createMpxEvent(document.body)
} else {
document.addEventListener('DOMContentLoaded', function () {
// eslint-disable-next-line no-new
new MpxEvent(document.body)
createMpxEvent(document.body)
}, false)
}
}
Expand Down
4 changes: 0 additions & 4 deletions packages/webpack-plugin/lib/platform/template/wx/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -384,10 +384,6 @@ module.exports = function getSpec ({ warn, error }) {
}
},
web ({ name, value }, { eventRules, el, usingComponents }) {
const parsed = parseMustacheWithContext(value)
if (parsed.hasBinding) {
value = '__invokeHandler(' + parsed.result + ', $event)'
}
const match = this.test.exec(name)
const prefix = match[1]
const eventName = match[2]
Expand Down
44 changes: 44 additions & 0 deletions packages/webpack-plugin/lib/template-compiler/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -1157,6 +1157,49 @@ function getModelConfig (el, match) {
}
}

function processEventWeb (el) {
const eventConfigMap = {}
el.attrsList.forEach(function ({ name, value }) {
if (/^@[a-zA-Z]+$/.test(name)) {
const parsedFunc = parseFuncStr(value)
if (parsedFunc) {
if (!eventConfigMap[name]) {
eventConfigMap[name] = {
configs: []
}
}
eventConfigMap[name].configs.push(
Object.assign({ name, value }, parsedFunc)
)
}
}
})

// let wrapper
for (const name in eventConfigMap) {
const { configs } = eventConfigMap[name]
if (!configs.length) continue
configs.forEach(({ name }) => {
if (name) {
// 清空原始事件绑定
let has
do {
has = getAndRemoveAttr(el, name).has
} while (has)
}
})
const value = `(e)=>__invoke(e, [${configs.map(
(item) => item.expStr
)}])`
addAttrs(el, [
{
name,
value
}
])
}
}

function processEventReact (el) {
const eventConfigMap = {}
el.attrsList.forEach(function ({ name, value }) {
Expand Down Expand Up @@ -2642,6 +2685,7 @@ function processElement (el, root, options, meta) {
// 预处理代码维度条件编译
processIfWeb(el)
processScoped(el)
processEventWeb(el)
// processWebExternalClassesHack(el, options)
processExternalClasses(el, options)
processComponentGenericsWeb(el, options, meta)
Expand Down
2 changes: 1 addition & 1 deletion packages/webpack-plugin/test/platform/common/mode.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ describe('template should transform correct', function () {
it('should work correct with web mode', function () {
const input = '<button @click@web="handleClick">获取用户信息</button>'
const output = compileTemplate(input, { mode: 'web' })
expect(output).toBe('<mpx-button @click="handleClick">获取用户信息</mpx-button>')
expect(output).toBe("<mpx-button @click='(e)=>__invoke(e, [[\"handleClick\"]])'>获取用户信息</mpx-button>")
})

it('should work normal if no attr in tag', function () {
Expand Down

0 comments on commit 9647bac

Please sign in to comment.