重构事件系统; 事件增加修饰符支持

pull/1/head 1.9.0
yutent 2023-04-17 16:13:59 +08:00
parent 5326af856c
commit c9b21cd790
3 changed files with 84 additions and 101 deletions

View File

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

View File

@ -36,7 +36,6 @@ const boolMap = Object.create(null)
export { boolMap }
export const WC_PART = Symbol('wc_path')
export const NO_CHANGE = Symbol('wc-noChange')
export const NOTHING = Symbol('wc-nothing')
export const __finalized__ = Symbol('finalized')
export const __props__ = Symbol('props')

View File

@ -1,4 +1,4 @@
import { boolMap, WC_PART, NO_CHANGE, NOTHING } from './constants.js'
import { boolMap, WC_PART, NOTHING } from './constants.js'
import { animate, MODES } from './anim.js'
const boundAttributeSuffix = '$wc$'
@ -45,6 +45,8 @@ const COMMENT_PART = 7
const templateCache = new WeakMap()
const walker = document.createTreeWalker(document, 129, null, false)
function noop() {}
function getTemplateHtml(strings, type) {
let len = strings.length - 1
let attrNames = []
@ -170,12 +172,19 @@ class Template {
)
let statics = value.split(marker)
let m = /([#:@])?(.*)/.exec(realName)
let decorates = []
if (m[1] === '@' && m[2].includes('.')) {
decorates = m[2].split('.')
m[2] = decorates.shift()
}
parts.push({
type: ATTRIBUTE_PART,
index: nodeIndex,
name: m[2],
strings: statics,
decorates,
ctor:
m[1] === ':'
? PropertyPart
@ -231,50 +240,6 @@ class Template {
return el
}
}
function resolveDirective(part, value, parent = part, attributeIndex) {
if (value === NO_CHANGE) {
return value
}
let currentDirective =
attributeIndex !== void 0
? parent.__directives?.[attributeIndex]
: parent.__directive
let nextDirectiveConstructor = isPrimitive(value)
? void 0
: value['_$litDirective$']
if (currentDirective?.constructor !== nextDirectiveConstructor) {
currentDirective._$notifyDirectiveConnectionChanged?.call(
currentDirective,
false
)
if (nextDirectiveConstructor === void 0) {
currentDirective = void 0
} else {
currentDirective = new nextDirectiveConstructor(part)
currentDirective._$initialize(part, parent, attributeIndex)
}
if (attributeIndex !== void 0) {
if (!parent.__directives) {
parent.__directives = []
}
parent.__directives[attributeIndex] = currentDirective
} else {
parent.__directive = currentDirective
}
}
if (currentDirective !== void 0) {
value = resolveDirective(
part,
currentDirective._$resolve(part, value.values),
currentDirective,
attributeIndex
)
}
return value
}
class TemplateInstance {
constructor(template, parent) {
@ -334,6 +299,7 @@ class TemplateInstance {
node,
templatePart.name,
templatePart.strings,
templatePart.decorates,
this,
options
)
@ -364,7 +330,7 @@ class TemplateInstance {
for (let part of this._parts) {
if (part !== void 0) {
if (part.strings !== void 0) {
part._$setValue(values, part, i)
part._$setValue(values, i)
i += part.strings.length - 2
} else {
part._$setValue(values[i])
@ -403,15 +369,14 @@ class ChildPart {
get endNode() {
return this._$endNode
}
_$setValue(value, directiveParent = this) {
value = resolveDirective(this, value, directiveParent)
_$setValue(value) {
if (isPrimitive(value)) {
if (value === NOTHING || value == null || value === '') {
if (this._$committedValue !== NOTHING) {
this.#clear()
}
this._$committedValue = NOTHING
} else if (value !== this._$committedValue && value !== NO_CHANGE) {
} else if (value !== this._$committedValue) {
this._commitText(value)
}
} else if (value['__dom_type__'] !== void 0) {
@ -522,12 +487,13 @@ class ChildPart {
}
// 常规属性
class AttributePart {
constructor(element, name, strings, parent, options = {}) {
constructor(element, name, strings, decorates, parent, options = {}) {
this.type = ATTRIBUTE_PART
this._$committedValue = NOTHING
this._$disconnectableChildren = void 0
this.element = element
this.name = name
this.decorates = decorates
this._$parent = parent
this.options = options
if (strings.length > 2 || strings[0] !== '' || strings[1] !== '') {
@ -544,15 +510,12 @@ class AttributePart {
return this._$parent._$isConnected
}
_$setValue(value, directiveParent = this, valueIndex, noCommit) {
_$setValue(value, valueIndex) {
let strings = this.strings
let change = false
let changed = false
if (strings === void 0) {
value = resolveDirective(this, value, directiveParent, 0)
change =
!isPrimitive(value) ||
(value !== this._$committedValue && value !== NO_CHANGE)
if (change) {
changed = !isPrimitive(value) || value !== this._$committedValue
if (changed) {
this._$committedValue = value
}
} else {
@ -560,16 +523,9 @@ class AttributePart {
value = strings[0]
for (let i = 0; i < strings.length - 1; i++) {
let v = resolveDirective(
this,
values[valueIndex + i],
directiveParent,
i
)
if (v === NO_CHANGE) {
v = this._$committedValue[i]
}
change || (change = !isPrimitive(v) || v !== this._$committedValue[i])
let v = values[valueIndex + i]
changed || (changed = !isPrimitive(v) || v !== this._$committedValue[i])
if (v === NOTHING) {
value = NOTHING
} else if (value !== NOTHING) {
@ -578,7 +534,7 @@ class AttributePart {
this._$committedValue[i] = v
}
}
if (change && !noCommit) {
if (changed) {
this.commitValue(value)
}
}
@ -638,57 +594,87 @@ class AnimPart extends AttributePart {
// 事件属性
class EventPart extends AttributePart {
#listener = null
#prevent = noop
#stop = noop
#checkSelf = noop
constructor(...args) {
super(...args)
this.type = EVENT_PART
}
_$setValue(newListener, directiveParent = this) {
newListener =
resolveDirective(this, newListener, directiveParent, 0) || NOTHING
if (newListener === NO_CHANGE) {
return
}
_$setValue(listener) {
let host = this.options.host
let oldListener = this._$committedValue
let shouldRemoveListener =
(newListener === NOTHING && oldListener !== NOTHING) ||
newListener.capture !== oldListener.capture ||
newListener.once !== oldListener.once ||
newListener.passive !== oldListener.passive
let shouldAddListener =
newListener !== NOTHING &&
(oldListener === NOTHING || shouldRemoveListener)
let options = {}
if (shouldRemoveListener) {
this.element.removeEventListener(this.name, this, oldListener)
if (this.decorates.length) {
for (let it of this.decorates) {
switch (it) {
case 'stop':
this.#stop = ev => ev.stopPropagation()
break
case 'prevent':
this.#prevent = ev => ev.preventDefault()
break
case 'self':
this.#checkSelf = ev => ev.target === this.element
break
case 'capture':
case 'once':
case 'passive':
options[it] = true
break
}
}
}
if (shouldAddListener) {
this.element.addEventListener(this.name, this, newListener)
let shouldRemove = listener !== this.#listener
if (this.#listener && host.$events[this.name]) {
for (let it of host.$events[this.name]) {
if (it.el === this.element) {
shouldRemove =
options.capture !== it.capture ||
options.once !== it.once ||
options.passive !== it.passive
if (shouldRemove) {
this.element.removeEventListener(this.name, it.listener, it.options)
}
break
}
}
}
this._$committedValue = newListener
if (host) {
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
listener: this,
options
})
} else {
host.$events[this.name] = [
{
el: this.element,
listener: this
listener: this,
options
}
]
}
}
}
handleEvent(event) {
if (typeof this._$committedValue === 'function') {
this._$committedValue.call(this.options.host || this.element, event)
} else {
this._$committedValue.handleEvent(event)
handleEvent(ev) {
this.#stop(ev)
this.#prevent(ev)
if (this.#checkSelf(ev) === false) {
return
}
this.#listener.call(this.options.host, ev)
}
}
@ -703,9 +689,7 @@ class ElementPart {
get _$isConnected() {
return this._$parent._$isConnected
}
_$setValue(value) {
resolveDirective(this, value)
}
_$setValue(value) {}
}
export function render(value, container, options = {}) {