web-dev-qa-db-fra.com

Vue js error: le modèle de composant doit contenir exactement un élément racine

Je ne sais pas quelle est l'erreur, jusqu'à présent, je teste via le journal de la console pour vérifier les modifications après la sélection d'un fichier (pour le téléchargement).

Quand je lance $ npm run watch, j'obtiens l'erreur suivante:

"Webpack regarde les fichiers…

95% émettant 

ERREUR Echec de la compilation avec 1 erreur
19:42:29

erreur dans ./resources/assets/js/components/File.vue

(Valeur émise au lieu d'une instance de Error) Syntaxe du modèle Vue Erreur:

Le modèle de composant doit contenir exactement un élément racine. Si vous utilisez v-if sur plusieurs éléments, utilisez v-else-if pour les chaîner au lieu.

@ ./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 "

Mon File.vue est

<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>

Des idées sur la façon de résoudre ceci? Quelle est en réalité l'erreur?

25
Pathros

Vous avez deux éléments racine dans votre modèle.

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

Et vous en avez besoin d'un.

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

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

Essentiellement dans Vue, vous devez n'avoir qu'un seul élément racine dans vos modèles.

69
Bert

Vous devez envelopper tout le code HTML dans un seul élément.

<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>
13
Hamoud

si, pour une raison quelconque, vous ne souhaitez pas ajouter de wrapper (dans mon premier cas, c'était pour les composants <tr/>), vous pouvez utiliser un composant fonctionnel.

Au lieu d'avoir un seul components/MyCompo.vue, vous aurez quelques fichiers dans un dossier components/MyCompo:

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

Avec cette structure, la façon dont vous appelez votre composant ne changera pas.

components/MyCompo/index.js contenu du fichier:

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) } )
    ]; 
  }
};

Et si vous avez des fonctions ou des données utilisées dans les deux modèles, transmettez-les en tant que propriétés et le tour est joué!

Je vous laisse imaginer la construction d’une liste de composants et de nombreuses fonctionnalités avec ce modèle.

6
blobmaster

Pour une réponse plus complète: http://www.compulsivecoders.com/tech/vuejs-component-template-should-contain-exactly-one-root-element/

Mais fondamentalement:

  • Actuellement, un modèle VueJS ne peut contenir qu'un seul élément racine (en raison d'un problème de rendu)
  • Dans les cas où vous avez réellement besoin de deux éléments racine, car la structure HTML ne vous permet pas de créer un élément parent enveloppant, vous pouvez utiliser vue-fragment .

Pour l'installer:

npm install vue-fragment

Pour l'utiliser:

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

// or

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

Ensuite, dans votre composant:

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

Le modèle de composant doit contenir exactement un élément racine. Si vous utilisez v-if sur plusieurs éléments, utilisez plutôt v-else-if pour les chaîner.

La bonne approche est

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

La mauvaise approche

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

Composants multi-racines

La solution à ce problème consiste à utiliser des composants fonctionnels. Ce sont des composants pour lesquels vous ne devez transmettre aucune donnée réactive. Ainsi, le composant ne surveille pas les modifications de données et ne se met pas à jour automatiquement lorsque quelque chose change dans le composant parent.

Comme il s’agit d’une solution de rechange qui a un prix, les composants fonctionnels ne sont pas liés au cycle de vie, ils sont moins nombreux et vous ne pouvez plus vous référer à this et tout est passé avec le contexte.

Voici comment créer un composant fonctionnel simple.

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) {
    // ...
  }
})

Maintenant que nous avons couvert en détail les composants fonctionnels, expliquons comment créer des composants racine multiples. Pour cela, je vais vous présenter un exemple générique.

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

Maintenant, regardons le template NavBarRoutes

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

Nous ne pouvons pas faire quelque chose comme ça, nous allons violer la restriction d'un seul composant racine

Solution Rendre ce composant fonctionnel et utiliser le rendu

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

Voilà, vous avez créé un composant multi-racine, Happy coding

Référence pour plus de détails, visitez: https://blog.carbonteq.com/vuejs-create-multi-root-components/

0
Farwa Saddique