像 flutter 风格用纯粹 js 构建页面
Go to file
ddfee6403f 增加font 2024-05-17 00:31:40 +08:00
.gitignore init 2024-01-12 04:22:52 +08:00
LICENSE Initial commit 2024-01-12 01:04:22 +08:00
README.md html5语义标签 2024-05-16 05:00:08 +08:00
index.html 发布配置 2024-01-12 04:38:20 +08:00
index.js 支持多类型参数 2024-05-16 06:46:41 +08:00
main.js 增加font 2024-05-17 00:30:42 +08:00
package.json 增加font 2024-05-17 00:31:40 +08:00

README.md

widgets

像 flutter 风格用纯粹 js 构建页面 { createElement List ListItem Span Button Img Input TextArea Avatar Dialog }

(本质上只是给创建 html 的js方法套了一层使其能够链式调用)

npm i @laniakeasupercluster/widgets
import { createElement, Button, Span } from '@laniakeasupercluster/widgets'

document.body.appendChild(createElement({
    style: { width: 320, height: 320, padding: 64 },
    children: [
        Span({ textContent: 'hello world!' })
        Button({
            textContent: 'click',
            onclick: event => {
                const randomNumber = Math.floor(Math.random() * 100)
                event.traget.textContent = 'click' + randomNumber
            }
        })
    ]
}))

dev

git clone git@git.satori.love:LaniakeaSupercluster/widgets.git
npm i
npm run dev

HTML 基本概念

对于UI书写划分为两类, 一是外观样式, 一是结构关系 一个元素的基本构成就是其外观样式, 因此它书写在声明它的同一列

div.w(128).h(64)

嵌套关系则应该换行并缩进, 保持与 HTML 一致的风格

document.body.appendChild(div.w(128).h(64).children([
    div.text('Hello world!'),
    div.text('Hello world!'),
    div.text('Hello world!')
]))

有时期望复用样式

const option = { style: { width: '128px', height: '64px' } }
div(option).children([
    div.text('Hello world!'),
    div.text('Hello world!'),
    div.text('Hello world!')
])

由于返回值是真实的 DOM 对象, 它具有原生 DOM 对象的所有方法, 因而可以这样使用它

const demo = div.w(128).h(64).children([
    div.text('Hello world!'),
    div.text('Hello world!'),
    div.text('Hello world!')
])
demo.textContent = 'hello world!'
document.body.appendChild(demo)

然而 dom 元素的 textContent 并不是一个函数方法而是一个变量值, 自然无法使用链式调用 demo.textContent('hello world!') 为了减少代码量也为了避免破坏dom基本结构, 所有额外提供的方法都使用缩写, 像是这样 demo.text('hello world!')

这样做的期望自然是将样式便捷地与数据混合处理, 像这样

import { div, span } from '@laniakeasupercluster/widgets'

const data = ['hello', 'world', 'and', 'you']
document.body.appendChild(div.w(20).h(20).children([
    ...data.filter(item => item.length >= 3).map(item => span.text(item))
]))

// 也许想要这样做
const data = ['hello', 'world', 'and', 'you'].filter(item => item.length >= 3)
const items = data.map(item => span.text(item)).map((item, index) => {
    if (index < 1) item.style.color = '#cc1414'
    return item
})

document.body.appendChild(div.w(20).h(20).children(items))

也许想要这样做

import { div, span } from '@laniakeasupercluster/widgets'

const data = ['hello', 'world', 'and', 'you'].filter(item => item.length >= 3)
const items = data.map(item => span.text(item)).map((item, index) => {
    if (index < 1) item.style.color = '#cc1414'
    return item
})

document.body.appendChild(div.w(20).h(20).children(items))

虽然这与 pug 中 div.w-8.h-12 赋予元素 class 名的概念基本相同, 但实际并不会给元素赋予 class 名, 它只是一个方法去设置元素样式, 因为在 js 的实现中过多引入 css 概念是没有意义的(至少目前我这么认为)

CSS 的便捷性还有两点, 一是伪元素和伪类(:hover ::after), 一是选择器(div.text#ctx.mix > .cc { width: 12px }), 在js中目前没有很好的实现方法, 此事只能再议

三种情境: div({}) div.text('') new div({})

符合直觉的标准

  1. 元素在初始化前是 class 而不是 function, 这在编辑器中渲染的样式也将不同
  2. 直接导出 html5 语义标签
  3. 额外添加的快捷方法都是缩写, 将避免与默认属性或方法冲突