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