Javascript Vue公司JS错误:组件模板应该只包含一个根元素

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/45000510/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 02:51:31  来源:igfitidea点击:

Vue js error: Component template should contain exactly one root element

javascriptnode.jslaravelvue.js

提问by Pathros

I don't know what the error is, so far I am testing through console log to check for changes after selecting a file (for uploading).

我不知道错误是什么,到目前为止,我正在通过控制台日志进行测试,以在选择文件(用于上传)后检查更改。

When I run $ npm run watch, i get the following error:

当我运行时$ npm run watch,出现以下错误:

"Webpack is watching the files…

95% emitting

ERROR Failed to compile with 1 errors
19:42:29

error in ./resources/assets/js/components/File.vue

(Emitted value instead of an instance of Error) Vue template syntax error:

Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead.

@ ./resources/assets/js/components/AvatarUpload.vue 5:2-181 @ ./resources/assets/js/app.js @ multi ./resources/assets/js/app.js ./resources/assets/sass/app.scss"

“Webpack 正在监视文件......

95% 排放

错误 无法编译,出现 1 个错误
19:42:29

./resources/assets/js/components/File.vue 中的错误

(Emitted value 而不是 Error 的实例) Vue 模板语法错误:

组件模板应该只包含一个根元素。如果您在多个元素上使用 v-if,请改用 v-else-if 来链接它们。

@ ./resources/assets/js/components/AvatarUpload.vue 5:2-181 @ ./resources/assets/js/app.js @ multi ./resources/assets/js/app.js ./resources/assets/ sass/app.scss"

My File.vue is

我的 File.vue 是

<template>
        <div class="form-group">
            <label for="avatar" class="control-label">Avatar</label>
            <input type="file" v-on:change="fileChange" id="avatar">
            <div class="help-block">
                Help block here updated 4  ...
            </div>
        </div>

        <div class="col-md-6">
            <input type="hidden" name="avatar_id">
            <img class="avatar" title="Current avatar">
        </div>
</template>

<script>
    export default{
        methods: {
            fileChange(){
                console.log('Test of file input change')
            }
        }
    }
</script>

Any ideas on how to solve this? What is actually the error?

关于如何解决这个问题的任何想法?实际上是什么错误?

回答by Bert

You have two root elements in your template.

您的模板中有两个根元素。

<div class="form-group">
  ...
</div>
<div class="col-md-6">
  ...
</div>

And you need one.

你需要一个。

<div>
    <div class="form-group">
      ...
    </div>

    <div class="col-md-6">
      ...
    </div>
</div>

Essentially in Vue you musthave only one root element in your templates.

基本上在 Vue中,你的模板中必须只有一个根元素

回答by Hamoud

You need to wrap all the html into one single element.

你需要用所有的HTML到一个单一的元素。

<template>
   <div>
        <div class="form-group">
            <label for="avatar" class="control-label">Avatar</label>
            <input type="file" v-on:change="fileChange" id="avatar">
            <div class="help-block">
                Help block here updated 4  ...
            </div>
        </div>

        <div class="col-md-6">
            <input type="hidden" name="avatar_id">
            <img class="avatar" title="Current avatar">
        </div>
   </div>

</template>

<script>
    export default{
        methods: {
            fileChange(){
                console.log('Test of file input change')
            }
        }
    }
</script>

回答by Charles Bochet

For a more complete answer: http://www.compulsivecoders.com/tech/vuejs-component-template-should-contain-exactly-one-root-element/

更完整的答案:http: //www.compulsivecoders.com/tech/vuejs-component-template-should-contain-exactly-one-root-element/

But basically:

但基本上:

  • Currently, a VueJS template can contain only one root element (because of rendering issue)
  • In cases you really need to have two root elements because HTML structure does not allow you to create a wrapping parent element, you can use vue-fragment.
  • 目前,一个 VueJS 模板只能包含一个根元素(因为渲染问题)
  • 如果你真的需要有两个根元素,因为 HTML 结构不允许你创建一个包装父元素,你可以使用vue-fragment

To install it:

要安装它:

npm install vue-fragment

To use it:

要使用它:

import Fragment from 'vue-fragment';
Vue.use(Fragment.Plugin);

// or

import { Plugin } from 'vue-fragment';
Vue.use(Plugin);

Then, in your component:

然后,在您的组件中:

<template>
  <fragment>
    <tr class="hola">
      ...
    </tr>
    <tr class="hello">
      ...
    </tr>
  </fragment>
</template>

回答by blobmaster

if, for any reasons, you don't want to add a wrapper (in my first case it was for <tr/>components), you can use a functionnal component.

如果出于任何原因,您不想添加包装器(在我的第一种情况下是用于<tr/>组件),则可以使用功能组件。

Instead of having a single components/MyCompo.vueyou will have few files in a components/MyCompofolder :

components/MyCompo.vue一个components/MyCompo文件夹中将有几个文件,而不是一个:

  • components/MyCompo/index.js
  • components/MyCompo/File.vue
  • components/MyCompo/Avatar.vue
  • components/MyCompo/index.js
  • components/MyCompo/File.vue
  • components/MyCompo/Avatar.vue

With this structure, the way you call your component won't change.

使用这种结构,您调用组件的方式不会改变。

