【问题标题】:Adding vee-validate / HTML attributes to input element in slot将 vee-validate / HTML 属性添加到插槽中的输入元素
【发布时间】:2018-06-23 01:30:22
【问题描述】:

在我的应用程序中,我有很多表单,大多数输入看起来都像这样:

<div class="form-group">
    <label for="language">{{ $t('form.language')}}</label>
    <input type="text" class="form-control" id="language" name="form.language" v-model="language" v-validate.initial="'required'" :data-vv-as="$t('form.language')" />
    <span class="invalid-feedback">{{ errors.first('language') }}</span>
</div>

这会一遍又一遍地重复。唯一真正改变的是字段名称和输入类型。有时它是一个选择,有时它是一个更复杂的组件,而不是简单的 HTML 组件。

我的想法是创建某种包装组件。所以我不必复制所有这些,只需使用类似的东西:

<form-group name="language">
    <input type="text" v-model="form.language">
</form-group>

我尝试用这种方式实现它,但它不起作用:

<template>
    <div class="form-group">
        <label :for="name">{{ $t('form.' + name)}}</label>
        <slot class="form-control"
              :id="name"
              :data-vv-name="name"
              v-validate.initial="'required'"
              :data-vv-as="$t('form.'+ name)">
        </slot>
        <span class="invalid-feedback">{{ errors.first(name) }}</span>
    </div>
</template>

<script>
    export default {
        props: ['name']
    }
</script>

你有什么想法吗?问题是我不能轻松地将 mixins 和 props 传递给开槽的元素/组件。

【问题讨论】:

  • 如果我理解正确的话,你想要一个带有插槽 A 的组件,并且在这个给定的插槽中你想给插槽添加“默认”属性?如 id、data-vv-name 等。这是正确的吗?
  • 如果是这种情况,您将属性发送到“插槽”本身,而不是插槽内容(输入)。根据您的输入的多样性,我建议您在组件上使用“type”属性和各种“v-if”,这将生成正确的组件。否则,更复杂的解决方案是使用使用渲染功能的组件。
  • @Antony 这是正确的。传递良好的类型是不可行的,因为有时我有一个选择字段或更复杂的组件(例如,带屏蔽的货币输入,带强度指示器的密码输入)。并且用 v-if 在输入之间切换也没有用,因为那时我必须对任何可能的类型进行硬编码。我想避免使组件不太混乱。

标签: javascript vue.js vuejs2 vue-component vee-validate


【解决方案1】:

scoped slots(Vue 2.5.0+)怎么样?

<!-- form-group.vue -->
<template>
  <div>
    <label />
    <slot v-bind="$props" />
    <span />
  </div>
</template>

以上,&lt;form-group&gt; 的所有 props 都使用v-bind 绑定到插槽。您可能只想指定某些字段:&lt;slot :id="name" :data-vv-name="name" /&gt;

<form-group name="age">
  <input type="number" slot-scope="slotProps" v-bind="slotProps" />
</form-group>

在这里,&lt;input&gt; 可以使用slot-scope 访问插槽道具,并为其命名(此处为slotProps)。 slotProps 将包含&lt;slot&gt; 的所有属性,如form-group.vue 中定义的那样。

更多示例:

<form-group name="language">
  <input type="text" slot-scope="sp" v-bind="sp" />
</form-group>

<form-group name="hello" value="friend">
  <span slot-scope="sp">
    {{ sp.name }}: {{ sp.value }}
  </span>
</form-group>

【讨论】:

    【解决方案2】:

    正如 cmets 中所说,无法将道具从 传递到插槽的内容,即您的&lt;input&gt;

    由于这是一个相当复杂的情况,它需要使用渲染函数,它将自定义属性发送到新标签中,同时应用一组默认属性。

    我在这里做了一个概念证明:https://codepen.io/anon/pen/Ozadop?editors=1010

    Vue.component('my-input', {
      render: function(createElement) {
        const defaultSlot = this.$slots.default[0];
        const domProps = Object.assign({
          value: this.value,
          someProp: 'foobar',
          test: "asdf",
          class: defaultSlot.data.staticClass
        }, defaultSlot.data.attrs);
        return createElement(
          defaultSlot.tag, // tag name
          {
            attrs: domProps,
            props: domProps,
            on: {
              input: (event) => {
                this.value = event.target.value
                this.$emit('input', event.target.value)
              }
            }
          }
        )
      },
      props: {
        name: {
          type: String,
          required: true
        },
        value: {
          type: String,
          required: true
        }
      }
    })
    
    new Vue({
      el: "#app",
      data() {
        return {
          name: "Your Name",
          age: 5
        }
      }
    });
    .red {
      border: 2px solid red;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js"></script>
    <div id="app">
      Hello, {{name}}!! You are {{age}} years old.
      <br/>
      <my-input v-model="name">
        <input customProp="myCustomProp"></input>
      </my-input>
    
      <my-input v-model="age">
        <input type="number" required class="red" custom="otherCustom"></input>
      </my-input>
    
    </div>

    请注意,这将要求将所有不是属性的东西应用到具有当前上下文的包装 Vue 组件。

    这需要进行调整以支持您的所有需求,例如选择字段和类似内容,但我相信这是一个好的开始。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-25
      • 2013-08-07
      • 2016-05-15
      • 1970-01-01
      • 1970-01-01
      • 2015-07-01
      • 2014-04-27
      • 2014-04-30
      相关资源
      最近更新 更多