Match-id-eb7f82b390c5406b3d957108c9dc9e8f650a0a74
This commit is contained in:
parent
423b0374b3
commit
4d24ebd544
|
@ -1,4 +1,4 @@
|
||||||
import { allDelegatedHorizonEvents } from '../../event/EventCollection';
|
import { allDelegatedHorizonEvents } from '../../event/EventHub';
|
||||||
import { updateCommonProp } from './UpdateCommonProp';
|
import { updateCommonProp } from './UpdateCommonProp';
|
||||||
import { setStyles } from './StyleHandler';
|
import { setStyles } from './StyleHandler';
|
||||||
import { lazyDelegateOnRoot, listenNonDelegatedEvent } from '../../event/EventBinding';
|
import { lazyDelegateOnRoot, listenNonDelegatedEvent } from '../../event/EventBinding';
|
||||||
|
@ -19,7 +19,6 @@ export function setDomProps(dom: Element, props: Object, isNativeTag: boolean, i
|
||||||
setStyles(dom, propVal);
|
setStyles(dom, propVal);
|
||||||
} else if (isEventProp(propName)) {
|
} else if (isEventProp(propName)) {
|
||||||
// 事件监听属性处理
|
// 事件监听属性处理
|
||||||
// TODO
|
|
||||||
const currentRoot = getCurrentRoot();
|
const currentRoot = getCurrentRoot();
|
||||||
if (!allDelegatedHorizonEvents.has(propName)) {
|
if (!allDelegatedHorizonEvents.has(propName)) {
|
||||||
listenNonDelegatedEvent(propName, dom, propVal);
|
listenNonDelegatedEvent(propName, dom, propVal);
|
||||||
|
|
|
@ -1,27 +1,29 @@
|
||||||
/**
|
/**
|
||||||
* 事件绑定实现,分为绑定委托事件和非委托事件
|
* 事件绑定实现,分为绑定委托事件和非委托事件
|
||||||
*/
|
*/
|
||||||
import { allDelegatedHorizonEvents, allDelegatedNativeEvents } from './EventCollection';
|
|
||||||
import {isDocument} from '../dom/utils/Common';
|
|
||||||
import {
|
import {
|
||||||
getNearestVNode,
|
allDelegatedHorizonEvents,
|
||||||
getNonDelegatedListenerMap,
|
allDelegatedNativeEvents,
|
||||||
} from '../dom/DOMInternalKeys';
|
} from './EventHub';
|
||||||
import {runDiscreteUpdates} from '../renderer/TreeBuilder';
|
import { isDocument } from '../dom/utils/Common';
|
||||||
import {isMounted} from '../renderer/vnode/VNodeUtils';
|
import { getNearestVNode, getNonDelegatedListenerMap } from '../dom/DOMInternalKeys';
|
||||||
import {SuspenseComponent} from '../renderer/vnode/VNodeTags';
|
import { runDiscreteUpdates } from '../renderer/TreeBuilder';
|
||||||
import {handleEventMain} from './HorizonEventMain';
|
import { handleEventMain } from './HorizonEventMain';
|
||||||
import {decorateNativeEvent} from './customEvents/EventFactory';
|
import { decorateNativeEvent } from './EventWrapper';
|
||||||
import { VNode } from '../renderer/vnode/VNode';
|
import { VNode } from '../renderer/vnode/VNode';
|
||||||
|
|
||||||
const listeningMarker = '_horizonListening' + Math.random().toString(36).slice(4);
|
const listeningMarker =
|
||||||
|
'_horizonListening' +
|
||||||
|
Math.random()
|
||||||
|
.toString(36)
|
||||||
|
.slice(4);
|
||||||
|
|
||||||
// 触发委托事件
|
// 触发委托事件
|
||||||
function triggerDelegatedEvent(
|
function triggerDelegatedEvent(
|
||||||
nativeEvtName: string,
|
nativeEvtName: string,
|
||||||
isCapture: boolean,
|
isCapture: boolean,
|
||||||
targetDom: EventTarget,
|
targetDom: EventTarget,
|
||||||
nativeEvent, // 事件对象event
|
nativeEvent // 事件对象event
|
||||||
) {
|
) {
|
||||||
// 执行之前的调度事件
|
// 执行之前的调度事件
|
||||||
runDiscreteUpdates();
|
runDiscreteUpdates();
|
||||||
|
@ -33,11 +35,7 @@ function triggerDelegatedEvent(
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听委托事件
|
// 监听委托事件
|
||||||
function listenToNativeEvent(
|
function listenToNativeEvent(nativeEvtName: string, delegatedElement: Element, isCapture: boolean): void {
|
||||||
nativeEvtName: string,
|
|
||||||
delegatedElement: Element,
|
|
||||||
isCapture: boolean,
|
|
||||||
): void {
|
|
||||||
let dom: Element | Document = delegatedElement;
|
let dom: Element | Document = delegatedElement;
|
||||||
// document层次可能触发selectionchange事件,为了捕获这类事件,selectionchange事件绑定在document节点上
|
// document层次可能触发selectionchange事件,为了捕获这类事件,selectionchange事件绑定在document节点上
|
||||||
if (nativeEvtName === 'selectionchange' && !isDocument(delegatedElement)) {
|
if (nativeEvtName === 'selectionchange' && !isDocument(delegatedElement)) {
|
||||||
|
@ -70,10 +68,15 @@ export function lazyDelegateOnRoot(currentRoot: VNode, eventName: string) {
|
||||||
|
|
||||||
const isCapture = isCaptureEvent(eventName);
|
const isCapture = isCaptureEvent(eventName);
|
||||||
const nativeEvents = allDelegatedHorizonEvents.get(eventName);
|
const nativeEvents = allDelegatedHorizonEvents.get(eventName);
|
||||||
nativeEvents.forEach(nativeEvents => {
|
|
||||||
listenToNativeEvent(nativeEvents, currentRoot.realNode, isCapture);
|
nativeEvents.forEach(nativeEvent => {
|
||||||
|
if (!currentRoot.delegatedNativeEvents.has(nativeEvent)) {
|
||||||
|
listenToNativeEvent(nativeEvent, currentRoot.realNode, isCapture);
|
||||||
|
currentRoot.delegatedNativeEvents.add(nativeEvent);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 通过horizon事件名获取到native事件名
|
// 通过horizon事件名获取到native事件名
|
||||||
function getNativeEvtName(horizonEventName, capture) {
|
function getNativeEvtName(horizonEventName, capture) {
|
||||||
let nativeName;
|
let nativeName;
|
||||||
|
@ -105,11 +108,7 @@ function getWrapperListener(horizonEventName, nativeEvtName, targetElement, list
|
||||||
}
|
}
|
||||||
|
|
||||||
// 非委托事件单独监听到各自dom节点
|
// 非委托事件单独监听到各自dom节点
|
||||||
export function listenNonDelegatedEvent(
|
export function listenNonDelegatedEvent(horizonEventName: string, domElement: Element, listener): void {
|
||||||
horizonEventName: string,
|
|
||||||
domElement: Element,
|
|
||||||
listener,
|
|
||||||
): void {
|
|
||||||
const isCapture = isCaptureEvent(horizonEventName);
|
const isCapture = isCaptureEvent(horizonEventName);
|
||||||
const nativeEvtName = getNativeEvtName(horizonEventName, isCapture);
|
const nativeEvtName = getNativeEvtName(horizonEventName, isCapture);
|
||||||
|
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
import {horizonEventToNativeMap} from './const';
|
|
||||||
|
|
||||||
// 需要委托的horizon事件和原生事件对应关系
|
|
||||||
export const allDelegatedHorizonEvents = new Map();
|
|
||||||
// 所有委托的原生事件集合
|
|
||||||
export const allDelegatedNativeEvents = new Set();
|
|
||||||
|
|
||||||
horizonEventToNativeMap.forEach((dependencies, horizonEvent) => {
|
|
||||||
allDelegatedHorizonEvents.set(horizonEvent, dependencies);
|
|
||||||
allDelegatedHorizonEvents.set(horizonEvent + 'Capture', dependencies);
|
|
||||||
|
|
||||||
dependencies.forEach(d => {
|
|
||||||
allDelegatedNativeEvents.add(d);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
// 需要委托的horizon事件和原生事件对应关系
|
||||||
|
export const allDelegatedHorizonEvents = new Map();
|
||||||
|
// 所有委托的原生事件集合
|
||||||
|
export const allDelegatedNativeEvents = new Set();
|
||||||
|
|
||||||
// Horizon事件和原生事件对应关系
|
// Horizon事件和原生事件对应关系
|
||||||
export const horizonEventToNativeMap = new Map([
|
export const horizonEventToNativeMap = new Map([
|
||||||
|
@ -33,10 +37,9 @@ export const horizonEventToNativeMap = new Map([
|
||||||
['onAnimationEnd', ['animationend']],
|
['onAnimationEnd', ['animationend']],
|
||||||
['onAnimationIteration', ['animationiteration']],
|
['onAnimationIteration', ['animationiteration']],
|
||||||
['onAnimationStart', ['animationstart']],
|
['onAnimationStart', ['animationstart']],
|
||||||
['onTransitionEnd', ['transitionend']]
|
['onTransitionEnd', ['transitionend']],
|
||||||
]);
|
]);
|
||||||
|
export const NativeEventToHorizonMap = {
|
||||||
export const CommonEventToHorizonMap = {
|
|
||||||
click: 'click',
|
click: 'click',
|
||||||
dblclick: 'doubleClick',
|
dblclick: 'doubleClick',
|
||||||
contextmenu: 'contextMenu',
|
contextmenu: 'contextMenu',
|
||||||
|
@ -69,11 +72,22 @@ export const CommonEventToHorizonMap = {
|
||||||
compositionend: 'compositionEnd',
|
compositionend: 'compositionEnd',
|
||||||
compositionupdate: 'compositionUpdate',
|
compositionupdate: 'compositionUpdate',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CHAR_CODE_SPACE = 32;
|
export const CHAR_CODE_SPACE = 32;
|
||||||
|
|
||||||
|
|
||||||
export const EVENT_TYPE_BUBBLE = 'Bubble';
|
export const EVENT_TYPE_BUBBLE = 'Bubble';
|
||||||
export const EVENT_TYPE_CAPTURE = 'Capture';
|
export const EVENT_TYPE_CAPTURE = 'Capture';
|
||||||
export const EVENT_TYPE_ALL = 'All';
|
export const EVENT_TYPE_ALL = 'All';
|
||||||
|
|
||||||
|
horizonEventToNativeMap.forEach((dependencies, horizonEvent) => {
|
||||||
|
allDelegatedHorizonEvents.set(horizonEvent, dependencies);
|
||||||
|
allDelegatedHorizonEvents.set(horizonEvent + 'Capture', dependencies);
|
||||||
|
|
||||||
|
dependencies.forEach(d => {
|
||||||
|
allDelegatedNativeEvents.add(d);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
export function transformToHorizonEvent(nativeEvtName: string) {
|
||||||
|
const name = NativeEventToHorizonMap[nativeEvtName];
|
||||||
|
// 例:dragEnd -> onDragEnd
|
||||||
|
return !name ? '' : `on${name[0].toUpperCase()}${name.slice(1)}`;
|
||||||
|
}
|
|
@ -1,19 +1,76 @@
|
||||||
import type { AnyNativeEvent } from './Types';
|
import { AnyNativeEvent, ListenerUnitList } from './Types';
|
||||||
import { ListenerUnitList } from './Types';
|
|
||||||
import type { VNode } from '../renderer/Types';
|
import type { VNode } from '../renderer/Types';
|
||||||
|
import { isInputElement, setPropertyWritable } from './utils';
|
||||||
import { CommonEventToHorizonMap, EVENT_TYPE_BUBBLE, EVENT_TYPE_CAPTURE, horizonEventToNativeMap } from './const';
|
import { decorateNativeEvent } from './EventWrapper';
|
||||||
import { getListeners as getChangeListeners } from './simulatedEvtHandler/ChangeEventHandler';
|
|
||||||
import { setPropertyWritable } from './utils';
|
|
||||||
import { decorateNativeEvent } from './customEvents/EventFactory';
|
|
||||||
import { getListenersFromTree } from './ListenerGetter';
|
import { getListenersFromTree } from './ListenerGetter';
|
||||||
import { asyncUpdates, runDiscreteUpdates } from '../renderer/Renderer';
|
import { asyncUpdates, runDiscreteUpdates } from '../renderer/Renderer';
|
||||||
import { findRoot } from '../renderer/vnode/VNodeUtils';
|
import { findRoot } from '../renderer/vnode/VNodeUtils';
|
||||||
import { syncRadiosHandler } from '../dom/valueHandler/InputValueHandler';
|
import { syncRadiosHandler } from '../dom/valueHandler/InputValueHandler';
|
||||||
|
import {
|
||||||
|
EVENT_TYPE_ALL,
|
||||||
|
EVENT_TYPE_BUBBLE,
|
||||||
|
EVENT_TYPE_CAPTURE,
|
||||||
|
horizonEventToNativeMap,
|
||||||
|
transformToHorizonEvent,
|
||||||
|
} from './EventHub';
|
||||||
|
import { getDomTag } from '../dom/utils/Common';
|
||||||
|
import { updateInputValueIfChanged } from '../dom/valueHandler/ValueChangeHandler';
|
||||||
|
import { getDom } from '../dom/DOMInternalKeys';
|
||||||
|
|
||||||
// web规范,鼠标右键key值
|
// web规范,鼠标右键key值
|
||||||
const RIGHT_MOUSE_BUTTON = 2;
|
const RIGHT_MOUSE_BUTTON = 2;
|
||||||
|
|
||||||
|
// 返回是否需要触发change事件标记
|
||||||
|
// | 元素 | 事件 | 需要值变更 |
|
||||||
|
// | --- | --- | --------------- |
|
||||||
|
// | <select/> / <input type="file/> | change | NO |
|
||||||
|
// | <input type="checkbox" /> <input type="radio" /> | click | YES |
|
||||||
|
// | <input type="input /> / <input type="text" /> | input / change | YES |
|
||||||
|
function shouldTriggerChangeEvent(targetDom, evtName) {
|
||||||
|
const { type } = targetDom;
|
||||||
|
const domTag = getDomTag(targetDom);
|
||||||
|
|
||||||
|
if (domTag === 'select' || (domTag === 'input' && type === 'file')) {
|
||||||
|
return evtName === 'change';
|
||||||
|
} else if (domTag === 'input' && (type === 'checkbox' || type === 'radio')) {
|
||||||
|
if (evtName === 'click') {
|
||||||
|
return updateInputValueIfChanged(targetDom);
|
||||||
|
}
|
||||||
|
} else if (isInputElement(targetDom)) {
|
||||||
|
if (evtName === 'input' || evtName === 'change') {
|
||||||
|
return updateInputValueIfChanged(targetDom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 支持input/textarea/select的onChange事件
|
||||||
|
*/
|
||||||
|
function getChangeListeners(
|
||||||
|
nativeEvtName: string,
|
||||||
|
nativeEvt: AnyNativeEvent,
|
||||||
|
vNode: null | VNode,
|
||||||
|
): ListenerUnitList {
|
||||||
|
if (!vNode) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const targetDom = getDom(vNode);
|
||||||
|
|
||||||
|
// 判断是否需要触发change事件
|
||||||
|
if (shouldTriggerChangeEvent(targetDom, nativeEvtName)) {
|
||||||
|
const event = decorateNativeEvent(
|
||||||
|
'onChange',
|
||||||
|
'change',
|
||||||
|
nativeEvt,
|
||||||
|
);
|
||||||
|
return getListenersFromTree(vNode, 'onChange', event, EVENT_TYPE_ALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
// 获取事件触发的普通事件监听方法队列
|
// 获取事件触发的普通事件监听方法队列
|
||||||
function getCommonListeners(
|
function getCommonListeners(
|
||||||
nativeEvtName: string,
|
nativeEvtName: string,
|
||||||
|
@ -22,8 +79,7 @@ function getCommonListeners(
|
||||||
target: null | EventTarget,
|
target: null | EventTarget,
|
||||||
isCapture: boolean,
|
isCapture: boolean,
|
||||||
): ListenerUnitList {
|
): ListenerUnitList {
|
||||||
const name = CommonEventToHorizonMap[nativeEvtName];
|
const horizonEvtName = transformToHorizonEvent(nativeEvtName);
|
||||||
const horizonEvtName = !name ? '' : `on${name[0].toUpperCase()}${name.slice(1)}`; // 例:dragEnd -> onDragEnd
|
|
||||||
|
|
||||||
if (!horizonEvtName) {
|
if (!horizonEvtName) {
|
||||||
return [];
|
return [];
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { VNode } from '../renderer/Types';
|
import { VNode } from '../renderer/Types';
|
||||||
import { DomComponent } from '../renderer/vnode/VNodeTags';
|
import { DomComponent } from '../renderer/vnode/VNodeTags';
|
||||||
import { EVENT_TYPE_ALL, EVENT_TYPE_CAPTURE, EVENT_TYPE_BUBBLE } from './const';
|
|
||||||
import { AnyNativeEvent, ListenerUnitList } from './Types';
|
import { AnyNativeEvent, ListenerUnitList } from './Types';
|
||||||
|
import { EVENT_TYPE_ALL, EVENT_TYPE_BUBBLE, EVENT_TYPE_CAPTURE } from './EventHub';
|
||||||
|
|
||||||
// 从vnode属性中获取事件listener
|
// 从vnode属性中获取事件listener
|
||||||
function getListenerFromVNode(vNode: VNode, eventName: string): Function | null {
|
function getListenerFromVNode(vNode: VNode, eventName: string): Function | null {
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
import {decorateNativeEvent} from '../customEvents/EventFactory';
|
|
||||||
import {getDom} from '../../dom/DOMInternalKeys';
|
|
||||||
import {updateInputValueIfChanged} from '../../dom/valueHandler/ValueChangeHandler';
|
|
||||||
import {isInputElement} from '../utils';
|
|
||||||
import {EVENT_TYPE_ALL} from '../const';
|
|
||||||
import {AnyNativeEvent, ListenerUnitList} from '../Types';
|
|
||||||
import {
|
|
||||||
getListenersFromTree,
|
|
||||||
} from '../ListenerGetter';
|
|
||||||
import {VNode} from '../../renderer/Types';
|
|
||||||
import {getDomTag} from '../../dom/utils/Common';
|
|
||||||
|
|
||||||
// 返回是否需要触发change事件标记
|
|
||||||
// | 元素 | 事件 | 需要值变更 |
|
|
||||||
// | --- | --- | --------------- |
|
|
||||||
// | <select/> / <input type="file/> | change | NO |
|
|
||||||
// | <input type="checkbox" /> <input type="radio" /> | click | YES |
|
|
||||||
// | <input type="input /> / <input type="text" /> | input / change | YES |
|
|
||||||
function shouldTriggerChangeEvent(targetDom, evtName) {
|
|
||||||
const { type } = targetDom;
|
|
||||||
const domTag = getDomTag(targetDom);
|
|
||||||
|
|
||||||
if (domTag === 'select' || (domTag === 'input' && type === 'file')) {
|
|
||||||
return evtName === 'change';
|
|
||||||
} else if (domTag === 'input' && (type === 'checkbox' || type === 'radio')) {
|
|
||||||
if (evtName === 'click') {
|
|
||||||
return updateInputValueIfChanged(targetDom);
|
|
||||||
}
|
|
||||||
} else if (isInputElement(targetDom)) {
|
|
||||||
if (evtName === 'input' || evtName === 'change') {
|
|
||||||
return updateInputValueIfChanged(targetDom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* 支持input/textarea/select的onChange事件
|
|
||||||
*/
|
|
||||||
export function getListeners(
|
|
||||||
nativeEvtName: string,
|
|
||||||
nativeEvt: AnyNativeEvent,
|
|
||||||
vNode: null | VNode
|
|
||||||
): ListenerUnitList {
|
|
||||||
if (!vNode) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
const targetDom = getDom(vNode);
|
|
||||||
|
|
||||||
// 判断是否需要触发change事件
|
|
||||||
if (shouldTriggerChangeEvent(targetDom, nativeEvtName)) {
|
|
||||||
const event = decorateNativeEvent(
|
|
||||||
'onChange',
|
|
||||||
'change',
|
|
||||||
nativeEvt,
|
|
||||||
);
|
|
||||||
return getListenersFromTree(vNode, 'onChange', event, EVENT_TYPE_ALL);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
|
@ -78,6 +78,7 @@ export class VNode {
|
||||||
// 根节点数据
|
// 根节点数据
|
||||||
toUpdateNodes: Set<VNode> | null; // 保存要更新的节点
|
toUpdateNodes: Set<VNode> | null; // 保存要更新的节点
|
||||||
delegatedEvents: Set<string>
|
delegatedEvents: Set<string>
|
||||||
|
delegatedNativeEvents: Set<string>
|
||||||
|
|
||||||
belongClassVNode: VNode | null = null; // 记录JSXElement所属class vNode,处理ref的时候使用
|
belongClassVNode: VNode | null = null; // 记录JSXElement所属class vNode,处理ref的时候使用
|
||||||
|
|
||||||
|
@ -98,6 +99,7 @@ export class VNode {
|
||||||
this.task = null;
|
this.task = null;
|
||||||
this.toUpdateNodes = new Set<VNode>();
|
this.toUpdateNodes = new Set<VNode>();
|
||||||
this.delegatedEvents = new Set<string>();
|
this.delegatedEvents = new Set<string>();
|
||||||
|
this.delegatedNativeEvents = new Set<string>();
|
||||||
this.updates = null;
|
this.updates = null;
|
||||||
this.stateCallbacks = null;
|
this.stateCallbacks = null;
|
||||||
this.state = null;
|
this.state = null;
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
import * as Horizon from '@cloudsop/horizon/index.ts';
|
import * as Horizon from '@cloudsop/horizon/index.ts';
|
||||||
import * as TestUtils from '../jest/testUtils';
|
import * as TestUtils from '../jest/testUtils';
|
||||||
|
|
||||||
|
function dispatchChangeEvent(input) {
|
||||||
|
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
|
||||||
|
nativeInputValueSetter.call(input, 'test');
|
||||||
|
|
||||||
|
input.dispatchEvent(new Event('input', { bubbles: true }));
|
||||||
|
}
|
||||||
|
|
||||||
describe('事件', () => {
|
describe('事件', () => {
|
||||||
const LogUtils = TestUtils.getLogUtils();
|
const LogUtils = TestUtils.getLogUtils();
|
||||||
it('根节点挂载全量事件', () => {
|
it('根节点挂载全量事件', () => {
|
||||||
|
@ -162,11 +169,7 @@ describe('事件', () => {
|
||||||
LogUtils.log('change');
|
LogUtils.log('change');
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
dispatchChangeEvent(inputRef.current);
|
||||||
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
|
|
||||||
nativeInputValueSetter.call(inputRef.current, 'test');
|
|
||||||
|
|
||||||
inputRef.current.dispatchEvent(new Event('input', { bubbles: true }));
|
|
||||||
|
|
||||||
expect(LogUtils.getAndClear()).toEqual(['change']);
|
expect(LogUtils.getAndClear()).toEqual(['change']);
|
||||||
});
|
});
|
||||||
|
@ -209,4 +212,63 @@ describe('事件', () => {
|
||||||
// 先选择选项1,radio1应该重新触发onchange
|
// 先选择选项1,radio1应该重新触发onchange
|
||||||
clickRadioAndExpect(radio1Ref.current, [2, 1]);
|
clickRadioAndExpect(radio1Ref.current, [2, 1]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('多根节点下,事件挂载正确', () => {
|
||||||
|
const root1 = document.createElement('div');
|
||||||
|
const root2 = document.createElement('div');
|
||||||
|
root1.key = 'root1';
|
||||||
|
root2.key = 'root2';
|
||||||
|
let input1, input2, update1, update2;
|
||||||
|
|
||||||
|
function App1() {
|
||||||
|
const [props, setProps] = Horizon.useState({});
|
||||||
|
update1 = setProps;
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
{...props}
|
||||||
|
ref={n => (input1 = n)}
|
||||||
|
onChange={() => {
|
||||||
|
LogUtils.log('input1 changed');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function App2() {
|
||||||
|
const [props, setProps] = Horizon.useState({});
|
||||||
|
update2 = setProps;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
{...props}
|
||||||
|
ref={n => (input2 = n)}
|
||||||
|
onChange={() => {
|
||||||
|
LogUtils.log('input2 changed');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 多根mount阶段挂载onChange事件
|
||||||
|
Horizon.render(<App1 key={1} />, root1);
|
||||||
|
Horizon.render(<App2 key={2} />, root2);
|
||||||
|
|
||||||
|
dispatchChangeEvent(input1);
|
||||||
|
expect(LogUtils.getAndClear()).toEqual(['input1 changed']);
|
||||||
|
dispatchChangeEvent(input2);
|
||||||
|
expect(LogUtils.getAndClear()).toEqual(['input2 changed']);
|
||||||
|
|
||||||
|
// 多根update阶段挂载onClick事件
|
||||||
|
update1({
|
||||||
|
onClick: () => LogUtils.log('input1 clicked'),
|
||||||
|
});
|
||||||
|
update2({
|
||||||
|
onClick: () => LogUtils.log('input2 clicked'),
|
||||||
|
});
|
||||||
|
|
||||||
|
input1.click();
|
||||||
|
expect(LogUtils.getAndClear()).toEqual(['input1 clicked']);
|
||||||
|
input2.click();
|
||||||
|
expect(LogUtils.getAndClear()).toEqual(['input2 clicked']);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { allDelegatedNativeEvents } from '../../../libs/horizon/src/event/EventCollection';
|
import { allDelegatedNativeEvents } from '@cloudsop/horizon/src/event/EventHub';
|
||||||
//import * as LogUtils from './logUtils';
|
//import * as LogUtils from './logUtils';
|
||||||
|
|
||||||
export const stopBubbleOrCapture = (e, value) => {
|
export const stopBubbleOrCapture = (e, value) => {
|
||||||
|
@ -107,4 +107,4 @@ export function getLogUtils() {
|
||||||
logger = new LogUtils();
|
logger = new LogUtils();
|
||||||
}
|
}
|
||||||
return logger;
|
return logger;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue