我正在使用Typescript编写VueJS(2.5.22)应用程序,并尝试在运行时动态添加组件。我遇到了Typescript的两个问题。将子组件添加为命名插槽,并订阅以从子组件发出事件。我可以通过添加子组件来解决插槽问题,但是我想使用命名插槽。感谢插槽上的任何输入。
我仍在尝试解决父组件订阅子事件并更新父组件属性的第二个问题。
子组件将发出“更新值”。如何在父组件上动态订阅此事件?
谢谢
请为以下项目创建标签:vuejs组件vuejs-动态组件vuejs-typescript vuejs-emit
parent component adding dynamically at run-time in created method
<div>
<p>Dynamic components</p>
<div ref="controls"></div>
</div>
export default class ParentComponent extends Vue {
public $refs: Vue['$refs'] & {
controls: HTMLElement
}
public $slots: Vue['$slots'] & {
TextBox: TextBox
}
vuejs created method
--------------------
const labelControlContainerClass = Vue.extend(LabelControlContainer)
const textBoxClass = Vue.extend(TextBox)
const fields = table.fields
for (const key in fields) {
if (fields.hasOwnProperty(key)) {
const element = fields[key]
if (element.fieldType === 'Char') {
const textBoxInstance = new textBoxClass({
// props
propsData: {
value: '',
placeholder: element.translatedCaption,
name: key
},
// how to subscript to "update-value" event???
})
textBoxInstance.$mount()
const instance = new labelControlContainerClass({
// props
propsData: {
caption: element.translatedCaption,
bold: false
},
})
instance.$mount()
instance.$el.appendChild(textBoxInstance.$el) // add child component, try adding named slots, but didn't work
this.$refs.controls.appendChild(instance.$el)
}
}
}
}
label component with slot. named slot didn't worked
<template>
<div class="controlContainer" :class="{vertial: labelTop}">
<span v-bind:class="{bold: bold}" class=".controlContainer__cisLabel">{{caption}}</span>
<slot name='control'></slot>
<slot></slot>
</div>
</template>
<script lang='ts'>
import Vue from 'vue'
import { Component, Prop } from 'vue-property-decorator'
@Component({
})
export default class LabelControlContainer extends Vue {
@Prop({ type: String, default: '' }) public caption: string
@Prop({ type: Boolean, default: true }) public bold: boolean
@Prop({ type: Boolean, default: false }) public labelTop: boolean
}
</script>
child component that is going to added to slot and emit on value change
export default class TextBox extends Vue {
@Prop({ type: String, default: 'placeholder text' }) public placeholder: string
@Prop({ type: Object, default: () => ({}) }) public attributes: any
@Prop({ type: Boolean, default: false }) public readonly: boolean
@Prop({ type: String, default: 'text' }) public mode: string
@Prop({ type: Boolean, default: true }) public isValid: boolean
@Prop({ type: String, default: '' }) public value: string
@Prop({ type: String, default: '' }) public name: string
@Prop({ type: Boolean, default: false }) public setFocus: boolean
private default = {}
private unlockable: boolean = this.readonly
private valueChanged(data: any): void {
this.$emit('update-value', data.value, this.name)
}
}
答案 0 :(得分:0)
我不使用TypeScript,但我认为这与TypeScript无关,因此我将使用普通JavaScript进行回答。
要以编程方式添加slot
元素,可以使用$slots
属性,如下所示:
vm.$slots.default = ['Hello']
vm.$slots. foo = ['Hello'] // for named slots
…但是不幸的是,插槽必须是VNode
的数组,而不是普通的DOM元素或Vue组件。您可以使用$createElement
方法来创建它们,如下所示:
vm.$slots.default = [vm.$createElement('div', ['Hello'])]
vm.$slots.default = [vm.$createElement('HelloWorld')] // custom component
因此您的代码将如下所示:
const TextBox = {
template: `
<div>{{ text }}</div>
`,
props: ['text']
}
const LabelControl = {
template: `
<div>
<slot name='control'></slot>
</div>
`,
components: {
TextBox
}
}
const LabelControlComponent = Vue.extend(LabelControl)
new Vue({
el: '#app',
template: `
<div>
<div ref='controls'></div>
</div>
`,
mounted () {
let texts = ['a', 'b', 'c', 'd']
texts.forEach(text => {
let labelControl = new LabelControlComponent()
labelControl.$slots.control = [
labelControl.$createElement('TextBox', {
props: { text }
})
]
labelControl.$mount()
this.$refs.controls.appendChild(labelControl.$el)
})
}
})
听取来自slot
子级的事件似乎是不可能的,因为它的作用域不同,但是您仍然可以使用$parent
属性直接调用父级方法或从父级发出事件。 / p>
const TextBox = {
template: `
<div @click='$parent.show(text)'>{{ text }}</div>
`
}
const LabelControl = {
methods: {
show (text) {
this.text = text
}
}
}
参考文献: