v1.18.3

响应式 DOM。
无需构建。

一个微型的、网络标准优先的模板系统,为普通 JavaScript 带来反应性、状态和组件。 没有捆绑商。没有 JSX。没有魔法。

7.6KBCDN gzip
0第三方部门
100%网络标准
javascript
import { html, state, effect } from '@beforesemicolon/markup'

const [count, updateCount] = state(0)

const doubleCount = () => count() * 2

effect(() => {
    console.log(count())
})

const countUp = () => updateCount((prev) => prev + 1)
const countDown = () => updateCount((prev) => prev - 1)

const App = html`
    <h1>Conunter</h1>
    <p><strong>Current count</strong>: ${count}</p>
    <p><strong>Double count</strong>: ${doubleCount}</p>
    <button type="button" onclick="${countDown}">-</button>
    <button type="button" onclick="${countUp}">+</button>
`

App.render(document.getElementById('app'))

拓展您的构建方式。

单独使用 Markup 作为反应式模板,或者在您的应用程序需要自定义元素、路由或本地化时添加重点配套包。

Web Components

@beforesemicolon/web-component

原生 Web Components API 之上的反应层。保留 Markup 的模板模型,同时添加props、状态、生命周期和范围样式。

阅读文档

Router

@beforesemicolon/router

作为 Web 组件标签的声明式路由。无需采用框架路由器即可编写页面、嵌套布局、查询路由和延迟加载视图。

阅读文档

Intl

@beforesemicolon/intl

组件优先接口的本地化。添加区域设置范围、翻译的消息和格式化程序帮助程序,以自然地融入 Markup 驱动的 UI。

阅读文档

平台就是框架。

Web 标准、Web API 和现代 JavaScript 就是您所需要的。 Markup 只是增加反应性。

反应性

模板文字和函数创建具有状态、生命周期和副作用的反应式 DOM。

很小 - 8KB 以下 gzip

CDN 浏览器构建以大约 7.6KB gzip 传输。无需一兆字节的框架即可交付企业应用程序。

网络标准

三个简单的 API 可以扩展您已知的平台。没有专有抽象。

即插即用

放入脚本标签并开始。没有构建步骤,没有 JSX,没有配置文件。

Web Components

增强原生 Web Components 的反应性。跳过手动 DOM 操作。

手术更新

数据驱动渲染意味着 DOM 仅在实际需要的地点和时间进行更新。

看起来像 HTML。感觉就像魔法一样。

反应状态、组件组成和生命周期——所有这些都来自您已经了解的 JavaScript 原语。

示例 01
待办事项 + localStorage
javascript
import { html, state, effect, repeat } from '@beforesemicolon/markup'

const [todos, setTodos] = state(
    JSON.parse(localStorage.getItem('todos') ?? '[]')
)

effect(() => {
    localStorage.setItem('todos', JSON.stringify(todos()))
})

const addTodo = () => {
    const text = window.prompt('What needs doing?')?.trim()

    if (text) setTodos((prev) => [...prev, { text, done: false }])
}

const toggle = (i) =>
    setTodos(todos().map((t, idx) => (idx === i ? { ...t, done: !t.done } : t)))

html`
    <button type="button" onclick="${addTodo}">Add</button>
    <ul>
        ${repeat(
            todos,
            (todo, i) => html`
                <li
                    class="${todo.done ? 'done' : ''}"
                    onclick="${() => toggle(i)}"
                >
                    ${todo.text}
                </li>
            `
        )}
    </ul>
`.render(document.querySelector('#app'))
示例 02
使用WebComponent的按钮组件
javascript
import { WebComponent, html } from '@beforesemicolon/web-component'
import stylesheet from './button.css' with { type: 'css' }

class Button extends WebComponent {
    static observedAttributes = ['disabled', 'type']

    type = 'button'
    disabled = false

    stylesheet = stylesheet

    handleClick = (evt) => {
        evt.stopPropagation()
        this.dispatch('click')
    }

    render = () => {
        return html`
            <button ${this.props} class="btn" onclick="${this.handleClick}">
                <slot></slot>
            </button>
        `
    }
}

customElements.define('bfs-button', Button)
示例 03
悬念(异步)
javascript
import { html, suspense } from '@beforesemicolon/markup'

const loadUser = async () => {
    const res = await fetch('/api/me')
    return res.json()
}

const renderUser = async () => {
    const user = await loadUser()
    return html`
        <article>
            <h2>${user.name}</h2>
            <p>${user.bio}</p>
        </article>
    `
}

html`
    <h1>Profile</h1>

    ${suspense(
        renderUser,
        html`<p>Loading profile...</p>`, // fallback
        (err) => html`<p>Failed: ${err.message}</p>` // catch
    )}
`.render(document.querySelector('#app'))
示例 04
页面路由
html
<!-- in <head>:
<script src="https://unpkg.com/@beforesemicolon/router/dist/client.js"></script>
-->

<nav>
    <page-link path="/">Home</page-link>
    <page-link path="/about">About</page-link>
    <page-link path="/users">Users</page-link>
</nav>

<page-route path="/">
    <h1>Welcome home</h1>
</page-route>

<page-route path="/about" src="./pages/about.js"></page-route>

<page-route path="/users" exact="false">
    <page-route src="./pages/users.js"></page-route>
    <page-route path="/:userId" src="./pages/user.js"></page-route>
</page-route>

<page-route path="/404"> 404 - Page not found! </page-route>

<page-redirect path="/404" title="404 - Page not found!"></page-redirect>
示例 05
模板生命周期
javascript
import { html, state } from '@beforesemicolon/markup'

const [seconds, setSeconds] = state(0)

html` <p>Elapsed: ${seconds}s</p> `
    .onMount(() => {
        // runs once when attached to the DOM
        const id = setInterval(() => setSeconds(seconds() + 1), 1000)
        return () => clearInterval(id)
    })
    .onUpdate(() => {
        // runs every time a tracked value changes
        console.log('tick', seconds())
    })
    .render(document.querySelector('#app'))

只需几秒钟即可安装。

选择你的武器。 Markup 可在 JavaScript 运行的任何地方工作。

<script src="https://unpkg.com/@beforesemicolon/markup/dist/client.js"></script>
npm install @beforesemicolon/markup
yarn add @beforesemicolon/markup
pnpm add @beforesemicolon/markup

构建网络, 你的方式。

加入开发人员,使用尊重平台和您时间的框架更快地交付。