【问题标题】:Nuxt: Mounting dynamic components to the DOM that is not rendered yetNuxt:将动态组件挂载到尚未渲染的 DOM
【发布时间】:2024-01-08 11:42:01
【问题描述】:

场景:
我在universal 模式下使用 Nuxt。该应用程序与一个无头 CMS 配合使用,该 CMS 提供了应呈现的组件的简单布局,以及组件名称及其道具 - 如下所示:

[
  {
    "tag": "div",
    "class": "col",
    "component": "dogs",
    "props": {
      "dogs": [
        {
          "id": 1,
          "name": "Barky"
        },
        {
           "id": 2,
           "name": "Jumpy"
        }
      ]
     }
   },
   {
    "tag": "div",
    "class": "col",
    "component": "cats",
    "props": {
      "cats": [
        {
           "id": 1,
           "name": "Miouwy"
        },
        {
           "id": 2,
           "name": "Fluffy"
        }
      ]
    }
  }
]

据我了解,我必须在 Nuxt 制作“快照”并将其交付给客户端之前将组件应用到 DOM。我的计划是在created() 生命周期中挂载组件——也就是说,只看名称,而不是要走的路。

主要问题:
我想将组件动态挂载到尚不存在的 DOM。


作为我想逃避的事情的一个例子 - 在 Nuxt 交付快照之后安装组件 - 在 mounted() 生命周期中。

<template>
  <section class="container">
    <div ref="layout-container" class="row"></div>
  </section>
</template>

<script>
  import { mapGetters } from 'vuex';
  import Vue from 'vue';
  import Dogs from '@/components/Dogs';
  import Cats from '@/components/Cats';

  export default {
    components: {
      Dogs,
      Cats
    },
    fetch({ store }) {
      store.dispatch('landing/updateContent');
    },
    computed: {
      ...mapGetters({
        content: 'landing/content',
      })
    },
    beforeCreate() {
      Vue.component('dogs', Dogs);
      Vue.component('cats', Cats);
    },
    mounted() {
      this.content.forEach((item) => {
        const CompClass = Vue.component(item.component);
        const instance = new CompClass({ propsData: item.props }).$mount();
        this.$refs['layout-container'].appendChild(instance.$el);
      })
    }
  };
</script>

非常感谢您提前提供任何指示!

编辑:回购这个例子:https://github.com/jpedryc/nuxt-test-render

【问题讨论】:

    标签: vue.js content-management-system vuex server-side-rendering nuxt.js


    【解决方案1】:

    尝试使用dynamic components 实现此功能

    模板:

    <component :is="item.component" />
    

    脚本:

    components: { cats: Cats, dogs: Dogs },
    

    那么你就不需要直接的 DOM 操作技巧了。当 Nuxt 在服务器上运行时(因为您在服务器上没有真正的 DOM),这将无法工作,并且还会阻止反应系统获取 pets 数组中的更改。

    【讨论】:

    • 感谢您的帮助。这个解决方案在定义的布局中会很好,但是上面的 items 数组是定义多个组件的多级对象数组(带有“子”键)的简化。我认为解决此问题的最佳方法是在将 DOM 提供给客户端之前尝试在服务器端渲染 DOM。
    【解决方案2】:

    解决方案
    我的主要问题是创建渲染布局并在 DOM 已交付给客户端后尝试将其连接起来。相反,我应该在虚拟 Vue DOM 中渲染组件——就在“快照”时刻之前。

    这就是我最终所做的——不安装渲染的组件:

    <template>
      <section class="container">
        <page-component/> <!-- A component without <template>, but with render() -->
      </section>
    </template>
    

    PageComponent 仅包含:

    import ...
    
    export default {
      components: {
        Dogs,
        Cats,
      },
      beforeCreate() {
        Vue.component('dogs', Dogs);
        Vue.component('cats', Cats);
      },
      render: function (h) {
        return createDynamicLayout(h);
      },
    }
    

    createDynamicLayout(h) 只是一个创建树的简单函数:

    return h('div', { 'class': 'row' }, [
      h('div', { 'class': 'col' }, h(<somwhere_call_dogs_component>)),
      h('div', { 'class': 'col' }, h(<somwhere_call_cats_component>)),
    ])
    

    【讨论】: