Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix dataset web #1797

Merged
merged 22 commits into from
Jan 14, 2025
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
Loading