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 }