# FormKit Schema 參考文件: - [FormKit Schema](https://formkit.com/advanced/schema) 雖然 Schema 是為生成表單而創建,但他能夠生成任何 HTML tag 或第三方 component Schema 是由 "schema nodes" 組成的物件陣列,每個物件代表一個 HTML element、component 或純文字節點。當傳入單純的字串時會產生文字,而 HTML element 和 component 由兩種物件定義(分別為 `$el` 和 `$cmp` 定義) ## Schema node 語法 ### 渲染任意 HTML Element ##### 欄位 - $el:可以帶入任意合法的 HTML tag,將會被渲染為 HTML element - attrs:透過 attrs 物件傳入任意 attribute - children:HTML 的實際內容 [live example](https://formkit.link/b31a8396f6c6cd24b58ee93132155949) ```json [ { $el: 'div', // 試著改成 h1 看看 attrs: { style: { color: 'red' }, 'data-foo': 'bar' }, children: 'Hello world' } ] ``` --- ### gbtFloatingLabelTextInput 說明:文字輸入框,但當使用者互動時會有label 漂浮的 動畫效果 ##### 欄位 - $formkit:對應的 FormKit 輸入類型 - name:FormKit 蒐集輸入資料 JSON 的 key - <font color="red">label</font>:必須帶入,漂浮用的 placeholder 文字 - <font color="red">placeholder</font>:不可帶入,避免和漂浮的 label 重疊 - inputType:最終會渲染上的 type,ex: `<input type="email">` - validation:驗證規則 - validationMessages:驗證錯誤訊息 ##### 範例 ```json { "$formkit": "gbtFloatingLabelTextInput", "name": "Firstname", "label": "Firstname", "inputType": "email", "validation": [ [ "required", "trim" ], [ "matches", "johnson" ] ], "validationMessages": { "required": "此欄位必填" }, } ``` --- ### gbtMultiSelect 說明:下拉選單輸入項,分為**多選**和**單選**兩種類型 ##### 欄位 - $formkit:對應的 FormKit 輸入類型 - name:FormKit 蒐集輸入資料 JSON 的 key - <font color="red">options</font>:下拉選單選項清單 - 結構:`Array<{ value: string, label: string }>` - value:FormKit 蒐集到 JSON 輸出值 (不一定要命名為 value,但須和 `vueMultiSelectOptions.trackBy` 選項設定一致) - label:顯示在下拉選單中的文字 (不一定要命名為 label,但須和 `vueMultiSelectOptions.label` 選項設定一致) - <font color="red">vueMultiSelectOptions</font>:轉接給 [Vue-Multiselect](https://vue-multiselect.js.org/#sub-option-groups) 套件使用的選項 - trackBy:指定使用 option 物件的哪個 key 值作為 FormKit 輸出值 - label:指定使用 option 物件的哪個 key 值作為顯示的文字 - placeholder - multiple:是否可多選 - validation:驗證規則 - validationMessages:驗證錯誤訊息 ##### 範例 ```json { "$formkit": "gbtMultiSelect", "name": "officeLocation", "options": [ { "value": "1", "label": "office 1" }, { "value": "2", "label": "office 2" }, { "value": "3", "label": "office 3" }, { "value": "4", "label": "office 4" }, { "value": "5", "label": "office 5" } ], "vueMultiSelectOptions": { "trackBy": "value", "label": "label", "placeholder": "Office Location", "multiple": true }, "validation": "required", "validationMessages": { "required": "此欄位必填" } } ``` --- ### gbtCheckbox 說明:checkbox 輸入項,分為**多選**和**單選**兩種類型 #### 單選 ##### 欄位 - $formkit:對應的 FormKit 輸入類型 - name:FormKit 蒐集輸入資料 JSON 的 key - <font color="red">label</font>:顯示在 checkbox 右側的文字 - validation:驗證規則 - validationMessages:驗證錯誤訊息 >Note:單選 checkbox 的輸出資料型別是 Boolean ##### 範例 ```json { "$formkit": "gbtCheckbox", "name": "SingleCheckbox", "label": "Single Checkbox", "validation": [ [ "required" ] ], "validationMessages": { "required": "此欄位必填" } } // Output { "SingleCheckbox": true } ``` #### 多選 ##### 欄位 - $formkit:對應的 FormKit 輸入類型 - name:FormKit 蒐集輸入資料 JSON 的 key - <font color="red">allowOther</font>:在所有選項後方額外顯示 "other" 的選項,並產生文字輸入框給使用者填寫 - <font color="red">options</font>:checkbox 選項清單 - 結構:`Array<{ value: string, label: string }>` - value:FormKit 蒐集到 JSON 輸出值 - label:顯示在 checkbox 右側的文字 - 注意事項: - 由於目前 other 的文字輸入框的字串值會直接收到陣列底下,為做區分,目前需在一般 checkbox 的 value 前加入 prefix - validation:驗證規則 - 目前當 `allowOther` 為 true 時,需額外帶入 `optionAllowOther` 規則使 other 選項的文字輸入框必填,可再討論是否做成固定規則 - validationMessages:驗證錯誤訊息 ##### 範例 ```json { "$formkit": "gbtCheckbox", "name": "Inquiries", "allowOther": true, "options": [ { "value": "gbtCheckbox-1", "label": "Request for Quotation" }, { "value": "gbtCheckbox-2", "label": "Form a Partnership" }, { "value": "gbtCheckbox-3", "label": "Talk to Sales" }, { "value": "gbtCheckbox-4", "label": "Educational Resource" }, { "value": "gbtCheckbox-5", "label": "Need More Information" }, { "value": "gbtCheckbox-6", "label": "After-sales Service" } ], "validation": [ [ "required" ], [ "optionAllowOther" ] ], "validationMessages": { "optionAllowOther": "Please provide a value for other." } } // Output { "Inquiries": [ "gbtCheckbox-2", "gbtCheckbox-1", "gbtCheckbox-3", "gbtCheckbox-4", "1234" // 這是 other 文字輸入框填寫的值 ] } ``` --- ## 條件渲染 FormKit schema 可以利用 references 和 expression 讓 schema nodes 和 attributes 根據條件判斷顯示,條件可透過兩種方式撰寫 1. 在 `$el` 和 `$cmp 上加 if 屬性 2. 在物件上加入 `if/then/else` ### `if` 屬性 在 `$el` 和 `$cmp` 上加入 `if` 屬性就大致就像 `v-if` 一樣,當條件為 truthy 就會被渲染 範例:[live example](https://formkit.link/176f4d6012faf01e451be85490ac0860) ```javascript <script setup> import { reactive } from 'vue' const data = reactive({ value: 0 }) const schema = [ { $el: 'h2', if: '$value >= 5 && $value <= 10', children: '$value + " is between 5-10!"', } ] </script> <template> <FormKit type="number" v-model="data.value" label="Enter a number between 5-10" /> <FormKitSchema :schema="schema" :data="data" /> </template> ``` ### `if/then/else` 物件 可用來處理更複雜的邏輯,依據條件渲染 schema node、attrs 屬性等等,並且可以巢狀使用 範例: 1. 用於 schema nodes [連結](https://formkit.link/6727a421e5d44fffb673cf427860171e) 2. 用於 attrs 和 props [連結](https://formkit.link/80b0046e93e37bcc59dc819e7b96dbcb) 3. 目前 survey 欄位排版以及下拉選單連動其他選項的寫法 [本機 Demo 網址](http://10.1.4.221:5173/) ```json { "$el": "div", "attrs": { "class": "gc-form-group" }, "children": [ { "$el": "div", "children": "About Your Inquiry", "attrs": { "class": "gc-form-group-title" } }, { "$el": "div", "attrs": { "class": "gc-form-row" }, "children": [ { "$el": "div", "attrs": { "class": "col" }, "children": [ { "$formkit": "gbtMultiSelect", "name": "productInterest", "id": "productInterest", "validation": "required", "options": [ { "value": "schema", "label": "schema" }, { "value": "custom", "label": "custom" }, { "value": "awesome", "label": "awesome" }, { "value": "other", "label": "other" } ], "validationMessages": { "required": "此欄位必填" }, "vueMultiSelectOptions": { "trackBy": "value", "label": "label", "placeholder": "Product you’re interested in*" } } ] }, { "if": "$get(productInterest).value === schema", "$el": "div", "attrs": { "class": "col" }, "children": [ { "key": "productInterest.schema", "name": "productUsedIn", "validation": "required", "options": [ { "id": "schema 1", "displayLabel": "schema 1" }, { "id": "schema 2", "displayLabel": "schema 2" }, { "id": "schema 3", "displayLabel": "schema 3" } ], "vueMultiSelectOptions": { "placeholder": "You are using the product for*", "trackBy": "id", "label": "displayLabel" }, "validationMessages": { "required": "此欄位必填22" }, "$formkit": "gbtMultiSelect" } ] }, { "if": "$get(productInterest).value === custom", "$el": "div", "attrs": { "class": "col" }, "children": [ { "key": "productInterest.custom", "name": "productUsedIn", "validation": "required", "options": [ { "id": "1", "displayLabel": "custom 1" }, { "id": "2", "displayLabel": "custom 2" }, { "id": "3", "displayLabel": "custom 3" } ], "vueMultiSelectOptions": { "placeholder": "You are using the product for*", "trackBy": "id", "label": "displayLabel" }, "validationMessages": { "required": "此欄位必填" }, "$formkit": "gbtMultiSelect" } ] }, { "if": "$get(productInterest).value === other", "$el": "div", "attrs": { "class": "col" }, "children": [ { "key": "productInterest.other", "name": "productUsedIn", "$formkit": "text", "placeholder": "test text placeholder" } ] } ] }, { "$el": "div", "attrs": { "class": "gc-form-row" }, "children": [ { "$el": "div", "attrs": { "class": "col" }, "children": [ { "name": "textarea", "placeholder": "Help us better understand your inquiry (limited to 1000 characters)*", "maxlength": 10, "validation": "required:trim", "$formkit": "textarea" } ] } ] } ] } ``` ## Survey 項目使用的 JSON 結構 ```json [ { "$el": "div", "attrs": { "class": "gc-form-group", "data-group-Id": "group-1111" }, "children": [ { "$el": "div", "children": "Inquiries*", "attrs": { "class": "gc-form-group-title" } }, { "$el": "div", "attrs": { "class": "gc-form-row" }, "children": [ { "$el": "div", "attrs": { "class": "col", "data-col-id": "col-1111" }, "children": [ { "$formkit": "gbtCheckbox", "name": "Inquiries", "allowOther": true, "options": [ { "value": "gbtCheckbox-1", "label": "Request for Quotation" }, { "value": "gbtCheckbox-2", "label": "Form a Partnership" }, { "value": "gbtCheckbox-3", "label": "Talk to Sales" }, { "value": "gbtCheckbox-4", "label": "Educational Resource" }, { "value": "gbtCheckbox-5", "label": "Need More Information" }, { "value": "gbtCheckbox-6", "label": "After-sales Service" } ], "validation": [ [ "required" ], [ "optionAllowOther" ] ], "validationMessages": { "optionAllowOther": "Please provide a value for other." } } ] } ] }, { "$el": "div", "attrs": { "class": "gc-form-row" }, "children": [ { "$el": "div", "attrs": { "class": "col" }, "children": [ { "$formkit": "gbtCheckbox", "name": "SingleCheckbox", "label": "Single Checkbox" } ] } ] } ] }, { "$el": "div", "attrs": { "class": "gc-form-group" }, "children": [ { "$el": "div", "children": "Profile", "attrs": { "class": "gc-form-group-title" } }, { "$el": "div", "attrs": { "class": "gc-form-row" }, "children": [ { "$el": "div", "attrs": { "class": "col" }, "children": [ { "name": "Firstname", "label": "Firstname", "validation": [ [ "required", "trim" ], [ "matches", "johnson" ] ], "help": "Label 會漂浮的文字框", "$formkit": "gbtFloatingLabelTextInput" } ] }, { "$el": "div", "attrs": { "class": "col" }, "children": [ { "name": "Lastname", "placeholder": "Lastname", "validation": [ [ "required", "trim" ] ], "$formkit": "text" } ] } ] }, { "$el": "div", "attrs": { "class": "gc-form-row" }, "children": [ { "$el": "div", "attrs": { "class": "col" }, "children": [ { "formkitInputType": "gbtFloatingLabelTextInput", "inputType": "email", "name": "email", "label": "Work Email", "validation": "required:trim|email", "help": "To ensure our emails be delivered to your inbox, please avoid using free-to-use email services such as Yahoo, Gmail, Hotmail etc.", "$formkit": "gbtFloatingLabelTextInput" } ] } ] } ] }, { "$el": "div", "attrs": { "class": "gc-form-group" }, "children": [ { "$el": "div", "children": "Company", "attrs": { "class": "gc-form-group-title" } }, { "$el": "div", "attrs": { "class": "gc-form-row" }, "children": [ { "$el": "div", "attrs": { "class": "col" }, "children": [ { "name": "Company", "id": "Company_123", "placeholder": "Company", "validation": "required:trim", "$formkit": "text" } ] }, { "if": "$get(Company_123).value", "$el": "div", "attrs": { "class": "col" }, "children": [ { "name": "URL", "placeholder": "URL", "validation": "required:trim", "$formkit": "text" } ] } ] }, { "$el": "div", "attrs": { "class": "gc-form-row" }, "children": [ { "$el": "div", "attrs": { "class": "col" }, "children": [ { "$formkit": "gbtMultiSelect", "name": "officeLocation", "options": [ { "value": "office 1", "label": "office 1" }, { "value": "office 2", "label": "office 2" }, { "value": "office 3", "label": "office 3" }, { "value": "office 4", "label": "office 4" }, { "value": "office 5", "label": "office 5" } ], "vueMultiSelectOptions": { "trackBy": "value", "label": "label", "placeholder": "Office Location", "multiple": true }, "validation": "required", "validationMessages": { "required": "此欄位必填" } } ] } ] } ] }, { "$el": "div", "attrs": { "class": "gc-form-group" }, "children": [ { "$el": "div", "children": "About Your Inquiry", "attrs": { "class": "gc-form-group-title" } }, { "$el": "div", "attrs": { "class": "gc-form-row" }, "children": [ { "$el": "div", "attrs": { "class": "col" }, "children": [ { "$formkit": "gbtMultiSelect", "name": "productInterest", "id": "productInterest", "validation": "required", "options": [ { "value": "schema", "label": "schema" }, { "value": "custom", "label": "custom" }, { "value": "awesome", "label": "awesome" }, { "value": "other", "label": "other" } ], "validationMessages": { "required": "此欄位必填" }, "vueMultiSelectOptions": { "trackBy": "value", "label": "label", "placeholder": "Product you’re interested in*" } } ] }, { "if": "$get(productInterest).value === schema", "$el": "div", "attrs": { "class": "col" }, "children": [ { "key": "productInterest.schema", "name": "productUsedIn", "validation": "required", "options": [ { "id": "schema 1", "displayLabel": "schema 1" }, { "id": "schema 2", "displayLabel": "schema 2" }, { "id": "schema 3", "displayLabel": "schema 3" } ], "vueMultiSelectOptions": { "placeholder": "You are using the product for*", "trackBy": "id", "label": "displayLabel" }, "validationMessages": { "required": "此欄位必填22" }, "$formkit": "gbtMultiSelect" } ] }, { "if": "$get(productInterest).value === custom", "$el": "div", "attrs": { "class": "col" }, "children": [ { "key": "productInterest.custom", "name": "productUsedIn", "validation": "required", "options": [ { "id": "1", "displayLabel": "custom 1" }, { "id": "2", "displayLabel": "custom 2" }, { "id": "3", "displayLabel": "custom 3" } ], "vueMultiSelectOptions": { "placeholder": "You are using the product for*", "trackBy": "id", "label": "displayLabel" }, "validationMessages": { "required": "此欄位必填" }, "$formkit": "gbtMultiSelect" } ] }, { "if": "$get(productInterest).value === other", "$el": "div", "attrs": { "class": "col" }, "children": [ { "key": "productInterest.other", "name": "productUsedIn", "$formkit": "text", "placeholder": "test text placeholder" } ] } ] }, { "$el": "div", "attrs": { "class": "gc-form-row" }, "children": [ { "$el": "div", "attrs": { "class": "col" }, "children": [ { "name": "textarea", "placeholder": "Help us better understand your inquiry (limited to 1000 characters)*", "maxlength": 10, "validation": "required:trim", "$formkit": "textarea" } ] } ] } ] }, { "$el": "div", "attrs": { "class": "privacy-policy", "innerHTML": "<div href=\"haha\">We will process your personal information in accordance with our <a href=\"hello\">Privacy Policy</a> and you may unsubscribe at any time.</div>" } } ] ```