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:29erreur 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?
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.
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>
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.
Pour une réponse plus complète: http://www.compulsivecoders.com/tech/vuejs-component-template-should-contain-exactly-one-root-element/
Mais fondamentalement:
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>
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/