236 lines
6.5 KiB
Vue
236 lines
6.5 KiB
Vue
<script setup lang="ts">
|
||
import { FormKitSchemaDefinition, getNode, type FormKitNode } from '@formkit/core';
|
||
import { onMounted } from 'vue';
|
||
import Guests from './guests.vue';
|
||
import Swal from 'sweetalert2'
|
||
|
||
async function submit(...args: any[]) {
|
||
console.debug('submit', `args :>> `, args);
|
||
await new Promise(r => setTimeout(r, 1000))
|
||
Swal.fire({
|
||
title: 'Submitted! 🎉',
|
||
icon: 'success',
|
||
showConfirmButton: false,
|
||
timer: 1500
|
||
})
|
||
}
|
||
|
||
const castNumber = (node: FormKitNode) => {
|
||
node.hook.input((value, next) => next(Number(value)))
|
||
}
|
||
|
||
onMounted(() => {
|
||
console.group('onMounted')
|
||
const nameNode = getNode('nameNodeId') // 用 id 获取节点
|
||
Object.assign(window, { nameNode })
|
||
console.debug(`nameNode :>> `, nameNode);
|
||
|
||
const schemaGroupInput = nameNode?.root.at('schemaGroup.input') // 用路径获取节点
|
||
console.debug(`schemaGroupInput :>> `, schemaGroupInput);
|
||
nameNode?.on('commit', ({ payload }) => {
|
||
console.debug('[nameNode] [on commit]', `payload :>> `, payload);
|
||
schemaGroupInput?.input(`姓名:${payload}`)
|
||
})
|
||
console.groupEnd()
|
||
})
|
||
|
||
const SCHEMA: FormKitSchemaDefinition = [
|
||
{
|
||
$el: 'h1',
|
||
children: [
|
||
{
|
||
$el: 'span',
|
||
children: 'JSON Schema Form',
|
||
},
|
||
],
|
||
attrs: {
|
||
class: 'font-bold text-2xl mb-4',
|
||
'data-foo': 'bar',
|
||
},
|
||
},
|
||
{
|
||
$formkit: 'group',
|
||
name: 'schemaGroup',
|
||
children: [
|
||
{
|
||
$formkit: 'text',
|
||
label: 'JSON Schema 渲染的输入框',
|
||
name: 'input',
|
||
validation: 'required',
|
||
validationLabel: 'validationLabel', // validation message 使用顺序:validationLabel > label > name
|
||
errors: ['显式设置的错误是非阻塞的,这意味着它们不会像验证错误那样阻止表单提交。您可以在表单文档中了解更多有关错误处理的信息。']
|
||
}
|
||
]
|
||
}
|
||
];
|
||
|
||
import autoAnimate from "@formkit/auto-animate"
|
||
onMounted(() => {
|
||
// setTimeout(() => {
|
||
autoAnimate(document.getElementById('attributes-group-wrapper')!);
|
||
// });
|
||
})
|
||
|
||
</script>
|
||
|
||
<template>
|
||
<div class="bg-white rounded-xl shadow-xl p-8 mx-auto my-16 max-w-[450px] dark:bg-gray-800 ">
|
||
<h1
|
||
class="font-bold text-2xl mb-4 color:gray-800 dark:text-white"
|
||
data-foo="bar"
|
||
>Tutorial Form</h1>
|
||
<FormKit
|
||
type="form"
|
||
#default="{ value }"
|
||
@submit="submit"
|
||
submit-label="提交 ✨"
|
||
>
|
||
<!-- v-auto-animate -->
|
||
<div
|
||
class="attributes-group"
|
||
id="attributes-group-wrapper"
|
||
>
|
||
<FormKit
|
||
type="group"
|
||
name="attributes"
|
||
:validation-rules="{
|
||
validateGroup: (node) => {
|
||
const name = (node.value as Record<string, any>).name
|
||
return name?.includes('测试') ? true : false
|
||
}
|
||
}"
|
||
validation-visibility="dirty"
|
||
validation="validateGroup"
|
||
:validation-messages="{
|
||
validateGroup: ({ name/* , args */ }) => {
|
||
return `分组 ${name} 下的姓名必须包含 '测试' 字符串。`
|
||
},
|
||
}"
|
||
#default="{ id, messages, fns, classes, value: attributes, }"
|
||
>
|
||
|
||
<FormKit
|
||
type="text"
|
||
name="name"
|
||
id="nameNodeId"
|
||
label="姓名"
|
||
:help="`现在 confirmName 的值是:${attributes?.confirmName}`"
|
||
some-attr="some-attr-value"
|
||
>
|
||
<template #label="{ classes, attrs, label, node: nameNode, value }">
|
||
<!-- <pre
|
||
class="font-mono text-sm p-4 bg-slate-100 mb-4">{{ JSON.stringify({ classes, attrs, label }, null, 2) }}</pre> -->
|
||
<label
|
||
for="nameNodeId"
|
||
v-bind="attrs"
|
||
:class="classes.label"
|
||
>{{ label }}<button
|
||
class="ml-2 px-2 py-1 bg-blue-500 text-white rounded"
|
||
type="button"
|
||
@click="
|
||
!value?.includes('测试')
|
||
? nameNode?.input('测试')
|
||
: nameNode?.input('')"
|
||
>点击{{ value?.includes('测试') ? '清空' : '填充' }}</button>
|
||
</label>
|
||
</template>
|
||
</FormKit>
|
||
|
||
<FormKit
|
||
v-if="attributes?.name"
|
||
:preserve="false"
|
||
name="confirmName"
|
||
type="toggle"
|
||
thumb-icon="star"
|
||
:value="true"
|
||
:label="`如果清空 name 输入框,这个确认框及其值将被移除。`"
|
||
/>
|
||
|
||
<FormKit
|
||
type="checkbox"
|
||
name="flavors"
|
||
label="最喜欢的冰淇淋口味"
|
||
:options="{
|
||
'vanilla': '香草',
|
||
'chocolate': '巧克力',
|
||
'strawberry': '草莓',
|
||
}"
|
||
validation="required|min:2"
|
||
/>
|
||
|
||
<FormKit
|
||
type="range"
|
||
name="strength"
|
||
label="力量"
|
||
value="5"
|
||
validation="min:2|max:9"
|
||
validation-visibility="live"
|
||
min="1"
|
||
max="10"
|
||
step="1"
|
||
help="这个角色应该有多少力量点?"
|
||
:plugins="[castNumber]"
|
||
class="mb-4"
|
||
/>
|
||
|
||
<FormKit
|
||
type="textarea"
|
||
auto-height
|
||
label="我有自动高度插件"
|
||
help="这个文本框会随着输入内容增加而增高"
|
||
/>
|
||
|
||
<!-- By default groups do not show validation messages, so we need to add it manually -->
|
||
<ul
|
||
class="error-box"
|
||
:class="classes.messages"
|
||
v-if="fns.length(messages)"
|
||
>
|
||
<li
|
||
v-for="message in messages"
|
||
:key="message.key"
|
||
:id="`${id}-${message.key}`"
|
||
:data-message-type="message.type"
|
||
>
|
||
{{ message.value }}
|
||
</li>
|
||
</ul>
|
||
</FormKit>
|
||
</div>
|
||
|
||
<div class="attributes-group">
|
||
<FormKitSchema :schema="SCHEMA" />
|
||
</div>
|
||
|
||
<Guests />
|
||
|
||
<FormKit
|
||
type="checkbox"
|
||
name="agree"
|
||
label="我同意FormKit是最好的表单开发框架。"
|
||
class="mb-4"
|
||
/>
|
||
|
||
<pre class="font-mono text-sm p-4 bg-slate-100 mb-4 dark:bg-gray-900 ">{{ value }}</pre>
|
||
|
||
</FormKit>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped>
|
||
ul.error-box {
|
||
padding: 0.75rem;
|
||
border: 1px solid #ef4444;
|
||
border-radius: 0.375rem;
|
||
background-color: #fee2e2;
|
||
color: #b91c1c;
|
||
font-size: 0.875rem;
|
||
line-height: 1.25rem;
|
||
}
|
||
|
||
ul.error-box p {
|
||
font-weight: 500;
|
||
}
|
||
</style>
|
||
|
||
<style></style> |