Match-id-78f2aee4f5dd7a1ca2ee2e40479e2c971fa947fc

This commit is contained in:
* 2022-02-07 18:13:21 +08:00 committed by *
commit bdc192774b
16 changed files with 68 additions and 143 deletions

View File

@ -58,6 +58,7 @@ export function getNearestVNode(dom: Node): null | VNode {
if (vNode) { // 如果是已经被框架标记过的 DOM 节点,那么直接返回其 VNode 实例
return vNode;
}
// 下面处理的是为被框架标记过的 DOM 节点,向上找其父节点是否被框架标记过
let parentDom = dom.parentNode;
let nearVNode = null;

View File

@ -226,15 +226,6 @@ export function unHideDom(tag: string, dom: Element | Text, props: Props) {
}
}
export function clearContainer(container: Container): void {
if (isElement(container)) {
container.textContent = '';
}
if (isDocument(container) && container.body != null) {
container.body.textContent = '';
}
}
export function prePortal(portal: Element): void {
listenDelegatedEvents(portal);
}

View File

@ -5,7 +5,7 @@ import {Props} from '../DOMOperator';
* input textarea
* @param doc document
*/
export function getFocusedDom(doc?: Document): HorizonDom | void {
export function getFocusedDom(doc?: Document): HorizonDom | null {
let currentDocument;
if (doc) {
currentDocument = doc;

View File

@ -78,6 +78,7 @@ export function listenDelegatedEvents(dom: Element) {
return;
}
dom[listeningMarker] = true;
allDelegatedNativeEvents.forEach((nativeEvtName: string) => {
// 委托冒泡事件
listenToNativeEvent(nativeEvtName, dom, false);

View File

@ -1,4 +1,4 @@
import type { AnyNativeEvent, ProcessingListenerList } from './Types';
import type { AnyNativeEvent } from './Types';
import type { VNode } from '../renderer/Types';
import {
@ -25,6 +25,7 @@ import { getListenersFromTree } from './ListenerGetter';
import { shouldUpdateValue, updateControlledValue } from './ControlledValueUpdater';
import { asyncUpdates, runDiscreteUpdates } from '../renderer/Renderer';
import { getExactNode } from '../renderer/vnode/VNodeUtils';
import {ListenerUnitList} from './Types';
// 获取事件触发的普通事件监听方法队列
function getCommonListeners(
@ -33,7 +34,7 @@ function getCommonListeners(
nativeEvent: AnyNativeEvent,
target: null | EventTarget,
isCapture: boolean,
): ProcessingListenerList {
): ListenerUnitList {
const horizonEvtName = getCustomEventNameWithOn(CommonEventToHorizonMap[nativeEvtName]);
if (!horizonEvtName) {
return [];
@ -67,20 +68,17 @@ function getCommonListeners(
}
// 按顺序执行事件队列
function processListeners(processingEventsList: ProcessingListenerList): void {
processingEventsList.forEach(eventUnitList => {
let lastVNode;
eventUnitList.forEach(eventUnit => {
const { vNode, currentTarget, listener, event } = eventUnit;
if (vNode !== lastVNode && event.isPropagationStopped()) {
return;
}
event.currentTarget = currentTarget;
runListenerAndCatchFirstError(listener, event);
event.currentTarget = null;
lastVNode = vNode;
});
function processListeners(listenerList: ListenerUnitList): void {
listenerList.forEach(eventUnit => {
const { currentTarget, listener, event } = eventUnit;
if (event.isPropagationStopped()) {
return;
}
event.currentTarget = currentTarget;
runListenerAndCatchFirstError(listener, event);
event.currentTarget = null;
});
// 执行所有事件后重新throw遇到的第一个错误
throwCaughtEventError();
}
@ -91,9 +89,9 @@ function getProcessListenersFacade(
nativeEvent: AnyNativeEvent,
target,
isCapture: boolean
): ProcessingListenerList {
): ListenerUnitList {
// 触发普通委托事件
let processingListenerList: ProcessingListenerList = getCommonListeners(
let listenerList: ListenerUnitList = getCommonListeners(
nativeEvtName,
vNode,
nativeEvent,
@ -104,7 +102,7 @@ function getProcessListenersFacade(
// 触发特殊handler委托事件
if (!isCapture) {
if (horizonEventToNativeMap.get('onChange').includes(nativeEvtName)) {
processingListenerList = processingListenerList.concat(getChangeListeners(
listenerList = listenerList.concat(getChangeListeners(
nativeEvtName,
nativeEvent,
vNode,
@ -113,7 +111,7 @@ function getProcessListenersFacade(
}
if (horizonEventToNativeMap.get('onSelect').includes(nativeEvtName)) {
processingListenerList = processingListenerList.concat(getSelectionListeners(
listenerList = listenerList.concat(getSelectionListeners(
nativeEvtName,
nativeEvent,
vNode,
@ -124,7 +122,7 @@ function getProcessListenersFacade(
if (nativeEvtName === 'compositionend' ||
nativeEvtName === 'compositionstart' ||
nativeEvtName === 'compositionupdate') {
processingListenerList = processingListenerList.concat(getCompositionListeners(
listenerList = listenerList.concat(getCompositionListeners(
nativeEvtName,
nativeEvent,
vNode,
@ -133,7 +131,7 @@ function getProcessListenersFacade(
}
if (horizonEventToNativeMap.get('onBeforeInput').includes(nativeEvtName)) {
processingListenerList = processingListenerList.concat(getBeforeInputListeners(
listenerList = listenerList.concat(getBeforeInputListeners(
nativeEvtName,
nativeEvent,
vNode,
@ -141,7 +139,7 @@ function getProcessListenersFacade(
));
}
}
return processingListenerList;
return listenerList;
}
// 触发可以被执行的horizon事件监听
@ -154,10 +152,10 @@ function triggerHorizonEvents(
const nativeEventTarget = getEventTarget(nativeEvent);
// 获取委托事件队列
const processingListenerList = getProcessListenersFacade(nativeEvtName, vNode, nativeEvent, nativeEventTarget, isCapture);
const listenerList = getProcessListenersFacade(nativeEvtName, vNode, nativeEvent, nativeEventTarget, isCapture);
// 处理触发的事件队列
processListeners(processingListenerList);
processListeners(listenerList);
}
@ -170,26 +168,26 @@ export function handleEventMain(
isCapture: boolean,
nativeEvent: AnyNativeEvent,
vNode: null | VNode,
target: EventTarget,
targetContainer: EventTarget,
): void {
let rootVNode = vNode;
if (vNode !== null) {
rootVNode = getExactNode(vNode, target);
if (!rootVNode) {
let startVNode = vNode;
if (startVNode !== null) {
startVNode = getExactNode(startVNode, targetContainer);
if (!startVNode) {
return;
}
}
// 有事件正在执行,同步执行事件
if (isInEventsExecution) {
triggerHorizonEvents(nativeEvtName, isCapture, nativeEvent, rootVNode);
triggerHorizonEvents(nativeEvtName, isCapture, nativeEvent, startVNode);
return;
}
// 没有事件在执行,经过调度再执行事件
isInEventsExecution = true;
try {
asyncUpdates(() => triggerHorizonEvents(nativeEvtName, isCapture, nativeEvent, rootVNode));
asyncUpdates(() => triggerHorizonEvents(nativeEvtName, isCapture, nativeEvent, startVNode));
} finally {
isInEventsExecution = false;
if (shouldUpdateValue()) {

View File

@ -1,62 +1,16 @@
import {VNode} from '../renderer/Types';
import {DomComponent} from '../renderer/vnode/VNodeTags';
import {throwIfTrue} from '../renderer/utils/throwIfTrue';
import type {Props} from '../dom/DOMOperator';
import {EVENT_TYPE_ALL, EVENT_TYPE_CAPTURE, EVENT_TYPE_BUBBLE} from './const';
import {ProcessingListenerList, ListenerUnitList} from './Types';
import {ListenerUnitList} from './Types';
import {CustomBaseEvent} from './customEvents/CustomBaseEvent';
// 返回是否应该阻止事件响应标记disabled组件不响应鼠标事件
function shouldPrevent(eventName: string, type: string, props: Props): boolean {
const canPreventMouseEvents = [
'onClick',
'onClickCapture',
'onDoubleClick',
'onDoubleClickCapture',
'onMouseDown',
'onMouseDownCapture',
'onMouseMove',
'onMouseMoveCapture',
'onMouseUp',
'onMouseUpCapture',
'onMouseEnter',
];
const interActiveElements = ['button', 'input', 'select', 'textarea'];
if (canPreventMouseEvents.includes(eventName)) {
return !!(props.disabled && interActiveElements.includes(type));
}
return false;
}
// 从vnode属性中获取事件listener
function getListener(vNode: VNode, eventName: string): Function | null {
const realNode = vNode.realNode;
if (realNode === null) {
return null;
}
const props = vNode.props;
if (props === null) {
return null;
}
const listener = props[eventName];
if (shouldPrevent(eventName, vNode.type, props)) {
return null;
}
throwIfTrue(
listener && typeof listener !== 'function',
'`%s` listener should be a function.',
eventName
);
return listener;
}
// 获取监听事件
export function getListenersFromTree(
targetVNode: VNode | null,
horizonEvtName: string | null,
horizonEvent: CustomBaseEvent,
eventType: string,
): ProcessingListenerList {
): ListenerUnitList {
if (!horizonEvtName) {
return [];
}
@ -71,7 +25,7 @@ export function getListenersFromTree(
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);
const captureListener = vNode.props[captureName];
if (captureListener) {
listeners.unshift({
vNode,
@ -82,7 +36,7 @@ export function getListenersFromTree(
}
}
if (eventType === EVENT_TYPE_ALL || eventType === EVENT_TYPE_BUBBLE) {
const bubbleListener = getListener(vNode, horizonEvtName);
const bubbleListener = vNode.props[horizonEvtName];
if (bubbleListener) {
listeners.push({
vNode,
@ -95,7 +49,7 @@ export function getListenersFromTree(
}
vNode = vNode.parent;
}
return listeners.length > 0 ? [listeners]: [];
return listeners;
}

View File

@ -12,5 +12,3 @@ export type ListenerUnit = {
};
export type ListenerUnitList = Array<ListenerUnit>;
export type ProcessingListenerList = Array<ListenerUnitList>;

View File

@ -34,7 +34,7 @@ export const horizonEventToNativeMap = new Map([
['onCompositionStart', ['compositionstart']],
['onCompositionUpdate', ['compositionupdate']],
['onBeforeInput', ['compositionend', 'keypress', 'textInput']],
['onChange', ['change', 'click', 'focusout', 'input',]],
['onChange', ['change', 'click', 'focusout', 'input']],
['onSelect', ['focusout', 'contextmenu', 'dragend', 'focusin',
'keydown', 'keyup', 'mousedown', 'mouseup', 'selectionchange']],

View File

@ -1,9 +1,10 @@
import type {VNode} from '../../renderer/Types';
import type {AnyNativeEvent, ProcessingListenerList} from '../Types';
import type {AnyNativeEvent} from '../Types';
import {getListenersFromTree} from '../ListenerGetter';
import {createHandlerCustomEvent} from '../customEvents/EventFactory';
import {CHAR_CODE_SPACE, EVENT_TYPE_ALL} from '../const';
import {CustomBaseEvent} from '../customEvents/CustomBaseEvent';
import {ListenerUnitList} from '../Types';
const SPACE_CHAR = String.fromCharCode(CHAR_CODE_SPACE);
function getInputCharsByNative(
@ -28,7 +29,7 @@ export function getListeners(
nativeEvent: AnyNativeEvent,
vNode: null | VNode,
target: null | EventTarget,
): ProcessingListenerList {
): ListenerUnitList {
const chars = getInputCharsByNative(nativeEvtName, nativeEvent);
// 无字符将要输入,无需处理
if (!chars) {

View File

@ -4,7 +4,7 @@ import {isInputValueChanged} from '../../dom/valueHandler/ValueChangeHandler';
import {addValueUpdateList} from '../ControlledValueUpdater';
import {isTextInputElement} from '../utils';
import {EVENT_TYPE_ALL} from '../const';
import {AnyNativeEvent, ProcessingListenerList} from '../Types';
import {AnyNativeEvent, ListenerUnitList} from '../Types';
import {
getListenersFromTree,
} from '../ListenerGetter';
@ -39,7 +39,7 @@ export function getListeners(
nativeEvt: AnyNativeEvent,
vNode: null | VNode,
target: null | EventTarget,
): ProcessingListenerList {
): ListenerUnitList {
if (!vNode) {
return [];
}

View File

@ -1,8 +1,9 @@
import type {VNode} from '../../renderer/Types';
import type {AnyNativeEvent, ProcessingListenerList} from '../Types';
import type {AnyNativeEvent} from '../Types';
import {getListenersFromTree} from '../ListenerGetter';
import {createHandlerCustomEvent} from '../customEvents/EventFactory';
import {EVENT_TYPE_ALL} from '../const';
import {ListenerUnitList} from '../Types';
const compositionEventObj = {
compositionstart: 'onCompositionStart',
@ -16,7 +17,7 @@ export function getListeners(
nativeEvt: AnyNativeEvent,
vNode: null | VNode,
target: null | EventTarget,
): ProcessingListenerList {
): ListenerUnitList {
const evtType = compositionEventObj[evtName];
const event = createHandlerCustomEvent(

View File

@ -4,10 +4,11 @@ import {getFocusedDom} from '../../dom/utils/Common';
import {getDom} from '../../dom/DOMInternalKeys';
import {isDocument} from '../../dom/utils/Common';
import {isTextInputElement} from '../utils';
import type {AnyNativeEvent, ProcessingListenerList} from '../Types';
import type {AnyNativeEvent} from '../Types';
import {getListenersFromTree} from '../ListenerGetter';
import type {VNode} from '../../renderer/Types';
import {EVENT_TYPE_ALL} from '../const';
import {ListenerUnitList} from '../Types';
const horizonEventName = 'onSelect'
@ -83,9 +84,9 @@ export function getListeners(
nativeEvt: AnyNativeEvent,
vNode: null | VNode,
target: null | EventTarget,
): ProcessingListenerList {
): ListenerUnitList {
const targetNode = vNode ? getDom(vNode) : window;
let eventUnitList: ProcessingListenerList = [];
let eventUnitList: ListenerUnitList = [];
switch (name) {
case 'focusin':
initTargetCache(targetNode, vNode);

View File

@ -34,8 +34,8 @@ export function callUseEffects(vNode: VNode) {
(effectConstant & EffectConstant.Effect) !== EffectConstant.NoEffect &&
(effectConstant & EffectConstant.DepsChange) !== EffectConstant.NoEffect
) {
hookEffects.push({effect, vNode});
hookRemoveEffects.push({effect, vNode});
hookEffects.push(effect);
hookRemoveEffects.push(effect);
// 异步调用
if (!isScheduling) {
@ -53,7 +53,7 @@ export function runAsyncEffects() {
// 调用effect destroy
const removeEffects = hookRemoveEffects;
hookRemoveEffects = [];
removeEffects.forEach(({effect}) => {
removeEffects.forEach((effect) => {
const destroy = effect.removeEffect;
effect.removeEffect = undefined;
@ -69,7 +69,7 @@ export function runAsyncEffects() {
// 调用effect create
const createEffects = hookEffects;
hookEffects = [];
createEffects.forEach(({effect}) => {
createEffects.forEach((effect) => {
try {
const create = effect.effect;
@ -91,7 +91,7 @@ export function callEffectRemove(vNode: VNode) {
if (removeEffect !== undefined) {
if ((effectConstant & EffectConstant.Effect) !== EffectConstant.NoEffect) { // 如果是useEffect就异步调用
hookRemoveEffects.push({effect, vNode});
hookRemoveEffects.push(effect);
if (!isScheduling) {
isScheduling = true;

View File

@ -27,7 +27,6 @@ import {
removeChildDom,
hideDom,
unHideDom,
clearContainer,
} from '../../dom/DOMOperator';
import {
callEffectRemove,
@ -56,28 +55,17 @@ function callComponentWillUnmount(vNode: VNode, instance: any) {
function callBeforeSubmitLifeCycles(
vNode: VNode,
): void {
switch (vNode.tag) {
case ClassComponent: { // 调用instance.getSnapshotBeforeUpdate
if (!vNode.isCreated) {
const prevProps = vNode.isLazyComponent
? mergeDefaultProps(vNode.type, vNode.oldProps)
: vNode.oldProps;
const prevState = vNode.oldState;
const instance = vNode.realNode;
if (vNode.tag === ClassComponent && !vNode.isCreated) { // 调用instance.getSnapshotBeforeUpdate
const prevProps = vNode.isLazyComponent
? mergeDefaultProps(vNode.type, vNode.oldProps)
: vNode.oldProps;
const prevState = vNode.oldState;
const instance = vNode.realNode;
const snapshot = instance.getSnapshotBeforeUpdate(prevProps, prevState);
const snapshot = instance.getSnapshotBeforeUpdate(prevProps, prevState);
// __snapshotResult会在调用componentDidUpdate的时候作为第三个参数
instance.__snapshotResult = snapshot;
}
return;
}
case TreeRoot: {
const root = vNode.realNode;
clearContainer(root.outerDom);
}
// No Default
// __snapshotResult会在调用componentDidUpdate的时候作为第三个参数
instance.__snapshotResult = snapshot;
}
}
@ -138,7 +126,6 @@ function callAfterSubmitLifeCycles(
if (vNode.isCreated && vNode.flags.Update) {
// button、input、select、textarea、如果有 autoFocus 属性需要focus
if (shouldAutoFocus(vNode.type, vNode.props)) {
// button、input、select、textarea、如果有 autoFocus 属性需要focus
vNode.realNode.focus();
}
}
@ -333,7 +320,7 @@ function submitClear(vNode: VNode): void {
clearVNode(clearChild);
clearChild = clearChild.next as VNode;
}
// 在所有子项都卸载后删除dom树中的节点
removeChildDom(currentParent, vNode.realNode);
currentParent.append(cloneDom);

View File

@ -11,7 +11,7 @@ import {
callBeforeSubmitLifeCycles, submitDeletion, submitAddition,
submitResetTextContent, submitUpdate, detachRef, submitClear,
} from './LifeCycleHandler';
import {tryRenderFromRoot, setProcessing} from '../TreeBuilder';
import {tryRenderFromRoot} from '../TreeBuilder';
import {
BySync,
InRender,
@ -81,11 +81,6 @@ export function submitToRender(treeRoot) {
throw error;
}
// 非批量即同步执行的没有必要去执行RenderQueueRenderQueue放的是异步的
if (!checkMode(BySync)) { // 非批量
callRenderQueueImmediate();
}
return null;
}
@ -96,7 +91,6 @@ function beforeSubmit(dirtyNodes: Array<VNode>) {
callBeforeSubmitLifeCycles(node);
}
} catch (error) {
throwIfTrue(node === null, 'Should be working on an effect.');
handleSubmitError(node, error);
}
});
@ -138,7 +132,6 @@ function submit(dirtyNodes: Array<VNode>) {
}
}
} catch (error) {
throwIfTrue(node === null, 'Should be working on an effect.');
handleSubmitError(node, error);
}
});
@ -155,7 +148,6 @@ function afterSubmit(dirtyNodes: Array<VNode>) {
attachRef(node);
}
} catch (error) {
throwIfTrue(node === null, 'Should be working on an effect.');
handleSubmitError(node, error);
}
});

View File

@ -261,14 +261,14 @@ export function getExactNode(targetVNode, targetContainer) {
if (isPortalRoot(vNode, targetContainer)) {
return null;
}
while (container !== null) {
const parentNode = getNearestVNode(container);
if (parentNode === null) {
return null;
}
if (parentNode.tag === DomComponent || parentNode.tag === DomText) {
vNode = parentNode;
return getExactNode(vNode, targetContainer);
return getExactNode(parentNode, targetContainer);
}
container = container.parentNode;
}