具有同步和事件的动态 Vue 组件
Dynamic Vue components with sync and events
我在 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
'd 道具),但我不知道是否可以不创建自定义指令。
我试过像这样添加到我的 props
对象,但没有成功:
props: {
color: '#f3f',
text: 'some other text',
'v-on:loaded': 'handleLoaded', // no luck
'volume.sync': 'someValue', // no luck
},
我的目标是让用户使用 vuedraggable
对侧边栏中的小部件进行重新排序,并将他们的布局偏好保存到数据库中,但一些小部件有 @event
s 和 .sync
ed prop
s。这可能吗?我欢迎任何建议!
我不知道有什么方法可以使用动态组件完成此操作。但是,您可以使用渲染函数来完成。
考虑这个数据结构,它是你的修改。
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 方法会查看 modules
中 template
中的所有属性,以决定如何呈现组件。对于属性,它只是传递它们。对于 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)
},
})
<script src="https://unpkg.com/vue@2.2.6/dist/vue.js"></script>
<div id="app"></div>
我在 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
'd 道具),但我不知道是否可以不创建自定义指令。
我试过像这样添加到我的 props
对象,但没有成功:
props: {
color: '#f3f',
text: 'some other text',
'v-on:loaded': 'handleLoaded', // no luck
'volume.sync': 'someValue', // no luck
},
我的目标是让用户使用 vuedraggable
对侧边栏中的小部件进行重新排序,并将他们的布局偏好保存到数据库中,但一些小部件有 @event
s 和 .sync
ed prop
s。这可能吗?我欢迎任何建议!
我不知道有什么方法可以使用动态组件完成此操作。但是,您可以使用渲染函数来完成。
考虑这个数据结构,它是你的修改。
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 方法会查看 modules
中 template
中的所有属性,以决定如何呈现组件。对于属性,它只是传递它们。对于 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)
},
})
<script src="https://unpkg.com/vue@2.2.6/dist/vue.js"></script>
<div id="app"></div>