公用事业

Markup 提供了许多实用函数,可帮助您进行模板化或一般使用 DOM:

为什么需要公用事业?

在 Markup 中,函数是一等公民,这意味着反应数据由函数表示。为了简单起见,您可以创建处理模板之外的特定逻辑的函数,这样事情看起来很干净,并且逻辑是可重用的。

您可以创建实用函数来处理以下事情:

您只需要在处理状态时定义实用程序。其他一切都可以保留为静态数据。

实用程序只是在模板中呈现的函数,只要它们所依赖的状态发生变化就需要调用它们。

自定义实用程序

当您开始定义自己的实用程序时,使用状态和模板的力量就会显现出来。让我们看一个简单的例子:

我们有一个常见的场景,我们有一个使用状态的输入字段,并且我们需要显示特定的消息,无论该值是否有效。

javascript
const [value, updateValue] = state(null)

const handleChange = (event) => {
    updateValue(event.target.value)
}

html` <input value="${value}" oninput="${handleChange}" /> `.render(
    document.body
)

我们可以直接在模板中添加消息的逻辑:

javascript
html`
    <input value="${value}" onchange="${handleChange}" />
    ${() => {
        if (/[a-z]{3,}/i.test(value())) {
            return ''
        }

        return 'Value must me at least 3 characters'
    }}
`.render(document.body)

这还不错,但模板中的逻辑占用空间,而且很多逻辑使模板难以阅读。

我意识到,当输入无效时,我想将字段标记为红色,并且这依赖于我们在函数中具有的相同逻辑。因此,我可以将该逻辑提取到一个函数中以实现可重用性:

javascript
const [value, updateValue] = state(null)

const isPristine = () => value() === null
const isValidValue = () => /[a-z]{3,}/i.test(value())

const handleChange = (event) => {
    updateValue(event.target.value)
}

html`
    <input value="${value}" oninput="${handleChange}" />
    ${isPristine} ${isValidValue}
`.render(document.body)
// renders: <input> true false

现在我有两个实用程序可以告诉我该值是否已更改,或者我可以在任何地方使用它来渲染任何内容是否有效。

但我不需要停在那里,我可以使用函数来表示我想要的任何东西,最终得到这样的结果:

javascript
const [value, updateValue] = state(null)

const isPristine = () => value() === null
const isValidValue = () => /[a-z]{3,}/i.test(value())
const valueCSSColor = () => (or(isPristine, isValidValue)() ? 'inherit' : 'red')

const handleChange = (event) => {
    updateValue(event.target.value)
}

html`
    <input
        value="${value}"
        oninput="${handleChange}"
        style="color: ${valueCSSColor}"
    />
    ${when(
        or(isPristine, isValidValue),
        html`<p>Your name</p>`,
        html`<p style="color: ${valueCSSColor}">
            Name must be at least 3 characters
        </p>`
    )}
`.render(document.body)

您可以看到我们有处理不同逻辑的函数,将它们组合成依赖于状态的更复杂的逻辑。

这种只需创建和组合函数来处理所有事情的能力进一步使 Markup 中的模板变得简单而有趣。

我们可以进一步将所有内容包装在可重用实用程序中,以处理可与多个表单字段一起使用的任何类型的表单输入值。

javascript
const formFieldValue = (pattern) => {
    const [value, updateValue] = state(null)

    const isPristine = () => value() === null
    const isValid = () => pattern.test(value())
    const isPristineOrValid = or(isPristine, isValid)
    const color = () => (isPristineOrValid() ? 'inherit' : 'red')

    return {
        value,
        updateValue,
        color,
        isPristine,
        isValid,
        isPristineOrValid,
    }
}

这使我可以轻松地为任何字段创建字段处理程序,如下所示:

javascript
const name = formFieldValue(/[a-z]{3,}/i)
const email = formFieldValue(/[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$/i)

const handleNameChange = (event) => {
    name.updateValue(event.target.value)
}

const handleEmailChange = (event) => {
    email.updateValue(event.target.value)
}

html`
    <input
        type="text"
        value="${name.value}"
        oninput="${handleNameChange}"
        style="color: ${name.color}"
    />
    ${when(
        name.isPristineOrValid,
        html`<p>Your name</p>`,
        html`<p style="color: ${name.color}">
            Name must be at least 3 characters
        </p>`
    )}

    <input
        type="email"
        value="${email.value}"
        oninput="${handleEmailChange}"
        style="color: ${email.color}"
    />
    ${when(
        email.isPristineOrValid,
        html`<p>Your email</p>`,
        html`<p style="color: ${email.color}">Email is not valid</p>`
    )}
`.render(document.body)

正如您所看到的,当谈到反应性时,Markup 严重且完全依赖于函数来完成工作。这种面向功能的性质使模板变得简单并且对任何人来说都熟悉。尝试一下!

编辑本文档