mirror of
https://github.com/Tencent/Hippy.git
synced 2026-10-29 06:06:52 +08:00
fix(react,vue): fix event register error
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
+8
@@ -458,6 +458,13 @@ declare namespace HippyTypes {
|
||||
CLOSED,
|
||||
}
|
||||
|
||||
export enum EventPhase {
|
||||
NONE,
|
||||
CAPTURING_PHASE,
|
||||
AT_TARGET,
|
||||
BUBBLING_PHASE,
|
||||
}
|
||||
|
||||
export interface DOMEvent {
|
||||
id: number;
|
||||
currentId: number;
|
||||
@@ -465,6 +472,7 @@ declare namespace HippyTypes {
|
||||
currentTarget?: number | object;
|
||||
params?: any;
|
||||
type: string;
|
||||
eventPhase: EventPhase;
|
||||
stopPropagation: () => void;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ import {
|
||||
isCaptureEvent,
|
||||
hasTargetEvent,
|
||||
} from '../utils';
|
||||
import { eventNamesMap, eventHandlerType, NATIVE_EVENT_INDEX, isNativeGesture } from '../utils/node';
|
||||
import { eventNamesMap, eventHandlerType, NATIVE_EVENT_INDEX } from '../utils/node';
|
||||
import { EventDispatcher } from '../event';
|
||||
import ViewNode from './view-node';
|
||||
|
||||
@@ -230,19 +230,18 @@ function getEventName(key: string) {
|
||||
return key;
|
||||
}
|
||||
|
||||
function createEventListener(name): (event: HippyTypes.DOMEvent) => void {
|
||||
function createEventListener(nativeName, originalName): (event: HippyTypes.DOMEvent) => void {
|
||||
return (event) => {
|
||||
const { id, currentId, params } = event;
|
||||
if (isNativeGesture(name)) {
|
||||
const dispatcherEvent = {
|
||||
id, name, currentId,
|
||||
};
|
||||
Object.assign(dispatcherEvent, params);
|
||||
EventDispatcher.receiveNativeGesture(dispatcherEvent, event);
|
||||
} else {
|
||||
const dispatcherEvent = [currentId, name, params];
|
||||
EventDispatcher.receiveUIComponentEvent(dispatcherEvent);
|
||||
}
|
||||
const { id, currentId, params, eventPhase } = event;
|
||||
const dispatcherEvent = {
|
||||
id,
|
||||
nativeName,
|
||||
originalName,
|
||||
params,
|
||||
currentId,
|
||||
eventPhase,
|
||||
};
|
||||
EventDispatcher.receiveComponentEvent(dispatcherEvent, event);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -496,22 +495,25 @@ class ElementNode extends ViewNode {
|
||||
if (typeof value === 'function') {
|
||||
const eventName = getEventName(key);
|
||||
this.attributes[eventName] = value;
|
||||
if (!this.events[eventName]) {
|
||||
this.events[eventName] = {
|
||||
if (!this.events[key]) {
|
||||
// add event initially
|
||||
this.events[key] = {
|
||||
name: eventName,
|
||||
type: eventHandlerType.ADD,
|
||||
isCapture: isCaptureEvent(key),
|
||||
listener: createEventListener(eventName),
|
||||
listener: createEventListener(eventName, key),
|
||||
};
|
||||
} else if (this.events[eventName] && this.events[eventName].type !== eventHandlerType.ADD) {
|
||||
this.events[eventName].type = eventHandlerType.ADD;
|
||||
} else if (this.events[key] && this.events[key].type !== eventHandlerType.ADD) {
|
||||
// add event again when it is removed before
|
||||
this.events[key].type = eventHandlerType.ADD;
|
||||
}
|
||||
} else {
|
||||
const eventName = getEventName(key);
|
||||
if (hasTargetEvent(eventName, this.events)
|
||||
if (hasTargetEvent(key, this.events)
|
||||
&& typeof value !== 'function') {
|
||||
// remove event
|
||||
delete this.attributes[eventName];
|
||||
this.events[eventName].type = eventHandlerType.REMOVE;
|
||||
this.events[key].type = eventHandlerType.REMOVE;
|
||||
return false;
|
||||
}
|
||||
this.attributes[key] = value;
|
||||
|
||||
@@ -19,8 +19,13 @@
|
||||
*/
|
||||
|
||||
import { Fiber } from '@hippy/react-reconciler';
|
||||
import { getFiberNodeFromId, getElementFromFiber, eventNamesMap, NATIVE_EVENT_INDEX } from '../utils/node';
|
||||
import { trace, isGlobalBubble } from '../utils';
|
||||
import {
|
||||
getFiberNodeFromId,
|
||||
getElementFromFiber,
|
||||
isNativeGesture,
|
||||
DOMEventPhase,
|
||||
} from '../utils/node';
|
||||
import { trace, warn, isGlobalBubble, isCaptureEvent } from '../utils';
|
||||
import HippyEventHub from './hub';
|
||||
import Event from './event';
|
||||
|
||||
@@ -29,70 +34,58 @@ type EventParam = string[] | number[];
|
||||
interface NativeEvent {
|
||||
id: number;
|
||||
currentId: number;
|
||||
name: string;
|
||||
nativeName: string;
|
||||
originalName: string;
|
||||
eventPhase: HippyTypes.EventPhase,
|
||||
params?: any
|
||||
}
|
||||
|
||||
const eventHubs = new Map();
|
||||
const componentName = ['%c[event]%c', 'color: green', 'color: auto'];
|
||||
|
||||
/**
|
||||
* convertEventName - convert all special event name
|
||||
* @param eventName
|
||||
* @param nodeItem
|
||||
*/
|
||||
function convertEventName(eventName: string, nodeItem: Fiber) {
|
||||
let processedEvenName = eventName;
|
||||
if (nodeItem.memoizedProps && !nodeItem.memoizedProps[eventName]) {
|
||||
const eventNameList = Object.keys(eventNamesMap);
|
||||
for (let i = 0; i < eventNameList.length; i += 1) {
|
||||
const uiEvent = eventNameList[i];
|
||||
const eventList = eventNamesMap[uiEvent];
|
||||
if (nodeItem.memoizedProps[uiEvent] && eventName === eventList[NATIVE_EVENT_INDEX]) {
|
||||
processedEvenName = uiEvent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return processedEvenName;
|
||||
}
|
||||
|
||||
function isNodePropFunction(prop: string, nextNodeItem: Fiber) {
|
||||
return !!(nextNodeItem.memoizedProps && typeof nextNodeItem.memoizedProps[prop] === 'function');
|
||||
}
|
||||
|
||||
/**
|
||||
* triggerEvent - process event
|
||||
* dispatchGestureEvent - dispatch event
|
||||
* @param {string} eventName
|
||||
* @param {NativeEvent} nativeEvent
|
||||
* @param {Fiber} currentItem
|
||||
* @param {Fiber} targetItem
|
||||
* @param {any} params
|
||||
* @param {HippyTypes.DOMEvent} domEvent
|
||||
*/
|
||||
function triggerEvent(
|
||||
function dispatchGestureEvent(
|
||||
eventName: string,
|
||||
nativeEvent: NativeEvent,
|
||||
currentItem: Fiber,
|
||||
targetItem: Fiber,
|
||||
params: any,
|
||||
domEvent: HippyTypes.DOMEvent,
|
||||
) {
|
||||
let isStopBubble: any = false;
|
||||
const captureEventName = `${eventName}Capture`;
|
||||
const targetNode = getElementFromFiber(targetItem);
|
||||
const currentTargetNode = getElementFromFiber(currentItem);
|
||||
try {
|
||||
// handle capture phase event
|
||||
if (isNodePropFunction(captureEventName, currentItem)) {
|
||||
const syntheticEvent = new Event(captureEventName, currentTargetNode, targetNode);
|
||||
Object.assign(syntheticEvent, nativeEvent);
|
||||
currentItem.memoizedProps[captureEventName](syntheticEvent);
|
||||
let isStopBubble: any = false;
|
||||
const targetNode = getElementFromFiber(targetItem);
|
||||
const currentTargetNode = getElementFromFiber(currentItem);
|
||||
const { eventPhase } = domEvent;
|
||||
// handle target & capture phase event
|
||||
if (isNodePropFunction(eventName, currentItem)
|
||||
&& isCaptureEvent(eventName)
|
||||
&& [DOMEventPhase.AT_TARGET, DOMEventPhase.CAPTURING_PHASE].indexOf(eventPhase) > -1) {
|
||||
const syntheticEvent = new Event(eventName, currentTargetNode, targetNode);
|
||||
Object.assign(syntheticEvent, { eventPhase }, params);
|
||||
currentItem.memoizedProps[eventName](syntheticEvent);
|
||||
if (!syntheticEvent.bubbles && domEvent) {
|
||||
domEvent.stopPropagation();
|
||||
}
|
||||
}
|
||||
// handle target phase event
|
||||
if (isNodePropFunction(eventName, currentItem)) {
|
||||
if (isNodePropFunction(eventName, currentItem)
|
||||
&& !isCaptureEvent(eventName)
|
||||
&& [DOMEventPhase.AT_TARGET, DOMEventPhase.BUBBLING_PHASE].indexOf(eventPhase) > -1) {
|
||||
// handle target & bubbling phase event
|
||||
const syntheticEvent = new Event(eventName, currentTargetNode, targetNode);
|
||||
Object.assign(syntheticEvent, nativeEvent);
|
||||
Object.assign(syntheticEvent, { eventPhase }, params);
|
||||
isStopBubble = currentItem.memoizedProps[eventName](syntheticEvent);
|
||||
// If callback have no return, use global bubble config to set isStopBubble.
|
||||
if (typeof isStopBubble !== 'boolean') {
|
||||
@@ -102,7 +95,7 @@ function triggerEvent(
|
||||
if (!syntheticEvent.bubbles) {
|
||||
isStopBubble = true;
|
||||
}
|
||||
if (isStopBubble !== false && domEvent) {
|
||||
if (isStopBubble && domEvent) {
|
||||
domEvent.stopPropagation();
|
||||
}
|
||||
}
|
||||
@@ -111,21 +104,67 @@ function triggerEvent(
|
||||
}
|
||||
}
|
||||
|
||||
function receiveNativeGesture(nativeEvent: NativeEvent, domEvent: HippyTypes.DOMEvent) {
|
||||
trace(...componentName, 'receiveNativeGesture', nativeEvent);
|
||||
if (!nativeEvent) {
|
||||
/**
|
||||
* dispatchUIEvent - dispatch ui event
|
||||
* @param {string} eventName
|
||||
* @param {NativeEvent} nativeEvent
|
||||
* @param {Fiber} currentItem
|
||||
* @param {Fiber} targetItem
|
||||
* @param {any} params
|
||||
* @param {HippyTypes.DOMEvent} domEvent
|
||||
*/
|
||||
function dispatchUIEvent(
|
||||
eventName: string,
|
||||
nativeEvent: NativeEvent,
|
||||
currentItem: Fiber,
|
||||
targetItem: Fiber,
|
||||
params: any,
|
||||
domEvent: HippyTypes.DOMEvent,
|
||||
) {
|
||||
let isStopBubble: any = false;
|
||||
const targetNode = getElementFromFiber(targetItem);
|
||||
const currentTargetNode = getElementFromFiber(currentItem);
|
||||
try {
|
||||
const { eventPhase } = domEvent;
|
||||
// handle target & bubbling phase event
|
||||
if (isNodePropFunction(eventName, currentItem)
|
||||
&& !isCaptureEvent(eventName)
|
||||
&& [DOMEventPhase.AT_TARGET, DOMEventPhase.BUBBLING_PHASE].indexOf(eventPhase) > -1) {
|
||||
const syntheticEvent = new Event(eventName, currentTargetNode, targetNode);
|
||||
Object.assign(syntheticEvent, { eventPhase }, params);
|
||||
currentItem.memoizedProps[eventName](syntheticEvent);
|
||||
isStopBubble = !isGlobalBubble();
|
||||
// event bubbles flag has higher priority
|
||||
if (!syntheticEvent.bubbles) {
|
||||
isStopBubble = true;
|
||||
}
|
||||
if (isStopBubble && domEvent) {
|
||||
domEvent.stopPropagation();
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
(console as any).reportUncaughtException(err);
|
||||
}
|
||||
}
|
||||
|
||||
function receiveComponentEvent(nativeEvent: NativeEvent, domEvent: HippyTypes.DOMEvent) {
|
||||
trace(...componentName, 'receiveComponentEvent', nativeEvent);
|
||||
if (!nativeEvent || !domEvent) {
|
||||
warn(...componentName, 'receiveComponentEvent', 'nativeEvent or domEvent not exist');
|
||||
return;
|
||||
}
|
||||
const { id, currentId, name } = nativeEvent;
|
||||
const { id, currentId, nativeName, originalName, params } = nativeEvent;
|
||||
const currentTargetNode = getFiberNodeFromId(currentId);
|
||||
const targetNode = getFiberNodeFromId(id);
|
||||
if (!currentTargetNode || !targetNode) {
|
||||
warn(...componentName, 'receiveComponentEvent', 'currentTargetNode or targetNode not exist');
|
||||
return;
|
||||
}
|
||||
const eventName = convertEventName(name, currentTargetNode);
|
||||
const currentItem: Fiber = currentTargetNode;
|
||||
const targetItem: Fiber = targetNode;
|
||||
triggerEvent(eventName, nativeEvent, currentItem, targetItem, domEvent);
|
||||
if (isNativeGesture(nativeName)) {
|
||||
dispatchGestureEvent(originalName, nativeEvent, currentTargetNode, targetNode, params, domEvent);
|
||||
} else {
|
||||
dispatchUIEvent(originalName, nativeEvent, currentTargetNode, targetNode, params, domEvent);
|
||||
}
|
||||
}
|
||||
|
||||
function getHippyEventHub(eventName: any) {
|
||||
@@ -157,24 +196,6 @@ function unregisterNativeEventHub(eventName: any) {
|
||||
}
|
||||
}
|
||||
|
||||
function receiveUIComponentEvent(nativeEvent: any[]) {
|
||||
trace(...componentName, 'receiveUIComponentEvent', nativeEvent);
|
||||
if (!nativeEvent || !Array.isArray(nativeEvent) || nativeEvent.length < 2) {
|
||||
return;
|
||||
}
|
||||
const [targetNodeId, eventName, eventParam] = nativeEvent;
|
||||
if (typeof targetNodeId !== 'number' || typeof eventName !== 'string') {
|
||||
return;
|
||||
}
|
||||
const targetNode = getFiberNodeFromId(targetNodeId);
|
||||
if (!targetNode) {
|
||||
return;
|
||||
}
|
||||
if (isNodePropFunction(eventName, targetNode)) {
|
||||
targetNode.memoizedProps[eventName](eventParam);
|
||||
}
|
||||
}
|
||||
|
||||
function receiveNativeEvent(nativeEvent: EventParam) {
|
||||
trace(...componentName, 'receiveNativeEvent', nativeEvent);
|
||||
if (!nativeEvent || !Array.isArray(nativeEvent) || nativeEvent.length < 2) {
|
||||
@@ -196,8 +217,7 @@ const EventDispatcher = {
|
||||
getHippyEventHub,
|
||||
unregisterNativeEventHub,
|
||||
receiveNativeEvent,
|
||||
receiveNativeGesture,
|
||||
receiveUIComponentEvent,
|
||||
receiveComponentEvent,
|
||||
};
|
||||
|
||||
if (global.__GLOBAL__) {
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
interface Event {
|
||||
type: string;
|
||||
bubbles: boolean;
|
||||
cancelable: boolean;
|
||||
timeStamp: Date | number;
|
||||
currentTarget: Element | null;
|
||||
target: Element | null;
|
||||
}
|
||||
@@ -37,7 +35,6 @@ class Event implements Event {
|
||||
public constructor(eventName: string, currentTarget: Element | null, target: Element | null) {
|
||||
this.type = eventName;
|
||||
this.bubbles = true;
|
||||
this.timeStamp = Date.now();
|
||||
// currentTarget is the node which the handler bind to
|
||||
this.currentTarget = currentTarget;
|
||||
// target is the node which triggered the real event
|
||||
|
||||
@@ -190,6 +190,13 @@ const eventNamesMap: EventNamesMap = {
|
||||
onPress: ['onPress', 'onClick'],
|
||||
};
|
||||
|
||||
const DOMEventPhase = {
|
||||
NONE: 0,
|
||||
CAPTURING_PHASE: 1,
|
||||
AT_TARGET: 2,
|
||||
BUBBLING_PHASE: 3,
|
||||
};
|
||||
|
||||
const nativeEventMap = {
|
||||
onClick: 'click',
|
||||
onLongClick: 'longclick',
|
||||
@@ -215,6 +222,7 @@ function translateToNativeEventName(name) {
|
||||
export {
|
||||
relativeToRefType,
|
||||
NATIVE_EVENT_INDEX,
|
||||
DOMEventPhase,
|
||||
eventHandlerType,
|
||||
eventNamesMap,
|
||||
nativeEventMap,
|
||||
|
||||
@@ -34,7 +34,7 @@ import {
|
||||
warn,
|
||||
} from '../util';
|
||||
import Native from '../runtime/native';
|
||||
import { eventHandlerType, isNativeGesture } from '../util/node';
|
||||
import { eventHandlerType } from '../util/node';
|
||||
import { updateChild, updateWithChildren } from './native';
|
||||
import { Event, EventDispatcher, EventEmitter } from './native/event';
|
||||
import { Text } from './native/components';
|
||||
@@ -200,19 +200,18 @@ function transverseEventNames(eventNames, callback) {
|
||||
}
|
||||
}
|
||||
|
||||
function createEventListener(name) {
|
||||
function createEventListener(nativeName, originalName) {
|
||||
return (event) => {
|
||||
const { id, currentId, params } = event;
|
||||
if (isNativeGesture(name)) {
|
||||
const dispatcherEvent = {
|
||||
id, name, currentId,
|
||||
};
|
||||
Object.assign(dispatcherEvent, params);
|
||||
EventDispatcher.receiveNativeGesture(dispatcherEvent, event);
|
||||
} else {
|
||||
const dispatcherEvent = [currentId, name, params];
|
||||
EventDispatcher.receiveUIComponentEvent(dispatcherEvent, event);
|
||||
}
|
||||
const { id, currentId, params, eventPhase } = event;
|
||||
const dispatcherEvent = {
|
||||
id,
|
||||
nativeName,
|
||||
originalName,
|
||||
currentId,
|
||||
params,
|
||||
eventPhase,
|
||||
};
|
||||
EventDispatcher.receiveComponentEvent(dispatcherEvent, event);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -540,7 +539,7 @@ class ElementNode extends ViewNode {
|
||||
this.events[nativeEventName] = {
|
||||
name: nativeEventName,
|
||||
type: eventHandlerType.ADD,
|
||||
listener: createEventListener(nativeEventName),
|
||||
listener: createEventListener(nativeEventName, eventName),
|
||||
isCapture: false,
|
||||
};
|
||||
} else if (this.events[nativeEventName] && this.events[nativeEventName].type !== eventHandlerType.ADD) {
|
||||
|
||||
+122
-112
@@ -9,7 +9,14 @@ let childNode;
|
||||
let textareaNode;
|
||||
let listview;
|
||||
let iframe;
|
||||
|
||||
const dispatcherEvent = {
|
||||
id: 0,
|
||||
nativeName: '',
|
||||
originalName: '',
|
||||
currentId: 0,
|
||||
params: {},
|
||||
eventPhase: 2,
|
||||
};
|
||||
before(() => {
|
||||
registerBuiltinElements();
|
||||
const rootNode = new ElementNode('div');
|
||||
@@ -26,7 +33,6 @@ before(() => {
|
||||
childNode.appendChild(textareaNode);
|
||||
childNode.appendChild(listview);
|
||||
textareaNode.addEventListener('test', () => {});
|
||||
|
||||
const app = {
|
||||
executed: null,
|
||||
$el: rootNode,
|
||||
@@ -53,167 +59,169 @@ test('receiveNativeEvent test', (t) => {
|
||||
});
|
||||
});
|
||||
|
||||
test('receiveNativeGesture with wrong node id test', (t) => {
|
||||
t.is(EventDispatcher.receiveNativeGesture(), undefined);
|
||||
EventDispatcher.receiveNativeGesture({
|
||||
id: 100,
|
||||
name: 'onTest',
|
||||
test('receiveComponentEvent with wrong node id test', (t) => {
|
||||
t.is(EventDispatcher.receiveComponentEvent(), undefined);
|
||||
const nativeEvent = Object.assign({}, dispatcherEvent, {
|
||||
currentId: 100,
|
||||
nativeName: 'onTest',
|
||||
});
|
||||
EventDispatcher.receiveComponentEvent(nativeEvent);
|
||||
t.pass();
|
||||
});
|
||||
|
||||
test('receiveComponentEvent with wrong event name test', (t) => {
|
||||
t.is(EventDispatcher.receiveComponentEvent(), undefined);
|
||||
const nativeEvent = Object.assign({}, dispatcherEvent, {
|
||||
currentId: 3,
|
||||
nativeName: 'test',
|
||||
});
|
||||
EventDispatcher.receiveComponentEvent(nativeEvent);
|
||||
t.pass();
|
||||
});
|
||||
|
||||
test('receiveComponentEvent test', (t) => {
|
||||
t.is(EventDispatcher.receiveComponentEvent(), undefined);
|
||||
const nativeEvent = Object.assign({}, dispatcherEvent, {
|
||||
currentId: 3,
|
||||
nativeName: 'onTouchDown',
|
||||
});
|
||||
EventDispatcher.receiveComponentEvent(nativeEvent);
|
||||
t.pass();
|
||||
});
|
||||
|
||||
test('receiveComponentEvent with wrong node id type test', (t) => {
|
||||
EventDispatcher.receiveComponentEvent({
|
||||
currentId: 'str',
|
||||
});
|
||||
t.pass();
|
||||
});
|
||||
|
||||
test('receiveNativeGesture with wrong event name test', (t) => {
|
||||
t.is(EventDispatcher.receiveNativeGesture(), undefined);
|
||||
EventDispatcher.receiveNativeGesture({
|
||||
id: 3,
|
||||
name: 'test',
|
||||
test('receiveComponentEvent with wrong event name type test', (t) => {
|
||||
EventDispatcher.receiveComponentEvent({
|
||||
currentId: 'str',
|
||||
});
|
||||
t.pass();
|
||||
});
|
||||
|
||||
test('receiveNativeGesture test', (t) => {
|
||||
t.is(EventDispatcher.receiveNativeGesture(), undefined);
|
||||
EventDispatcher.receiveNativeGesture({
|
||||
id: 3,
|
||||
name: 'onTouchDown',
|
||||
});
|
||||
t.pass();
|
||||
});
|
||||
|
||||
test('receiveUIComponentEvent with wrong node id type test', (t) => {
|
||||
EventDispatcher.receiveUIComponentEvent([
|
||||
'str',
|
||||
]);
|
||||
t.pass();
|
||||
});
|
||||
|
||||
test('receiveUIComponentEvent with wrong event name type test', (t) => {
|
||||
EventDispatcher.receiveUIComponentEvent([
|
||||
10,
|
||||
200,
|
||||
]);
|
||||
t.pass();
|
||||
});
|
||||
|
||||
test('receiveUIComponentEvent with wrong event name test', (t) => {
|
||||
EventDispatcher.receiveUIComponentEvent([
|
||||
10,
|
||||
'onTest',
|
||||
]);
|
||||
t.pass();
|
||||
});
|
||||
|
||||
test('receiveUIComponentEvent onChangeText test', (t) => {
|
||||
t.is(EventDispatcher.receiveUIComponentEvent(), undefined);
|
||||
EventDispatcher.receiveUIComponentEvent([
|
||||
textareaNode.nodeId,
|
||||
'onChangeText',
|
||||
{
|
||||
test('receiveComponentEvent onChangeText test', (t) => {
|
||||
t.is(EventDispatcher.receiveComponentEvent(), undefined);
|
||||
const nativeEvent = Object.assign({}, dispatcherEvent, {
|
||||
currentId: textareaNode.nodeId,
|
||||
nativeName: 'onChangeText',
|
||||
params: {
|
||||
text: 'Hello world',
|
||||
},
|
||||
]);
|
||||
});
|
||||
EventDispatcher.receiveComponentEvent(nativeEvent);
|
||||
t.pass();
|
||||
});
|
||||
|
||||
test('receiveUIComponentEvent onSelectionChange test', (t) => {
|
||||
t.is(EventDispatcher.receiveUIComponentEvent(), undefined);
|
||||
EventDispatcher.receiveUIComponentEvent([
|
||||
textareaNode.nodeId,
|
||||
'onSelectionChange',
|
||||
{
|
||||
test('receiveComponentEvent onSelectionChange test', (t) => {
|
||||
t.is(EventDispatcher.receiveComponentEvent(), undefined);
|
||||
const nativeEvent = Object.assign({}, dispatcherEvent, {
|
||||
currentId: textareaNode.nodeId,
|
||||
nativeName: 'onSelectionChange',
|
||||
params: {
|
||||
selection: {
|
||||
start: 1,
|
||||
end: 2,
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
EventDispatcher.receiveComponentEvent(nativeEvent);
|
||||
t.pass();
|
||||
});
|
||||
|
||||
test('receiveUIComponentEvent onKeyboardWillShow test', (t) => {
|
||||
t.is(EventDispatcher.receiveUIComponentEvent(), undefined);
|
||||
EventDispatcher.receiveUIComponentEvent([
|
||||
textareaNode.nodeId,
|
||||
'onKeyboardWillShow',
|
||||
{
|
||||
test('receiveComponentEvent onKeyboardWillShow test', (t) => {
|
||||
t.is(EventDispatcher.receiveComponentEvent(), undefined);
|
||||
const nativeEvent = Object.assign({}, dispatcherEvent, {
|
||||
currentId: textareaNode.nodeId,
|
||||
nativeName: 'onKeyboardWillShow',
|
||||
params: {
|
||||
keyboardHeight: 123,
|
||||
},
|
||||
]);
|
||||
});
|
||||
EventDispatcher.receiveComponentEvent(nativeEvent);
|
||||
t.pass();
|
||||
});
|
||||
|
||||
test('receiveUIComponentEvent onContentSizeChange test', (t) => {
|
||||
t.is(EventDispatcher.receiveUIComponentEvent(), undefined);
|
||||
EventDispatcher.receiveUIComponentEvent([
|
||||
textareaNode.nodeId,
|
||||
'onContentSizeChange',
|
||||
{
|
||||
test('receiveComponentEvent onContentSizeChange test', (t) => {
|
||||
t.is(EventDispatcher.receiveComponentEvent(), undefined);
|
||||
const nativeEvent = Object.assign({}, dispatcherEvent, {
|
||||
currentId: textareaNode.nodeId,
|
||||
nativeName: 'onContentSizeChange',
|
||||
params: {
|
||||
contentSize: {
|
||||
width: 1,
|
||||
height: 2,
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
EventDispatcher.receiveComponentEvent(nativeEvent);
|
||||
t.pass();
|
||||
});
|
||||
|
||||
test('receiveUIComponentEvent div.onScroll test', (t) => {
|
||||
t.is(EventDispatcher.receiveUIComponentEvent(), undefined);
|
||||
EventDispatcher.receiveUIComponentEvent([
|
||||
childNode.nodeId,
|
||||
'onScroll',
|
||||
{
|
||||
test('receiveComponentEvent div.onScroll test', (t) => {
|
||||
t.is(EventDispatcher.receiveComponentEvent(), undefined);
|
||||
const nativeEvent = Object.assign({}, dispatcherEvent, {
|
||||
currentId: childNode.nodeId,
|
||||
nativeName: 'onScroll',
|
||||
params: {
|
||||
contentOffset: {
|
||||
x: 1,
|
||||
y: 2,
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
EventDispatcher.receiveComponentEvent(nativeEvent);
|
||||
t.pass();
|
||||
});
|
||||
|
||||
test('receiveUIComponentEvent ul.onScroll test', (t) => {
|
||||
t.is(EventDispatcher.receiveUIComponentEvent(), undefined);
|
||||
EventDispatcher.receiveUIComponentEvent([
|
||||
listview.nodeId,
|
||||
'onScroll',
|
||||
{
|
||||
test('receiveComponentEvent ul.onScroll test', (t) => {
|
||||
t.is(EventDispatcher.receiveComponentEvent(), undefined);
|
||||
const nativeEvent = Object.assign({}, dispatcherEvent, {
|
||||
currentId: listview.nodeId,
|
||||
nativeName: 'onScroll',
|
||||
params: {
|
||||
contentOffset: {
|
||||
x: 1,
|
||||
y: 2,
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
EventDispatcher.receiveComponentEvent(nativeEvent);
|
||||
t.pass();
|
||||
});
|
||||
|
||||
test('receiveUIComponentEvent onTouch test', (t) => {
|
||||
t.is(EventDispatcher.receiveUIComponentEvent(), undefined);
|
||||
EventDispatcher.receiveUIComponentEvent([
|
||||
childNode.nodeId,
|
||||
'onTouchDown',
|
||||
{
|
||||
test('receiveComponentEvent onTouch test', (t) => {
|
||||
t.is(EventDispatcher.receiveComponentEvent(), undefined);
|
||||
const nativeEvent1 = Object.assign({}, dispatcherEvent, {
|
||||
currentId: childNode.nodeId,
|
||||
nativeName: 'onTouchDown',
|
||||
params: {
|
||||
page_x: 1,
|
||||
page_y: 2,
|
||||
},
|
||||
]);
|
||||
EventDispatcher.receiveUIComponentEvent([
|
||||
childNode.nodeId,
|
||||
'onTouchMove',
|
||||
{
|
||||
});
|
||||
const nativeEvent2 = Object.assign({}, dispatcherEvent, {
|
||||
currentId: childNode.nodeId,
|
||||
nativeName: 'onTouchMove',
|
||||
params: {
|
||||
page_x: 1,
|
||||
page_y: 2,
|
||||
},
|
||||
]);
|
||||
});
|
||||
EventDispatcher.receiveComponentEvent(nativeEvent1);
|
||||
EventDispatcher.receiveComponentEvent(nativeEvent2);
|
||||
t.pass();
|
||||
});
|
||||
|
||||
test('receiveUIComponentEvent onLayout test', (t) => {
|
||||
t.is(EventDispatcher.receiveUIComponentEvent(), undefined);
|
||||
EventDispatcher.receiveUIComponentEvent([
|
||||
childNode.nodeId,
|
||||
'onLayout',
|
||||
{
|
||||
test('receiveComponentEvent onLayout test', (t) => {
|
||||
t.is(EventDispatcher.receiveComponentEvent(), undefined);
|
||||
const nativeEvent = Object.assign({}, dispatcherEvent, {
|
||||
currentId: childNode.nodeId,
|
||||
nativeName: 'onLayout',
|
||||
params: {
|
||||
layout: {
|
||||
x: 1,
|
||||
y: 2,
|
||||
@@ -221,18 +229,20 @@ test('receiveUIComponentEvent onLayout test', (t) => {
|
||||
height: 200,
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
EventDispatcher.receiveComponentEvent(nativeEvent);
|
||||
t.pass();
|
||||
});
|
||||
|
||||
test('receiveUIComponentEvent onLoad test', (t) => {
|
||||
t.is(EventDispatcher.receiveUIComponentEvent(), undefined);
|
||||
EventDispatcher.receiveUIComponentEvent([
|
||||
iframe.nodeId,
|
||||
'onLoad',
|
||||
{
|
||||
test('receiveComponentEvent onLoad test', (t) => {
|
||||
t.is(EventDispatcher.receiveComponentEvent(), undefined);
|
||||
const nativeEvent = Object.assign({}, dispatcherEvent, {
|
||||
currentId: iframe.nodeId,
|
||||
nativeName: 'onLoad',
|
||||
params: {
|
||||
url: 'http://hippyjs.org',
|
||||
},
|
||||
]);
|
||||
});
|
||||
EventDispatcher.receiveComponentEvent(nativeEvent);
|
||||
t.pass();
|
||||
});
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
|
||||
import { trace, getApp } from '../../../util';
|
||||
import { getNodeById } from '../../../util/node';
|
||||
import { trace, getApp, warn } from '../../../util';
|
||||
import { getNodeById, DOMEventPhase } from '../../../util/node';
|
||||
import { Event } from './event';
|
||||
|
||||
const componentName = ['%c[event]%c', 'color: green', 'color: auto'];
|
||||
@@ -40,33 +40,27 @@ function getVueEventName(eventName, targetNode) {
|
||||
return str.charAt(0).toLowerCase() + str.slice(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Special Touch Event handler compatible for previous camelCase touch event,
|
||||
* such as touchStart, touchMove etc.
|
||||
* @type {{isTouchEvent(), mapTouchEvent()}}
|
||||
*/
|
||||
const SpecialTouchHandler = {
|
||||
isTouchEvent(eventName) {
|
||||
return ['onTouchDown', 'onTouchMove', 'onTouchEnd', 'onTouchCancel'].indexOf(eventName) >= 0;
|
||||
},
|
||||
convertTouchEvent(eventName, nativeEvent) {
|
||||
let touchEvent;
|
||||
if (eventName === 'onTouchDown') {
|
||||
touchEvent = new Event('touchStart');
|
||||
} else {
|
||||
touchEvent = new Event(`t${eventName.slice(3, eventName.length)}`);
|
||||
}
|
||||
touchEvent.touches = {
|
||||
0: {
|
||||
clientX: nativeEvent.page_x,
|
||||
clientY: nativeEvent.page_y,
|
||||
},
|
||||
length: 1,
|
||||
};
|
||||
return touchEvent;
|
||||
},
|
||||
};
|
||||
function isTouchEvent(eventName) {
|
||||
return ['onTouchDown', 'onTouchMove', 'onTouchEnd', 'onTouchCancel'].indexOf(eventName) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert events
|
||||
*/
|
||||
function convertEvent(eventName, targetEvent, params) {
|
||||
if (isTouchEvent(eventName)) {
|
||||
Object.assign(targetEvent, {
|
||||
touches: {
|
||||
0: {
|
||||
clientX: params.page_x,
|
||||
clientY: params.page_y,
|
||||
},
|
||||
length: 1,
|
||||
},
|
||||
});
|
||||
}
|
||||
return targetEvent;
|
||||
}
|
||||
const EventDispatcher = {
|
||||
/**
|
||||
* Redirect native events to Vue directly.
|
||||
@@ -86,62 +80,46 @@ const EventDispatcher = {
|
||||
/**
|
||||
* Receive native interactive events.
|
||||
*/
|
||||
receiveNativeGesture(nativeEvent, domEvent) {
|
||||
trace(...componentName, 'receiveNativeGesture', nativeEvent);
|
||||
if (!nativeEvent) {
|
||||
receiveComponentEvent(nativeEvent, domEvent) {
|
||||
trace(...componentName, 'receiveComponentEvent', nativeEvent);
|
||||
if (!nativeEvent || !domEvent) {
|
||||
warn(...componentName, 'receiveComponentEvent', 'nativeEvent or domEvent not exist');
|
||||
return;
|
||||
}
|
||||
const { id, currentId, name } = nativeEvent;
|
||||
const { id, currentId, nativeName, originalName, params, eventPhase } = nativeEvent;
|
||||
const currentTargetNode = getNodeById(currentId);
|
||||
const targetNode = getNodeById(id);
|
||||
if (!currentTargetNode || !targetNode) {
|
||||
warn(...componentName, 'receiveComponentEvent', 'currentTargetNode or targetNode not exist');
|
||||
return;
|
||||
}
|
||||
const eventName = getVueEventName(name, currentTargetNode);
|
||||
const targetEvent = new Event(eventName);
|
||||
const { processEventData } = currentTargetNode._meta.component;
|
||||
if (processEventData) {
|
||||
processEventData(targetEvent, name, nativeEvent);
|
||||
}
|
||||
currentTargetNode.dispatchEvent(targetEvent, targetNode, domEvent);
|
||||
if (SpecialTouchHandler.isTouchEvent(name)) {
|
||||
currentTargetNode.dispatchEvent(SpecialTouchHandler.convertTouchEvent(name, nativeEvent), targetNode, domEvent);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Receive the events like keyboard typing
|
||||
*/
|
||||
receiveUIComponentEvent(nativeEvent) {
|
||||
trace(...componentName, 'receiveUIComponentEvent', nativeEvent);
|
||||
if (!nativeEvent || !(nativeEvent instanceof Array) || nativeEvent.length < 2) {
|
||||
return;
|
||||
}
|
||||
const [targetNodeId, eventName, params] = nativeEvent;
|
||||
if (typeof targetNodeId !== 'number' || typeof eventName !== 'string') {
|
||||
return;
|
||||
}
|
||||
const targetNode = getNodeById(targetNodeId);
|
||||
if (!targetNode) {
|
||||
return;
|
||||
}
|
||||
const targetEventName = getVueEventName(eventName, targetNode);
|
||||
const targetEvent = new Event(targetEventName);
|
||||
// Post event parameters process.
|
||||
if (eventName === 'onLayout') {
|
||||
const { layout } = params;
|
||||
targetEvent.top = layout.y;
|
||||
targetEvent.left = layout.x;
|
||||
targetEvent.bottom = layout.y + layout.height;
|
||||
targetEvent.right = layout.x + layout.width;
|
||||
targetEvent.width = layout.width;
|
||||
targetEvent.height = layout.height;
|
||||
} else {
|
||||
const { processEventData } = targetNode._meta.component;
|
||||
if (processEventData) {
|
||||
processEventData(targetEvent, eventName, params);
|
||||
try {
|
||||
if ([DOMEventPhase.AT_TARGET, DOMEventPhase.BUBBLING_PHASE].indexOf(eventPhase) > -1) {
|
||||
const targetEvent = new Event(originalName);
|
||||
Object.assign(targetEvent, { eventPhase });
|
||||
if (nativeName === 'onLayout') {
|
||||
const { layout } = params;
|
||||
targetEvent.top = layout.y;
|
||||
targetEvent.left = layout.x;
|
||||
targetEvent.bottom = layout.y + layout.height;
|
||||
targetEvent.right = layout.x + layout.width;
|
||||
targetEvent.width = layout.width;
|
||||
targetEvent.height = layout.height;
|
||||
} else {
|
||||
const { processEventData } = currentTargetNode._meta.component;
|
||||
if (processEventData) {
|
||||
processEventData(targetEvent, nativeName, params);
|
||||
}
|
||||
}
|
||||
currentTargetNode.dispatchEvent(
|
||||
convertEvent(nativeName, targetEvent, params),
|
||||
targetNode,
|
||||
domEvent,
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('receiveComponentEvent error', err);
|
||||
}
|
||||
targetNode.dispatchEvent(targetEvent, targetNode);
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -26,12 +26,9 @@ class Event {
|
||||
this.bubbles = true;
|
||||
this.cancelable = true;
|
||||
this.eventPhase = false;
|
||||
this.timeStamp = Date.now();
|
||||
// TODO: Should point to VDOM element.
|
||||
this.originalTarget = null;
|
||||
this.currentTarget = null;
|
||||
this.target = null;
|
||||
// Private properties
|
||||
this._canceled = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -122,6 +122,14 @@ const nativeEventMap = {
|
||||
onTouchCancel: 'touchcancel',
|
||||
};
|
||||
|
||||
const DOMEventPhase = {
|
||||
NONE: 0,
|
||||
CAPTURING_PHASE: 1,
|
||||
AT_TARGET: 2,
|
||||
BUBBLING_PHASE: 3,
|
||||
};
|
||||
|
||||
|
||||
function isNativeGesture(name) {
|
||||
return !!nativeEventMap[name];
|
||||
}
|
||||
@@ -141,6 +149,7 @@ export {
|
||||
relativeToRefType,
|
||||
eventHandlerType,
|
||||
nativeEventMap,
|
||||
DOMEventPhase,
|
||||
recursivelyUnCacheNode,
|
||||
requestIdleCallback,
|
||||
cancelIdleCallback,
|
||||
|
||||
Reference in New Issue
Block a user