首页 > 解决方案 > 为什么这个简单的 VueJS 组件模板渲染在 DOM 中不正确的位置,在表格上方?

问题描述

下面提供的示例不是实际有问题的代码,而是尽可能接近简化的案例,以便在此处进行讨论。


破碎的例子

以下代码呈现一个表格,但意外地将组件值放在表格元素上方,无论是在视觉上还是在我在 DOM 中检查它时:

<html>
<head><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script></head>
<body>
  <div id="app">

    <table border="1">
        <tr><td>A</td><td>B</td></tr>
        <test></test>
        <tr><td>Y</td><td>Z</td></tr>
    </table>

  </div>

  <script>
    const Test = {
      template: '<tr><td>ONE</td><td>TWO</td></tr>'
    }

    const app = new Vue({
      el: '#app',
      components: { Test },
    });
  </script>
</body>
</html>

渲染输出:

VueJS 组件出现在表格之前

检查的DOM:

DOM 显示 Component 在根元素之上

一个类似的例子,但有效

但是,VueJS 似乎对其他嵌套对象没有问题。以下工作正常。这是同样的事情,但有一个列表:

<html>
<head><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script></head>
<body>

  <div id="app">
    <ul>
      <li>TOP</li>
      <test></test>
      <li>BOTTOM</li>
    </ul>
  </div>

  <script>

    const Test = {
      template: '<li>MIDDLE</li>'
    }

    const app = new Vue({
      el: '#app',
      components: { Test },
    });

  </script>
</body>
</html>

在高层次上,它们在结构上似乎是相同的——一个包含三个项目的容器。在第一种情况下,它是一个包含行(损坏)的表格,在第二种情况下,它是一个包含项目(作品)的列表。

问题

有人可以解释这种行为,引擎盖下发生了什么,理想情况下如何解决?

实际问题的背景

实际代码涉及具有表头 ( thead) 部分和标题行 ( tr) 的表格,而组件数据出现在表体 ( tbody) 内部,出于各种原因,我不想用其他组件污染页面,也不更改现有组件代码。


有用的一边

虽然不相关,但对于同船的读者来说,我是偶然发现的<test/><test></test>并不是一回事。实际上,如果您使用上面的工作案例并尝试一下,您会发现最后一个元素丢失了。跳到 VueJS 并阅读关于self-close-components 的内容,因为只有官方的“void”元素可以自关闭。

标签: htmlvue.js

解决方案


此问题与Vue.js中的DOM 模板解析有关。如文档中所述:

一些 HTML 元素,例如<ul>,和对可以出现在其中的元素有限制<ol>,而一些元素例如,和只能出现在某些其他元素中。<table><select><li><tr><option>

当使用具有此类限制的元素的组件时,这将导致问题。例如:

<table>
   <blog-post-row></blog-post-row>
</table>

自定义组件<blog-post-row>将作为无效内容被吊出,导致最终呈现的输出出现错误。

这与您面临的完全相同的问题,正如您的演示中<Test>所呈现的那样。table幸运的是,is特殊属性提供了解决此问题的方法。您只需要<Test>在父组件内部调用,例如:

<table border="1">
    <tr><td>A</td><td>B</td></tr>
    <tr is="test"></tr>
    <tr><td>Y</td><td>Z</td></tr>
</table>

工作演示:

const Test = {
  template: '<tr><td>ONE</td><td>TWO</td></tr>'
}

const app = new Vue({
  el: '#app',
  components: {
    Test
  },
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet">
<div id="app">

  <table class="table">
    <tr>
      <td>A</td>
      <td>B</td>
    </tr>
    <tr is="test"></tr>
    <tr>
      <td>Y</td>
      <td>Z</td>
    </tr>
    
  </table>

</div>


推荐阅读