diff --git a/libs/horizon/src/dom/DOMExternal.ts b/libs/horizon/src/dom/DOMExternal.ts
index 077d0801..02f11e53 100644
--- a/libs/horizon/src/dom/DOMExternal.ts
+++ b/libs/horizon/src/dom/DOMExternal.ts
@@ -23,7 +23,7 @@ function createRoot(children: any, container: Container, callback?: Callback) {
container._treeRoot = treeRoot;
// 根节点挂接全量事件
- listenDelegatedEvents(container as Element);
+ // listenDelegatedEvents(container as Element);
// 执行回调
if (typeof callback === 'function') {
diff --git a/libs/horizon/src/dom/DOMPropertiesHandler/DOMPropertiesHandler.ts b/libs/horizon/src/dom/DOMPropertiesHandler/DOMPropertiesHandler.ts
index c7f76f2f..1ac626a0 100644
--- a/libs/horizon/src/dom/DOMPropertiesHandler/DOMPropertiesHandler.ts
+++ b/libs/horizon/src/dom/DOMPropertiesHandler/DOMPropertiesHandler.ts
@@ -4,9 +4,11 @@ import {
import { updateCommonProp } from './UpdateCommonProp';
import { setStyles } from './StyleHandler';
import {
- listenNonDelegatedEvent
+ lazyDelegateOnRoot,
+ listenNonDelegatedEvent,
} from '../../event/EventBinding';
import { isEventProp } from '../validators/ValidateProps';
+import { getCurrentRoot } from '../../renderer/TreeBuilder';
// 初始化DOM属性和更新 DOM 属性
export function setDomProps(
@@ -27,8 +29,12 @@ export function setDomProps(
setStyles(dom, propVal);
} else if (isEventProp(propName)) {
// 事件监听属性处理
+ // TODO
+ const currentRoot = getCurrentRoot();
if (!allDelegatedHorizonEvents.has(propName)) {
listenNonDelegatedEvent(propName, dom, propVal);
+ } else if (currentRoot && !currentRoot.delegatedEvents.has(propName)) {
+ lazyDelegateOnRoot(currentRoot, propName);
}
} else if (propName === 'children') { // 只处理纯文本子节点,其他children在VNode树中处理
const type = typeof propVal;
@@ -147,6 +153,7 @@ export function compareProps(
if (!allDelegatedHorizonEvents.has(propName)) {
toUpdateProps[propName] = newPropValue;
}
+ // TODO
} else {
toUpdateProps[propName] = newPropValue;
}
diff --git a/libs/horizon/src/dom/valueHandler/SelectValueHandler.ts b/libs/horizon/src/dom/valueHandler/SelectValueHandler.ts
index 75812620..d7c5852f 100644
--- a/libs/horizon/src/dom/valueHandler/SelectValueHandler.ts
+++ b/libs/horizon/src/dom/valueHandler/SelectValueHandler.ts
@@ -43,7 +43,7 @@ export function getSelectPropsWithoutValue(dom: HorizonSelect, properties: Objec
return {
...properties,
value: undefined,
- }
+ };
}
export function updateSelectValue(dom: HorizonSelect, properties: IProperty, isInit: boolean = false) {
diff --git a/libs/horizon/src/event/EventBinding.ts b/libs/horizon/src/event/EventBinding.ts
index 54d3fdb4..66bf94a7 100644
--- a/libs/horizon/src/event/EventBinding.ts
+++ b/libs/horizon/src/event/EventBinding.ts
@@ -1,7 +1,7 @@
/**
* 事件绑定实现,分为绑定委托事件和非委托事件
*/
-import {allDelegatedNativeEvents} from './EventCollection';
+import { allDelegatedHorizonEvents, allDelegatedNativeEvents } from './EventCollection';
import {isDocument} from '../dom/utils/Common';
import {
getNearestVNode,
@@ -12,6 +12,7 @@ import {isMounted} from '../renderer/vnode/VNodeUtils';
import {SuspenseComponent} from '../renderer/vnode/VNodeTags';
import {handleEventMain} from './HorizonEventMain';
import {decorateNativeEvent} from './customEvents/EventFactory';
+import { VNode } from '../renderer/vnode/VNode';
const listeningMarker = '_horizonListening' + Math.random().toString(36).slice(4);
@@ -26,18 +27,20 @@ function triggerDelegatedEvent(
runDiscreteUpdates();
const nativeEventTarget = nativeEvent.target || nativeEvent.srcElement;
- let targetVNode = getNearestVNode(nativeEventTarget);
+ const targetVNode = getNearestVNode(nativeEventTarget);
- if (targetVNode !== null) {
- if (isMounted(targetVNode)) {
- if (targetVNode.tag === SuspenseComponent) {
- targetVNode = null;
- }
- } else {
- // vNode已销毁
- targetVNode = null;
- }
- }
+ // if (targetVNode !== null) {
+ // if (isMounted(targetVNode)) {
+ // if (targetVNode.tag === SuspenseComponent) {
+ // debugger
+ // targetVNode = null;
+ // }
+ // } else {
+ // debugger
+ // // vNode已销毁
+ // targetVNode = null;
+ // }
+ // }
handleEventMain(nativeEvtName, isCapture, nativeEvent, targetVNode, targetDom);
}
@@ -73,6 +76,16 @@ export function listenDelegatedEvents(dom: Element) {
});
}
+// 事件懒委托,当用户定义事件后,再进行委托到根节点
+export function lazyDelegateOnRoot(currentRoot: VNode, eventName: string) {
+ currentRoot.delegatedEvents.add(eventName);
+
+ const isCapture = isCaptureEvent(eventName);
+ const nativeEvents = allDelegatedHorizonEvents.get(eventName);
+ nativeEvents.forEach(nativeEvents => {
+ listenToNativeEvent(nativeEvents, currentRoot.realNode, isCapture);
+ });
+}
// 通过horizon事件名获取到native事件名
function getNativeEvtName(horizonEventName, capture) {
let nativeName;
diff --git a/libs/horizon/src/event/HorizonEventMain.ts b/libs/horizon/src/event/HorizonEventMain.ts
index f0480724..35db487b 100644
--- a/libs/horizon/src/event/HorizonEventMain.ts
+++ b/libs/horizon/src/event/HorizonEventMain.ts
@@ -8,7 +8,6 @@ import {
EVENT_TYPE_CAPTURE,
} from './const';
import { getListeners as getChangeListeners } from './simulatedEvtHandler/ChangeEventHandler';
-import { getListeners as getSelectionListeners } from './simulatedEvtHandler/SelectionEventHandler';
import {
setPropertyWritable,
} from './utils';
@@ -81,6 +80,7 @@ function getProcessListeners(
target,
isCapture: boolean,
): ListenerUnitList {
+ // TODO 重复从树中获取监听器
// 触发普通委托事件
let listenerList: ListenerUnitList = getCommonListeners(
nativeEvtName,
@@ -100,15 +100,6 @@ function getProcessListeners(
target,
));
}
-
- if (horizonEventToNativeMap.get('onSelect').includes(nativeEvtName)) {
- listenerList = listenerList.concat(getSelectionListeners(
- nativeEvtName,
- nativeEvent,
- vNode,
- target,
- ));
- }
}
return listenerList;
}
diff --git a/libs/horizon/src/event/const.ts b/libs/horizon/src/event/const.ts
index 449663e9..c0e185a4 100644
--- a/libs/horizon/src/event/const.ts
+++ b/libs/horizon/src/event/const.ts
@@ -28,8 +28,7 @@ export const horizonEventToNativeMap = new Map([
['onCompositionStart', ['compositionstart']],
['onCompositionUpdate', ['compositionupdate']],
['onChange', ['change', 'click', 'focusout', 'input']],
- ['onSelect', ['focusout', 'contextmenu', 'dragend', 'focusin',
- 'keydown', 'keyup', 'mousedown', 'mouseup', 'selectionchange']],
+ ['onSelect', ['select']],
['onAnimationEnd', ['animationend']],
['onAnimationIteration', ['animationiteration']],
diff --git a/libs/horizon/src/event/simulatedEvtHandler/ChangeEventHandler.ts b/libs/horizon/src/event/simulatedEvtHandler/ChangeEventHandler.ts
index c0ad947d..f1b781af 100644
--- a/libs/horizon/src/event/simulatedEvtHandler/ChangeEventHandler.ts
+++ b/libs/horizon/src/event/simulatedEvtHandler/ChangeEventHandler.ts
@@ -12,6 +12,11 @@ import {VNode} from '../../renderer/Types';
import {getDomTag} from '../../dom/utils/Common';
// 返回是否需要触发change事件标记
+// | 元素 | 事件 | 需要值变更 |
+// | --- | --- | --------------- |
+// | / | click | YES |
+// | | input / change | YES |
function shouldTriggerChangeEvent(targetDom, evtName) {
const { type } = targetDom;
const domTag = getDomTag(targetDom);
diff --git a/libs/horizon/src/event/utils.ts b/libs/horizon/src/event/utils.ts
index 09d1b240..37ec6218 100644
--- a/libs/horizon/src/event/utils.ts
+++ b/libs/horizon/src/event/utils.ts
@@ -1,9 +1,7 @@
export function isInputElement(dom?: HTMLElement): boolean {
- if (dom instanceof HTMLInputElement || dom instanceof HTMLTextAreaElement) {
- return true;
- }
- return false;
+ return dom instanceof HTMLInputElement || dom instanceof HTMLTextAreaElement;
+
}
export function setPropertyWritable(obj, propName) {
diff --git a/libs/horizon/src/renderer/TreeBuilder.ts b/libs/horizon/src/renderer/TreeBuilder.ts
index 12626215..32bc6c14 100644
--- a/libs/horizon/src/renderer/TreeBuilder.ts
+++ b/libs/horizon/src/renderer/TreeBuilder.ts
@@ -43,6 +43,11 @@ let unrecoverableErrorDuringBuild: any = null;
// 当前运行的vNode节点
let processing: VNode | null = null;
+let currentRoot: VNode | null = null;
+export function getCurrentRoot() {
+ return currentRoot;
+}
+
export function setProcessing(vNode: VNode | null) {
processing = vNode;
}
@@ -267,7 +272,7 @@ function buildVNodeTree(treeRoot: VNode) {
// 总体任务入口
function renderFromRoot(treeRoot) {
runAsyncEffects();
-
+ currentRoot = treeRoot;
// 1. 构建vNode树
buildVNodeTree(treeRoot);
@@ -278,6 +283,7 @@ function renderFromRoot(treeRoot) {
// 2. 提交变更
submitToRender(treeRoot);
+ currentRoot = null;
if (window.__HORIZON_DEV_HOOK__) {
const hook = window.__HORIZON_DEV_HOOK__;
diff --git a/libs/horizon/src/renderer/submit/Submit.ts b/libs/horizon/src/renderer/submit/Submit.ts
index e80f911a..d19dfea2 100644
--- a/libs/horizon/src/renderer/submit/Submit.ts
+++ b/libs/horizon/src/renderer/submit/Submit.ts
@@ -114,21 +114,21 @@ function submit(dirtyNodes: Array) {
if ((node.flags & ResetText) === ResetText) {
submitResetTextContent(node);
}
-
+
if ((node.flags & Ref) === Ref) {
if (!node.isCreated) {
// 需要执行
detachRef(node, true);
}
}
-
+
isAdd = (node.flags & Addition) === Addition;
isUpdate = (node.flags & Update) === Update;
if (isAdd && isUpdate) {
// Addition
submitAddition(node);
FlagUtils.removeFlag(node, Addition);
-
+
// Update
submitUpdate(node);
} else {
@@ -161,7 +161,7 @@ function afterSubmit(dirtyNodes: Array) {
if ((node.flags & Update) === Update || (node.flags & Callback) === Callback) {
callAfterSubmitLifeCycles(node);
}
-
+
if ((node.flags & Ref) === Ref) {
attachRef(node);
}
diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts
index d3e6c23a..d67f0e73 100644
--- a/libs/horizon/src/renderer/vnode/VNode.ts
+++ b/libs/horizon/src/renderer/vnode/VNode.ts
@@ -74,7 +74,10 @@ export class VNode {
suspenseState: SuspenseState;
path = ''; // 保存从根到本节点的路径
+
+ // 根节点数据
toUpdateNodes: Set | null; // 保存要更新的节点
+ delegatedEvents: Set
belongClassVNode: VNode | null = null; // 记录JSXElement所属class vNode,处理ref的时候使用
@@ -94,6 +97,7 @@ export class VNode {
this.realNode = realNode;
this.task = null;
this.toUpdateNodes = new Set();
+ this.delegatedEvents = new Set();
this.updates = null;
this.stateCallbacks = null;
this.state = null;