widgets/main.js
2024-05-15 22:38:07 +08:00

225 lines
10 KiB
JavaScript

export function createElement({ innerText, innerHTML, textContent, readOnly, children = [], dataset, style, classList = [], ...attributes }, tagName = 'div') {
const element = document.createElement(tagName)
for (const key in attributes) {
if (key.startsWith('on')) element[key] = attributes[key] // 如果是事件则直接赋值
else element.setAttribute(key, attributes[key]) // 否则是属性则使用setAttribute
}
if (dataset) Object.assign(element.dataset, dataset)
if (style) Object.assign(element.style, style)
if (classList.length) element.classList.add(...classList)
if (textContent) element.textContent = textContent
if (innerText) element.innerText = innerText
if (innerHTML) element.innerHTML = innerHTML
if (readOnly) element.readOnly = readOnly
if (children) children.forEach(child => element.appendChild(child))
return element
}
/* HTML5 语义标签 */
export const List = (options) => createElement(options, 'ul')
export const ListItem = (options) => createElement(options, 'li')
export const Span = (options) => createElement(options, 'span')
export const Button = (options) => createElement({ ...options, style: { cursor: 'pointer', ...options.style } }, 'button')
export const Form = (options) => createElement(options, 'form')
export const Header = (options) => createElement(options, 'header')
export const Nav = (options) => createElement(options, 'nav')
export const Main = (options) => createElement(options, 'main')
export const Article = (options) => createElement(options, 'article')
export const Section = (options) => createElement(options, 'section')
export const Aside = (options) => createElement(options, 'aside')
export const Footer = (options) => createElement(options, 'footer')
export const H1 = (options) => createElement(options, 'h1')
export const H2 = (options) => createElement(options, 'h2')
export const H3 = (options) => createElement(options, 'h3')
export const H4 = (options) => createElement(options, 'h4')
export const H5 = (options) => createElement(options, 'h5')
export const H6 = (options) => createElement(options, 'h6')
export const P = (options) => createElement(options, 'p')
export const A = (options) => createElement(options, 'a')
export const Strong = (options) => createElement(options, 'strong')
export const Em = (options) => createElement(options, 'em')
export const Small = (options) => createElement(options, 'small')
export const Mark = (options) => createElement(options, 'mark')
export const Del = (options) => createElement(options, 'del')
export const Ins = (options) => createElement(options, 'ins')
export const Pre = (options) => createElement(options, 'pre')
export const Code = (options) => createElement(options, 'code')
export const Blockquote = (options) => createElement(options, 'blockquote')
export const Q = (options) => createElement(options, 'q')
export const Cite = (options) => createElement(options, 'cite')
export const Hr = (options) => createElement(options, 'hr')
export const Br = (options) => createElement(options, 'br')
export const Ol = (options) => createElement(options, 'ol')
export const Ul = (options) => createElement(options, 'ul')
export const Li = (options) => createElement(options, 'li')
export const Dl = (options) => createElement(options, 'dl')
export const Dt = (options) => createElement(options, 'dt')
export const Dd = (options) => createElement(options, 'dd')
export const Figure = (options) => createElement(options, 'figure')
export const Figcaption = (options) => createElement(options, 'figcaption')
export const Img = (options) => createElement(options, 'img')
export const Video = (options) => createElement(options, 'video')
export const Audio = (options) => createElement(options, 'audio')
export const Canvas = (options) => createElement(options, 'canvas')
export const Svg = (options) => createElement(options, 'svg')
export const Math = (options) => createElement(options, 'math')
export const Table = (options) => createElement(options, 'table')
export const Caption = (options) => createElement(options, 'caption')
export const Thead = (options) => createElement(options, 'thead')
export const Tfoot = (options) => createElement(options, 'tfoot')
export const Tbody = (options) => createElement(options, 'tbody')
export const Tr = (options) => createElement(options, 'tr')
export const Th = (options) => createElement(options, 'th')
export const Td = (options) => createElement(options, 'td')
export const Col = (options) => createElement(options, 'col')
export const Colgroup = (options) => createElement(options, 'colgroup')
export const Fieldset = (options) => createElement(options, 'fieldset')
export const Legend = (options) => createElement(options, 'legend')
export const Label = (options) => createElement(options, 'label')
export const Input = (options) => createElement(options, 'input')
export const Select = (options) => createElement(options, 'select')
export const TextArea = (options) => createElement(options, 'textarea')
export const Div = (options) => createElement(options, 'div')
export function Avatar(options) {
const element = createElement(options, 'img')
element.onerror = () => element.src = '/favicon.ico'
return element
}
export function Dialog(options) {
const element = createElement({
tabIndex: 0,
style: {
position: 'fixed',
top: 0,
left: 0,
zIndex: 1000,
width: '100%',
height: '100%',
backdropFilter: 'blur(5px)',
duration: '0.5s',
transition: 'all 0.5s'
},
onclick: async event => {
if (event.target !== event.currentTarget) return
await event.target.animate([{ opacity: 1 }, { opacity: 0 }], { duration: 100 }).finished
await event.target.remove()
},
onkeydown: async event => {
if (event.key !== 'Escape') return
await event.target.animate([{ opacity: 1 }, { opacity: 0 }], { duration: 100 }).finished
await event.target.remove()
},
children: [
createElement({
...options,
style: {
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
backgroundColor: '#fff',
borderRadius: '150px',
boxShadow: '0 0 1em #ccc',
overflow: 'hidden',
display: 'flex',
justifyContent: 'center',
...options.style,
}
})
]
})
const observer = new MutationObserver(mutationsList => {
for (const mutation of mutationsList) {
if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
element.focus()
element.animate([{ opacity: 0 }, { opacity: 1 }], { duration: 100 }).finished
return observer.disconnect()
}
}
})
observer.observe(document.body, { childList: true, subtree: true })
return element
}
export class div extends HTMLDivElement {
constructor(options) {
super()
for (const key in options) {
if (key === 'text') {
this.textContent = options[key]
continue
}
if (key.startsWith('on')) this[key] = options[key]
else this.setAttribute(key, options[key])
}
}
static w(width) { return new this({ style: { width } }) }
static h(height) { return new this({ style: { height } }) }
static x(left) { return new this({ style: { left } }) }
static y(top) { return new this({ style: { top } }) }
static z(index) { return new this({ style: { zIndex: index } }) }
static r(radius) { return new this({ style: { borderRadius: radius } }) }
static b(border) { return new this({ style: { border } }) }
static p(padding) { return new this({ style: { padding } }) }
static m(margin) { return new this({ style: { margin } }) }
static o(opacity) { return new this({ style: { opacity } }) }
static flex(flex) { return new this({ style: { flex } }) }
static grid(grid) { return new this({ style: { grid } }) }
static text(text) {
console.log('text::', new this({ text }))
return new this({ text })
}
static children(children) { return new this({ children }) }
w(width) { this.style.width = width + 'px'; return this }
h(height) { this.style.height = height + 'px'; return this }
x(left) { this.style.left = left; return this }
y(top) { this.style.top = top; return this }
z(index) { this.style.zIndex = index; return this }
r(radius) { this.style.borderRadius = radius; return this }
b(border) { this.style.border = border; return this }
p(padding) { this.style.padding = padding; return this }
m(margin) { this.style.margin = margin; return this }
o(opacity) { this.style.opacity = opacity; return this }
flex(flex) { this.style.flex = flex; return this }
grid(grid) { this.style.grid = grid; return this }
text(text) {
console.log('text', text)
this.textContent = text; return this
}
children(children) {
children.forEach(child => {
console.log('child', child)
this.appendChild(child)
});
return this
}
}
export class pre extends HTMLPreElement {
constructor(options) {
super()
for (const key in options) {
if (key.startsWith('on')) this[key] = options[key]
else this.setAttribute(key, options[key])
}
}
static text(text) { return new this({ textContent: text }) }
}
customElements.define('my-div', div, { extends: 'div' })
customElements.define('my-pre', pre, { extends: 'pre' })
export default {
createElement, List, ListItem, Span, Button, Img, Input, TextArea, Avatar, Dialog,
Div, Form, Header, Nav, Main, Article, Section, Aside, Footer,
H1, H2, H3, H4, H5, H6, P, A, Strong, Em, Small, Mark, Del, Ins, Pre, Code,
Blockquote, Q, Cite, Hr, Br, Ol, Ul, Li, Dl, Dt, Dd, Figure, Figcaption,
Video, Audio, Canvas, Svg, Math, Table, Caption, Thead, Tfoot, Tbody, Tr, Th, Td,
Col, Colgroup, Fieldset, Legend, Label, Select, TextArea,
div, pre
}