Compare commits
No commits in common. "master" and "1.11.2" have entirely different histories.
|
@ -1,9 +1,12 @@
|
||||||
*.min.js
|
*.min.js
|
||||||
.httpserver
|
.httpserver
|
||||||
|
index.html
|
||||||
|
test.js
|
||||||
.vscode
|
.vscode
|
||||||
node_modules/
|
node_modules/
|
||||||
dist/
|
dist/
|
||||||
|
*.sublime-project
|
||||||
|
*.sublime-workspace
|
||||||
package-lock.json
|
package-lock.json
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
test/
|
|
|
@ -1,5 +1,5 @@
|
||||||
## Wkit
|
## Wkit
|
||||||
> 一个简单易用、功能完善的用于开发`web components`的轻量级开发库。模板解析基于`lit-html`二次开发
|
> A library for building fast, lightweight web components.
|
||||||
|
|
||||||
![downloads](https://img.shields.io/npm/dt/wkit.svg)
|
![downloads](https://img.shields.io/npm/dt/wkit.svg)
|
||||||
![version](https://img.shields.io/npm/v/wkit.svg)
|
![version](https://img.shields.io/npm/v/wkit.svg)
|
||||||
|
@ -15,7 +15,6 @@
|
||||||
- `:xxx=yyy`, 属性绑定, 类似`vue`,在属性前加上`:`, 该属性不再使用`setAttribute()`, 而是直接赋值, 可满足你需要传递复杂数据结构的需求。
|
- `:xxx=yyy`, 属性绑定, 类似`vue`,在属性前加上`:`, 该属性不再使用`setAttribute()`, 而是直接赋值, 可满足你需要传递复杂数据结构的需求。
|
||||||
- `#animation={type}`, 开箱即用的动画配置, 内置6种动画`fade(默认), scale, bounce, micro-bounce, rotate, slide`
|
- `#animation={type}`, 开箱即用的动画配置, 内置6种动画`fade(默认), scale, bounce, micro-bounce, rotate, slide`
|
||||||
- `ref=xxx`, 类似`vue`的节点标识, 可方便的在`mounted()`之后通过 `this.$refs.xxx` 来访问该节点
|
- `ref=xxx`, 类似`vue`的节点标识, 可方便的在`mounted()`之后通过 `this.$refs.xxx` 来访问该节点
|
||||||
- 内置特色的双向绑定方法`live()`
|
|
||||||
- 用内置的`bind()`方法来给当前组件绑定事件时, 组件移除时事件也会自动销毁,无需手动销毁。
|
- 用内置的`bind()`方法来给当前组件绑定事件时, 组件移除时事件也会自动销毁,无需手动销毁。
|
||||||
- 灵活的`props`定义
|
- 灵活的`props`定义
|
||||||
|
|
||||||
|
@ -85,7 +84,3 @@ Hello.reg('hello')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 开源协议
|
|
||||||
|
|
||||||
- BSD 3-Clause License (Lit框架的html模板解析的源码)
|
|
||||||
- MIT (除Lit代码之外的所有代码)
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "wkit",
|
"name": "wkit",
|
||||||
"version": "1.12.0",
|
"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",
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://git.wkit.fun/bytedo/wkit.git"
|
"url": "git+https://git.wkit.fun/bytedo/wkit.git"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"wkit",
|
"wkit",
|
||||||
|
|
|
@ -83,14 +83,16 @@ function getType(v) {
|
||||||
let type = String
|
let type = String
|
||||||
let attribute = true
|
let attribute = true
|
||||||
if (v.includes('!')) {
|
if (v.includes('!')) {
|
||||||
if (v.startsWith('str!')) {
|
v = v.split('!')
|
||||||
v = v.slice(4)
|
let _t = v.shift()
|
||||||
} else if (v.startsWith('num!')) {
|
if (_t === 'str') {
|
||||||
|
v = v.join('!')
|
||||||
|
} else if (_t === 'num') {
|
||||||
type = Number
|
type = Number
|
||||||
v = +v.slice(4) || 0
|
v = +v.shift() || 0
|
||||||
} else if (v.startsWith('bool!')) {
|
} else if (_t === 'bool') {
|
||||||
type = Boolean
|
type = Boolean
|
||||||
v = v.slice(5)
|
v = v.shift()
|
||||||
v = v !== 'false' && v !== ''
|
v = v !== 'false' && v !== ''
|
||||||
}
|
}
|
||||||
attribute = false
|
attribute = false
|
||||||
|
|
148
src/html.js
148
src/html.js
|
@ -6,30 +6,31 @@
|
||||||
|
|
||||||
import { boolMap, WC_PART, NOTHING } from './constants.js'
|
import { boolMap, WC_PART, NOTHING } from './constants.js'
|
||||||
import { animate, MODES } from './anim.js'
|
import { animate, MODES } from './anim.js'
|
||||||
import { nextTick, noop } from './utils.js'
|
import { nextTick } from './utils.js'
|
||||||
|
|
||||||
const BIND_ATTR_SUFFIX = '{{$wkit$}}'
|
const boundAttributeSuffix = '$wc$'
|
||||||
const MARKER = `{{^wkit${String(Math.random()).slice(-8)}^}}`
|
const marker = `wc$${String(Math.random()).slice(9)}$`
|
||||||
const MARKER_MATCH = '?' + MARKER
|
const markerMatch = '?' + marker
|
||||||
const NODE_MARKER = `<${MARKER_MATCH}>`
|
const nodeMarker = `<${markerMatch}>`
|
||||||
|
const createMarker = (v = '') => document.createComment(v)
|
||||||
// 是否原始值
|
|
||||||
const isPrimitive = value =>
|
const isPrimitive = value =>
|
||||||
value === null || (typeof value !== 'object' && typeof value !== 'function')
|
value === null || (typeof value != 'object' && typeof value != 'function')
|
||||||
const isArray = Array.isArray
|
const isArray = Array.isArray
|
||||||
const isIterable = value =>
|
const isIterable = value =>
|
||||||
value ? isArray(value) || typeof value[Symbol.iterator] === 'function' : false
|
isArray(value) ||
|
||||||
|
typeof (value === null || value === void 0
|
||||||
|
? false
|
||||||
|
: value[Symbol.iterator]) === 'function'
|
||||||
const SPACE_CHAR = `[ \n\f\r]`
|
const SPACE_CHAR = `[ \n\f\r]`
|
||||||
const ATTR_VALUE_CHAR = `[^ \n\f\r"'\`<>=]`
|
const ATTR_VALUE_CHAR = `[^ \n\f\r"'\`<>=]`
|
||||||
const NAME_CHAR = `[^\\s"'>=/]`
|
const NAME_CHAR = `[^\\s"'>=/]`
|
||||||
const TEXT_END_REGEX = /<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g
|
const textEndRegex = /<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g
|
||||||
const COMMENT_START = 1
|
const COMMENT_START = 1
|
||||||
const TAG_NAME = 2
|
const TAG_NAME = 2
|
||||||
const DYNAMIC_TAG_NAME = 3
|
const DYNAMIC_TAG_NAME = 3
|
||||||
const COMMENT_END_REGEXP = /-->/g
|
const commentEndRegex = /-->/g
|
||||||
const COMMENT_END_REGEXP_2 = />/g
|
const comment2EndRegex = />/g
|
||||||
const TAG_END_REGEXP = new RegExp(
|
const tagEndRegex = new RegExp(
|
||||||
`>|${SPACE_CHAR}(?:(${NAME_CHAR}+)(${SPACE_CHAR}*=${SPACE_CHAR}*(?:${ATTR_VALUE_CHAR}|("|')|))|$)`,
|
`>|${SPACE_CHAR}(?:(${NAME_CHAR}+)(${SPACE_CHAR}*=${SPACE_CHAR}*(?:${ATTR_VALUE_CHAR}|("|')|))|$)`,
|
||||||
'g'
|
'g'
|
||||||
)
|
)
|
||||||
|
@ -37,9 +38,9 @@ const ENTIRE_MATCH = 0
|
||||||
const ATTRIBUTE_NAME = 1
|
const ATTRIBUTE_NAME = 1
|
||||||
const SPACES_AND_EQUALS = 2
|
const SPACES_AND_EQUALS = 2
|
||||||
const QUOTE_CHAR = 3
|
const QUOTE_CHAR = 3
|
||||||
const SINGLE_QUOTE_REGEXP = /'/g
|
const singleQuoteAttrEndRegex = /'/g
|
||||||
const DOUBLE_QUOTE_REGEXP = /"/g
|
const doubleQuoteAttrEndRegex = /"/g
|
||||||
const RAW_TEXT_ELEM_REGEXP = /^(?:script|style|textarea|title)$/i
|
const rawTextElement = /^(?:script|style|textarea|title)$/i
|
||||||
const HTML_RESULT = 1
|
const HTML_RESULT = 1
|
||||||
const SVG_RESULT = 2
|
const SVG_RESULT = 2
|
||||||
const ATTRIBUTE_PART = 1
|
const ATTRIBUTE_PART = 1
|
||||||
|
@ -51,12 +52,14 @@ const COMMENT_PART = 7
|
||||||
const TEMPLATE_CACHE = new Map()
|
const TEMPLATE_CACHE = new Map()
|
||||||
const walker = document.createTreeWalker(document, 129, null, false)
|
const walker = document.createTreeWalker(document, 129, null, false)
|
||||||
|
|
||||||
|
function noop() {}
|
||||||
|
|
||||||
function getTemplateHtml(strings, type) {
|
function getTemplateHtml(strings, type) {
|
||||||
let len = strings.length - 1
|
let len = strings.length - 1
|
||||||
let attrNames = []
|
let attrNames = []
|
||||||
let html2 = type === SVG_RESULT ? '<svg>' : ''
|
let html2 = type === SVG_RESULT ? '<svg>' : ''
|
||||||
let rawTextEndRegex
|
let rawTextEndRegex
|
||||||
let regex = TEXT_END_REGEX
|
let regex = textEndRegex
|
||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
let s = strings[i]
|
let s = strings[i]
|
||||||
let attrNameEndIndex = -1
|
let attrNameEndIndex = -1
|
||||||
|
@ -70,26 +73,25 @@ function getTemplateHtml(strings, type) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
lastIndex = regex.lastIndex
|
lastIndex = regex.lastIndex
|
||||||
|
if (regex === textEndRegex) {
|
||||||
if (regex === TEXT_END_REGEX) {
|
|
||||||
if (match[COMMENT_START] === '!--') {
|
if (match[COMMENT_START] === '!--') {
|
||||||
regex = COMMENT_END_REGEXP
|
regex = commentEndRegex
|
||||||
} else if (match[COMMENT_START] !== void 0) {
|
} else if (match[COMMENT_START] !== void 0) {
|
||||||
regex = COMMENT_END_REGEXP_2
|
regex = comment2EndRegex
|
||||||
} else if (match[TAG_NAME] !== void 0) {
|
} else if (match[TAG_NAME] !== void 0) {
|
||||||
if (RAW_TEXT_ELEM_REGEXP.test(match[TAG_NAME])) {
|
if (rawTextElement.test(match[TAG_NAME])) {
|
||||||
rawTextEndRegex = new RegExp(`</${match[TAG_NAME]}`, 'g')
|
rawTextEndRegex = new RegExp(`</${match[TAG_NAME]}`, 'g')
|
||||||
}
|
}
|
||||||
regex = TAG_END_REGEXP
|
regex = tagEndRegex
|
||||||
} else if (match[DYNAMIC_TAG_NAME] !== void 0) {
|
} else if (match[DYNAMIC_TAG_NAME] !== void 0) {
|
||||||
regex = TAG_END_REGEXP
|
regex = tagEndRegex
|
||||||
}
|
}
|
||||||
} else if (regex === TAG_END_REGEXP) {
|
} else if (regex === tagEndRegex) {
|
||||||
if (match[ENTIRE_MATCH] === '>') {
|
if (match[ENTIRE_MATCH] === '>') {
|
||||||
regex =
|
regex =
|
||||||
rawTextEndRegex !== null && rawTextEndRegex !== void 0
|
rawTextEndRegex !== null && rawTextEndRegex !== void 0
|
||||||
? rawTextEndRegex
|
? rawTextEndRegex
|
||||||
: TEXT_END_REGEX
|
: textEndRegex
|
||||||
attrNameEndIndex = -1
|
attrNameEndIndex = -1
|
||||||
} else if (match[ATTRIBUTE_NAME] === void 0) {
|
} else if (match[ATTRIBUTE_NAME] === void 0) {
|
||||||
attrNameEndIndex = -2
|
attrNameEndIndex = -2
|
||||||
|
@ -98,65 +100,52 @@ function getTemplateHtml(strings, type) {
|
||||||
attrName = match[ATTRIBUTE_NAME]
|
attrName = match[ATTRIBUTE_NAME]
|
||||||
regex =
|
regex =
|
||||||
match[QUOTE_CHAR] === void 0
|
match[QUOTE_CHAR] === void 0
|
||||||
? TAG_END_REGEXP
|
? tagEndRegex
|
||||||
: match[QUOTE_CHAR] === '"'
|
: match[QUOTE_CHAR] === '"'
|
||||||
? DOUBLE_QUOTE_REGEXP
|
? doubleQuoteAttrEndRegex
|
||||||
: SINGLE_QUOTE_REGEXP
|
: singleQuoteAttrEndRegex
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
regex === DOUBLE_QUOTE_REGEXP ||
|
regex === doubleQuoteAttrEndRegex ||
|
||||||
regex === SINGLE_QUOTE_REGEXP
|
regex === singleQuoteAttrEndRegex
|
||||||
) {
|
) {
|
||||||
regex = TAG_END_REGEXP
|
regex = tagEndRegex
|
||||||
} else if (
|
} else if (regex === commentEndRegex || regex === comment2EndRegex) {
|
||||||
regex === COMMENT_END_REGEXP ||
|
regex = textEndRegex
|
||||||
regex === COMMENT_END_REGEXP_2
|
|
||||||
) {
|
|
||||||
regex = TEXT_END_REGEX
|
|
||||||
} else {
|
} else {
|
||||||
regex = TAG_END_REGEXP
|
regex = tagEndRegex
|
||||||
rawTextEndRegex = void 0
|
rawTextEndRegex = void 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let end =
|
let end =
|
||||||
regex === TAG_END_REGEXP && strings[i + 1].startsWith('/>') ? ' ' : ''
|
regex === tagEndRegex && strings[i + 1].startsWith('/>') ? ' ' : ''
|
||||||
html2 +=
|
html2 +=
|
||||||
regex === TEXT_END_REGEX
|
regex === textEndRegex
|
||||||
? s + NODE_MARKER
|
? s + nodeMarker
|
||||||
: attrNameEndIndex >= 0
|
: attrNameEndIndex >= 0
|
||||||
? (attrNames.push(attrName),
|
? (attrNames.push(attrName),
|
||||||
s.slice(0, attrNameEndIndex) +
|
s.slice(0, attrNameEndIndex) +
|
||||||
BIND_ATTR_SUFFIX +
|
boundAttributeSuffix +
|
||||||
s.slice(attrNameEndIndex)) +
|
s.slice(attrNameEndIndex)) +
|
||||||
MARKER +
|
marker +
|
||||||
end
|
end
|
||||||
: s +
|
: s +
|
||||||
MARKER +
|
marker +
|
||||||
(attrNameEndIndex === -2 ? (attrNames.push(void 0), i) : end)
|
(attrNameEndIndex === -2 ? (attrNames.push(void 0), i) : end)
|
||||||
}
|
}
|
||||||
let htmlResult =
|
let htmlResult =
|
||||||
html2 + (strings[len] || '<?>') + (type === SVG_RESULT ? '</svg>' : '')
|
html2 + (strings[len] || '<?>') + (type === SVG_RESULT ? '</svg>' : '')
|
||||||
if (!isArray(strings) || !strings.hasOwnProperty('raw')) {
|
if (!Array.isArray(strings) || !strings.hasOwnProperty('raw')) {
|
||||||
throw new Error('invalid html ast')
|
throw new Error('invalid html ast')
|
||||||
}
|
}
|
||||||
return [htmlResult, attrNames]
|
return [htmlResult, attrNames]
|
||||||
}
|
}
|
||||||
|
|
||||||
function createElement(v = '') {
|
|
||||||
let el = document.createElement('template')
|
|
||||||
el.innerHTML = v
|
|
||||||
return el
|
|
||||||
}
|
|
||||||
|
|
||||||
function createMarker(v = '') {
|
|
||||||
return document.createComment(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
class Template {
|
class Template {
|
||||||
parts = []
|
parts = []
|
||||||
|
|
||||||
constructor({ strings, values, __dom_type__: type }, options) {
|
constructor({ strings, ['__dom_type__']: type }, options) {
|
||||||
let node
|
let node
|
||||||
let nodeIndex = 0
|
let nodeIndex = 0
|
||||||
let attrNameIndex = 0
|
let attrNameIndex = 0
|
||||||
|
@ -164,7 +153,7 @@ class Template {
|
||||||
let parts = this.parts
|
let parts = this.parts
|
||||||
let [html2, attrNames] = getTemplateHtml(strings, type)
|
let [html2, attrNames] = getTemplateHtml(strings, type)
|
||||||
|
|
||||||
this.el = createElement(html2)
|
this.el = Template.createElement(html2)
|
||||||
|
|
||||||
walker.currentNode = this.el.content
|
walker.currentNode = this.el.content
|
||||||
|
|
||||||
|
@ -181,14 +170,17 @@ class Template {
|
||||||
let attrsToRemove = []
|
let attrsToRemove = []
|
||||||
|
|
||||||
for (let name of node.getAttributeNames()) {
|
for (let name of node.getAttributeNames()) {
|
||||||
if (name.endsWith(BIND_ATTR_SUFFIX) || name.startsWith(MARKER)) {
|
if (
|
||||||
|
name.endsWith(boundAttributeSuffix) ||
|
||||||
|
name.startsWith(marker)
|
||||||
|
) {
|
||||||
let realName = attrNames[attrNameIndex++]
|
let realName = attrNames[attrNameIndex++]
|
||||||
attrsToRemove.push(name)
|
attrsToRemove.push(name)
|
||||||
if (realName !== void 0) {
|
if (realName !== void 0) {
|
||||||
let value = node.getAttribute(
|
let value = node.getAttribute(
|
||||||
realName.toLowerCase() + BIND_ATTR_SUFFIX
|
realName.toLowerCase() + boundAttributeSuffix
|
||||||
)
|
)
|
||||||
let statics = value.split(MARKER)
|
let statics = value.split(marker)
|
||||||
let m = /([#:@])?(.*)/.exec(realName)
|
let m = /([#:@])?(.*)/.exec(realName)
|
||||||
let decorates = []
|
let decorates = []
|
||||||
|
|
||||||
|
@ -224,8 +216,8 @@ class Template {
|
||||||
node.removeAttribute(name)
|
node.removeAttribute(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (RAW_TEXT_ELEM_REGEXP.test(node.tagName)) {
|
if (rawTextElement.test(node.tagName)) {
|
||||||
let strings2 = node.textContent.split(MARKER)
|
let strings2 = node.textContent.split(marker)
|
||||||
let lastIndex = strings2.length - 1
|
let lastIndex = strings2.length - 1
|
||||||
if (lastIndex > 0) {
|
if (lastIndex > 0) {
|
||||||
node.textContent = ''
|
node.textContent = ''
|
||||||
|
@ -239,19 +231,24 @@ class Template {
|
||||||
}
|
}
|
||||||
} else if (node.nodeType === 8) {
|
} else if (node.nodeType === 8) {
|
||||||
let data = node.data
|
let data = node.data
|
||||||
if (data === MARKER_MATCH) {
|
if (data === markerMatch) {
|
||||||
parts.push({ type: CHILD_PART, index: nodeIndex })
|
parts.push({ type: CHILD_PART, index: nodeIndex })
|
||||||
} else {
|
} else {
|
||||||
let i = -1
|
let i = -1
|
||||||
while ((i = node.data.indexOf(MARKER, i + 1)) !== -1) {
|
while ((i = node.data.indexOf(marker, i + 1)) !== -1) {
|
||||||
parts.push({ type: COMMENT_PART, index: nodeIndex })
|
parts.push({ type: COMMENT_PART, index: nodeIndex })
|
||||||
i += MARKER.length - 1
|
i += marker.length - 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nodeIndex++
|
nodeIndex++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static createElement(html2) {
|
||||||
|
let el = document.createElement('template')
|
||||||
|
el.innerHTML = html2
|
||||||
|
return el
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TemplateInstance {
|
class TemplateInstance {
|
||||||
|
@ -381,7 +378,7 @@ class ChildPart {
|
||||||
} else if (value !== this.#value) {
|
} else if (value !== this.#value) {
|
||||||
this.#commitText(value)
|
this.#commitText(value)
|
||||||
}
|
}
|
||||||
} else if (value.__dom_type__ !== void 0) {
|
} else if (value['__dom_type__'] !== void 0) {
|
||||||
this.#commitTemplateResult(value)
|
this.#commitTemplateResult(value)
|
||||||
} else if (value.nodeType !== void 0) {
|
} else if (value.nodeType !== void 0) {
|
||||||
this.#commitNode(value)
|
this.#commitNode(value)
|
||||||
|
@ -418,11 +415,12 @@ class ChildPart {
|
||||||
}
|
}
|
||||||
|
|
||||||
#commitTemplateResult(result) {
|
#commitTemplateResult(result) {
|
||||||
let { values, __dom_type__: type } = result
|
let { values, ['__dom_type__']: type } = result
|
||||||
let template =
|
let template =
|
||||||
typeof type === 'number'
|
typeof type === 'number'
|
||||||
? this.#getTemplate(result)
|
? this.#getTemplate(result)
|
||||||
: (type.el === void 0 && (type.el = createElement(type.h)), type)
|
: (type.el === void 0 && (type.el = Template.createElement(type.h)),
|
||||||
|
type)
|
||||||
|
|
||||||
if (this.#value?.$template === template) {
|
if (this.#value?.$template === template) {
|
||||||
this.#value.update(values)
|
this.#value.update(values)
|
||||||
|
@ -529,10 +527,6 @@ class AttributePart {
|
||||||
let strings = this.strings
|
let strings = this.strings
|
||||||
let changed = false
|
let changed = false
|
||||||
|
|
||||||
if (typeof value === 'function') {
|
|
||||||
value = value(this.element)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strings === void 0) {
|
if (strings === void 0) {
|
||||||
changed = !isPrimitive(value) || value !== this.#value
|
changed = !isPrimitive(value) || value !== this.#value
|
||||||
if (changed) {
|
if (changed) {
|
||||||
|
@ -554,8 +548,7 @@ class AttributePart {
|
||||||
this.#value[i] = v
|
this.#value[i] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// value属性做特殊处理, 解决输入框无法清空的问题
|
if (changed) {
|
||||||
if (changed || this.name === 'value') {
|
|
||||||
this.commitValue(value)
|
this.commitValue(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -578,10 +571,6 @@ class AttributePart {
|
||||||
} else {
|
} else {
|
||||||
elem.removeAttribute(attr)
|
elem.removeAttribute(attr)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// value 绑定, 特殊处理
|
|
||||||
if (attr === 'value') {
|
|
||||||
elem.value = value
|
|
||||||
} else {
|
} else {
|
||||||
if (value === null || value === void 0) {
|
if (value === null || value === void 0) {
|
||||||
elem.removeAttribute(attr)
|
elem.removeAttribute(attr)
|
||||||
|
@ -591,7 +580,6 @@ class AttributePart {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// 赋值属性
|
// 赋值属性
|
||||||
class PropertyPart extends AttributePart {
|
class PropertyPart extends AttributePart {
|
||||||
constructor(...args) {
|
constructor(...args) {
|
||||||
|
|
37
src/index.js
37
src/index.js
|
@ -59,42 +59,6 @@ export function styleMap(data = {}) {
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
// 三元运算符的函数封装(只为了省个参数)
|
|
||||||
export function when(condition, trueCase = '', falseCase = '') {
|
|
||||||
return condition ? trueCase : falseCase
|
|
||||||
}
|
|
||||||
|
|
||||||
// swicth语句的封装
|
|
||||||
export function which(target, list = [], defaultCase = '') {
|
|
||||||
for (let [name, content] of list) {
|
|
||||||
if (target === name) {
|
|
||||||
return content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return defaultCase
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 双向绑定
|
|
||||||
* @param key<String> 绑定的字段
|
|
||||||
* @param el 当前对象, 无需传递, 由框架内部处理
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export function live(key, el) {
|
|
||||||
let callback = ev => {
|
|
||||||
Function('o', 'v', `o.${key} = v`)(this, ev.target.value)
|
|
||||||
this.$requestUpdate()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (el && !el.__live__) {
|
|
||||||
bind(el, 'input', callback)
|
|
||||||
this.$events.input ??= []
|
|
||||||
this.$events.input.push({ el, listener: callback, options: false })
|
|
||||||
el.__live__ = true
|
|
||||||
}
|
|
||||||
return Function('o', `return o.${key}`)(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Component extends HTMLElement {
|
export class Component extends HTMLElement {
|
||||||
/**
|
/**
|
||||||
* 声明可监听变化的属性列表
|
* 声明可监听变化的属性列表
|
||||||
|
@ -423,7 +387,6 @@ export class Component extends HTMLElement {
|
||||||
this.activated()
|
this.activated()
|
||||||
}
|
}
|
||||||
this.mounted()
|
this.mounted()
|
||||||
this.$requestUpdate()
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
nextTick(_ => this.updated(props))
|
nextTick(_ => this.updated(props))
|
||||||
|
|
24
src/utils.js
24
src/utils.js
|
@ -4,7 +4,7 @@
|
||||||
* @date 2023/03/07 22:11:30
|
* @date 2023/03/07 22:11:30
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function noop() {}
|
function noop() {}
|
||||||
|
|
||||||
export function $(selector, container, multi) {
|
export function $(selector, container, multi) {
|
||||||
let fn = multi ? 'querySelectorAll' : 'querySelector'
|
let fn = multi ? 'querySelectorAll' : 'querySelector'
|
||||||
|
@ -108,7 +108,7 @@ export function offset(node) {
|
||||||
/**
|
/**
|
||||||
* 事件绑定
|
* 事件绑定
|
||||||
*/
|
*/
|
||||||
export function bind(dom, type = '', selector, fn, phase = false) {
|
export function bind(dom, type = '', selector, fn, phase = true) {
|
||||||
let events = type.split(',')
|
let events = type.split(',')
|
||||||
let callback
|
let callback
|
||||||
let isWc = dom && dom.host === dom
|
let isWc = dom && dom.host === dom
|
||||||
|
@ -121,7 +121,7 @@ export function bind(dom, type = '', selector, fn, phase = false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof selector === 'function') {
|
if (typeof selector === 'function') {
|
||||||
phase = fn || false
|
phase = fn
|
||||||
fn = selector
|
fn = selector
|
||||||
selector = null
|
selector = null
|
||||||
} else {
|
} else {
|
||||||
|
@ -168,22 +168,12 @@ export function bind(dom, type = '', selector, fn, phase = false) {
|
||||||
events.forEach(function (t) {
|
events.forEach(function (t) {
|
||||||
t = t.trim()
|
t = t.trim()
|
||||||
if (isWc) {
|
if (isWc) {
|
||||||
host.$events[t] ??= []
|
if (host.$events[t]) {
|
||||||
|
host.$events[t].push({ el: dom, listener: callback, options: phase })
|
||||||
let _list = host.$events[t]
|
} else {
|
||||||
if (_list.length) {
|
host.$events[t] = [{ el: dom, listener: callback, options: phase }]
|
||||||
let idx = _list.findIndex(
|
|
||||||
it =>
|
|
||||||
it.el === dom && it.listener === callback && it.options === phase
|
|
||||||
)
|
|
||||||
if (idx > -1) {
|
|
||||||
let item = _list[idx]
|
|
||||||
_list.splice(idx, 1)
|
|
||||||
dom.removeEventListener(t, item.listener, item.options)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_list.push({ el: dom, listener: callback, options: phase })
|
|
||||||
}
|
|
||||||
dom.addEventListener(t, callback, phase)
|
dom.addEventListener(t, callback, phase)
|
||||||
})
|
})
|
||||||
return callback
|
return callback
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
<!doctype html>
|
|
||||||
<html lang="zh-CN">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
|
|
||||||
<title>wkit test page</title>
|
|
||||||
<style>
|
|
||||||
body {line-height: 1.5;font-size:14px;background:var(--page-color);color:var(--text-color);}
|
|
||||||
::-webkit-scrollbar {
|
|
||||||
width: 6px;
|
|
||||||
}
|
|
||||||
::-webkit-scrollbar-track {
|
|
||||||
border-radius: 10px;
|
|
||||||
background: var(--summary-bg-color);
|
|
||||||
}
|
|
||||||
::-webkit-scrollbar-thumb {
|
|
||||||
border-radius: 3px;
|
|
||||||
background: var(--border-color-dark);
|
|
||||||
}
|
|
||||||
::-webkit-scrollbar-thumb:hover {
|
|
||||||
background: var(--summary-color);
|
|
||||||
}
|
|
||||||
@media screen and (max-width: 480px) {
|
|
||||||
::-webkit-scrollbar {
|
|
||||||
display: none;
|
|
||||||
width: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script type="importmap">
|
|
||||||
{
|
|
||||||
"imports":{
|
|
||||||
"es.shim":"//jscdn.ink/es.shim/latest/index.js",
|
|
||||||
"wkit":"//127.0.0.1:9999/src/index.js",
|
|
||||||
"wkitd":"//jscdn.ink/wkitd/1.3.10/index.js",
|
|
||||||
"fetch":"//jscdn.ink/@bytedo/fetch/latest/next.js",
|
|
||||||
"@bd/ui/":"//jscdn.ink/@bd/ui/0.1.16/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<script type="module" src="./test.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<wc-app></wc-app>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
31
test/test.js
31
test/test.js
|
@ -1,31 +0,0 @@
|
||||||
import { html, Component, live } from 'wkit'
|
|
||||||
|
|
||||||
class App extends Component {
|
|
||||||
foo = ''
|
|
||||||
|
|
||||||
bar = { a: 333 }
|
|
||||||
|
|
||||||
created() {
|
|
||||||
// live = live.bind(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
reset() {
|
|
||||||
this.foo = ''
|
|
||||||
this.bar.a = '666'
|
|
||||||
this.$requestUpdate()
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return html`
|
|
||||||
<p>${this.foo}</p>
|
|
||||||
<p>${this.bar.a}</p>
|
|
||||||
<input value=${live.bind(this, 'bar.a')} />
|
|
||||||
<input value=${this.foo} />
|
|
||||||
<input value=${live.bind(this, 'foo')} />
|
|
||||||
|
|
||||||
<button @click=${this.reset}>666</button>
|
|
||||||
`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
App.reg('app')
|
|
Loading…
Reference in New Issue