将 vee-validate / HTML 属性添加到插槽中的输入元素
Adding vee-validate / HTML attributes to input element in slot
在我的应用程序中,我有很多表单,大多数输入看起来完全像这样:
<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>
这会被一遍又一遍地复制。唯一真正改变的是字段名称和输入类型。有时它是一个 select,有时它是一个更复杂的组件,而不是简单的 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 传递给开槽 element/component.
如评论中所述,无法将 props 从 传递到插槽的内容,即您的 <input>
。
由于这是相当复杂的情况,因此需要使用渲染函数,在应用一组默认属性的同时将自定义属性发送到新标记中。
我在这里做了一个概念验证: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 组件。
这需要进行调整以支持您的所有需求,例如 select 字段和类似内容,但我相信这是一个好的开始。
scoped slots (Vue 2.5.0+) 怎么样?
<!-- form-group.vue -->
<template>
<div>
<label />
<slot v-bind="$props" />
<span />
</div>
</template>
以上,<form-group>
的所有道具都绑定到使用v-bind
的插槽。您可能只想指定某些字段:<slot :id="name" :data-vv-name="name" />
<form-group name="age">
<input type="number" slot-scope="slotProps" v-bind="slotProps" />
</form-group>
在这里,<input>
可以通过使用 slot-scope
来访问插槽道具,给它一个名字(这里 slotProps
)。 slotProps
将包含在 form-group.vue
.
中定义的 <slot>
的所有属性
更多示例:
<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>
在我的应用程序中,我有很多表单,大多数输入看起来完全像这样:
<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>
这会被一遍又一遍地复制。唯一真正改变的是字段名称和输入类型。有时它是一个 select,有时它是一个更复杂的组件,而不是简单的 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 传递给开槽 element/component.
如评论中所述,无法将 props 从 传递到插槽的内容,即您的 <input>
。
由于这是相当复杂的情况,因此需要使用渲染函数,在应用一组默认属性的同时将自定义属性发送到新标记中。
我在这里做了一个概念验证: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 组件。
这需要进行调整以支持您的所有需求,例如 select 字段和类似内容,但我相信这是一个好的开始。
scoped slots (Vue 2.5.0+) 怎么样?
<!-- form-group.vue -->
<template>
<div>
<label />
<slot v-bind="$props" />
<span />
</div>
</template>
以上,<form-group>
的所有道具都绑定到使用v-bind
的插槽。您可能只想指定某些字段:<slot :id="name" :data-vv-name="name" />
<form-group name="age">
<input type="number" slot-scope="slotProps" v-bind="slotProps" />
</form-group>
在这里,<input>
可以通过使用 slot-scope
来访问插槽道具,给它一个名字(这里 slotProps
)。 slotProps
将包含在 form-group.vue
.
<slot>
的所有属性
更多示例:
<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>