diff --git a/runtime/main/model/compiler.ts b/runtime/main/model/compiler.ts index fa260340..e445895f 100644 --- a/runtime/main/model/compiler.ts +++ b/runtime/main/model/compiler.ts @@ -41,7 +41,9 @@ import { bindSubVm, bindSubVmAfterInitialized, newWatch, - bindDir + bindDir, + updateTagCounter, + setAttributeStyle } from './directive'; import { createBlock, @@ -58,6 +60,7 @@ import Vm from './index'; import Element from '../../vdom/Element'; import Comment from '../../vdom/Comment'; import Node from '../../vdom/Node'; +import Document from '../../vdom/Document'; import { VmOptions } from './vmOptions'; export interface FragBlockInterface { @@ -125,6 +128,13 @@ export function build(vm: Vm) { const opt: any = vm._vmOptions || {}; const template: any = opt.template || {}; compile(vm, template, vm._parentEl); + // foreach vm + const doc: Document = vm._app.doc; + const body: Node = doc.body; + compileVm(vm, body); + compileCounter(vm, body); + compileElementAndElement(vm, body); + compileAttrStyle(vm, body); Log.debug(`"OnReady" lifecycle in Vm(${vm._type}).`); vm.$emit('hook:onReady'); if (vm._parent) { @@ -184,6 +194,149 @@ function compile(vm: Vm, target: TemplateInterface, dest: FragBlockInterface | E compileNativeComponent(vm, target, dest, type); } +function compileVm(vm: Vm, body: Node): void { + if (body.nodeType === Node.NodeType.Element) { + const node: Element = body as Element; + let count = 0; + node.children.forEach((child: Node) => { + const el = child as Element; + const tag = child.type; + if (count === 0) { + setTagStyle(vm, el, tag, true, false, false); + } else if (count === node.children.length - 1) { + setTagStyle(vm, el, tag, false, true, false); + } + count++; + compileVmChild(vm, child); + + }); + } +} + +function compileVmChild(vm: Vm, body: Node): void { + if (body.nodeType === Node.NodeType.Element) { + const node: Element = body as Element; + let count = 0; + node.children.forEach((child: Node) => { + const el = child as Element; + const tag = child.type; + if (count === 0) { + setTagStyle(vm, el, tag, true, false, false); + } else if (count === node.children.length - 1) { + setTagStyle(vm, el, tag, false, true, false); + } + count++; + compileVm(vm, child); + }); + } +} + +function compileCounter(vm: Vm, body: Node): void { + if (body.nodeType === Node.NodeType.Element) { + const node: Element = body as Element; + let count = {}; + + node.children.forEach((child: Node) => { + const el = child as Element; + const tag = child.type; + if (count[tag] === undefined) { + count[tag] = 1; + } else { + count[tag] = count[tag] + 1; + } + const css = vm._css || {}; + if (css) { + const data = css[tag] || {}; + if (data) { + const counterIncrement = data['counterIncrement']; + if (counterIncrement !== undefined) { + updateTagCounter(el, count[tag]); + } + } + } + compileCounterChild(vm, child); + }); + } +} + +function compileCounterChild(vm: Vm, body: Node): void { + if (body.nodeType === Node.NodeType.Element) { + const node: Element = body as Element; + let count = {}; + + node.children.forEach((child: Node) => { + const el = child as Element; + const tag = child.type; + if (count[tag] === undefined) { + count[tag] = 1; + } else { + count[tag] = count[tag] + 1; + } + const css = vm._css || {}; + if (css) { + const data = css[tag] || {}; + if (data) { + const counterIncrement = data['counterIncrement']; + if (counterIncrement !== undefined) { + updateTagCounter(el, count[tag]); + } + } + } + compileCounter(vm, child); + }); + } +} + +function compileAttrStyle(vm: Vm, body: Node): void { + if (body.nodeType === Node.NodeType.Element) { + const node: Element = body as Element; + node.children.forEach((child: Node) => { + const el = child as Element; + setAttributeStyle(vm, el); + compileAttrStyleChild(vm, child); + }); + } +} + +function compileAttrStyleChild(vm: Vm, body: Node): void { + if (body.nodeType === Node.NodeType.Element) { + const node: Element = body as Element; + node.children.forEach((child: Node) => { + const el = child as Element; + setAttributeStyle(vm, el); + compileAttrStyle(vm, child); + }); + } +} + +function compileElementAndElement(vm: Vm, body: Node): void { + if (body.nodeType === Node.NodeType.Element) { + const node: Element = body as Element; + node.children.forEach((child: Node) => { + if (child.nextSibling) { + const el = child.nextSibling as Element; + const tag = child.type + '+' + child.nextSibling.type; + setTagStyle(vm, el, tag, false, false, false); + } + compileElementAndElementChild(vm, child); + }); + } +} + +function compileElementAndElementChild(vm: Vm, body: Node): void { + if (body.nodeType === Node.NodeType.Element) { + const node: Element = body as Element; + node.children.forEach((child: Node) => { + if (child.nextSibling) { + const el = child.nextSibling as Element; + const tag = child.type + '+' + child.nextSibling.type; + setTagStyle(vm, el, tag, false, false, false); + } + compileElementAndElement(vm, child); + }); + } +} + /** * Compile a dynamic component. * @param {Vm} vm - Vm object needs to be compiled. @@ -494,7 +647,7 @@ function resetElementStyle(vm: Vm, element: Element): void { } setUniversalStyle(vm, element); if (element.type) { - setTagStyle(vm, element, element.type); + setTagStyle(vm, element, element.type, false, false, false); } if (element.id) { setIdStyle(vm, element, element.id); @@ -568,7 +721,6 @@ function compileNativeComponent(vm: Vm, template: TemplateInterface, dest: FragB if (!vm._rootEl) { vm._rootEl = element; - // Bind event earlier because of lifecycle issues. const binding: any = vm._externalBinding || {}; const target = binding.template; @@ -685,7 +837,6 @@ function bindRepeat(vm: Vm, target: TemplateInterface, fragBlock: FragBlockInter } trackMap[key] = item; }); - // Remove unused element foreach old item. const reusedList: any[] = []; const cacheList: any[] = []; @@ -705,7 +856,6 @@ function bindRepeat(vm: Vm, target: TemplateInterface, fragBlock: FragBlockInter }); } }); - // Create new element for each new item. children.length = 0; vms.length = 0; diff --git a/runtime/main/model/directive.ts b/runtime/main/model/directive.ts index 9167466c..2b03ee7a 100644 --- a/runtime/main/model/directive.ts +++ b/runtime/main/model/directive.ts @@ -57,9 +57,20 @@ const SETTERS = { event: 'addEvent', idStyle: 'setIdStyle', tagStyle: 'setTagStyle', - universalStyle: 'setUniversalStyle' + attrStyle: 'setAttrStyle', + tagAndTagStyle: 'setTagAndTagStyle', + tagAndIdStyle: 'setTagAndIdStyle', + universalStyle: 'setUniversalStyle', + firstOrLastChildStyle: 'setFirstOrLastChildStyle' }; +enum ContentType {Content_String, Content_Open_Quote, Content_Close_Quote, Content_Attr, Content_Counter}; +interface ContentObject { + value: string, + contentType: ContentType +} +let finallyItems: Array = []; + /** * Bind id, attr, classnames, style, events to an element. * @param {Vm} vm - Vm object. @@ -109,7 +120,8 @@ export function bindElement(vm: Vm, el: Element, template: TemplateInterface, pa setStyle(vm, el, template.style); setIdStyle(vm, el, template.id); setClass(vm, el, template.classList); - setTagStyle(vm, el, template.type); + setTagStyle(vm, el, template.type, false, false, true); + setTagAndIdStyle(vm, el, template.type, template.id); setUniversalStyle(vm, el); applyStyle(vm, el); @@ -464,6 +476,11 @@ function selectIdStyle(css: object, id: string, vm: Vm): any { return selectStyle(css, key, vm); } +function selectTagAndIdStyle(css: object, tag: string, id: string, vm: Vm): any { + const key = tag + '#' + id; + return selectStyle(css, key, vm); +} + /** * Replace style. * @param {*} oStyle - Current style. @@ -668,7 +685,7 @@ export function setIdStyle(vm: Vm, el: Element, id: Function | string): void { * @param {*} css - Css style. * @param {string} name - Bind by name. */ -function doSetStyle(vm: Vm, el: Element, style: any, css: any, name: string): void { +function doSetStyle(vm: Vm, el: Element, style: any, css: any, name: string, isFirst?: boolean, isLast?: boolean, isSetContent?: boolean): void { if (!style) { return; } @@ -676,7 +693,7 @@ function doSetStyle(vm: Vm, el: Element, style: any, css: any, name: string): vo Object.assign(typeStyle, style); setAnimation(typeStyle, css); setFontFace(typeStyle, css); - bindDir(vm, el, name, typeStyle); + bindDir(vm, el, name, typeStyle, isFirst, isLast, isSetContent); } /** @@ -714,10 +731,23 @@ function setAnimation(style: any, css: any): void { * @param {Element} el - ELement component. * @param {string} tag - Tag. */ -export function setTagStyle(vm: Vm, el: Element, tag: string): void { +export function setTagStyle(vm: Vm, el: Element, tag: string, isFirst?: boolean, isLast?: boolean, isSetContent?: boolean): void { const css = vm._css || {}; if (tag && typeof tag === 'string') { - doSetStyle(vm, el, selectStyle(css, tag, vm), css, 'tagStyle'); + let tagStyle = 'tagStyle'; + if (tag.indexOf('+') > 0) { + tagStyle = 'tagAndTagStyle'; + } + doSetStyle(vm, el, selectStyle(css, tag, vm), css, tagStyle, isFirst, isLast, isSetContent); + } +} + +export function setTagAndIdStyle(vm: Vm, el: Element, tag: string, id: Function | string): void { + const css = vm._css || {}; + if (typeof id === 'string') { + if (tag && typeof tag === 'string') { + doSetStyle(vm, el, selectTagAndIdStyle(css, tag, id, vm), css, 'tagAndIdStyle'); + } } } @@ -788,26 +818,71 @@ function bindEvents(vm: Vm, el: Element, events: object, eventType?: string): vo * @param {string} name - Method name. * @param {Object} data - Data that needed. */ -export function bindDir(vm: Vm, el: Element, name: string, data: object): void { +export function bindDir(vm: Vm, el: Element, name: string, data: object, isFirst?: boolean, isLast?: boolean, isSetContent?: boolean): void { if (!data) { return; } - const keys = Object.keys(data); + let keys = Object.keys(data); let i = keys.length; if (!i) { return; } - const methodName = SETTERS[name]; - const method = el[methodName]; + let methodName = SETTERS[name]; + let method = el[methodName]; const isSetStyle = methodName === 'setStyle'; if (methodName === 'setIdStyle') { for (const id in el.idStyle) { el.idStyle[id] = ''; } } + if (name === 'tagStyle' || name === 'tagAndIdStyle') { + let j: number = 0; + let k: number = 0; + let temp: string = null; + for (j = 0; j < i - 1; j++) { + for (k = 0; k < i - 1 - j; k++) { + if (keys[k] > keys[k + 1]) { + temp = keys[k + 1]; + keys[k + 1] = keys[k]; + keys[k] = temp; + } + } + } + } while (i--) { - const key = keys[i]; + let key = keys[i]; const value = data[key]; + if (name === 'tagStyle') { + if (key.endsWith(':first-child') || key.endsWith(':last-child')) { + methodName = SETTERS['firstOrLastChildStyle']; + } else { + methodName = SETTERS[name]; + } + if (key.endsWith(':first-child') && isFirst) { + key = key.replace(':first-child', ''); + } else if (key.endsWith(':last-child') && isLast) { + key = key.replace(':last-child', ''); + } + + if (isSetContent && (key === 'content::before' || key === 'content::after')) { + finallyItems = []; + splitItems(value); + let newValue = setContent(el, key); + methodName = SETTERS['attr']; + method = el[methodName]; + method.call(el, 'value', newValue); + continue; + } + } + + if (name === 'tagAndIdStyle') { + const newValue = updateTagAndIdStyle(el, key, value); + methodName = SETTERS['attr']; + method = el[methodName]; + method.call(el, 'value', newValue); + continue; + } + method = el[methodName]; if (key === 'ref') { vm.$refs[value] = el; } @@ -914,3 +989,290 @@ function applyStyle(vm: Vm, el: Element): void { function isArray(params: any): params is Array { return Array.isArray(params); } + +function splitItems(valueStr: string): void { + let i: number; + let item: string = ''; + let startQuote: boolean = false; + let itemList: string[] = []; + const len = valueStr.length; + for (i = 0; i < len; i++) { + if (!startQuote) { + if (valueStr[i] === '"') { + const itemLength = item.length; + if (itemLength > 0) { + const itemListLength = itemList.length; + itemList[itemListLength] = item; + } + item = '"'; + startQuote = true; + continue; + } else { + item = item + valueStr[i]; + if (i === len - 1) { + const itemListLength = itemList.length; + itemList[itemListLength] = item; + } + continue; + } + } else { + if (valueStr[i] === '"') { + item = item + valueStr[i]; + startQuote = false; + const itemListLength = itemList.length; + itemList[itemListLength] = item; + item = ''; + continue; + } else { + item = item + valueStr[i]; + continue; + } + } + } + doSplitItem(itemList); +} + +function doSplitItem(itemList: string[]): void { + let i: number; + let itemListLength = itemList.length; + for (i = 0; i < itemListLength; i++ ) { + let item = itemList[i].trim(); + if (item.indexOf('"') === 0) { + item = item.replace('"', ''); + item = item.replace('"', ''); + const contentObject: ContentObject = { + value: item, + contentType: ContentType.Content_String + }; + const finallyItemsLength = finallyItems.length; + finallyItems[finallyItemsLength] = contentObject; + } else { + splitItem(item.trim()); + if (finallyItems.length > 0) { + continue; + } else { + return; + } + } + } +} + +function splitItem(item: string): void{ + if (item.length === 0) { + return; + } + let finallyItemsLength = finallyItems.length; + if (item.indexOf('open-quote') === 0) { + const subItem = item.substr(0, 10); + const contentObject: ContentObject = { + value: subItem, + contentType: ContentType.Content_Open_Quote + }; + finallyItems[finallyItemsLength] = contentObject; + splitItem(item.substr(10).trim()); + } else if (item.indexOf('close-quote') === 0) { + const subItem = item.substr(0, 11); + const contentObject: ContentObject = { + value: subItem, + contentType: ContentType.Content_Close_Quote + }; + finallyItems[finallyItemsLength] = contentObject; + splitItem(item.substr(11).trim()); + } else if (item.indexOf('attr') === 0) { + const fromIndex = item.indexOf('('); + const toIndex = item.indexOf(')'); + const subLen = toIndex - fromIndex - 1; + const subItem = item.substr(fromIndex + 1, subLen).trim(); + const contentObject: ContentObject = { + value: subItem, + contentType: ContentType.Content_Attr + }; + finallyItems[finallyItemsLength] = contentObject; + splitItem(item.substr(toIndex + 1).trim()); + } else if (item.indexOf('counter') === 0) { + const toIndex = item.indexOf(')'); + const subItem = 'counter(0)'; + const contentObject: ContentObject = { + value: subItem, + contentType: ContentType.Content_Counter + }; + finallyItems[finallyItemsLength] = contentObject; + splitItem(item.substr(toIndex + 1).trim()); + } else { + finallyItems = []; + } +} + +function setContent(el: Element, key: string): string { + const itemLength = finallyItems.length; + let contentValue = ''; + let newValue = ''; + if (itemLength > 0) { + let i: number; + for (i = 0; i < itemLength; i++) { + const contentType = finallyItems[i].contentType; + switch (contentType) { + case ContentType.Content_String: + contentValue = contentValue + getContentString(finallyItems[i].value); + break; + case ContentType.Content_Open_Quote: + contentValue = contentValue + getContentOpenQuote(el, key); + break; + case ContentType.Content_Close_Quote: + contentValue = contentValue + getContentCloseQuote(el, key); + break; + case ContentType.Content_Attr: + contentValue = contentValue + getContentAttr(el, finallyItems[i].value); + break; + case ContentType.Content_Counter: + contentValue = contentValue + finallyItems[i].value; + break; + } + } + const oldValue = el.attr['value']; + if (key === 'content::before') { + newValue = contentValue + oldValue; + } else if (key === 'content::after') { + newValue = oldValue + contentValue; + } + } + return newValue; +} + +function getContentString(value: string): string { + let contentValue = value.replace('\"', ''); + contentValue = contentValue.replace('\"', ''); + return contentValue; +} + +function getContentOpenQuote(el: Element, key: string): string { + let contentValue = ''; + if (el.isOpen) { + contentValue = '\''; + } else { + contentValue = '\"'; + el.isOpen = true; + } + if (key === 'content::before') { + el.hasBefore = true; + } + return contentValue; +} + +function getContentCloseQuote(el: Element, key: string): string { + let contentValue = ''; + if (el.isOpen) { + contentValue = '\"'; + } else { + contentValue = ''; + } + if (el.isOpen && key === 'content::after') { + el.hasAfter = true; + } + return contentValue; +} + +function getContentAttr(el: Element, value: string): string { + let contentValue = el.attr[value]; + if (contentValue === undefined) { + contentValue = ''; + } + return contentValue; +} + +export function updateTagCounter(el: Element, counter: number): void { + let value = el.attr['value']; + if (value !== undefined) { + let fromIndex = value.indexOf('counter'); + if (fromIndex !== -1) { + value = value.replace('counter(0)', counter); + const methodName = SETTERS['attr']; + const method = el[methodName]; + method.call(el, 'value', value); + } + } +} + +function updateTagAndIdStyle(el: Element, key: string, value: string): string { + let newValue = ''; + let contentValue = ''; + let oldValue = el.attr['value']; + if (key === 'content::before') { + if (value === 'open-quote' || value === 'close-quote') { + if (value === 'open-quote' && key === 'content::before') { + contentValue = '\"'; + if (el.hasBefore) { + oldValue = oldValue.substr(1, oldValue.length); + } + newValue = contentValue + oldValue; + oldValue = newValue; + } else if (el.hasBefore && value === 'close-quote' && key === 'content::before') { + el.hasBefore = false; + oldValue = oldValue.substr(1, oldValue.length); + newValue = oldValue; + } + } + } else if (key === 'content::after') { + if (value === 'open-quote' && key === 'content::after') { + contentValue = '\"'; + if (el.hasBefore) { + contentValue = '\''; + } + if (el.hasAfter) { + oldValue = oldValue.substr(0, oldValue.length - 1); + } + newValue = oldValue + contentValue; + } else if (value === 'close-quote' && key === 'content::after' && el.hasBefore) { + contentValue = '\"'; + if (el.hasAfter) { + oldValue = oldValue.substr(0, oldValue.length - 1); + } + newValue = oldValue + contentValue; + } + } + if (value === 'no-open-quote' || value === 'no-close-quote') { + newValue = oldValue; + if (key === 'content::before' && value === 'no-open-quote') { + if (el.hasBefore) { + newValue = oldValue.substr(1); + } + } + if (key === 'content::after') { + if (el.hasAfter) { + newValue = oldValue.substr(0, oldValue.length - 1); + } + } + } + return newValue; +} + +export function setAttributeStyle(vm: Vm, el: Element): void { + const css = vm._css; + if (css) { + const keys = Object.keys(css); + if (keys !== undefined || keys !== null) { + const i = keys.length; + let j: number = 0; + for (j; j < i; j++) { + let cssKey = keys[j].trim(); + if (cssKey.indexOf('[') === 0) { + cssKey = cssKey.substr(1, cssKey.length - 2); + let equalIndex = cssKey.indexOf('='); + if (equalIndex !== -1) { + const attrId = cssKey.substr(0, equalIndex).trim(); + let attrValue = cssKey.substr(equalIndex + 1).trim(); + if (attrValue.indexOf('\"') !== -1) { + attrValue = attrValue.replace('"', '').trim(); + attrValue = attrValue.replace('"', '').trim(); + } + const elValue = el.attr[attrId]; + if (elValue !== undefined && elValue === attrValue) { + let newKey = keys[j]; + bindDir(vm, el, 'attrStyle', css[newKey]); + } + } + } + } + } + } +} \ No newline at end of file diff --git a/runtime/vdom/Element.ts b/runtime/vdom/Element.ts index 83a7bc07..6ca28f43 100644 --- a/runtime/vdom/Element.ts +++ b/runtime/vdom/Element.ts @@ -47,6 +47,9 @@ class Element extends Node { private _event: any; private _idStyle: any; private _tagStyle: any; + private _attrStyle: any; + private _tagAndTagStyle: any; + private _firstOrLastChildStyle: any; private _universalStyle: any; private _id: string | null; private _classList: any[]; @@ -55,6 +58,9 @@ class Element extends Node { private _isCustomComponent: boolean; private _inheritedStyle: object; private _target:TemplateInterface; + private _hasBefore: boolean; + private _hasAfter: boolean; + private _isOpen: boolean; protected _children: Node[]; protected _pureChildren: Element[]; @@ -104,6 +110,9 @@ class Element extends Node { this._event = {}; this._idStyle = {}; this._tagStyle = {}; + this._attrStyle = {}; + this._tagAndTagStyle = {}; + this._firstOrLastChildStyle = {}; this._universalStyle = {}; this._id = null; this._classList = []; @@ -171,6 +180,30 @@ class Element extends Node { this._vm = newVm; } + public get hasBefore() { + return this._hasBefore; + } + + public set hasBefore(hasBefore: boolean) { + this._hasBefore = hasBefore; + } + + public get hasAfter() { + return this._hasAfter; + } + + public set hasAfter(hasAfter: boolean) { + this._hasAfter = hasAfter; + } + + public get isOpen() { + return this._isOpen; + } + + public set isOpen(isOpen: boolean) { + this._isOpen = isOpen; + } + /** * Class style object of this Element, which keys is style name, and values is style values. * @type {JSON} @@ -777,7 +810,7 @@ class Element extends Node { return; } // If inline id class style has define return. - if (this.style[key] || this._idStyle[key] || this._classStyle[key]) { + if (this.style[key] || this._idStyle[key] || this._attrStyle[key] || this._classStyle[key] || this._firstOrLastChildStyle[key] || this._tagAndTagStyle[key]) { return; } this._tagStyle[key] = value; @@ -789,12 +822,63 @@ class Element extends Node { } } + public setAttrStyle(key: string, value: string | number, silent: boolean = false): void { + if (this._attrStyle[key] === value && silent !== false) { + return; + } + // If inline id style define return. + if (this.style[key] || this._idStyle[key]) { + return; + } + this._attrStyle[key] = value; + const taskCenter = this.getTaskCenter(this.docId); + if (!silent && taskCenter) { + const result = {}; + result[key] = value; + taskCenter.send('dom', { action: 'updateStyle' }, [this.ref, result]); + } + } + + public setTagAndTagStyle(key: string, value: string | number, silent: boolean = false): void { + if (this._tagAndTagStyle[key] === value && silent !== false) { + return; + } + // If inline id class style has define return. + if (this.style[key] || this._idStyle[key] || this._attrStyle[key] || this._classStyle[key] || this._firstOrLastChildStyle[key]) { + return; + } + this._tagAndTagStyle[key] = value; + const taskCenter = this.getTaskCenter(this.docId); + if (!silent && taskCenter) { + const result = {}; + result[key] = value; + taskCenter.send('dom', { action: 'updateStyle' }, [this.ref, result]); + } + } + + public setFirstOrLastChildStyle(key: string, value: string | number, silent: boolean = false): void { + if (this._firstOrLastChildStyle[key] === value && silent !== false) { + return; + } + // If inline id class style has define return. + if (this.style[key] || this._idStyle[key] || this._attrStyle[key]) { + return; + } + this._firstOrLastChildStyle[key] = value; + const taskCenter = this.getTaskCenter(this.docId); + if (!silent && taskCenter) { + const result = {}; + result[key] = value; + taskCenter.send('dom', { action: 'updateStyle' }, [this.ref, result]); + } + } + public setUniversalStyle(key: string, value: string | number, silent: boolean = false): void { if (this._universalStyle[key] === value && silent !== false) { return; } // If inline id class style has define return. - if (this.style[key] || this._idStyle[key] || this._classStyle[key] || this._tagStyle[key]) { + if (this.style[key] || this._idStyle[key] || this._classStyle[key] || this._tagStyle[key] || this._tagAndTagStyle[key]) { return; } this._universalStyle[key] = value; @@ -881,7 +965,10 @@ class Element extends Node { const style = Object.assign({}, this._inheritedStyle); this.assignStyle(style, this._universalStyle); this.assignStyle(style, this._tagStyle); + this.assignStyle(style, this._tagAndTagStyle); this.assignStyle(style, this._classStyle); + this.assignStyle(style, this._attrStyle); + this.assignStyle(style, this._firstOrLastChildStyle); this.assignStyle(style, this._idStyle); this.assignStyle(style, this.style); return style; @@ -983,6 +1070,9 @@ class Element extends Node { this._event = {}; this._idStyle = {}; this._tagStyle = {}; + this._attrStyle = {}; + this._tagAndTagStyle = {}; + this._firstOrLastChildStyle = {}; this._universalStyle = {}; this._classList.length = 0;