svelte - 如何绑定(bind) slim 的动态组件值

标签 svelte svelte-component

假设我有这个主应用程序:

<script>
  import Field from '../components/Field.svelte';

  const components = {};
  const fields = [
    {
      id: 'Check',
      type: 'CheckBox',
      value: false,
    },
    {
      id: 'Text',
    },
  ];

  $: console.log(components);
</script>

<form>
  {#each fields as item}
    <Field {...item} bind:bind={components[item.bind]} bind:this={components[item.id]} />
  {/each}
</form>
我有两个组件,CheckBoxTextArea , 两者都只是实现 HTML
输入,字段组件的实现如下:
<script>
  import CheckBox from './CheckBox.svelte';
  import TextArea from './TextArea.svelte';

  export let attributes = {};
  export let type = 'TextArea';
  export let value = '';
  export let id;
  export let bind;

  const fieldComponents = {
    CheckBox: CheckBox,
    TextArea: TextArea,
  };
</script>

<svelte:component this={fieldComponents[type]} {bind} {id} {value} {attributes} />
这样我就创建了一个具有复选框和文本区域的动态表单。
我想要的是可以从组件内部访问的“绑定(bind)”属性,
并且能够绑定(bind)另一个组件,这样我就可以实现
像这样的东西:
<input type="checkbox" bind:checked={bind.value}>
这意味着如果 textarea 将有文本,复选框将被选中,
如果它为空,则该复选框将被取消选中。
在所有组件渲染后,我可以使用 components 访问它们
对象,因为我像这样绑定(bind)它们 bind:this={components[item.id]}但是在它们渲染之前我无法访问它们,有没有办法让它变得如此
组件是否可以动态绑定(bind)到其他组件?
我演示了只使用了 2 个组件,它也可能是一大组
组件。
我想确定绑定(bind)的方法是使用 bind里面的属性(property)fields匹配 id 的数组另一个领域的。

最佳答案

我的建议是使用 Svelte 商店并将您的表单配置对象保存在商店中。这将允许您的任何 Svelte 组件访问表单状态。

可以在 https://svelte.dev/repl/3f161dd253624d4ea7a3b8b9e5763e96?version=3.21.0 测试和 fork 一个工作示例

示例应用程序的代码分解如下。

App.svelte 在哪里:

<script>
/*
@abstract This app is used to demonstrate one way to track form state with Svelte.
We use the 'store' to save an object that will contain our form field configurations
and field values. A JSON string formatted configuration is used as opposed to a purely javascipt object so that we can for instance pull in our form configuration from a back-end database to dynmaically build our form (in this example we are simply hard-coding the JSON into the app, but for production you might want to pull from an server-side API).
*/
import Field from './Field.svelte'; // used to build our form fields
import Box from './Box.svelte'; // just for show
import { storeFE } from './store.js';   // store our form state
let objForm;    // @testing - used to listen for changes in our form state

// @testing - keep up to date on the form object
const unsubscribe = storeFE.subscribe(value => {
        objForm = value;
});

// opting for JSON string config (which is what we would want if we are pulling this config from say a server data API)
// the 'fIndex' value is used within our form components know which form element object to work with within our main 'storeFE' object store. the 'fType' value tells the Field.svelte component which form element to build
let objFormConfig = JSON.parse(`{
    "formElements": [
        {
                "fIndex":0,
                "fId":"cc2",
                "fType": "CheckBox",
                "fValue": "true",
                "fDisable":"ct1.fValue==''"
        },
        {
                "fIndex":1,
                "fId":"ct1",
                "fType": "TextArea",
                "fValue": "textee area",
                "fChangeEvent":"cc2 disable",
                "fDisable":"cc2 checked is false"
        }
    ]
}`);
// @testing: let us know when the form values have changed (the storeFE object has updated)
$: {
    console.log('objForm:');
    console.log(objForm);
}
$storeFE = objFormConfig;   // save the initial form configuration to the store
</script>
<form>
{#each objFormConfig.formElements as item}
    <Box>
    <Field objAttributes={item}></Field>
    </Box>
{/each}
</form>

在哪里 Field.svelte 是:
<script>
import CheckBox from './CheckBox.svelte';
import TextArea from './TextArea.svelte';

export let objAttributes = {};

const fieldComponents = {
    'CheckBox': CheckBox,
    'TextArea': TextArea
};
</script>
<div>
        <svelte:component this={fieldComponents[objAttributes.fType]} {objAttributes} />
</div>

在哪里 CheckBox.svelte 是:
<script>
/* Here we want to get the store index */
import { storeFE } from './store.js';
export let objAttributes = {};
const fIndex = objAttributes.fIndex;
const strDisable = objAttributes.fDisable;
function fDisable() {
    if (strDisable) {
        console.log('do some stuff like check: '+strDisable);
    }
}
console.log("checkbox here, showing you my field attributes:");
console.log(objAttributes);
</script>
<h2>
    My checkbox
</h2>
<input id={objAttributes.fId} type=checkbox bind:checked={$storeFE.formElements[fIndex].fValue} on:change={fDisable}>

在哪里 TextArea.svelte 是:
<script>
import { storeFE } from './store.js';
export let objAttributes = {};
const fIndex = objAttributes.fIndex;


console.log("textarea here, showing you my field attributes:");
console.log(objAttributes);
</script>
<h2>
    My text
</h2>
<textarea bind:value={$storeFE.formElements[fIndex].fValue}></textarea>

在哪里 store.js 是:
import { writable } from 'svelte/store';
export let storeFE = writable({});

Box.svelte 不是必需的,只是为了展示(来自 Svelte 教程):
<style>
    .box {
        width: 300px;
        border: 1px solid #aaa;
        border-radius: 2px;
        box-shadow: 2px 2px 8px rgba(0,0,0,0.1);
        padding: 1em;
        margin: 0 0 1em 0;
    }
</style>

<div class="box">
    <slot></slot>
</div>

在这个 Svelte REPL 应用程序中可以找到另一个带有表单验证的代码示例:
https://svelte.dev/repl/253ddd578806497b8b54c339490f8221?version=3.21.0

关于svelte - 如何绑定(bind) slim 的动态组件值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59810747/

相关文章:

javascript - 为什么 Svelte 被称为编译器而其他框架被称为转译器

javascript - slim /工兵 : Body empty on POST

javascript - 如何将带有 Node 后端的 Svelte 前端部署到 Heroku?

svelte - 是否可以在 Svelte 3 中直接绑定(bind)对象字段?

javascript - 如何在 Svelte 组件中基于 props 定义 CSS 字段?

components - Svelte - 组件一如何使用组件二的功能?

web-component - 在 Svelte 自定义组件中使用第三方库

javascript - 为什么我们需要在 Svelte 中通过 'detail' 对象访问自定义事件数据?

Svelte 自定义元素 API

javascript - Svelte:如何将数据或 Prop 从子组件传递给父组件?