components/MyCompo/index.jsfile content :

components/MyCompo/index.js文件内容:

import File from './File';
import Avatar from './Avatar';   

const commonSort=(a,b)=>b-a;

export default {
  functional: true,
  name: 'MyCompo',
  props: [ 'someProp', 'plopProp' ],
  render(createElement, context) {
    return [
        createElement( File, { props: Object.assign({light: true, sort: commonSort},context.props) } ),
        createElement( Avatar, { props: Object.assign({light: false, sort: commonSort},context.props) } )
    ]; 
  }
};

And if you have some function or data used in both templates, passed them as properties and that's it !

如果您在两个模板中都使用了一些函数或数据,请将它们作为属性传递,就是这样!

I let you imagine building list of components and so much features with this pattern.

我让你想象用这种模式构建组件列表和这么多功能。

回答by Farwa Saddique

Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead.

组件模板应该只包含一个根元素。如果您在多个元素上使用 v-if,请改用 v-else-if 来链接它们。

The right approach is

正确的做法是

<template>
  <div> <!-- The root -->
    <p></p> 
    <p></p>
  </div>
</template>

The wrong approach

错误的做法

<template> <!-- No root Element -->
    <p></p> 
    <p></p>
</template>

Multi Root Components

多根组件

The way around to that problem is using functional components, they are components where you have to pass no reactive data means component will not be watching for any data changes as well as not updating it self when something in parent component changes.

解决这个问题的方法是使用功能组件,它们是您必须传递无反应数据的组件,这意味着组件不会监视任何数据更改,也不会在父组件中的某些内容发生更改时自行更新。

As this is a work around it comes with a price, functional components don't have any life cycle hooks passed to it, they are instance less as well you cannot refer to thisanymore and everything is passed with context.

由于这是一个有代价的解决方法,功能组件没有任何生命周期钩子传递给它,它们的实例更少,你不能再引用this,所有的东西都通过上下文传递。

Here is how you can create a simple functional component.

以下是创建简单功能组件的方法。

Vue.component('my-component', {
    // you must set functional as true
  functional: true,
  // Props are optional
  props: {
    // ...
  },
  // To compensate for the lack of an instance,
  // we are now provided a 2nd context argument.
  render: function (createElement, context) {
    // ...
  }
})

Now that we have covered functional components in some detail lets cover how to create multi root components, for that I am gonna present you with a generic example.

现在我们已经详细介绍了功能组件,让我们介绍如何创建多根组件,为此我将向您展示一个通用示例。

<template>
 <ul>
     <NavBarRoutes :routes="persistentNavRoutes"/>
     <NavBarRoutes v-if="loggedIn" :routes="loggedInNavRoutes" />
     <NavBarRoutes v-else :routes="loggedOutNavRoutes" />
 </ul>
</template>

Now if we take a look at NavBarRoutes template

现在,如果我们看一下 NavBarRoutes 模板

<template>
 <li
 v-for="route in routes"
 :key="route.name"
 >
 <router-link :to="route">
 {{ route.title }}
 </router-link>
 </li>
</template>

We cant do some thing like this we will be violating single root component restriction

我们不能做这样的事情,我们将违反单个根组件限制

SolutionMake this component functional and use render

解决方案使该组件具有功能并使用渲染

{
functional: true,
render(h, { props }) {
 return props.routes.map(route =>
  <li key={route.name}>
    <router-link to={route}>
      {route.title}
    </router-link>
  </li>
 )
}

Here you have it you have created a multi root component, Happy coding

至此,你已经创建了一个多根组件,Happy coding

Reference for more details visit: https://blog.carbonteq.com/vuejs-create-multi-root-components/

更多详情请参考:https: //blog.carbonteq.com/vuejs-create-multi-root-components/

回答by armyofda12mnkeys

I was confused as I knew VueJS should only contain 1 root element and yet I was still getting this same "template syntax error Component template should contain exactly one root element..." error on an extremely simple component. Turns out I had just mispelled </template> as </tempate> and that was giving me this same error in a few files I copied and pasted. In summary, check your syntax for any mispellings in your component.

我很困惑,因为我知道 VueJS 应该只包含 1 个根元素,但我仍然在一个非常简单的组件上遇到同样的“模板语法错误组件模板应该包含一个根元素......”错误。原来我刚刚将 </template> 拼错为 </tempate>,这在我复制和粘贴的几个文件中给了我同样的错误。总之,检查您的组件中是否有任何拼写错误的语法。

回答by Koko Monsef

instead of using this

而不是使用这个

Vue.component('tabs', {
    template: `
        <div class="tabs">
          <ul>
            <li class="is-active"><a>Pictures</a></li>
            <li><a>Music</a></li>
            <li><a>Videos</a></li>
            <li><a>Documents</a></li>
          </ul>
        </div>

        <div class="tabs-content">
          <slot></slot>
        </div>
    `,
});

you should use

你应该使用


Vue.component('tabs', {
    template: `
      <div>
        <div class="tabs">
          <ul>
            <li class="is-active"><a>Pictures</a></li>
            <li><a>Music</a></li>
            <li><a>Videos</a></li>
            <li><a>Documents</a></li>
          </ul>
        </div>

        <div class="tabs-content">
          <slot></slot>
        </div>
      </div>
    `,
});