Vue 3:从其他组件设置动态组件

Vue 3: set dynamic component from other component

我有一个显示组件(app-display),里面有动态组件(默认:app-empty):

    app.component('appDisplay', {
        template: `<component :is="currentComponent"></component>`,
        data() {
            return {currentComponent: 'appEmpty'}
        }
    });

我需要创建 app-message 的新实例,为该实例设置 属性 message,并在单击按钮时将该实例设置为 app-display 的当前组件.

这是问题的浏览器代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue component reference</title>
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="app"></div>
<script>
    // main application with button & display panel
    const app = self.Vue.createApp({
        template: `
          <app-btn></app-btn>
          <app-display></app-display>
        `
    });

    // button component to fire action
    app.component('appBtn', {
        template: `
          <button v-on:click="setDisplay">Display message</button>`,
        methods: {
            setDisplay() {
                console.log('I need to set "appMessage" (with some "message" param) as inner component to "app-display" here.');
            }
        }
    });

    // component with dynamic component inside
    app.component('appDisplay', {
        template: `<component :is="currentComponent"></component>`,
        data() {
            return {currentComponent: 'appEmpty'}
        }
    });

    // default component to display
    app.component('appEmpty', {
        template: `<div>I'm empty.</div>`
    });

    // this component with custom message should be displayed on button click
    app.component('appMessage', {
        template: `
          <div>{{ message }}</div>
        `,
        props: {
            message: String
        }
    });
    // mount main app to the page
    app.mount('#app');
</script>
</body>
</html>

如何从 app-btn 访问 app-display

您应该从按钮组件向主组件发出一个事件,其中包含要显示的组件名称和消息,并且在主组件中您应该定义一条消息和当前组件名称,该名称将由发出的事件的处理程序更新,并且作为道具传递给显示它们的组件:

   // main application with button & display panel
    const app = self.Vue.createApp({
        template: `
          <app-btn @change-content="changeContent"></app-btn>
          <app-display :currentComponent="componentName" :message="msg"></app-display>
        `,
        data(){
         return{
            componentName:'appEmpty',
            msg:''
         }
        },
        methods:{
           changeContent(compName,msg){
           console.log(compName,msg)
             this.componentName=compName
             this.msg=msg
           }
        }
    });

    // button component to fire action
    app.component('appBtn', {
        template: `
          <button v-on:click="setDisplay">Display message</button>`,
        methods: {
            setDisplay() {
            this.$emit('change-content','appMessage','Hello message :)')
            
            }
        }
    });

    // component with dynamic component inside
    app.component('appDisplay', {
        props:{
        currentComponent:{
             type:String,
             default:'appEmpty'
           }
        },
        template: `<component :is="currentComponent"></component>`,
      
    });

    // default component to display
    app.component('appEmpty', {
        template: `<div>I'm empty.</div>`
    });

    // this component with custom message should be displayed on button click
    app.component('appMessage', {
        template: `
          <div>{{ message }}</div>
        `,
        props: {
            message: String
        }
    });
    // mount main app to the page
    app.mount('#app');
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue component reference</title>
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="app"></div>

</body>
</html>