Match-id-c129f1002ec86566362106c475c16f5a771e5763
This commit is contained in:
parent
17a8e1b13e
commit
2cddb7a6e5
|
@ -27,6 +27,7 @@ module.exports = {
|
|||
},
|
||||
rules: {
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
'@typescript-eslint/no-empty-function': 'off',
|
||||
semi: ['warn', 'always'],
|
||||
|
|
|
@ -9,8 +9,6 @@ import { getSelectionInfo, resetSelectionRange, SelectionData } from './Selectio
|
|||
import { shouldAutoFocus } from './utils/Common';
|
||||
import { NSS } from './utils/DomCreator';
|
||||
import { adjustStyleValue } from './DOMPropertiesHandler/StyleHandler';
|
||||
|
||||
import { listenDelegatedEvents } from '../event/EventBinding';
|
||||
import type { VNode } from '../renderer/Types';
|
||||
import {
|
||||
setInitValue,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export interface IProperty {
|
||||
export interface Props {
|
||||
[propName: string]: any;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
import { updateCommonProp } from '../DOMPropertiesHandler/UpdateCommonProp';
|
||||
import { IProperty } from '../utils/Interface';
|
||||
import { isInputElement } from '../utils/Common';
|
||||
import { getVNodeProps } from '../DOMInternalKeys';
|
||||
import { updateInputValueIfChanged } from './ValueChangeHandler';
|
||||
import { Props } from '../utils/Interface';
|
||||
|
||||
function getInitValue(dom: HTMLInputElement, properties: IProperty) {
|
||||
const { value, defaultValue, checked, defaultChecked } = properties;
|
||||
function getInitValue(dom: HTMLInputElement, props: Props) {
|
||||
const { value, defaultValue, checked, defaultChecked } = props;
|
||||
|
||||
const defaultValueStr = defaultValue != null ? defaultValue : '';
|
||||
const initValue = value != null ? value : defaultValueStr;
|
||||
|
@ -14,15 +11,15 @@ function getInitValue(dom: HTMLInputElement, properties: IProperty) {
|
|||
return { initValue, initChecked };
|
||||
}
|
||||
|
||||
export function getInputPropsWithoutValue(dom: HTMLInputElement, properties: IProperty) {
|
||||
export function getInputPropsWithoutValue(dom: HTMLInputElement, props: Props) {
|
||||
// checked属于必填属性,无法置
|
||||
let {checked} = properties;
|
||||
let {checked} = props;
|
||||
if (checked == null) {
|
||||
checked = getInitValue(dom, properties).initChecked;
|
||||
checked = getInitValue(dom, props).initChecked;
|
||||
}
|
||||
|
||||
return {
|
||||
...properties,
|
||||
...props,
|
||||
value: undefined,
|
||||
defaultValue: undefined,
|
||||
defaultChecked: undefined,
|
||||
|
@ -30,8 +27,8 @@ export function getInputPropsWithoutValue(dom: HTMLInputElement, properties: IPr
|
|||
};
|
||||
}
|
||||
|
||||
export function updateInputValue(dom: HTMLInputElement, properties: IProperty) {
|
||||
const {value, checked} = properties;
|
||||
export function updateInputValue(dom: HTMLInputElement, props: Props) {
|
||||
const {value, checked} = props;
|
||||
|
||||
if (value != null) { // 处理 dom.value 逻辑
|
||||
if (dom.value !== String(value)) {
|
||||
|
@ -43,9 +40,9 @@ export function updateInputValue(dom: HTMLInputElement, properties: IProperty) {
|
|||
}
|
||||
|
||||
// 设置input的初始值
|
||||
export function setInitInputValue(dom: HTMLInputElement, properties: IProperty) {
|
||||
const {value, defaultValue} = properties;
|
||||
const {initValue, initChecked} = getInitValue(dom, properties);
|
||||
export function setInitInputValue(dom: HTMLInputElement, props: Props) {
|
||||
const {value, defaultValue} = props;
|
||||
const {initValue, initChecked} = getInitValue(dom, props);
|
||||
|
||||
if (value != null || defaultValue != null) {
|
||||
// value 的使用优先级 value 属性 > defaultValue 属性 > 空字符串
|
||||
|
@ -59,27 +56,3 @@ export function setInitInputValue(dom: HTMLInputElement, properties: IProperty)
|
|||
// checked 的使用优先级 checked 属性 > defaultChecked 属性 > false
|
||||
dom.defaultChecked = Boolean(initChecked);
|
||||
}
|
||||
|
||||
// 找出同一form内,name相同的Radio,更新它们Handler的Value
|
||||
export function syncRadiosHandler(targetRadio: Element) {
|
||||
if (isInputElement(targetRadio)) {
|
||||
const props = getVNodeProps(targetRadio);
|
||||
if (props) {
|
||||
const { name, type } = props;
|
||||
if (type === 'radio' && name != null) {
|
||||
const radioList = document.querySelectorAll<HTMLInputElement>(`input[type="radio"][name="${name}"]`);
|
||||
for (let i = 0; i < radioList.length; i++) {
|
||||
const radio = radioList[i];
|
||||
if (radio === targetRadio) {
|
||||
continue;
|
||||
}
|
||||
if (radio.form != null && targetRadio.form != null && radio.form !== targetRadio.form) {
|
||||
continue;
|
||||
}
|
||||
|
||||
updateInputValueIfChanged(radio);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Children } from '../../external/ChildrenUtil';
|
||||
import { IProperty } from '../utils/Interface';
|
||||
import { Props } from '../utils/Interface';
|
||||
|
||||
// 把 const a = 'a'; <option>gir{a}ffe</option> 转成 giraffe
|
||||
function concatChildren(children) {
|
||||
|
@ -11,11 +11,11 @@ function concatChildren(children) {
|
|||
return content;
|
||||
}
|
||||
|
||||
export function getOptionPropsWithoutValue(dom: Element, properties: IProperty) {
|
||||
const content = concatChildren(properties.children);
|
||||
export function getOptionPropsWithoutValue(dom: Element, props: Props) {
|
||||
const content = concatChildren(props.children);
|
||||
|
||||
return {
|
||||
...properties,
|
||||
...props,
|
||||
children: content || undefined, // 覆盖children
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {HorizonSelect, IProperty} from '../utils/Interface';
|
||||
import {HorizonSelect, Props} from '../utils/Interface';
|
||||
|
||||
function updateMultipleValue(options, newValues) {
|
||||
const newValueSet = new Set();
|
||||
|
@ -46,8 +46,8 @@ export function getSelectPropsWithoutValue(dom: HorizonSelect, properties: Objec
|
|||
};
|
||||
}
|
||||
|
||||
export function updateSelectValue(dom: HorizonSelect, properties: IProperty, isInit: boolean = false) {
|
||||
const {value, defaultValue, multiple} = properties;
|
||||
export function updateSelectValue(dom: HorizonSelect, props: Props, isInit: boolean = false) {
|
||||
const {value, defaultValue, multiple} = props;
|
||||
|
||||
const oldMultiple = dom._multiple !== undefined ? dom._multiple : dom.multiple;
|
||||
const newMultiple = Boolean(multiple);
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import {IProperty} from '../utils/Interface';
|
||||
import {Props} from '../utils/Interface';
|
||||
|
||||
|
||||
// 值的优先级 value > children > defaultValue
|
||||
function getInitValue(properties: IProperty) {
|
||||
const {value} = properties;
|
||||
function getInitValue(props: Props) {
|
||||
const {value} = props;
|
||||
|
||||
if (value == null) {
|
||||
const {defaultValue, children} = properties;
|
||||
const {defaultValue, children} = props;
|
||||
let initValue = defaultValue;
|
||||
|
||||
// children content存在时,会覆盖defaultValue
|
||||
|
@ -30,15 +30,15 @@ export function getTextareaPropsWithoutValue(dom: HTMLTextAreaElement, propertie
|
|||
};
|
||||
}
|
||||
|
||||
export function updateTextareaValue(dom: HTMLTextAreaElement, properties: IProperty, isInit: boolean = false) {
|
||||
export function updateTextareaValue(dom: HTMLTextAreaElement, props: Props, isInit: boolean = false) {
|
||||
if (isInit) {
|
||||
const initValue = getInitValue(properties);
|
||||
const initValue = getInitValue(props);
|
||||
if (initValue !== '') {
|
||||
dom.value = initValue;
|
||||
}
|
||||
} else {
|
||||
// 获取当前节点的 value 值
|
||||
let value = properties.value;
|
||||
let value = props.value;
|
||||
if (value != null) {
|
||||
value = String(value);
|
||||
// 当且仅当值实际发生变化时才去设置节点的value值
|
||||
|
|
|
@ -54,7 +54,8 @@ export function watchValueChange(dom) {
|
|||
}
|
||||
}
|
||||
|
||||
export function updateInputValueIfChanged(dom) {
|
||||
// 更新input dom的handler 状态,返回是否更新
|
||||
export function updateInputHandlerIfChanged(dom) {
|
||||
const handler = dom[HANDLER_KEY];
|
||||
if (!handler) {
|
||||
return true;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* 处理组件被代理和不被代理情况下的不同逻辑
|
||||
*/
|
||||
|
||||
import {HorizonDom, HorizonSelect, IProperty} from '../utils/Interface';
|
||||
import {HorizonDom, HorizonSelect, Props} from '../utils/Interface';
|
||||
import {
|
||||
getInputPropsWithoutValue,
|
||||
setInitInputValue,
|
||||
|
@ -22,7 +22,7 @@ import {
|
|||
} from './TextareaValueHandler';
|
||||
|
||||
// 获取元素除了被代理的值以外的属性
|
||||
function getPropsWithoutValue(type: string, dom: HorizonDom, properties: IProperty) {
|
||||
function getPropsWithoutValue(type: string, dom: HorizonDom, properties: Props) {
|
||||
switch (type) {
|
||||
case 'input':
|
||||
return getInputPropsWithoutValue(<HTMLInputElement>dom, properties);
|
||||
|
@ -38,7 +38,7 @@ function getPropsWithoutValue(type: string, dom: HorizonDom, properties: IProper
|
|||
}
|
||||
|
||||
// 其它属性挂载完成后处理被代理值相关的属性
|
||||
function setInitValue(type: string, dom: HorizonDom, properties: IProperty) {
|
||||
function setInitValue(type: string, dom: HorizonDom, properties: Props) {
|
||||
switch (type) {
|
||||
case 'input':
|
||||
setInitInputValue(<HTMLInputElement>dom, properties);
|
||||
|
@ -55,7 +55,7 @@ function setInitValue(type: string, dom: HorizonDom, properties: IProperty) {
|
|||
}
|
||||
|
||||
// 更新需要适配的属性
|
||||
function updateValue(type: string, dom: HorizonDom, properties: IProperty) {
|
||||
function updateValue(type: string, dom: HorizonDom, properties: Props) {
|
||||
switch (type) {
|
||||
case 'input':
|
||||
updateInputValue(<HTMLInputElement>dom, properties);
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
|
||||
*/
|
||||
|
||||
import { getVNodeProps } from '../dom/DOMInternalKeys';
|
||||
import { getDomTag } from '../dom/utils/Common';
|
||||
import { Props } from '../dom/utils/Interface';
|
||||
import { updateTextareaValue } from '../dom/valueHandler/TextareaValueHandler';
|
||||
import { updateInputHandlerIfChanged } from '../dom/valueHandler/ValueChangeHandler';
|
||||
import { updateInputValue } from '../dom/valueHandler/InputValueHandler';
|
||||
|
||||
// 记录表单控件 input/textarea/select的onChange事件的targets
|
||||
let changeEventTargets: Array<any> | null = null;
|
||||
|
||||
// 存储队列中缓存组件
|
||||
export function recordChangeEventTargets(target: EventTarget): void {
|
||||
if (changeEventTargets) {
|
||||
changeEventTargets.push(target);
|
||||
} else {
|
||||
changeEventTargets = [target];
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否需要控制value与props保持一致
|
||||
export function shouldControlValue(): boolean {
|
||||
return changeEventTargets !== null && changeEventTargets.length > 0;
|
||||
}
|
||||
|
||||
// 从缓存队列中对受控组件进行赋值
|
||||
export function tryControlValue() {
|
||||
if (!changeEventTargets) {
|
||||
return;
|
||||
}
|
||||
changeEventTargets.forEach(target => {
|
||||
controlValue(target);
|
||||
});
|
||||
changeEventTargets = null;
|
||||
}
|
||||
|
||||
// 受控组件值重新赋值
|
||||
function controlValue(target: Element) {
|
||||
const props = getVNodeProps(target);
|
||||
if (props) {
|
||||
const type = getDomTag(target);
|
||||
switch (type) {
|
||||
case 'input':
|
||||
controlInputValue(<HTMLInputElement>target, props);
|
||||
break;
|
||||
case 'textarea':
|
||||
updateTextareaValue(<HTMLTextAreaElement>target, props);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function controlInputValue(inputDom: HTMLInputElement, props: Props) {
|
||||
const { name, type } = props;
|
||||
|
||||
// 如果是 radio,先更新相同 name 的 radio
|
||||
if (type === 'radio' && name != null) {
|
||||
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) {
|
||||
continue;
|
||||
}
|
||||
|
||||
updateInputHandlerIfChanged(radio);
|
||||
}
|
||||
} else {
|
||||
updateInputValue(inputDom, props);
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,6 @@ import { decorateNativeEvent } from './EventWrapper';
|
|||
import { getListenersFromTree } from './ListenerGetter';
|
||||
import { asyncUpdates, runDiscreteUpdates } from '../renderer/Renderer';
|
||||
import { findRoot } from '../renderer/vnode/VNodeUtils';
|
||||
import { syncRadiosHandler } from '../dom/valueHandler/InputValueHandler';
|
||||
import {
|
||||
EVENT_TYPE_ALL,
|
||||
EVENT_TYPE_BUBBLE,
|
||||
|
@ -14,8 +13,9 @@ import {
|
|||
transformToHorizonEvent,
|
||||
} from './EventHub';
|
||||
import { getDomTag } from '../dom/utils/Common';
|
||||
import { updateInputValueIfChanged } from '../dom/valueHandler/ValueChangeHandler';
|
||||
import { updateInputHandlerIfChanged } from '../dom/valueHandler/ValueChangeHandler';
|
||||
import { getDom } from '../dom/DOMInternalKeys';
|
||||
import { recordChangeEventTargets, shouldControlValue, tryControlValue } from './FormValueController';
|
||||
|
||||
// web规范,鼠标右键key值
|
||||
const RIGHT_MOUSE_BUTTON = 2;
|
||||
|
@ -34,11 +34,11 @@ function shouldTriggerChangeEvent(targetDom, evtName) {
|
|||
return evtName === 'change';
|
||||
} else if (domTag === 'input' && (type === 'checkbox' || type === 'radio')) {
|
||||
if (evtName === 'click') {
|
||||
return updateInputValueIfChanged(targetDom);
|
||||
return updateInputHandlerIfChanged(targetDom);
|
||||
}
|
||||
} else if (isInputElement(targetDom)) {
|
||||
if (evtName === 'input' || evtName === 'change') {
|
||||
return updateInputValueIfChanged(targetDom);
|
||||
return updateInputHandlerIfChanged(targetDom);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -52,6 +52,7 @@ function getChangeListeners(
|
|||
nativeEvtName: string,
|
||||
nativeEvt: AnyNativeEvent,
|
||||
vNode: null | VNode,
|
||||
target: EventTarget
|
||||
): ListenerUnitList {
|
||||
if (!vNode) {
|
||||
return [];
|
||||
|
@ -60,6 +61,8 @@ function getChangeListeners(
|
|||
|
||||
// 判断是否需要触发change事件
|
||||
if (shouldTriggerChangeEvent(targetDom, nativeEvtName)) {
|
||||
recordChangeEventTargets(target);
|
||||
|
||||
const event = decorateNativeEvent(
|
||||
'onChange',
|
||||
'change',
|
||||
|
@ -129,8 +132,7 @@ function triggerHorizonEvents(
|
|||
nativeEvent: AnyNativeEvent,
|
||||
vNode: VNode | null,
|
||||
) {
|
||||
const target = nativeEvent.target || nativeEvent.srcElement;
|
||||
let hasTriggeredChangeEvent = false;
|
||||
const target = nativeEvent.target || nativeEvent.srcElement!;
|
||||
|
||||
// 触发普通委托事件
|
||||
let listenerList: ListenerUnitList = getCommonListeners(
|
||||
|
@ -147,17 +149,15 @@ function triggerHorizonEvents(
|
|||
nativeEvtName,
|
||||
nativeEvent,
|
||||
vNode,
|
||||
target
|
||||
);
|
||||
if (changeListeners.length) {
|
||||
hasTriggeredChangeEvent = true;
|
||||
listenerList = listenerList.concat(changeListeners);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理触发的事件队列
|
||||
processListeners(listenerList);
|
||||
|
||||
return hasTriggeredChangeEvent;
|
||||
}
|
||||
|
||||
|
||||
|
@ -188,15 +188,13 @@ export function handleEventMain(
|
|||
|
||||
// 没有事件在执行,经过调度再执行事件
|
||||
isInEventsExecution = true;
|
||||
let hasTriggeredChangeEvent = false;
|
||||
try {
|
||||
hasTriggeredChangeEvent = asyncUpdates(() => triggerHorizonEvents(nativeEvtName, isCapture, nativeEvent, startVNode));
|
||||
asyncUpdates(() => triggerHorizonEvents(nativeEvtName, isCapture, nativeEvent, startVNode));
|
||||
} finally {
|
||||
isInEventsExecution = false;
|
||||
if (hasTriggeredChangeEvent) {
|
||||
if (shouldControlValue()) {
|
||||
runDiscreteUpdates();
|
||||
// 若是Radio,同步同组其他Radio的Handler Value
|
||||
syncRadiosHandler(nativeEvent.target as Element);
|
||||
tryControlValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue