DOM property operations
一、作用
二、获取属性值
备注
isAttributeNameSafe()由 isAttributeNameSafe 实现checkAttributeStringCoercion()由 CheckStringCoercion#checkAttributeStringCoercion 实现
/**
* Get the value for a attribute on a node. Only used in DEV for SSR validation.
* The third argument is used as a hint of what the expected value is. Some
* attributes have multiple equivalent values.
*
* 获取节点上某个属性的值。仅在开发环境中用于 SSR 验证。第三个参数用作预期值的提示。
* 某些属性有多个等效值。
*/
export function getValueForAttribute(
node: Element,
name: string,
expected: mixed,
): mixed {
if (__DEV__) {
if (!isAttributeNameSafe(name)) {
return;
}
if (!node.hasAttribute(name)) {
// shouldRemoveAttribute
// 是否应移除属性
switch (typeof expected) {
case 'function':
case 'symbol':
return expected;
case 'boolean': {
const prefix = name.toLowerCase().slice(0, 5);
if (prefix !== 'data-' && prefix !== 'aria-') {
return expected;
}
}
}
return expected === undefined ? undefined : null;
}
const value = node.getAttribute(name);
if (__DEV__) {
checkAttributeStringCoercion(expected, name);
}
if (value === '' + (expected as any)) {
return expected;
}
return value;
}
}
三、获取自定义组件上属性的值
备注
isAttributeNameSafe()由 isAttributeNameSafe 实现checkAttributeStringCoercion()由 CheckStringCoercion#checkAttributeStringCoercion 实现
export function getValueForAttributeOnCustomComponent(
node: Element,
name: string,
expected: mixed,
): mixed {
if (__DEV__) {
if (!isAttributeNameSafe(name)) {
return;
}
if (!node.hasAttribute(name)) {
// shouldRemoveAttribute
// 是否应移除属性
switch (typeof expected) {
case 'symbol':
case 'object':
// Symbols and objects are ignored when they're emitted so
// it would be expected that they end up not having an attribute.
// 当符号和对象被输出时会被忽略,所以预计它们最终不会有属性。
return expected;
case 'function':
return expected;
case 'boolean':
if (expected === false) {
return expected;
}
}
return expected === undefined ? undefined : null;
}
const value = node.getAttribute(name);
if (value === '' && expected === true) {
return true;
}
if (__DEV__) {
checkAttributeStringCoercion(expected, name);
}
if (value === '' + (expected as any)) {
return expected;
}
return value;
}
}
四、为属性设置值
备注
isAttributeNameSafe()由 isAttributeNameSafe 实现checkAttributeStringCoercion()由 CheckStringCoercion#checkAttributeStringCoercion 实现enableTrustedTypesIntegration由 ReactFeatureFlags#enableTrustedTypesIntegration 提供
export function setValueForAttribute(
node: Element,
name: string,
value: mixed,
) {
if (isAttributeNameSafe(name)) {
// If the prop isn't in the special list, treat it as a simple attribute.
// shouldRemoveAttribute
// 如果该属性不在特殊列表中,则将其视为普通属性 shouldRemoveAttribute
if (value === null) {
node.removeAttribute(name);
return;
}
switch (typeof value) {
case 'undefined':
case 'function':
case 'symbol':
node.removeAttribute(name);
return;
case 'boolean': {
const prefix = name.toLowerCase().slice(0, 5);
if (prefix !== 'data-' && prefix !== 'aria-') {
node.removeAttribute(name);
return;
}
}
}
if (__DEV__) {
checkAttributeStringCoercion(value, name);
}
node.setAttribute(
name,
enableTrustedTypesIntegration ? (value as any) : '' + (value as any),
);
}
}
五、为已知属性设置值
备注
checkAttributeStringCoercion()由 CheckStringCoercion#checkAttributeStringCoercion 实现enableTrustedTypesIntegration由 ReactFeatureFlags#enableTrustedTypesIntegration 提供
export function setValueForKnownAttribute(
node: Element,
name: string,
value: mixed,
) {
if (value === null) {
node.removeAttribute(name);
return;
}
switch (typeof value) {
case 'undefined':
case 'function':
case 'symbol':
case 'boolean': {
node.removeAttribute(name);
return;
}
}
if (__DEV__) {
checkAttributeStringCoercion(value, name);
}
node.setAttribute(
name,
enableTrustedTypesIntegration ? (value as any) : '' + (value as any),
);
}
六、为命名空间属性设置值
export function setValueForNamespacedAttribute(
node: Element,
namespace: string,
name: string,
value: mixed,
) {
if (value === null) {
node.removeAttribute(name);
return;
}
switch (typeof value) {
case 'undefined':
case 'function':
case 'symbol':
case 'boolean': {
node.removeAttribute(name);
return;
}
}
if (__DEV__) {
checkAttributeStringCoercion(value, name);
}
node.setAttributeNS(
namespace,
name,
enableTrustedTypesIntegration ? (value as any) : '' + (value as any),
);
}
七、在自定义组件上设置属性值
export function setValueForPropertyOnCustomComponent(
node: Element,
name: string,
value: mixed,
) {
if (name[0] === 'o' && name[1] === 'n') {
const useCapture = name.endsWith('Capture');
const eventName = name.slice(2, useCapture ? name.length - 7 : undefined);
const prevProps = getFiberCurrentPropsFromNode(node);
const prevValue = prevProps != null ? prevProps[name] : null;
if (typeof prevValue === 'function') {
node.removeEventListener(eventName, prevValue, useCapture);
}
if (typeof value === 'function') {
if (typeof prevValue !== 'function' && prevValue !== null) {
// If we previously assigned a non-function type into this node, then
// remove it when switching to event listener mode.
// 如果之前我们给这个节点分配了非函数类型,那么在切换到事件监听器模式时将其移除
if (name in (node as any)) {
(node as any)[name] = null;
} else if (node.hasAttribute(name)) {
node.removeAttribute(name);
}
}
node.addEventListener(eventName, value as EventListener, useCapture);
return;
}
}
trackHostMutation();
if (name in (node as any)) {
(node as any)[name] = value;
return;
}
if (value === true) {
node.setAttribute(name, '');
return;
}
// From here, it's the same as any attribute
// 从这里开始,它和任何属性都是一样的
setValueForAttribute(node, name, value);
}