From b4e7f5dfaeb52bc8f776ae5c83281a355b146bcf Mon Sep 17 00:00:00 2001 From: yutent Date: Thu, 30 Nov 2023 00:17:59 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=A8=A1=E6=9D=BF=E8=A7=A3?= =?UTF-8?q?=E6=9E=90;=E4=BF=AE=E5=A4=8D=E4=BA=8B=E4=BB=B6=E7=BB=91?= =?UTF-8?q?=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/constants.js | 1 - src/html.js | 136 ++++++++++++++++++++++++++--------------------- src/index.js | 5 +- 3 files changed, 78 insertions(+), 64 deletions(-) diff --git a/src/constants.js b/src/constants.js index afb01be..0ea5289 100644 --- a/src/constants.js +++ b/src/constants.js @@ -44,7 +44,6 @@ export const __props__ = Symbol('props') export const __changed_props__ = Symbol('changed_props') export const __mounted__ = Symbol('mounted') export const __pending__ = Symbol('pending') -export const __children__ = Symbol('children') export const RESET_CSS_STYLE = `* {box-sizing: border-box;margin: 0;padding: 0;}::before,::after {box-sizing: border-box;}::selection {background: var(--selection-background, var(--color-plain-a));color: var(--selection-color, inherit);}` diff --git a/src/html.js b/src/html.js index 6c53405..a33fe76 100644 --- a/src/html.js +++ b/src/html.js @@ -6,6 +6,7 @@ import { boolMap, WC_PART, NOTHING } from './constants.js' import { animate, MODES } from './anim.js' +import { nextTick } from './utils.js' const boundAttributeSuffix = '$wc$' const marker = `wc$${String(Math.random()).slice(9)}$` @@ -265,7 +266,7 @@ class TemplateInstance { } while ((node = walker.nextNode()) !== null) } - _clone(options) { + clone(options) { let { el: { content }, parts @@ -326,7 +327,7 @@ class TemplateInstance { return fragment } - _update(values) { + update(values) { let i = 0 for (let part of this.$parts) { if (part !== void 0) { @@ -343,9 +344,10 @@ class TemplateInstance { } class ChildPart { + #value = NOTHING + constructor(startNode, endNode, parent, options) { this.type = CHILD_PART - this._$committedValue = NOTHING this.startNode = startNode this.endNode = endNode this.$parent = parent @@ -364,46 +366,43 @@ class ChildPart { $setValue(value) { if (isPrimitive(value)) { if (value === NOTHING || value == null || value === '') { - if (this._$committedValue !== NOTHING) { + if (this.#value !== NOTHING) { this.#clear() } - this._$committedValue = NOTHING - } else if (value !== this._$committedValue) { - this._commitText(value) + this.#value = NOTHING + } else if (value !== this.#value) { + this.#commitText(value) } } else if (value['__dom_type__'] !== void 0) { - this._commitTemplateResult(value) + this.#commitTemplateResult(value) } else if (value.nodeType !== void 0) { - this._commitNode(value) + this.#commitNode(value) } else if (isIterable(value)) { - this._commitIterable(value) + this.#commitIterable(value) } else { - this._commitText(value) + this.#commitText(value) } } - _insert(node, target = this.endNode) { + #insert(node, target = this.endNode) { return this.startNode.parentNode.insertBefore(node, target) } - _commitNode(value) { - if (this._$committedValue !== value) { + #commitNode(value) { + if (this.#value !== value) { this.#clear() - this._$committedValue = this._insert(value) + this.#value = this.#insert(value) } } - _commitText(value) { - if ( - this._$committedValue !== NOTHING && - isPrimitive(this._$committedValue) - ) { + #commitText(value) { + if (this.#value !== NOTHING && isPrimitive(this.#value)) { let node = this.startNode.nextSibling node.data = value } else { - this._commitNode(document.createTextNode(value)) + this.#commitNode(document.createTextNode(value)) } - this._$committedValue = value + this.#value = value } - _commitTemplateResult(result) { + #commitTemplateResult(result) { let { values, ['__dom_type__']: type } = result let template = typeof type === 'number' @@ -411,16 +410,16 @@ class ChildPart { : (type.el === void 0 && (type.el = Template.createElement(type.h)), type) - if (this._$committedValue?.$template === template) { - this._$committedValue._update(values) + if (this.#value?.$template === template) { + this.#value.update(values) } else { let instance = new TemplateInstance(template, this) - let fragment = instance._clone(this.options) + let fragment = instance.clone(this.options) - instance._update(values) + instance.update(values) - this._commitNode(fragment) - this._$committedValue = instance + this.#commitNode(fragment) + this.#value = instance } } #getTemplate(result) { @@ -432,20 +431,21 @@ class ChildPart { } return template } - _commitIterable(value) { - if (!isArray(this._$committedValue)) { - this._$committedValue = [] + + #commitIterable(value) { + if (!isArray(this.#value)) { + this.#value = [] this.#clear() } - let itemParts = this._$committedValue + let itemParts = this.#value let partIndex = 0 let itemPart for (let item of value) { if (partIndex === itemParts.length) { itemParts.push( (itemPart = new ChildPart( - this._insert(createMarker()), - this._insert(createMarker()), + this.#insert(createMarker()), + this.#insert(createMarker()), this, this.options )) @@ -472,19 +472,19 @@ class ChildPart { } // 常规属性 class AttributePart { + #value = NOTHING + constructor(element, name, strings, decorates, parent, options = {}) { this.type = ATTRIBUTE_PART - this._$committedValue = NOTHING + this.element = element this.name = name this.decorates = decorates this.$parent = parent this.options = options if (strings.length > 2 || strings[0] !== '' || strings[1] !== '') { - this._$committedValue = Array(strings.length - 1).fill(null) + this.#value = Array(strings.length - 1).fill(null) this.strings = strings - } else { - this._$committedValue = NOTHING } } get tagName() { @@ -495,9 +495,9 @@ class AttributePart { let strings = this.strings let changed = false if (strings === void 0) { - changed = !isPrimitive(value) || value !== this._$committedValue + changed = !isPrimitive(value) || value !== this.#value if (changed) { - this._$committedValue = value + this.#value = value } } else { let values = value @@ -506,13 +506,13 @@ class AttributePart { for (let i = 0; i < strings.length - 1; i++) { let v = values[valueIndex + i] - changed || (changed = !isPrimitive(v) || v !== this._$committedValue[i]) + changed || (changed = !isPrimitive(v) || v !== this.#value[i]) if (v === NOTHING) { value = NOTHING } else if (value !== NOTHING) { value += (v !== null && v !== void 0 ? v : '') + strings[i + 1] } - this._$committedValue[i] = v + this.#value[i] = v } } if (changed) { @@ -587,9 +587,27 @@ class EventPart extends AttributePart { 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 options = {} + let events = host.$events[this.name] + + if (!events) { + events = host.$events[this.name] = [] + } if (this.decorates.length) { for (let it of this.decorates) { @@ -614,42 +632,40 @@ class EventPart extends AttributePart { let shouldRemove = listener !== this.#listener - if (this.#listener && host.$events[this.name]) { - for (let it of host.$events[this.name]) { + if (this.#listener) { + for (let i = -1, it; (it = events[++i]); ) { if (it.el === this.element) { 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) + events[i] = null } break } } } + events = events.filter(it => it !== null) + host.$events[this.name] = events + if (listener && shouldRemove) { this.element.addEventListener(this.name, this, options) this.#listener = listener - if (host.$events[this.name]) { - host.$events[this.name].push({ - el: this.element, - listener: this, - options - }) - } else { - host.$events[this.name] = [ - { - el: this.element, - listener: this, - options - } - ] - } + events.push({ + el: this.element, + listener: this, + options + }) } + + nextTick(_ => this.#clearBindings()) } + handleEvent(ev) { this.#stop(ev) this.#prevent(ev) diff --git a/src/index.js b/src/index.js index c1a92ce..ebf73d3 100644 --- a/src/index.js +++ b/src/index.js @@ -13,8 +13,7 @@ import { __props__, __changed_props__, __mounted__, - __pending__, - __children__ + __pending__ } from './constants.js' import { css, adoptStyles } from './css.js' import { render, html, svg, raw } from './html.js' @@ -406,7 +405,7 @@ export class Component extends HTMLElement { #render() { try { let ast = this.render() - this[__children__] = render(ast, this.root, { + render(ast, this.root, { host: this }) } catch (err) {