增加事件销毁机制

pull/1/head 1.6.0
yutent 2023-03-24 16:45:39 +08:00
parent f7e0ce08c3
commit 7568e701cf
4 changed files with 70 additions and 15 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "@bd/core", "name": "@bd/core",
"version": "1.5.14", "version": "1.6.0",
"type": "module", "type": "module",
"description": "百搭UI组件库的核心", "description": "百搭UI组件库的核心",
"main": "dist/index.js", "main": "dist/index.js",

View File

@ -302,15 +302,15 @@ class TemplateInstance {
parts parts
} = this._$template } = this._$template
let fragment = (options?.creationScope || document).importNode( let fragment = document.importNode(content, true)
content,
true
)
walker.currentNode = fragment
let node = walker.nextNode()
let nodeIndex = 0 let nodeIndex = 0
let partIndex = 0 let partIndex = 0
let templatePart = parts[0] let templatePart = parts[0]
let node = null
walker.currentNode = fragment
node = walker.nextNode()
// 没有动态绑定时, 查一遍是否有ref属性 // 没有动态绑定时, 查一遍是否有ref属性
if (templatePart === void 0) { if (templatePart === void 0) {
this.#checkRef(node, walker, options) this.#checkRef(node, walker, options)
@ -381,7 +381,7 @@ class ChildPart {
this._$endNode = endNode this._$endNode = endNode
this._$parent = parent this._$parent = parent
this.options = options this.options = options
this.__isConnected = options?.isConnected || true this.__isConnected = options.isConnected || true
} }
get _$isConnected() { get _$isConnected() {
return this._$parent?._$isConnected || this.__isConnected return this._$parent?._$isConnected || this.__isConnected
@ -421,8 +421,8 @@ class ChildPart {
this._commitText(value) this._commitText(value)
} }
} }
_insert(node, ref = this._$endNode) { _insert(node, target = this._$endNode) {
return this._$startNode.parentNode.insertBefore(node, ref) return this._$startNode.parentNode.insertBefore(node, target)
} }
_commitNode(value) { _commitNode(value) {
if (this._$committedValue !== value) { if (this._$committedValue !== value) {
@ -519,7 +519,7 @@ class ChildPart {
} }
// 常规属性 // 常规属性
class AttributePart { class AttributePart {
constructor(element, name, strings, parent, options) { constructor(element, name, strings, parent, options = {}) {
this.type = ATTRIBUTE_PART this.type = ATTRIBUTE_PART
this._$committedValue = NOTHING this._$committedValue = NOTHING
this._$disconnectableChildren = void 0 this._$disconnectableChildren = void 0
@ -629,6 +629,7 @@ class EventPart extends AttributePart {
if (newListener === NO_CHANGE) { if (newListener === NO_CHANGE) {
return return
} }
let host = this.options.host
let oldListener = this._$committedValue let oldListener = this._$committedValue
let shouldRemoveListener = let shouldRemoveListener =
(newListener === NOTHING && oldListener !== NOTHING) || (newListener === NOTHING && oldListener !== NOTHING) ||
@ -646,10 +647,25 @@ class EventPart extends AttributePart {
this.element.addEventListener(this.name, this, newListener) this.element.addEventListener(this.name, this, newListener)
} }
this._$committedValue = newListener this._$committedValue = newListener
if (host) {
if (host.$events[this.name]) {
host.$events[this.name].push({
el: this.element,
listener: this
})
} else {
host.$events[this.name] = [
{
el: this.element,
listener: this
}
]
}
}
} }
handleEvent(event) { handleEvent(event) {
if (typeof this._$committedValue === 'function') { if (typeof this._$committedValue === 'function') {
this._$committedValue.call(this.options?.host || this.element, event) this._$committedValue.call(this.options.host || this.element, event)
} else { } else {
this._$committedValue.handleEvent(event) this._$committedValue.handleEvent(event)
} }

View File

@ -97,12 +97,18 @@ export class Component extends HTMLElement {
this[__mounted__] = false this[__mounted__] = false
// 这里提前定义一次, 是为了在connectedCallback之前, 就已有赋值时报错的bug // 这里提前定义一次, 是为了在connectedCallback之前, 就已有赋值时报错的bug
this[__changed_props__] = new Map() // 记录一次渲染周期内变化的属性 this[__changed_props__] = new Map() // 记录一次渲染周期内变化的属性
this.host = this
this.root = this.shadowRoot || this.attachShadow({ mode: 'open' }) this.root = this.shadowRoot || this.attachShadow({ mode: 'open' })
this.root.ownHost = this
Object.defineProperty(this, '$refs', { Object.defineProperty(this, '$refs', {
value: Object.create(null), value: Object.create(null),
enumerable: false enumerable: false
}) })
Object.defineProperty(this, '$events', {
value: Object.create(null),
enumerable: false
})
this.created() this.created()
} }
@ -135,6 +141,17 @@ export class Component extends HTMLElement {
disconnectedCallback() { disconnectedCallback() {
this[__children__]?.setConnected(false) this[__children__]?.setConnected(false)
if (!document.body.contains(this)) {
let $events = this.$events
if ($events) {
for (let name in $events) {
for (let it of $events[name]) {
unbind(it.el, name, it.listener, it.options)
}
}
}
}
this.unmounted() this.unmounted()
} }
// 监听属性变化 // 监听属性变化

View File

@ -70,6 +70,8 @@ export function offset(node) {
export function bind(dom, type, selector, fn, phase = true) { export function bind(dom, type, selector, fn, phase = true) {
let events = type.split(',') let events = type.split(',')
let callback let callback
let isWc = dom.host === dom
let host = isWc ? dom : null
if (typeof selector === 'function') { if (typeof selector === 'function') {
phase = fn phase = fn
@ -82,13 +84,25 @@ export function bind(dom, type, selector, fn, phase = true) {
fn = fn || noop fn = fn || noop
} }
if (isWc === false && dom !== document && dom !== document.body) {
let node = dom.parentNode
while (node) {
if (node.ownHost) {
isWc = true
host = node.ownHost
break
}
node = node.parentNode
}
}
if (selector) { if (selector) {
callback = function (ev) { callback = function (ev) {
let agents = $(selector, ev.currentTarget) let agents = $(selector, dom)
let elem = ev.target let elem = ev.target
if (agents) { if (agents) {
while (true) { while (true) {
if (elem === ev.currentTarget) { if (elem === dom) {
break break
} }
if (agents.contains(elem)) { if (agents.contains(elem)) {
@ -105,7 +119,15 @@ export function bind(dom, type, selector, fn, phase = true) {
} }
events.forEach(function (t) { events.forEach(function (t) {
dom.addEventListener(t.trim(), callback, phase) t = t.trim()
if (isWc) {
if (host.$events[t]) {
host.$events[t].push({ el: dom, listener: callback, options: phase })
} else {
host.$events[t] = [{ el: dom, listener: callback, options: phase }]
}
}
dom.addEventListener(t, callback, phase)
}) })
return callback return callback
} }