Refactor event handler setup: improve arrow function and function call handling, enhance error logging

This commit is contained in:
Astrian Zheng 2025-05-14 21:57:38 +10:00
parent c44c9fc2c0
commit e9ddbcdf47
Signed by: Astrian
SSH Key Fingerprint: SHA256:rVnhx3DAKjujCwWE13aDl7uV6+9U1MvydLkNRXJrBiA

View File

@ -269,8 +269,8 @@ export default (options: ComponentOptions) => {
// Handle arrow function: @click="e => setState('count', count + 1)" // Handle arrow function: @click="e => setState('count', count + 1)"
this._setupArrowFunctionHandler(element, eventName, handlerValue) this._setupArrowFunctionHandler(element, eventName, handlerValue)
} else if (handlerValue.includes('(') && handlerValue.includes(')')) { } else if (handlerValue.includes('(') && handlerValue.includes(')')) {
// Handle function call: @click="increment(5)" // Handle function call: @click="increment(5)"
this._setupFunctionCallHandler(element, eventName, handlerValue) this._setupFunctionCallHandler(element, eventName, handlerValue)
} else if (typeof (this as any)[handlerValue] === 'function') { } else if (typeof (this as any)[handlerValue] === 'function') {
// Handle method reference: @click="handleClick" // Handle method reference: @click="handleClick"
element.addEventListener(eventName, (this as any)[handlerValue].bind(this)) element.addEventListener(eventName, (this as any)[handlerValue].bind(this))
@ -287,56 +287,56 @@ export default (options: ComponentOptions) => {
this._textBindings = textBindings this._textBindings = textBindings
} }
// Handle arrow function // Handle arrow function
private _setupArrowFunctionHandler(element: Element, eventName: string, handlerValue: string) { private _setupArrowFunctionHandler(element: Element, eventName: string, handlerValue: string) {
element.addEventListener(eventName, (event: Event) => { element.addEventListener(eventName, (event: Event) => {
try { try {
// Arrow function parsing // Arrow function parsing
const arrowIndex = handlerValue.indexOf('=>') const arrowIndex = handlerValue.indexOf('=>')
const paramsStr = handlerValue.substring(0, arrowIndex).trim() const paramsStr = handlerValue.substring(0, arrowIndex).trim()
let bodyStr = handlerValue.substring(arrowIndex + 2).trim() let bodyStr = handlerValue.substring(arrowIndex + 2).trim()
// Check if the function body is wrapped in {} // Check if the function body is wrapped in {}
const isMultiline = bodyStr.startsWith('{') && bodyStr.endsWith('}') const isMultiline = bodyStr.startsWith('{') && bodyStr.endsWith('}')
// If it is a multiline function body, remove the outer braces // If it is a multiline function body, remove the outer braces
if (isMultiline) { if (isMultiline) {
// Remove the outer braces // Remove the outer braces
bodyStr = bodyStr.substring(1, bodyStr.length - 1) bodyStr = bodyStr.substring(1, bodyStr.length - 1)
// Build code for multiline arrow function // Build code for multiline arrow function
const functionCode = ` const functionCode = `
return function(${paramsStr}) { return function(${paramsStr}) {
${bodyStr} ${bodyStr}
} }
` `
// Create context object // Create context object
const context = this._createHandlerContext(event, element) const context = this._createHandlerContext(event, element)
// Create and call function // Create and call function
const handlerFn = new Function(functionCode).call(null) const handlerFn = new Function(functionCode).call(null)
handlerFn.apply(context, [event]) handlerFn.apply(context, [event])
} else { } else {
// Single line arrow function, directly return expression result // Single line arrow function, directly return expression result
const functionCode = ` const functionCode = `
return function(${paramsStr}) { return function(${paramsStr}) {
return ${bodyStr} return ${bodyStr}
} }
` `
// Create context object // Create context object
const context = this._createHandlerContext(event, element) const context = this._createHandlerContext(event, element)
// Create and call function // Create and call function
const handlerFn = new Function(functionCode).call(null) const handlerFn = new Function(functionCode).call(null)
handlerFn.apply(context, [event]) handlerFn.apply(context, [event])
} }
} catch (err) { } catch (err) {
console.error(`Error executing arrow function handler: ${handlerValue}`, err) console.error(`Error executing arrow function handler: ${handlerValue}`, err)
} }
}) })
} }
// Create handler context // Create handler context
private _createHandlerContext(event: Event, element: Element) { private _createHandlerContext(event: Event, element: Element) {
@ -356,62 +356,62 @@ export default (options: ComponentOptions) => {
setState: this.setState.bind(this), setState: this.setState.bind(this),
getState: this.getState.bind(this) getState: this.getState.bind(this)
} }
// Add all methods of the component // Add all methods of the component
Object.getOwnPropertyNames(Object.getPrototypeOf(this)).forEach(name => { Object.getOwnPropertyNames(Object.getPrototypeOf(this)).forEach(name => {
if (typeof (this as any)[name] === 'function' && name !== 'constructor') { if (typeof (this as any)[name] === 'function' && name !== 'constructor') {
context[name] = (this as any)[name].bind(this) context[name] = (this as any)[name].bind(this)
} }
}) })
return context return context
} }
// Handle function call, such as @click="increment(5)" // Handle function call, such as @click="increment(5)"
private _setupFunctionCallHandler(element: Element, eventName: string, handlerValue: string) { private _setupFunctionCallHandler(element: Element, eventName: string, handlerValue: string) {
element.addEventListener(eventName, (event: Event) => { element.addEventListener(eventName, (event: Event) => {
try { try {
// Create context object // Create context object
const context = this._createHandlerContext(event, element) const context = this._createHandlerContext(event, element)
// Create and execute function call // Create and execute function call
const fnStr = ` const fnStr = `
with(this) { with(this) {
${handlerValue} ${handlerValue}
} }
` `
new Function(fnStr).call(context) new Function(fnStr).call(context)
} catch (err) { } catch (err) {
console.error(`Error executing function call handler: ${handlerValue}`, err) console.error(`Error executing function call handler: ${handlerValue}`, err)
} }
}) })
} }
// Handle simple expression, such as @click="count++" or @input="name = $event.target.value" // Handle simple expression, such as @click="count++" or @input="name = $event.target.value"
private _setupExpressionHandler(element: Element, eventName: string, handlerValue: string) { private _setupExpressionHandler(element: Element, eventName: string, handlerValue: string) {
element.addEventListener(eventName, (event: Event) => { element.addEventListener(eventName, (event: Event) => {
try { try {
// Create context object // Create context object
const context = this._createHandlerContext(event, element) const context = this._createHandlerContext(event, element)
// Create expression function // Create expression function
const fnStr = ` const fnStr = `
with(this) { with(this) {
${handlerValue} ${handlerValue}
} }
` `
// Execute expression // Execute expression
const result = new Function(fnStr).call(context) const result = new Function(fnStr).call(context)
// If the expression returns a value, it can be used for two-way binding // If the expression returns a value, it can be used for two-way binding
return result return result
} catch (err) { } catch (err) {
console.error(`Error executing expression handler: ${handlerValue}`, err) console.error(`Error executing expression handler: ${handlerValue}`, err)
} }
}) })
} }
// Update text node // Update text node
private _updateTextNode(node: Text, expr: string, template: string) { private _updateTextNode(node: Text, expr: string, template: string) {