diff --git a/package.json b/package.json index b05fcd6..6962b20 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wkit", - "version": "1.11.1", + "version": "1.11.2", "type": "module", "description": "A library for building fast, lightweight web components.", "main": "dist/index.js", diff --git a/src/html.js b/src/html.js index a33fe76..b8c3eb9 100644 --- a/src/html.js +++ b/src/html.js @@ -143,16 +143,20 @@ function getTemplateHtml(strings, type) { } class Template { + parts = [] + constructor({ strings, ['__dom_type__']: type }, options) { - this.parts = [] let node let nodeIndex = 0 let attrNameIndex = 0 let partCount = strings.length - 1 let parts = this.parts let [html2, attrNames] = getTemplateHtml(strings, type) + this.el = Template.createElement(html2) + walker.currentNode = this.el.content + if (type === SVG_RESULT) { let content = this.el.content let svgElement = content.firstChild @@ -327,6 +331,7 @@ class TemplateInstance { return fragment } + update(values) { let i = 0 for (let part of this.$parts) { @@ -344,10 +349,10 @@ class TemplateInstance { } class ChildPart { + type = CHILD_PART #value = NOTHING constructor(startNode, endNode, parent, options) { - this.type = CHILD_PART this.startNode = startNode this.endNode = endNode this.$parent = parent @@ -363,7 +368,7 @@ class ChildPart { return parentNode } - $setValue(value) { + $setValue(value, clear) { if (isPrimitive(value)) { if (value === NOTHING || value == null || value === '') { if (this.#value !== NOTHING) { @@ -382,16 +387,22 @@ class ChildPart { } else { this.#commitText(value) } + if (clear) { + nextTick(_ => this.#clearBindings()) + } } + #insert(node, target = this.endNode) { return this.startNode.parentNode.insertBefore(node, target) } + #commitNode(value) { if (this.#value !== value) { this.#clear() this.#value = this.#insert(value) } } + #commitText(value) { if (this.#value !== NOTHING && isPrimitive(this.#value)) { let node = this.startNode.nextSibling @@ -402,6 +413,7 @@ class ChildPart { } this.#value = value } + #commitTemplateResult(result) { let { values, ['__dom_type__']: type } = result let template = @@ -422,12 +434,14 @@ class ChildPart { this.#value = instance } } + #getTemplate(result) { - let template = TEMPLATE_CACHE.get(result.strings.join()) + let key = result.strings.join() + let template = TEMPLATE_CACHE.get(key) if (template === void 0) { template = new Template(result, this.options) - TEMPLATE_CACHE.set(result.strings.join(), template) + TEMPLATE_CACHE.set(key, template) } return template } @@ -469,14 +483,32 @@ class ChildPart { start = node } } + + /** + * 清除已被移除的节点事件 + */ + #clearBindings() { + let host = this.options.host + let events = host.$events + + for (let ev in events) { + for (let i = -1, it; (it = events[ev][++i]); ) { + if (!host.root.contains(it.el)) { + it.el.removeEventListener(this.name, it.listener, it.options) + events[ev][i] = null + } + } + events[ev] = events[ev].filter(e => e !== null) + } + } } // 常规属性 class AttributePart { + type = ATTRIBUTE_PART + #value = NOTHING constructor(element, name, strings, decorates, parent, options = {}) { - this.type = ATTRIBUTE_PART - this.element = element this.name = name this.decorates = decorates @@ -494,6 +526,7 @@ class AttributePart { $setValue(value, valueIndex) { let strings = this.strings let changed = false + if (strings === void 0) { changed = !isPrimitive(value) || value !== this.#value if (changed) { @@ -521,26 +554,28 @@ class AttributePart { } commitValue(value) { - let isBoolAttr = boolMap[this.name] + let elem = this.element + let attr = this.name + let isBoolAttr = boolMap[attr] // ref属性不渲染到节点上 - if (this.name === 'ref') { - this.options.host.$refs[value] = this.element + if (attr === 'ref') { + this.options.host.$refs[value] = elem return } if (isBoolAttr) { - this.element[isBoolAttr] = !(value === false || value === null) + elem[isBoolAttr] = !(value === false || value === null) - if (this.element[isBoolAttr]) { - this.element.setAttribute(this.name, '') + if (elem[isBoolAttr]) { + elem.setAttribute(attr, '') } else { - this.element.removeAttribute(this.name) + elem.removeAttribute(attr) } } else { if (value === null || value === void 0) { - this.element.removeAttribute(this.name) + elem.removeAttribute(attr) } else { - this.element.setAttribute(this.name, value) + elem.setAttribute(attr, value) } } } @@ -562,20 +597,23 @@ class AnimPart extends AttributePart { } commitValue({ type = 'fade', duration, custom, immediate = false } = {}) { + let elem = this.element let fromto = MODES[type] || MODES.fade if (custom) { fromto = custom } - this.element.$animate = function (out = false) { + elem.$animate = function (out = false) { return animate.call(this, duration, fromto, out) } - this.element.$animate.immediate = immediate + elem.$animate.immediate = immediate } } // 事件属性 class EventPart extends AttributePart { + type = EVENT_PART + #listener = null #prevent = noop @@ -584,30 +622,14 @@ class EventPart extends AttributePart { constructor(...args) { super(...args) - this.type = EVENT_PART - } - - #clearBindings() { - let host = this.options.host - let events = host.$events[this.name] - - for (let i = -1, it; (it = events[++i]); ) { - if (!host.root.contains(it.el)) { - this.element.removeEventListener(this.name, it.listener, it.options) - events[i] = null - } - } - host.$events[this.name] = events.filter(it => it !== null) } $setValue(listener) { let host = this.options.host + let elem = this.element + let name = this.name let options = {} - let events = host.$events[this.name] - - if (!events) { - events = host.$events[this.name] = [] - } + let events = host.$events[name] || [] if (this.decorates.length) { for (let it of this.decorates) { @@ -619,7 +641,7 @@ class EventPart extends AttributePart { this.#prevent = ev => ev.preventDefault() break case 'self': - this.#checkSelf = ev => ev.target === this.element + this.#checkSelf = ev => ev.target === elem break case 'capture': case 'once': @@ -634,14 +656,14 @@ class EventPart extends AttributePart { if (this.#listener) { for (let i = -1, it; (it = events[++i]); ) { - if (it.el === this.element) { + if (it.el === elem) { shouldRemove = shouldRemove || options.capture !== it.capture || options.once !== it.once || options.passive !== it.passive if (shouldRemove) { - this.element.removeEventListener(this.name, it.listener, it.options) + it.el.removeEventListener(name, it.listener, it.options) events[i] = null } break @@ -650,20 +672,14 @@ class EventPart extends AttributePart { } events = events.filter(it => it !== null) - host.$events[this.name] = events + host.$events[name] = events if (listener && shouldRemove) { - this.element.addEventListener(this.name, this, options) + elem.addEventListener(name, this, options) this.#listener = listener - events.push({ - el: this.element, - listener: this, - options - }) + events.push({ el: elem, listener: this, options }) } - - nextTick(_ => this.#clearBindings()) } handleEvent(ev) { @@ -677,14 +693,14 @@ class EventPart extends AttributePart { } class ElementPart { + type = ELEMENT_PART constructor(element, parent, options) { this.element = element - this.type = ELEMENT_PART this.$parent = parent this.options = options } - $setValue(value) {} + $setValue() {} } export function render(value, container, options = {}) { @@ -699,7 +715,7 @@ export function render(value, container, options = {}) { ) container[WC_PART] = part } - part.$setValue(value) + part.$setValue(value, true) return part } diff --git a/src/index.js b/src/index.js index ebf73d3..39e1947 100644 --- a/src/index.js +++ b/src/index.js @@ -223,9 +223,6 @@ export class Component extends HTMLElement { return value }, set: (target, prop, value, receiver) => { - if (prop === 'length' && options.type === Array) { - return true - } let oldValue = target[prop] Reflect.set(target, prop, value, receiver)