Match-id-edaf12c965ee317921dfeec240b997c57737f6bc
This commit is contained in:
commit
0cbb857941
|
@ -91,7 +91,7 @@ export function getEventListeners(dom: EventTarget): Set<string> {
|
|||
return elementListeners;
|
||||
}
|
||||
|
||||
export function getEventToListenerMap(target: EventTarget): Map<string, EventListener> {
|
||||
export function getNonDelegatedListenerMap(target: EventTarget): Map<string, EventListener> {
|
||||
let eventsMap = target[internalKeys.nonDelegatedEvents];
|
||||
if (!eventsMap) {
|
||||
eventsMap = new Map();
|
||||
|
|
|
@ -21,6 +21,7 @@ import {
|
|||
getTextareaPropsWithoutValue,
|
||||
updateTextareaValue,
|
||||
} from './TextareaValueHandler';
|
||||
import {getDomTag} from "../utils/Common";
|
||||
|
||||
// 获取元素除了被代理的值以外的属性
|
||||
function getPropsWithoutValue(type: string, dom: HorizonDom, properties: IProperty) {
|
||||
|
@ -72,7 +73,8 @@ function updateValue(type: string, dom: HorizonDom, properties: IProperty) {
|
|||
}
|
||||
}
|
||||
|
||||
function resetValue(dom: HorizonDom, type: string, properties: IProperty) {
|
||||
function resetValue(dom: HorizonDom, properties: IProperty) {
|
||||
const type = getDomTag(dom);
|
||||
switch (type) {
|
||||
case 'input':
|
||||
resetInputValue(<HTMLInputElement>dom, properties);
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
import {getVNodeProps} from '../dom/DOMInternalKeys';
|
||||
import {resetValue} from '../dom/valueHandler';
|
||||
import {getDomTag} from '../dom/utils/Common';
|
||||
|
||||
let updateList = null;
|
||||
let updateList: Array<any> | null = null;
|
||||
|
||||
// 受控组件值重新赋值
|
||||
function updateValue(target: Element) {
|
||||
const props = getVNodeProps(target);
|
||||
if (props) {
|
||||
const type = getDomTag(target);
|
||||
resetValue(target, type, props);
|
||||
resetValue(target, props);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
/**
|
||||
* 事件绑定实现
|
||||
* 事件绑定实现,分为绑定委托事件和非委托事件
|
||||
*/
|
||||
import {allDelegatedNativeEvents} from './EventCollection';
|
||||
import {isDocument} from '../dom/utils/Common';
|
||||
import {
|
||||
getEventListeners,
|
||||
getEventToListenerMap,
|
||||
getNearestVNode,
|
||||
getNonDelegatedListenerMap,
|
||||
} from '../dom/DOMInternalKeys';
|
||||
import {createCustomEventListener} from './WrapperListener';
|
||||
import {CustomBaseEvent} from './customEvents/CustomBaseEvent';
|
||||
import {runDiscreteUpdates} from '../renderer/TreeBuilder';
|
||||
import {getEventTarget} from './utils';
|
||||
import {isMounted} from '../renderer/vnode/VNodeUtils';
|
||||
import {SuspenseComponent} from '../renderer/vnode/VNodeTags';
|
||||
import {handleEventMain} from './HorizonEventMain';
|
||||
|
||||
const listeningMarker =
|
||||
'_horizonListening' +
|
||||
Math.random()
|
||||
.toString(36)
|
||||
.slice(4);
|
||||
const listeningMarker = '_horizonListening' + Math.random().toString(36).slice(4);
|
||||
|
||||
// 获取节点上已经委托事件名称
|
||||
function getListenerSetKey(nativeEvtName: string, isCapture: boolean): string {
|
||||
|
@ -22,6 +23,33 @@ function getListenerSetKey(nativeEvtName: string, isCapture: boolean): string {
|
|||
return `${nativeEvtName}__${sufix}`;
|
||||
}
|
||||
|
||||
// 触发委托事件
|
||||
function triggerDelegatedEvent(
|
||||
nativeEvtName: string,
|
||||
isCapture: boolean,
|
||||
targetDom: EventTarget,
|
||||
nativeEvent, // 事件对象event
|
||||
) {
|
||||
// 执行之前的调度事件
|
||||
runDiscreteUpdates();
|
||||
|
||||
const nativeEventTarget = getEventTarget(nativeEvent);
|
||||
let targetVNode = getNearestVNode(nativeEventTarget);
|
||||
|
||||
if (targetVNode !== null) {
|
||||
if (isMounted(targetVNode)) {
|
||||
if (targetVNode.tag === SuspenseComponent) {
|
||||
targetVNode = null;
|
||||
}
|
||||
} else {
|
||||
// vNode已销毁
|
||||
targetVNode = null;
|
||||
}
|
||||
}
|
||||
handleEventMain(nativeEvtName, isCapture, nativeEvent, targetVNode, targetDom);
|
||||
}
|
||||
|
||||
// 监听委托事件
|
||||
function listenToNativeEvent(
|
||||
nativeEvtName: string,
|
||||
delegatedElement: Element,
|
||||
|
@ -37,12 +65,8 @@ function listenToNativeEvent(
|
|||
const listenerSetKey = getListenerSetKey(nativeEvtName, isCapture);
|
||||
|
||||
if (!listenerSet.has(listenerSetKey)) {
|
||||
const listener = createCustomEventListener(
|
||||
target,
|
||||
nativeEvtName,
|
||||
isCapture,
|
||||
);
|
||||
target.addEventListener(nativeEvtName, listener, !!isCapture);
|
||||
const listener = triggerDelegatedEvent.bind(null, nativeEvtName, isCapture, target);
|
||||
target.addEventListener(nativeEvtName, listener, isCapture);
|
||||
listenerSet.add(listenerSetKey);
|
||||
}
|
||||
}
|
||||
|
@ -54,11 +78,11 @@ export function listenDelegatedEvents(dom: Element) {
|
|||
return;
|
||||
}
|
||||
dom[listeningMarker] = true;
|
||||
allDelegatedNativeEvents.forEach((eventName: string) => {
|
||||
allDelegatedNativeEvents.forEach((nativeEvtName: string) => {
|
||||
// 委托冒泡事件
|
||||
listenToNativeEvent(eventName, dom, false);
|
||||
listenToNativeEvent(nativeEvtName, dom, false);
|
||||
// 委托捕获事件
|
||||
listenToNativeEvent(eventName, dom, true);
|
||||
listenToNativeEvent(nativeEvtName, dom, true);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -86,7 +110,7 @@ function getIsCapture(horizonEventName) {
|
|||
|
||||
// 封装监听函数
|
||||
function getWrapperListener(horizonEventName, nativeEvtName, targetElement, listener) {
|
||||
return (event) => {
|
||||
return event => {
|
||||
const customEvent = new CustomBaseEvent(horizonEventName, nativeEvtName, event, null, targetElement);
|
||||
listener(customEvent);
|
||||
};
|
||||
|
@ -102,19 +126,20 @@ export function listenNonDelegatedEvent(
|
|||
const nativeEvtName = getNativeEvtName(horizonEventName, isCapture);
|
||||
|
||||
// 先判断是否存在老的监听事件,若存在则移除
|
||||
const eventToListenerMap = getEventToListenerMap(domElement);
|
||||
if (eventToListenerMap.get(horizonEventName)) {
|
||||
domElement.removeEventListener(nativeEvtName, eventToListenerMap.get(horizonEventName));
|
||||
const nonDelegatedListenerMap = getNonDelegatedListenerMap(domElement);
|
||||
const currentListener = nonDelegatedListenerMap.get(horizonEventName);
|
||||
if (currentListener) {
|
||||
domElement.removeEventListener(nativeEvtName, currentListener);
|
||||
}
|
||||
|
||||
if (typeof listener !== 'function') {
|
||||
eventToListenerMap.delete(nativeEvtName);
|
||||
nonDelegatedListenerMap.delete(nativeEvtName);
|
||||
return;
|
||||
}
|
||||
|
||||
// 为了和委托事件对外行为一致,将事件对象封装成CustomBaseEvent
|
||||
const wrapperListener = getWrapperListener(horizonEventName, nativeEvtName, domElement, listener);
|
||||
// 添加新的监听
|
||||
eventToListenerMap.set(horizonEventName, wrapperListener);
|
||||
nonDelegatedListenerMap.set(horizonEventName, wrapperListener);
|
||||
domElement.addEventListener(nativeEvtName, wrapperListener, isCapture);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { AnyNativeEvent, ProcessingListenerList } from './types';
|
||||
import type { AnyNativeEvent, ProcessingListenerList } from './Types';
|
||||
import type { VNode } from '../renderer/Types';
|
||||
|
||||
import {
|
||||
|
@ -34,12 +34,12 @@ function getCommonListeners(
|
|||
target: null | EventTarget,
|
||||
isCapture: boolean,
|
||||
): ProcessingListenerList {
|
||||
const customEventName = getCustomEventNameWithOn(CommonEventToHorizonMap[nativeEvtName]);
|
||||
if (!customEventName) {
|
||||
const horizonEvtName = getCustomEventNameWithOn(CommonEventToHorizonMap[nativeEvtName]);
|
||||
if (!horizonEvtName) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// 火狐浏览器兼容。火狐浏览器下功能键将触发keypress事件 火狐下keypress的charcode有值,keycode为0
|
||||
// 火狐浏览器兼容。火狐浏览器下功能键将触发keypress事件 火狐下keypress的charCode有值,keyCode为0
|
||||
if (nativeEvtName === 'keypress' && uniqueCharCode(nativeEvent) === 0) {
|
||||
return [];
|
||||
}
|
||||
|
@ -52,23 +52,22 @@ function getCommonListeners(
|
|||
if (nativeEvtName === 'focusin') {
|
||||
nativeEvtName = 'focus';
|
||||
}
|
||||
|
||||
if (nativeEvtName === 'focusout') {
|
||||
nativeEvtName = 'blur';
|
||||
}
|
||||
|
||||
const customEvent = createCommonCustomEvent(customEventName, nativeEvtName, nativeEvent, null, target);
|
||||
const horizonEvent = createCommonCustomEvent(horizonEvtName, nativeEvtName, nativeEvent, null, target);
|
||||
return getListenersFromTree(
|
||||
vNode,
|
||||
customEventName,
|
||||
customEvent,
|
||||
horizonEvtName,
|
||||
horizonEvent,
|
||||
isCapture ? EVENT_TYPE_CAPTURE : EVENT_TYPE_BUBBLE,
|
||||
);
|
||||
}
|
||||
|
||||
// 按顺序执行事件队列
|
||||
export function processListeners(
|
||||
processingEventsList: ProcessingListenerList
|
||||
): void {
|
||||
function processListeners(processingEventsList: ProcessingListenerList): void {
|
||||
processingEventsList.forEach(eventUnitList => {
|
||||
let lastVNode;
|
||||
eventUnitList.forEach(eventUnit => {
|
||||
|
@ -88,7 +87,7 @@ export function processListeners(
|
|||
|
||||
function getProcessListenersFacade(
|
||||
nativeEvtName: string,
|
||||
vNode: VNode,
|
||||
vNode: VNode | null,
|
||||
nativeEvent: AnyNativeEvent,
|
||||
target,
|
||||
isCapture: boolean
|
||||
|
@ -150,15 +149,12 @@ function triggerHorizonEvents(
|
|||
nativeEvtName: string,
|
||||
isCapture: boolean,
|
||||
nativeEvent: AnyNativeEvent,
|
||||
vNode: null | VNode,
|
||||
vNode: VNode | null,
|
||||
): void {
|
||||
const nativeEventTarget = getEventTarget(nativeEvent);
|
||||
const processingListenerList = getProcessListenersFacade(
|
||||
nativeEvtName,
|
||||
vNode,
|
||||
nativeEvent,
|
||||
nativeEventTarget,
|
||||
isCapture);
|
||||
|
||||
// 获取委托事件队列
|
||||
const processingListenerList = getProcessListenersFacade(nativeEvtName, vNode, nativeEvent, nativeEventTarget, isCapture);
|
||||
|
||||
// 处理触发的事件队列
|
||||
processListeners(processingListenerList);
|
||||
|
@ -168,6 +164,7 @@ function triggerHorizonEvents(
|
|||
// 其他事件正在执行中标记
|
||||
let isInEventsExecution = false;
|
||||
|
||||
// 处理委托事件入口
|
||||
export function handleEventMain(
|
||||
nativeEvtName: string,
|
||||
isCapture: boolean,
|
||||
|
@ -192,13 +189,7 @@ export function handleEventMain(
|
|||
// 没有事件在执行,经过调度再执行事件
|
||||
isInEventsExecution = true;
|
||||
try {
|
||||
asyncUpdates(() =>
|
||||
triggerHorizonEvents(
|
||||
nativeEvtName,
|
||||
isCapture,
|
||||
nativeEvent,
|
||||
rootVNode,
|
||||
));
|
||||
asyncUpdates(() => triggerHorizonEvents(nativeEvtName, isCapture, nativeEvent, rootVNode));
|
||||
} finally {
|
||||
isInEventsExecution = false;
|
||||
if (shouldUpdateValue()) {
|
||||
|
|
|
@ -7,11 +7,7 @@ import {ProcessingListenerList, ListenerUnitList} from './Types';
|
|||
import {CustomBaseEvent} from './customEvents/CustomBaseEvent';
|
||||
|
||||
// 返回是否应该阻止事件响应标记,disabled组件不响应鼠标事件
|
||||
function shouldPrevent(
|
||||
name: string,
|
||||
type: string,
|
||||
props: Props,
|
||||
): boolean {
|
||||
function shouldPrevent(eventName: string, type: string, props: Props): boolean {
|
||||
const canPreventMouseEvents = [
|
||||
'onClick',
|
||||
'onClickCapture',
|
||||
|
@ -26,17 +22,14 @@ function shouldPrevent(
|
|||
'onMouseEnter',
|
||||
];
|
||||
const interActiveElements = ['button', 'input', 'select', 'textarea'];
|
||||
if (canPreventMouseEvents.includes(name)) {
|
||||
if (canPreventMouseEvents.includes(eventName)) {
|
||||
return !!(props.disabled && interActiveElements.includes(type));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 从vnode属性中获取事件listener
|
||||
function getListener(
|
||||
vNode: VNode,
|
||||
eventName: string,
|
||||
): Function | null {
|
||||
function getListener(vNode: VNode, eventName: string): Function | null {
|
||||
const realNode = vNode.realNode;
|
||||
if (realNode === null) {
|
||||
return null;
|
||||
|
@ -60,14 +53,14 @@ function getListener(
|
|||
// 获取监听事件
|
||||
export function getListenersFromTree(
|
||||
targetVNode: VNode | null,
|
||||
name: string | null,
|
||||
horizonEvtName: string | null,
|
||||
horizonEvent: CustomBaseEvent,
|
||||
eventType: string,
|
||||
): ProcessingListenerList {
|
||||
if (!name) {
|
||||
if (!horizonEvtName) {
|
||||
return [];
|
||||
}
|
||||
const captureName = name + EVENT_TYPE_CAPTURE;
|
||||
|
||||
const listeners: ListenerUnitList = [];
|
||||
|
||||
let vNode = targetVNode;
|
||||
|
@ -77,6 +70,7 @@ export function getListenersFromTree(
|
|||
const {realNode, tag} = vNode;
|
||||
if (tag === DomComponent && realNode !== null) {
|
||||
if (eventType === EVENT_TYPE_ALL || eventType === EVENT_TYPE_CAPTURE) {
|
||||
const captureName = horizonEvtName + EVENT_TYPE_CAPTURE;
|
||||
const captureListener = getListener(vNode, captureName);
|
||||
if (captureListener) {
|
||||
listeners.unshift({
|
||||
|
@ -88,7 +82,7 @@ export function getListenersFromTree(
|
|||
}
|
||||
}
|
||||
if (eventType === EVENT_TYPE_ALL || eventType === EVENT_TYPE_BUBBLE) {
|
||||
const bubbleListener = getListener(vNode, name);
|
||||
const bubbleListener = getListener(vNode, horizonEvtName);
|
||||
if (bubbleListener) {
|
||||
listeners.push({
|
||||
vNode,
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
import {isMounted} from '../renderer/vnode/VNodeUtils';
|
||||
import {SuspenseComponent} from '../renderer/vnode/VNodeTags';
|
||||
import {getNearestVNode} from '../dom/DOMInternalKeys';
|
||||
import {handleEventMain} from './HorizonEventMain';
|
||||
import {runDiscreteUpdates} from '../renderer/Renderer';
|
||||
import {getEventTarget} from './utils';
|
||||
|
||||
// 触发委托事件
|
||||
function triggerDelegatedEvent(
|
||||
nativeEvtName: string,
|
||||
isCapture: boolean,
|
||||
targetDom: EventTarget,
|
||||
nativeEvent,
|
||||
) {
|
||||
// 执行之前的调度事件
|
||||
runDiscreteUpdates();
|
||||
|
||||
const nativeEventTarget = getEventTarget(nativeEvent);
|
||||
let targetVNode = getNearestVNode(nativeEventTarget);
|
||||
|
||||
if (targetVNode !== null) {
|
||||
if (isMounted(targetVNode)) {
|
||||
if (targetVNode.tag === SuspenseComponent) {
|
||||
targetVNode = null;
|
||||
}
|
||||
} else {
|
||||
// vnode已销毁
|
||||
targetVNode = null;
|
||||
}
|
||||
}
|
||||
handleEventMain(nativeEvtName, isCapture, nativeEvent, targetVNode, targetDom);
|
||||
}
|
||||
|
||||
// 生成委托事件的监听方法
|
||||
export function createCustomEventListener(
|
||||
target: EventTarget,
|
||||
nativeEvtName: string,
|
||||
isCapture: boolean,
|
||||
): EventListener {
|
||||
return triggerDelegatedEvent.bind(null, nativeEvtName, isCapture, target);
|
||||
}
|
|
@ -67,7 +67,7 @@ export class CustomBaseEvent {
|
|||
customEvtName: string | null,
|
||||
nativeEvtName: string,
|
||||
nativeEvt: { [propName: string]: any },
|
||||
vNode: VNode,
|
||||
vNode: VNode | null,
|
||||
target: null | EventTarget
|
||||
) {
|
||||
// 复制原生属性到自定义事件
|
||||
|
|
|
@ -50,7 +50,5 @@ export function getCustomEventNameWithOn(name) {
|
|||
if (!name) {
|
||||
return '';
|
||||
}
|
||||
const capitalizedEvent = name[0].toUpperCase() + name.slice(1);
|
||||
const horizonEventName = 'on' + capitalizedEvent;
|
||||
return horizonEventName;
|
||||
return 'on' + name[0].toUpperCase() + name.slice(1);
|
||||
}
|
||||
|
|
|
@ -2,14 +2,16 @@
|
|||
export const ByAsync = 'BY_ASYNC';
|
||||
export const BySync = 'BY_SYNC';
|
||||
export const InRender = 'IN_RENDER';
|
||||
export const InEvent = 'IN_EVENT';
|
||||
|
||||
type RenderMode = typeof ByAsync | typeof BySync | typeof InRender;
|
||||
type RenderMode = typeof ByAsync | typeof BySync | typeof InRender | typeof InEvent;
|
||||
|
||||
// 当前执行模式标记
|
||||
let executeMode = {
|
||||
[ByAsync]: false,
|
||||
[BySync]: false,
|
||||
[InRender]: false,
|
||||
[InEvent]: false,
|
||||
};
|
||||
|
||||
export function changeMode(mode: RenderMode, state = true) {
|
||||
|
@ -21,7 +23,7 @@ export function checkMode(mode: RenderMode) {
|
|||
}
|
||||
|
||||
export function isExecuting() {
|
||||
return executeMode[ByAsync] || executeMode[BySync] || executeMode[InRender];
|
||||
return executeMode[ByAsync] || executeMode[BySync] || executeMode[InRender] || executeMode[InEvent];
|
||||
}
|
||||
|
||||
export function copyExecuteMode() {
|
||||
|
|
|
@ -22,10 +22,11 @@ import { findDomParent, getSiblingVNode } from './vnode/VNodeUtils';
|
|||
import {
|
||||
ByAsync,
|
||||
BySync,
|
||||
InRender,
|
||||
InEvent,
|
||||
changeMode,
|
||||
checkMode,
|
||||
copyExecuteMode,
|
||||
InRender,
|
||||
isExecuting,
|
||||
setExecuteMode
|
||||
} from './ExecuteMode';
|
||||
|
@ -331,7 +332,7 @@ export function runDiscreteUpdates() {
|
|||
|
||||
export function asyncUpdates(fn, ...param) {
|
||||
const preMode = copyExecuteMode();
|
||||
changeMode(ByAsync, true);
|
||||
changeMode(InEvent, true);
|
||||
try {
|
||||
return fn(...param);
|
||||
} finally {
|
||||
|
|
Loading…
Reference in New Issue