我在Vue.js 2.3中使用<component v-for="...">
标签来动态呈现组件列表。
模板如下所示:
<some-component v-for="{name, props}, index in modules" :key="index">
<component :is="name" v-bind="props"></component>
</some-component>
modules
数组位于我的组件data()
中:
modules: [
{
name: 'some-thing',
props: {
color: '#0f0',
text: 'some text',
},
},
{
name: 'some-thing',
props: {
color: '#f3f',
text: 'some other text',
},
},
],
我使用v-bind={...}
对象语法来动态绑定道具,这非常有效。我还想用这种方法将事件监听器绑定到v-on
(并使用.sync
&#39; d props),但我不知道如果没有创建自定义,它是否可行指令。
我尝试添加到这样的props
个对象,但它没有工作:
props: {
color: '#f3f',
text: 'some other text',
'v-on:loaded': 'handleLoaded', // no luck
'volume.sync': 'someValue', // no luck
},
我的目标是让用户使用vuedraggable
在侧边栏中重新排序小部件,并将其布局首选项保留在数据库中,但某些小部件包含@event
和.sync
ed prop
s。这可能吗?我欢迎任何建议!
答案 0 :(得分:3)
我不知道如何使用动态组件完成此操作。但是,您可以使用渲染功能来完成它。
考虑这个数据结构,这是对你的修改。
modules: [
{
name: 'some-thing',
props: {
color: '#0f0',
text: 'some text',
},
sync:{
"volume": "volume"
},
on:{
loaded: "handleLoaded"
}
},
{
name: 'other-thing',
on:{
clicked: "onClicked"
}
},
],
我在这里定义了另外两个属性:sync
和on
。 sync
属性是一个对象,其中包含您希望sync
所需的所有属性的列表。例如,其中一个组件的sync
属性包含volume: "volume"
。这表示您希望通常添加为:volume.sync="volume"
的属性。没有办法(我知道)你可以动态地将它添加到动态组件中,但是在渲染功能中,你可以将它分解为它的去糖部分并添加属性和updated:volume
的处理程序。
与on
属性类似,在渲染函数中,我们可以为由键调用的事件添加处理程序,该事件调用值中标识的方法。以下是该渲染函数的可能实现。
render(h){
let components = []
let modules = Object.assign({}, this.modules)
for (let template of this.modules) {
let def = {on:{}, props:{}}
// add props
if (template.props){
def.props = template.props
}
// add sync props
if (template.sync){
for (let sync of Object.keys(template.sync)){
// sync properties are just sugar for a prop and a handler
// for `updated:prop`. So here we add the prop and the handler.
def.on[`update:${sync}`] = val => this[sync] = val
def.props[sync] = this[template.sync[sync]]
}
}
// add handers
if (template.on){
// for current purposes, the handler is a string containing the
// name of the method to call
for (let handler of Object.keys(template.on)){
def.on[handler] = this[template.on[handler]]
}
}
components.push(h(template.name, def))
}
return h('div', components)
}
基本上,render方法会查看template
中modules
中的所有属性,以决定如何渲染组件。在属性的情况下,它只是传递它们。对于sync
属性,它将其分解为属性和事件处理程序,对于on
处理程序,它会添加适当的事件处理程序。
以下是此工作的一个示例。
console.clear()
Vue.component("some-thing", {
props: ["volume","text","color"],
template: `
<div>
<span :style="{color}">{{text}}</span>
<input :value="volume" @input="$emit('update:volume', $event.target.value)" />
<button @click="$emit('loaded')">Click me</button>
</div>
`
})
Vue.component("other-thing", {
template: `
<div>
<button @click="$emit('clicked')">Click me</button>
</div>
`
})
new Vue({
el: "#app",
data: {
modules: [{
name: 'some-thing',
props: {
color: '#0f0',
text: 'some text',
},
sync: {
"volume": "volume"
},
on: {
loaded: "handleLoaded"
}
},
{
name: 'other-thing',
on: {
clicked: "onClicked"
}
},
],
volume: "stuff"
},
methods: {
handleLoaded() {
alert('loaded')
},
onClicked() {
alert("clicked")
}
},
render(h) {
let components = []
let modules = Object.assign({}, this.modules)
for (let template of this.modules) {
let def = {
on: {},
props: {}
}
// add props
if (template.props) {
def.props = template.props
}
// add sync props
if (template.sync) {
for (let sync of Object.keys(template.sync)) {
// sync properties are just sugar for a prop and a handler
// for `updated:prop`. So here we add the prop and the handler.
def.on[`update:${sync}`] = val => this[sync] = val
def.props[sync] = this[template.sync[sync]]
}
}
// add handers
if (template.on) {
// for current purposes, the handler is a string containing the
// name of the method to call
for (let handler of Object.keys(template.on)) {
def.on[handler] = this[template.on[handler]]
}
}
components.push(h(template.name, def))
}
return h('div', components)
},
})
&#13;
<script src="https://unpkg.com/vue@2.2.6/dist/vue.js"></script>
<div id="app"></div>
&#13;