Match-id-c3d530104af803ccd0d7aef09548027b4c8d60f7
This commit is contained in:
parent
1ecc732b33
commit
a72fb10ef3
|
@ -17,7 +17,7 @@
|
|||
* 处理文本框、输入框中框选范围内的数据
|
||||
*/
|
||||
|
||||
import { getIFrameFocusedDom, isText } from './utils/Common';
|
||||
import { getIFrameFocusedDom, isNull, isText } from './utils/Common';
|
||||
|
||||
import { isElement } from './utils/Common';
|
||||
|
||||
|
@ -30,7 +30,7 @@ function setSelectionRange(dom: HTMLInputElement | HTMLTextAreaElement, range) {
|
|||
const { start, end } = range;
|
||||
let realEnd = end;
|
||||
|
||||
if (realEnd == null) {
|
||||
if (isNull(realEnd)) {
|
||||
realEnd = start;
|
||||
}
|
||||
|
||||
|
|
|
@ -84,3 +84,7 @@ const types = ['button', 'input', 'select', 'textarea'];
|
|||
export function shouldAutoFocus(tagName: string, props: Props): boolean {
|
||||
return types.includes(tagName) ? Boolean(props.autoFocus) : false;
|
||||
}
|
||||
|
||||
export function isNull(val) {
|
||||
return val === null || val === undefined;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
*/
|
||||
|
||||
import { getPropDetails, PROPERTY_TYPE, PropDetails } from './PropertiesData';
|
||||
import { isNull } from '../utils/Common';
|
||||
|
||||
const INVALID_EVENT_NAME_REGEX = /^on[^A-Z]/;
|
||||
|
||||
|
@ -73,7 +74,7 @@ export function isInvalidValue(
|
|||
propDetails: PropDetails | null,
|
||||
isNativeTag: boolean
|
||||
): boolean {
|
||||
if (value == null) {
|
||||
if (isNull(value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -104,7 +105,7 @@ export function validateProps(type, props) {
|
|||
}
|
||||
|
||||
// style属性必须是对象
|
||||
if (props.style != null && typeof props.style !== 'object') {
|
||||
if (!isNull(props.style) && typeof props.style !== 'object') {
|
||||
throw new Error('style should be a object.');
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
import { updateCommonProp } from '../DOMPropertiesHandler/UpdateCommonProp';
|
||||
import { Props } from '../utils/Interface';
|
||||
import { isNull } from '../utils/Common';
|
||||
|
||||
function getInitValue(dom: HTMLInputElement, props: Props) {
|
||||
const { value, defaultValue, checked, defaultChecked } = props;
|
||||
|
@ -29,7 +30,7 @@ function getInitValue(dom: HTMLInputElement, props: Props) {
|
|||
export function getInputPropsWithoutValue(dom: HTMLInputElement, props: Props) {
|
||||
// checked属于必填属性,无法置
|
||||
let { checked } = props;
|
||||
if (checked == null) {
|
||||
if (isNull(checked)) {
|
||||
checked = getInitValue(dom, props).initChecked;
|
||||
}
|
||||
|
||||
|
@ -45,12 +46,12 @@ export function getInputPropsWithoutValue(dom: HTMLInputElement, props: Props) {
|
|||
export function updateInputValue(dom: HTMLInputElement, props: Props) {
|
||||
const { value, checked } = props;
|
||||
|
||||
if (value != null) {
|
||||
if (!isNull(value)) {
|
||||
// 处理 dom.value 逻辑
|
||||
if (dom.value !== String(value)) {
|
||||
dom.value = String(value);
|
||||
}
|
||||
} else if (checked != null) {
|
||||
} else if (!isNull(checked)) {
|
||||
updateCommonProp(dom, 'checked', checked, true);
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +61,7 @@ export function setInitInputValue(dom: HTMLInputElement, props: Props) {
|
|||
const { value, defaultValue } = props;
|
||||
const { initValue, initChecked } = getInitValue(dom, props);
|
||||
|
||||
if (value != null || defaultValue != null) {
|
||||
if (!isNull(value) || !isNull(defaultValue)) {
|
||||
// value 的使用优先级 value 属性 > defaultValue 属性 > 空字符串
|
||||
const initValueStr = String(initValue);
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
*/
|
||||
|
||||
import { HorizonSelect, Props } from '../utils/Interface';
|
||||
import { isNull } from '../utils/Common';
|
||||
|
||||
function updateMultipleValue(options, newValues) {
|
||||
const newValueSet = new Set();
|
||||
|
@ -69,18 +70,18 @@ export function updateSelectValue(dom: HorizonSelect, props: Props, isInit = fal
|
|||
dom._multiple = newMultiple;
|
||||
|
||||
// 设置了 value 属性
|
||||
if (value != null) {
|
||||
if (!isNull(value)) {
|
||||
updateValue(dom.options, value, newMultiple);
|
||||
} else if (oldMultiple !== newMultiple) {
|
||||
// 修改了 multiple 属性
|
||||
// 切换 multiple 之后,如果设置了 defaultValue 需要重新应用
|
||||
if (defaultValue != null) {
|
||||
if (!isNull(defaultValue)) {
|
||||
updateValue(dom.options, defaultValue, newMultiple);
|
||||
} else {
|
||||
// 恢复到未选定状态
|
||||
updateValue(dom.options, newMultiple ? [] : '', newMultiple);
|
||||
}
|
||||
} else if (isInit && defaultValue != null) {
|
||||
} else if (isInit && !isNull(defaultValue)) {
|
||||
// 设置了 defaultValue 属性
|
||||
updateValue(dom.options, defaultValue, newMultiple);
|
||||
}
|
||||
|
|
|
@ -14,12 +14,13 @@
|
|||
*/
|
||||
|
||||
import { Props } from '../utils/Interface';
|
||||
import { isNull } from '../utils/Common';
|
||||
|
||||
// 值的优先级 value > children > defaultValue
|
||||
function getInitValue(props: Props) {
|
||||
const { value } = props;
|
||||
|
||||
if (value == null) {
|
||||
if (isNull(value)) {
|
||||
const { defaultValue, children } = props;
|
||||
let initValue = defaultValue;
|
||||
|
||||
|
@ -30,7 +31,7 @@ function getInitValue(props: Props) {
|
|||
}
|
||||
|
||||
// defaultValue 属性未配置,置为空字符串
|
||||
initValue = initValue != null ? initValue : '';
|
||||
initValue = initValue ?? '';
|
||||
return initValue;
|
||||
} else {
|
||||
return value;
|
||||
|
|
|
@ -62,13 +62,6 @@ function isCaptureEvent(horizonEventName) {
|
|||
return horizonEventName.slice(-7) === 'Capture';
|
||||
}
|
||||
|
||||
// 利用冒泡事件模拟不冒泡事件,需要直接在根节点绑定
|
||||
export function listenSimulatedDelegatedEvents(root: VNode) {
|
||||
for (let i = 0; i < simulatedDelegatedEvents.length; i++) {
|
||||
lazyDelegateOnRoot(root, simulatedDelegatedEvents[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// 事件懒委托,当用户定义事件后,再进行委托到根节点
|
||||
export function lazyDelegateOnRoot(currentRoot: VNode, eventName: string) {
|
||||
currentRoot.delegatedEvents.add(eventName);
|
||||
|
@ -80,11 +73,8 @@ export function lazyDelegateOnRoot(currentRoot: VNode, eventName: string) {
|
|||
const nativeFullName = isCapture ? nativeEvent + 'capture' : nativeEvent;
|
||||
|
||||
// 事件存储在DOM节点属性,避免多个VNode(root和portal)对应同一个DOM, 造成事件重复监听
|
||||
let events = currentRoot.realNode.$EV;
|
||||
|
||||
if (!events) {
|
||||
events = (currentRoot.realNode as any).$EV = {};
|
||||
}
|
||||
currentRoot.realNode.$EV = currentRoot.realNode.$EV || {};
|
||||
const events = currentRoot.realNode.$EV;
|
||||
|
||||
if (!events[nativeFullName]) {
|
||||
events[nativeFullName] = listenToNativeEvent(nativeEvent, currentRoot.realNode, isCapture);
|
||||
|
@ -92,6 +82,13 @@ export function lazyDelegateOnRoot(currentRoot: VNode, eventName: string) {
|
|||
});
|
||||
}
|
||||
|
||||
// 利用冒泡事件模拟不冒泡事件,需要直接在根节点绑定
|
||||
export function listenSimulatedDelegatedEvents(root: VNode) {
|
||||
for (let i = 0; i < simulatedDelegatedEvents.length; i++) {
|
||||
lazyDelegateOnRoot(root, simulatedDelegatedEvents[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// 通过horizon事件名获取到native事件名
|
||||
function getNativeEvtName(horizonEventName, capture) {
|
||||
let nativeName;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
import { getVNodeProps } from '../dom/DOMInternalKeys';
|
||||
import { getDomTag } from '../dom/utils/Common';
|
||||
import { getDomTag, isNull } from '../dom/utils/Common';
|
||||
import { Props } from '../dom/utils/Interface';
|
||||
import { updateTextareaValue } from '../dom/valueHandler/TextareaValueHandler';
|
||||
import { updateInputHandlerIfChanged } from '../dom/valueHandler/ValueChangeHandler';
|
||||
|
@ -41,14 +41,14 @@ function controlInputValue(inputDom: HTMLInputElement, props: Props) {
|
|||
const { name, type } = props;
|
||||
|
||||
// 如果是 radio,找出同一form内,name相同的Radio,更新它们Handler的Value
|
||||
if (type === 'radio' && name != null) {
|
||||
if (type === 'radio' && !isNull(name)) {
|
||||
const radioList = document.querySelectorAll<HTMLInputElement>(`input[type="radio"][name="${name}"]`);
|
||||
for (let i = 0; i < radioList.length; i++) {
|
||||
const radio = radioList[i];
|
||||
if (radio === inputDom) {
|
||||
continue;
|
||||
}
|
||||
if (radio.form != null && inputDom.form != null && radio.form !== inputDom.form) {
|
||||
if (!isNull(radio.form) && !isNull(inputDom.form) && radio.form !== inputDom.form) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -87,34 +87,30 @@ export function getListenersFromTree(
|
|||
return listeners;
|
||||
}
|
||||
|
||||
// 获取enter和leave事件队列
|
||||
export function collectMouseListeners(
|
||||
leaveEvent: null | WrappedEvent,
|
||||
enterEvent: null | WrappedEvent,
|
||||
from: VNode | null,
|
||||
to: VNode | null,
|
||||
): ListenerUnitList {
|
||||
// 确定公共父节点,作为在树上遍历的终点
|
||||
const commonParent = from && to ? getCommonAncestor(from, to) : null;
|
||||
let leaveEventList: ListenerUnitList = [];
|
||||
if (from && leaveEvent) {
|
||||
// 遍历树,获取绑定的leave事件
|
||||
leaveEventList = getMouseListenersFromTree(
|
||||
leaveEvent,
|
||||
from,
|
||||
commonParent,
|
||||
);
|
||||
|
||||
// 获取父节点
|
||||
function getParent(inst: VNode | null): VNode | null {
|
||||
if (inst === null) {
|
||||
return null;
|
||||
}
|
||||
let enterEventList: ListenerUnitList = [];
|
||||
if (to && enterEvent) {
|
||||
// 先触发父节点enter事件,所以需要逆序
|
||||
enterEventList = getMouseListenersFromTree(
|
||||
enterEvent,
|
||||
to,
|
||||
commonParent,
|
||||
).reverse();
|
||||
do {
|
||||
inst = inst.parent;
|
||||
} while (inst && inst.tag !== DomComponent);
|
||||
return inst || null;
|
||||
}
|
||||
|
||||
// 寻找两个节点的共同最近祖先,如果没有则返回null
|
||||
function getCommonAncestor(instA: VNode, instB: VNode): VNode | null {
|
||||
const parentsSet = new Set<VNode>();
|
||||
for (let tempA: VNode | null = instA; tempA; tempA = getParent(tempA)) {
|
||||
parentsSet.add(tempA);
|
||||
}
|
||||
return [...leaveEventList, ...enterEventList];
|
||||
for (let tempB: VNode | null = instB; tempB; tempB = getParent(tempB)) {
|
||||
if (parentsSet.has(tempB)) {
|
||||
return tempB;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getMouseListenersFromTree(
|
||||
|
@ -149,27 +145,32 @@ function getMouseListenersFromTree(
|
|||
return listeners;
|
||||
}
|
||||
|
||||
// 寻找两个节点的共同最近祖先,如果没有则返回null
|
||||
function getCommonAncestor(instA: VNode, instB: VNode): VNode | null {
|
||||
const parentsSet = new Set<VNode>();
|
||||
for (let tempA: VNode | null = instA; tempA; tempA = getParent(tempA)) {
|
||||
parentsSet.add(tempA);
|
||||
// 获取enter和leave事件队列
|
||||
export function collectMouseListeners(
|
||||
leaveEvent: null | WrappedEvent,
|
||||
enterEvent: null | WrappedEvent,
|
||||
from: VNode | null,
|
||||
to: VNode | null,
|
||||
): ListenerUnitList {
|
||||
// 确定公共父节点,作为在树上遍历的终点
|
||||
const commonParent = from && to ? getCommonAncestor(from, to) : null;
|
||||
let leaveEventList: ListenerUnitList = [];
|
||||
if (from && leaveEvent) {
|
||||
// 遍历树,获取绑定的leave事件
|
||||
leaveEventList = getMouseListenersFromTree(
|
||||
leaveEvent,
|
||||
from,
|
||||
commonParent,
|
||||
);
|
||||
}
|
||||
for (let tempB: VNode | null = instB; tempB; tempB = getParent(tempB)) {
|
||||
if (parentsSet.has(tempB)) {
|
||||
return tempB;
|
||||
}
|
||||
let enterEventList: ListenerUnitList = [];
|
||||
if (to && enterEvent) {
|
||||
// 先触发父节点enter事件,所以需要逆序
|
||||
enterEventList = getMouseListenersFromTree(
|
||||
enterEvent,
|
||||
to,
|
||||
commonParent,
|
||||
).reverse();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 获取父节点
|
||||
function getParent(inst: VNode | null): VNode | null {
|
||||
if (inst === null) {
|
||||
return null;
|
||||
}
|
||||
do {
|
||||
inst = inst.parent;
|
||||
} while (inst && inst.tag !== DomComponent);
|
||||
return inst || null;
|
||||
return [...leaveEventList, ...enterEventList];
|
||||
}
|
||||
|
|
|
@ -182,6 +182,10 @@ function getNewNode(parentNode: VNode, newChild: any, oldNode: VNode | null) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -374,7 +378,7 @@ function diffArrayNodesHandler(parentNode: VNode, firstChild: VNode | null, newC
|
|||
// 4. 新节点还有一部分,但是老节点已经没有了
|
||||
if (oldNode === null) {
|
||||
let isDirectAdd = false;
|
||||
// TODO: 是否可以扩大至非dom类型节点
|
||||
// 是否可以扩大至非dom类型节点待确认
|
||||
// 如果dom节点在上次添加前没有节点,说明本次添加时,可以直接添加到最后,不需要通过 getSiblingDom 函数找到 before 节点
|
||||
if (
|
||||
parentNode.tag === DomComponent &&
|
||||
|
@ -513,7 +517,7 @@ function diffIteratorNodesHandler(
|
|||
}
|
||||
|
||||
// 新节点是字符串类型
|
||||
function diffStringNodeHandler(parentNode: VNode, newChild: any, firstChildVNode: VNode, isComparing: boolean) {
|
||||
function diffStringNodeHandler(parentNode: VNode, newChild: any, firstChildVNode: VNode | null, isComparing: boolean) {
|
||||
let newTextNode: VNode | null = null;
|
||||
|
||||
// 第一个vNode是Text,则复用
|
||||
|
@ -560,7 +564,7 @@ function diffObjectNodeHandler(
|
|||
}
|
||||
|
||||
let resultNode: VNode | null = null;
|
||||
let startDelVNode = firstChildVNode;
|
||||
let startDelVNode: VNode | null = firstChildVNode;
|
||||
if (newChild.vtype === TYPE_COMMON_ELEMENT) {
|
||||
if (canReuseNode) {
|
||||
// 可以复用
|
||||
|
|
Loading…
Reference in New Issue