首页 > 解决方案 > Vue 组件在“手动”多次使用时不会呈现......但在循环重复时有效

问题描述

我有如下代码。前 5 个组件正确渲染,但接下来的 3 个未正确渲染。仅呈现这 3 个中的第一个:

在此处输入图像描述

const test = {
  data() {
    return {
      count: 0
    };
  },
  props: {
    text: {
      type: Number,
      required: true
    }
  },
  template: `
    <button @click="count++">
      [ {{text}} ] You clicked me {{ count }} times.
    </button>
    `
};

const app = Vue.createApp({});
app.component("test", test);
app.mount("#app");
<!DOCTYPE html>
<html>
  <body>
    <div id="app">
      <div v-for="i in 5">
        <test :text="i" />
      </div>

      <hr />

      <test :text="99" />
      <test :text="42" />
      <test :text="55" />
    </div>

    <script
      id="vue"
      src="https://unpkg.com/vue@3.0.11/dist/vue.global.prod.js"
    ></script>
  </body>
</html>

显然......我希望能够不仅在循环中使用组件。我错过了什么?

顺便说一句,我能够用最新的 vue 2.x 重现同样的行为(vue 应用程序初始化代码略有不同,ofc)

标签: javascriptvue.jsvuejs3

解决方案


该问题是由自闭合元件引起的。请参阅下面的更新演示...

为什么

在 HTML5 规范中,仅允许在“void”元素上使用自闭合标签(Void 元素是那些可能不包含任何内容的元素 - asbrimg) - 请参阅这个 SO question - Are (non-void) self-closing tags valid在 HTML5 中?

因此,这里发生的情况是浏览器会解释您的无效 HTML(当页面加载时 - 甚至在 Vue 启动之前),就像这样(只需运行您的代码片段,注释掉app.mount()并在开发工具中检查 HTML):

    <div id="app">
      <div v-for="i in 5">
        <test :text="i"></test>
      </div>

      <hr>

      <test :text="99">
        <test :text="42">
          <test :text="55">
          </test>
        </test>
      </test>
    </div>

现在很容易看出为什么v-for工作正常,第一个组件渲染正常,但其余的不是(test组件没有默认插槽)

请注意,仅在使用 DOM 内模板并且与字符串模板(选项)或 SFC 文件(并且 Vue ESLint 规则和Vue 样式指南template实际上推荐使用自闭合标签)时,这才是问题

const test = {
  data() {
    return {
      count: 0
    };
  },
  props: {
    text: {
      type: Number,
      required: true
    }
  },
  template: `
    <button @click="count++">
      [ {{text}} ] You clicked me {{ count }} times.
    </button>
    `
};

const app = Vue.createApp({});
app.component("test", test);
app.mount("#app");
<!DOCTYPE html>
<html>
  <body>
    <div id="app">
      <div v-for="i in 5">
        <test :text="i"></test>
      </div>

      <hr />

      <test :text="99" ></test>
      <test :text="42" ></test>
      <test :text="55" ></test>
    </div>

    <script
      id="vue"
      src="https://unpkg.com/vue@3.0.11/dist/vue.global.prod.js"
    ></script>
  </body>
</html>


推荐阅读