Match-id-faffd764b594db29fe1fde20f07ce87444d16c7e
This commit is contained in:
parent
696d2de905
commit
14ac0163a1
|
@ -24,11 +24,12 @@ const internalKeys = {
|
|||
};
|
||||
|
||||
// 通过 VNode 实例获取 DOM 节点
|
||||
export function getDom(vNode: VNode): Element | Text | void {
|
||||
export function getDom(vNode: VNode): Element | Text | null {
|
||||
const {tag} = vNode;
|
||||
if (tag === DomComponent || tag === DomText) {
|
||||
return vNode.realNode;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 将 VNode 属性相关信息挂到 DOM 对象的特定属性上
|
||||
|
|
|
@ -5,7 +5,7 @@ import {
|
|||
import {
|
||||
createDom,
|
||||
} from './utils/DomCreator';
|
||||
import { getSelectionInfo, resetSelectionRange, selectionData } from './SelectionRangeHandler';
|
||||
import { getSelectionInfo, resetSelectionRange, SelectionData } from './SelectionRangeHandler';
|
||||
import { isElement, isComment, isDocument, isDocumentFragment, getDomTag, shouldAutoFocus } from './utils/Common';
|
||||
import { NSS } from './utils/DomCreator';
|
||||
import { adjustStyleValue } from './DOMPropertiesHandler/StyleHandler';
|
||||
|
@ -37,7 +37,7 @@ export type Props = {
|
|||
|
||||
export type Container = (Element & { _treeRoot?: VNode }) | (Document & { _treeRoot?: VNode });
|
||||
|
||||
let selectionInfo: null | selectionData = null;
|
||||
let selectionInfo: null | SelectionData = null;
|
||||
|
||||
function getChildNS(parentNS: string | null, tagName: string): string {
|
||||
if (parentNS === NSS.svg && tagName === 'foreignObject') {
|
||||
|
@ -54,12 +54,12 @@ function getChildNS(parentNS: string | null, tagName: string): string {
|
|||
}
|
||||
|
||||
// 获取容器
|
||||
export function getNSCtx(dom?: Container, parentNS: string, type: string): string {
|
||||
export function getNSCtx(parentNS: string, type: string, dom: Container | undefined): string {
|
||||
return dom ? getChildNS(dom.namespaceURI ?? null, dom.nodeName) : getChildNS(parentNS, type);
|
||||
}
|
||||
|
||||
export function prepareForSubmit(): void {
|
||||
selectionInfo = <selectionData>getSelectionInfo();
|
||||
selectionInfo = <SelectionData>getSelectionInfo();
|
||||
}
|
||||
|
||||
export function resetAfterSubmit(): void {
|
||||
|
|
|
@ -8,7 +8,7 @@ import {
|
|||
} from '../../event/EventBinding';
|
||||
import { isEventProp, isNativeElement } from '../validators/ValidateProps';
|
||||
|
||||
function updateOneProp(dom, propName, propVal, isNativeTag, isInit?: boolean) {
|
||||
function updateOneProp(dom, propName, isNativeTag, propVal?, isInit?: boolean) {
|
||||
if (propName === 'style') {
|
||||
setStyles(dom, propVal);
|
||||
} else if (propName === 'dangerouslySetInnerHTML') {
|
||||
|
@ -42,7 +42,7 @@ export function setDomProps(
|
|||
const propName = keysOfProps[i];
|
||||
const propVal = props[propName];
|
||||
|
||||
updateOneProp(dom, propName, propVal, isNativeTag, true);
|
||||
updateOneProp(dom, propName, isNativeTag, propVal, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ export function updateDomProps(
|
|||
for (let i = 0; i < changeList.length; i++) {
|
||||
const { propName, propVal } = changeList[i];
|
||||
|
||||
updateOneProp(dom, propName, propVal, isNativeTag);
|
||||
updateOneProp(dom, propName, isNativeTag, propVal);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,7 +111,7 @@ export function compareProps(
|
|||
for (let i = 0; i < keysOfNewProps.length; i++) {
|
||||
const propName = keysOfNewProps[i];
|
||||
const newPropValue = newProps[propName];
|
||||
const oldPropValue = oldProps != null ? oldProps[propName] : undefined;
|
||||
const oldPropValue = oldProps != null ? oldProps[propName] : null;
|
||||
|
||||
if (newPropValue === oldPropValue || (newPropValue == null && oldPropValue == null)) {
|
||||
// 新旧属性值未发生变化,或者新旧属性皆为空值,不需要进行处理
|
||||
|
|
|
@ -1,3 +1,20 @@
|
|||
/**
|
||||
* 对一些没有写单位的样式进行适配,例如:width: 10 => width: 10px
|
||||
* 对空值或布尔值进行适配,转为空字符串
|
||||
* 去掉多余空字符
|
||||
*/
|
||||
export function adjustStyleValue(name, value) {
|
||||
let validValue = value;
|
||||
|
||||
if (typeof value === 'number' && value !== 0 && isNeedUnitCSS(name)) {
|
||||
validValue = `${value}px`;
|
||||
} else if (value === '' || value == null || typeof value === 'boolean') {
|
||||
validValue = '';
|
||||
}
|
||||
|
||||
return validValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 DOM 节点的 style 属性
|
||||
*/
|
||||
|
@ -32,20 +49,3 @@ function isNeedUnitCSS(propName: string) {
|
|||
|| propName.startsWith('box')
|
||||
|| propName.endsWith('Opacity'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 对一些没有写单位的样式进行适配,例如:width: 10 => width: 10px
|
||||
* 对空值或布尔值进行适配,转为空字符串
|
||||
* 去掉多余空字符
|
||||
*/
|
||||
export function adjustStyleValue(name, value) {
|
||||
let validValue = value;
|
||||
|
||||
if (typeof value === 'number' && value !== 0 && isNeedUnitCSS(name)) {
|
||||
validValue = `${value}px`;
|
||||
} else if (value === '' || value == null || typeof value === 'boolean') {
|
||||
validValue = '';
|
||||
}
|
||||
|
||||
return validValue;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,13 @@ const svgHumpAttr = new Set(['allowReorder', 'autoReverse', 'baseFrequency', 'ba
|
|||
'stitchTiles', 'surfaceScale','systemLanguage', 'tableValues', 'targetX', 'targetY',
|
||||
'textLength','viewBox', 'viewTarget', 'xChannelSelector','yChannelSelector', 'zoomAndPan']);
|
||||
|
||||
// 驼峰 变 “-”
|
||||
function convertToLowerCase(str) {
|
||||
const replacer = (match, char) => `-${char.toLowerCase()}`;
|
||||
|
||||
return str.replace(/([A-Z])/g, replacer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 给 dom 设置属性
|
||||
* attrName 指代码中属性设置的属性名称(如 class)
|
||||
|
@ -70,12 +77,3 @@ export function updateCommonProp(dom: Element, attrName: string, value: any, isN
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 驼峰 变 “-”
|
||||
function convertToLowerCase(str) {
|
||||
const replacer = (match, char) => {
|
||||
return `-${char.toLowerCase()}`;
|
||||
}
|
||||
|
||||
return str.replace(/([A-Z])/g, replacer);
|
||||
};
|
||||
|
|
|
@ -105,16 +105,16 @@ export function getSelectionInfo() {
|
|||
};
|
||||
}
|
||||
|
||||
export interface selectionData {
|
||||
export interface SelectionData {
|
||||
focusedDom: HTMLInputElement | HTMLTextAreaElement | void;
|
||||
selectionRange: {
|
||||
start: number;
|
||||
end: number;
|
||||
start: number | null;
|
||||
end: number | null;
|
||||
};
|
||||
}
|
||||
|
||||
// 防止选择范围内的信息因为节点删除或其他原因导致的信息丢失
|
||||
export function resetSelectionRange(preSelectionRangeData: selectionData) {
|
||||
export function resetSelectionRange(preSelectionRangeData: SelectionData) {
|
||||
// 当前 focus 的元素
|
||||
const currentFocusedDom = getIFrameFocusedDom();
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ export enum PROPERTY_TYPE {
|
|||
STRING, // 普通的字符串类型
|
||||
SPECIAL, // 需要特殊处理的属性类型
|
||||
BOOLEAN_STR, // 字符串类型的 true false
|
||||
};
|
||||
}
|
||||
|
||||
export type PropDetails = {
|
||||
propName: string;
|
||||
|
@ -15,10 +15,6 @@ export type PropDetails = {
|
|||
attrNS: string | null;
|
||||
};
|
||||
|
||||
export function getPropDetails(name: string): PropDetails | null {
|
||||
return propsDetailData[name] || null;
|
||||
}
|
||||
|
||||
// 属性相关数据
|
||||
// 依次为 propertyName、type、attributeName、attributeNamespace,不填则使用默认值
|
||||
// type 默认 STRING
|
||||
|
@ -123,3 +119,7 @@ propertiesData.forEach(record => {
|
|||
attrNS,
|
||||
};
|
||||
});
|
||||
|
||||
export function getPropDetails(name: string): PropDetails | null {
|
||||
return propsDetailData[name] || null;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,11 @@ function isInvalidBoolean(
|
|||
return false;
|
||||
}
|
||||
|
||||
// 是事件属性
|
||||
export function isEventProp(propName) {
|
||||
return propName.substr(0, 2) === 'on';
|
||||
}
|
||||
|
||||
function isValidProp(tagName, name, value) {
|
||||
// 校验事件名称
|
||||
if (isEventProp(name)) {
|
||||
|
@ -79,11 +84,6 @@ export function isInvalidValue(
|
|||
return false;
|
||||
}
|
||||
|
||||
// 是事件属性
|
||||
export function isEventProp(propName) {
|
||||
return propName.substr(0, 2) === 'on';
|
||||
}
|
||||
|
||||
// dev模式下校验属性是否合法
|
||||
export function validateProps(type, props) {
|
||||
if (!props) {
|
||||
|
|
|
@ -1,14 +1,5 @@
|
|||
import {HorizonSelect, IProperty} from '../utils/Interface';
|
||||
|
||||
// 更新 <option>
|
||||
function updateValue(options, newValues: any, isMultiple: boolean) {
|
||||
if (isMultiple) {
|
||||
updateMultipleValue(options, newValues);
|
||||
} else {
|
||||
updateSingleValue(options, newValues);
|
||||
}
|
||||
}
|
||||
|
||||
function updateMultipleValue(options, newValues) {
|
||||
const newValueSet = new Set();
|
||||
|
||||
|
@ -39,6 +30,15 @@ function updateSingleValue(options, newValue) {
|
|||
}
|
||||
}
|
||||
|
||||
// 更新 <option>
|
||||
function updateValue(options, newValues: any, isMultiple: boolean) {
|
||||
if (isMultiple) {
|
||||
updateMultipleValue(options, newValues);
|
||||
} else {
|
||||
updateSingleValue(options, newValues);
|
||||
}
|
||||
}
|
||||
|
||||
export function getSelectPropsWithoutValue(dom: HorizonSelect, properties: Object) {
|
||||
return {
|
||||
...properties,
|
||||
|
|
|
@ -21,7 +21,6 @@ export type JSXElement = {
|
|||
key: any;
|
||||
ref: any;
|
||||
props: any;
|
||||
|
||||
belongClassVNode: any;
|
||||
};
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
let isMessageLoopRunning = false;
|
||||
let browserCallback = null;
|
||||
const { port1, port2 } = new MessageChannel();
|
||||
|
||||
|
||||
export function isOverTime() {
|
||||
|
@ -33,7 +34,7 @@ const callRenderTasks = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const { port1, port2 } = new MessageChannel();
|
||||
|
||||
port1.onmessage = callRenderTasks;
|
||||
|
||||
export function requestBrowserCallback(callback) {
|
||||
|
|
|
@ -12,30 +12,6 @@ let callingQueueTask: any | null = null;
|
|||
// 防止重入
|
||||
let isCallingRenderQueue = false;
|
||||
|
||||
export function pushRenderCallback(callback: RenderCallback) {
|
||||
if (renderQueue === null) {
|
||||
renderQueue = [callback];
|
||||
// 高优先级的异步调度
|
||||
callingQueueTask = runAsync(callRenderQueue, ImmediatePriority);
|
||||
} else {
|
||||
// 不需要调度,在syncQueue创建的时候已经调度了
|
||||
renderQueue.push(callback);
|
||||
}
|
||||
|
||||
// 返回一个空对象,用于区别null
|
||||
return {};
|
||||
}
|
||||
|
||||
export function callRenderQueueImmediate() {
|
||||
if (callingQueueTask !== null) {
|
||||
// 取消异步调度
|
||||
cancelTask(callingQueueTask);
|
||||
callingQueueTask = null;
|
||||
}
|
||||
|
||||
callRenderQueue();
|
||||
}
|
||||
|
||||
// 执行render回调
|
||||
function callRenderQueue() {
|
||||
if (!isCallingRenderQueue && renderQueue !== null) {
|
||||
|
@ -64,3 +40,27 @@ function callRenderQueue() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function pushRenderCallback(callback: RenderCallback) {
|
||||
if (renderQueue === null) {
|
||||
renderQueue = [callback];
|
||||
// 高优先级的异步调度
|
||||
callingQueueTask = runAsync(callRenderQueue, ImmediatePriority);
|
||||
} else {
|
||||
// 不需要调度,在syncQueue创建的时候已经调度了
|
||||
renderQueue.push(callback);
|
||||
}
|
||||
|
||||
// 返回一个空对象,用于区别null
|
||||
return {};
|
||||
}
|
||||
|
||||
export function callRenderQueueImmediate() {
|
||||
if (callingQueueTask !== null) {
|
||||
// 取消异步调度
|
||||
cancelTask(callingQueueTask);
|
||||
callingQueueTask = null;
|
||||
}
|
||||
|
||||
callRenderQueue();
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* 调度器的核心实现
|
||||
*/
|
||||
|
||||
import { Node } from '../taskExecutor/TaskQueue';
|
||||
import {
|
||||
requestBrowserCallback,
|
||||
isOverTime,
|
||||
|
@ -21,39 +22,11 @@ let isProcessing = false;
|
|||
// 调度中,等待浏览器回调
|
||||
let isWaiting = false;
|
||||
|
||||
function runAsync(callback, priorityLevel= NormalPriority ) {
|
||||
let increment;
|
||||
switch (priorityLevel) {
|
||||
case ImmediatePriority:
|
||||
increment = -1;
|
||||
break;
|
||||
case NormalPriority:
|
||||
default:
|
||||
increment = 10000;
|
||||
break;
|
||||
}
|
||||
|
||||
const task = {
|
||||
id: idCounter++,
|
||||
callback,
|
||||
order: idCounter + increment,
|
||||
};
|
||||
|
||||
add(task);
|
||||
|
||||
if (!isWaiting && !isProcessing) {
|
||||
isWaiting = true;
|
||||
requestBrowserCallback(callTasks);
|
||||
}
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
function callTasks() {
|
||||
isWaiting = false;
|
||||
isProcessing = true;
|
||||
|
||||
let task = null;
|
||||
let task: Node | null= null;
|
||||
try {
|
||||
task = first();
|
||||
|
||||
|
@ -89,6 +62,34 @@ function callTasks() {
|
|||
}
|
||||
}
|
||||
|
||||
function runAsync(callback, priorityLevel= NormalPriority ) {
|
||||
let increment;
|
||||
switch (priorityLevel) {
|
||||
case ImmediatePriority:
|
||||
increment = -1;
|
||||
break;
|
||||
case NormalPriority:
|
||||
default:
|
||||
increment = 10000;
|
||||
break;
|
||||
}
|
||||
|
||||
const task = {
|
||||
id: idCounter++,
|
||||
callback,
|
||||
order: idCounter + increment,
|
||||
};
|
||||
|
||||
add(task);
|
||||
|
||||
if (!isWaiting && !isProcessing) {
|
||||
isWaiting = true;
|
||||
requestBrowserCallback(callTasks);
|
||||
}
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
function cancelTask(task) {
|
||||
task.callback = null;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*/
|
||||
|
||||
type Queue = Array<Node>;
|
||||
type Node = {
|
||||
export type Node = {
|
||||
id: number;
|
||||
order: number;
|
||||
};
|
||||
|
@ -11,15 +11,10 @@ type Node = {
|
|||
// 任务队列
|
||||
const taskQueue: Queue = [];
|
||||
|
||||
export function add(node: Node): void {
|
||||
// 查找第一个大于等于 value 的下标,都比 value 小则返回 -1
|
||||
const idx = getBiggerIdx(node);
|
||||
|
||||
if (idx === -1) {
|
||||
taskQueue.push(node);
|
||||
} else {
|
||||
taskQueue.splice(idx, 0, node);
|
||||
}
|
||||
function compare(a: Node, b: Node) {
|
||||
// 优先先用index排序,其次用id
|
||||
const diff = a.order - b.order;
|
||||
return diff !== 0 ? diff : a.id - b.id;
|
||||
}
|
||||
|
||||
// 二分法查找第一个大于等于 value 的下标,都比 value 小则返回 -1,时间复杂度O(logn)
|
||||
|
@ -37,11 +32,22 @@ function getBiggerIdx(node: Node) {
|
|||
}
|
||||
}
|
||||
|
||||
return (left < taskQueue.length) ? left : -1;
|
||||
return left < taskQueue.length ? left : -1;
|
||||
}
|
||||
|
||||
export function add(node: Node): void {
|
||||
// 查找第一个大于等于 value 的下标,都比 value 小则返回 -1
|
||||
const idx = getBiggerIdx(node);
|
||||
|
||||
if (idx === -1) {
|
||||
taskQueue.push(node);
|
||||
} else {
|
||||
taskQueue.splice(idx, 0, node);
|
||||
}
|
||||
}
|
||||
|
||||
export function first(): Node | null {
|
||||
const val = taskQueue[0];
|
||||
const val: Node | null | undefined = taskQueue[0];
|
||||
return val !== undefined ? val : null;
|
||||
}
|
||||
|
||||
|
@ -53,9 +59,3 @@ export function shift(): Node | null {
|
|||
export function remove(node: Node) {
|
||||
taskQueue.splice(taskQueue.indexOf(node), 1);
|
||||
}
|
||||
|
||||
function compare(a: Node, b: Node) {
|
||||
// 优先先用index排序,其次用id
|
||||
const diff = a.order - b.order;
|
||||
return diff !== 0 ? diff : a.id - b.id;
|
||||
}
|
||||
|
|
|
@ -175,7 +175,7 @@ export function onlyUpdateChildVNodes(processing: VNode): VNode | null {
|
|||
// 此vNode无需更新,但是子树需要
|
||||
if (!processing.isCreated && processing.child !== null) {
|
||||
// 更新子节点
|
||||
let child = processing.child;
|
||||
let child: VNode | null = processing.child;
|
||||
while (child !== null) {
|
||||
updateVNode(child, child.props);
|
||||
updateVNodePath(child);
|
||||
|
|
|
@ -37,6 +37,19 @@ export function updateChildShouldUpdate(vNode: VNode) {
|
|||
vNode.childShouldUpdate = false;
|
||||
}
|
||||
|
||||
// 更新从当前节点到根节点的childShouldUpdate为true
|
||||
export function setParentsChildShouldUpdate(parent: VNode | null) {
|
||||
let node = parent;
|
||||
while (node !== null) {
|
||||
if (node.childShouldUpdate) {
|
||||
break;
|
||||
}
|
||||
node.childShouldUpdate = true;
|
||||
|
||||
node = node.parent;
|
||||
}
|
||||
}
|
||||
|
||||
// 设置节点的所有父节点的childShouldUpdate
|
||||
export function updateParentsChildShouldUpdate(vNode: VNode) {
|
||||
let node = vNode.parent;
|
||||
|
@ -51,16 +64,3 @@ export function updateParentsChildShouldUpdate(vNode: VNode) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新从当前节点到根节点的childShouldUpdate为true
|
||||
export function setParentsChildShouldUpdate(parent: VNode | null) {
|
||||
let node = parent;
|
||||
while (node !== null) {
|
||||
if (node.childShouldUpdate) {
|
||||
break;
|
||||
}
|
||||
node.childShouldUpdate = true;
|
||||
|
||||
node = node.parent;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue