Gérer les cas extrêmes
Cette page suppose que vous avez lu Bases des composants. Si vous ne savez pas encore grand-chose sur les composants, je vous recommande de le lire en premier.
Les fonctions enregistrées ici sont toutes liées à la gestion des cas extrêmes, c'est-à-dire certains cas particuliers qui nécessitent quelques petits ajustements aux règles de Vue. Veuillez cependant noter que ces fonctions présentent toutes des inconvénients ou des scénarios dangereux. Nous le noterons dans chaque cas, veuillez donc faire attention lorsque vous utilisez chaque fonction.
Répertoire
entre composants Une alternative aux références circulaires Définition du modèle
- Accéder aux éléments et composants
- Dans la grande majorité des cas, nous ferions mieux de ne pas accéder à l'intérieur d'une autre instance de composant ou manuellement manipuler des éléments du DOM. Mais il existe certainement des situations où il est approprié de faire ces choses.
// Vue 根实例 new Vue({ data: { foo: 1 }, computed: { bar: function () { /* ... */ } }, methods: { baz: function () { /* ... */ } } })
Tous les composants enfants peuvent accéder à cette instance ou l'utiliser comme magasin global.
// 获取根组件的数据 this.$root.foo // 写入根组件的数据 this.$root.foo = 2 // 访问根组件的计算属性 this.$root.bar // 调用根组件的方法 this.$root.baz()
C'est pratique pour les démos ou les très petites applications avec un petit nombre de composants. Cependant, ce modèle ne s’étend pas aux moyennes et grandes applications. Par conséquent, dans la plupart des cas, nous vous recommandons fortement d'utiliser Vuex pour gérer l'état de l'application.
Accès à l'instance du composant parent
Semblable à $root
, l'attribut $parent
peut être utilisé pour accéder au composant parent à partir d'un enfant Exemple de composant. Il offre la possibilité d'atteindre le composant parent à tout moment ultérieurement, au lieu de transmettre des données au composant enfant sous forme d'accessoires. $root
类似,$parent
属性可以用来从一个子组件访问父组件的实例。它提供了一种机会,可以在后期随时触达父级组件,以替代将数据以 prop 的方式传入子组件的方式。
在绝大多数情况下,触达父级组件会使得你的应用更难调试和理解,尤其是当你变更了父级组件的数据的时候。当我们稍后回看那个组件的时候,很难找出那个变更是从哪里发起的。
另外在一些可能适当的时候,你需要特别地共享一些组件库。举个例子,在和 JavaScript API 进行交互而不渲染 HTML 的抽象组件内,诸如这些假设性的 Google 地图组件一样:
<google-map> <google-map-markers v-bind:places="iceCreamShops"></google-map-markers> </google-map>
这个 <google-map>
组件可以定义一个 map
属性,所有的子组件都需要访问它。在这种情况下 <google-map-markers>
可能想要通过类似 this.$parent.getMap
的方式访问那个地图,以便为其添加一组标记。你可以在这里查阅这种模式。
请留意,尽管如此,通过这种模式构建出来的那个组件的内部仍然是容易出现问题的。比如,设想一下我们添加一个新的 <google-map-region>
组件,当 <google-map-markers>
在其内部出现的时候,只会渲染那个区域内的标记:
<google-map> <google-map-region v-bind:shape="cityBoundaries"> <google-map-markers v-bind:places="iceCreamShops"></google-map-markers> </google-map-region> </google-map>
那么在 <google-map-markers>
内部你可能发现自己需要一些类似这样的 hack:
var map = this.$parent.map || this.$parent.$parent.map
很快它就会失控。这也是我们针对需要向任意更深层级的组件提供上下文信息时推荐依赖注入的原因。
访问子组件实例或子元素
尽管存在 prop 和事件,有的时候你仍可能需要在 JavaScript 里直接访问一个子组件。为了达到这个目的,你可以通过 ref
特性为这个子组件赋予一个 ID 引用。例如:
<base-input ref="usernameInput"></base-input>
现在在你已经定义了这个 ref
this.$refs.usernameInput🎜Le composant
<google-map>
pourrait définir une carte
, tous les composants enfants doivent y accéder. Dans ce cas, <google-map-markers>
souhaitera peut-être accéder à cette carte via quelque chose comme this.$parent.getMap
afin d'ajouter un ensemble de marques. Vous pouvez consulter ce modèle ici 🎜. 🎜🎜Veuillez noter que, malgré cela, les composants internes du composant construit selon ce modèle sont toujours sujets à des problèmes. Par exemple, imaginez que nous ajoutions un nouveau composant <google-map-region>
et que lorsque <google-map-markers>
apparaisse à l'intérieur, seul le rendu sera effectué. marqueurs dans cette zone : 🎜<input ref="input">🎜 Ensuite, à l'intérieur de
<google-map-markers>
, vous pourriez avoir besoin d'un hack comme celui-ci : 🎜methods: { // 用来从父级组件聚焦输入框 focus: function () { this.$refs.input.focus() } }🎜 Cela peut devenir incontrôlable assez rapidement. C'est pourquoi nous recommandons l'injection de dépendances🎜 lorsque vous devez fournir des informations contextuelles à des composants plus profonds. raison. 🎜🎜🎜🎜
🎜🎜Accès aux instances ou sous-éléments de sous-composants🎜🎜🎜🎜Malgré l'existence d'accessoires et d'événements, vous pouvez parfois avoir besoin d'accéder à un sous-composant directement en JavaScript. Pour y parvenir, vous pouvez attribuer une référence d'ID au composant enfant via l'attribut ref
. Par exemple : 🎜
this.$refs.usernameInput.focus()🎜Maintenant dans le composant où vous avez défini cette
ref
, vous pouvez utiliser : 🎜<google-map> <google-map-region v-bind:shape="cityBoundaries"> <google-map-markers v-bind:places="iceCreamShops"></google-map-markers> </google-map-region> </google-map>
pour accéder à cette instance <base-input>
en cas d'urgence. Par exemple, concentrez par programme la zone de saisie à partir d’un composant parent. Dans l'exemple précédent, le composant <base-input>
peut également utiliser un ref
similaire pour donner accès à l'élément spécifié à l'intérieur, par exemple : <base-input>
实例,以便不时之需。比如程序化地从一个父级组件聚焦这个输入框。在刚才那个例子中,该 <base-input>
组件也可以使用一个类似的 ref
提供对内部这个指定元素的访问,例如:
provide: function () { return { getMap: this.getMap } }
甚至可以通过其父级组件定义方法:
inject: ['getMap']
这样就允许父级组件通过下面的代码聚焦 <base-input>
里的输入框:
// 一次性将这个日期选择器附加到一个输入框上 // 它会被挂载到 DOM 上。 mounted: function () { // Pikaday 是一个第三方日期选择器的库 this.picker = new Pikaday({ field: this.$refs.input, format: 'YYYY-MM-DD' }) }, // 在组件被销毁之前, // 也销毁这个日期选择器。 beforeDestroy: function () { this.picker.destroy() }
当 ref
和 v-for
一起使用的时候,你得到的引用将会是一个包含了对应数据源的这些子组件的数组。
$refs
只会在组件渲染完成之后生效,并且它们不是响应式的。这仅作为一个用于直接操作子组件的“逃生舱”——你应该避免在模板或计算属性中访问$refs
。
依赖注入
在此之前,在我们描述访问父级组件实例的时候,展示过一个类似这样的例子:
mounted: function () { var picker = new Pikaday({ field: this.$refs.input, format: 'YYYY-MM-DD' }) this.$once('hook:beforeDestroy', function () { picker.destroy() }) }
在这个组件里,所有 <google-map>
的后代都需要访问一个 getMap
方法,以便知道要跟哪个地图进行交互。不幸的是,使用 $parent
属性无法很好的扩展到更深层级的嵌套组件上。这也是依赖注入的用武之地,它用到了两个新的实例选项:provide
和 inject
。
provide
选项允许我们指定我们想要提供给后代组件的数据/方法。在这个例子中,就是 <google-map>
内部的 getMap
方法:
mounted: function () { this.attachDatepicker('startDateInput') this.attachDatepicker('endDateInput') }, methods: { attachDatepicker: function (refName) { var picker = new Pikaday({ field: this.$refs[refName], format: 'YYYY-MM-DD' }) this.$once('hook:beforeDestroy', function () { picker.destroy() }) } }
然后在任何后代组件里,我们都可以使用 inject
选项来接收指定的我们想要添加在这个实例上的属性:
name: 'unique-name-of-my-component'
你可以在这里看到完整的示例。相比 $parent
来说,这个用法可以让我们在任意后代组件中访问 getMap
,而不需要暴露整个 <google-map>
实例。这允许我们更好的持续研发该组件,而不需要担心我们可能会改变/移除一些子组件依赖的东西。同时这些组件之间的接口是始终明确定义的,就和 props
Vue.component('unique-name-of-my-component', { // ... })Even Les méthodes peuvent être définies via son composant parent :
name: 'stack-overflow', template: '<div><stack-overflow></stack-overflow></div>'Cela permet au composant parent de se concentrer sur la zone de saisie dans
<base-input>
via le code suivant : <p> <span>{{ folder.name }}</span> <tree-folder-contents :children="folder.children"/> </p>
ref < Lorsque /code> est utilisé avec v-for
, la référence que vous obtiendrez sera un tableau contenant ces sous-composants de la source de données correspondante. $refs
ne prendra effet qu'après le rendu du composant, et ils ne sont pas réactifs. Cela ne sert que de « trappe de secours » pour manipuler directement les composants enfants - vous devez éviter d'accéder à $refs
dans les modèles ou les propriétés calculées.
Injection de dépendances
🎜à Auparavant, lorsque nous avons décrit l'instance de composant parent d'accès, un exemple comme celui-ci a été affiché : 🎜<ul> <li v-for="child in children"> <tree-folder v-if="child.children" :folder="child"/> <span v-else>{{ child.name }}</span> </li> </ul>🎜Dans ce composant, tous les descendants de
<google-map>
doivent accéder à une méthode getMap
afin de savoir quoi suivre. Quelle carte interagir avec. Malheureusement, l'utilisation de l'attribut $parent
ne s'adapte pas bien aux composants imbriqués plus profonds. C'est là qu'intervient l'injection de dépendances, en utilisant deux nouvelles options d'instance : provide
et inject
. 🎜🎜L'option provide
nous permet de spécifier les données/méthodes que nous voulons fournir aux composants descendants. Dans cet exemple, il s'agit de la méthode getMap
à l'intérieur de <google-map>
: 🎜Failed to mount component: template or render function not defined.🎜 Ensuite, dans n'importe quel composant descendant, nous pouvons utiliser
inject< /code > option pour recevoir les attributs spécifiés que nous souhaitons ajouter sur cette instance : 🎜beforeCreate: function () {
this.$options.components.TreeFolderContents = require('./tree-folder-contents.vue').default
}
🎜 Vous pouvez les trouver ici Voir l'exemple complet. Par rapport à $parent
, cette utilisation nous permet d'accéder à getMap
dans n'importe quel composant descendant sans exposer l'intégralité de l'instance <google-map> code>. Cela nous permet de mieux continuer à développer le composant sans craindre de modifier/supprimer quelque chose dont dépendent les sous-composants. En même temps, l'interface entre ces composants est toujours clairement définie, tout comme props
. 🎜🎜En fait, vous pouvez considérer l'injection de dépendances comme une partie d'un "prop largement valide", sauf : 🎜🎜🎜🎜Le composant ancêtre n'a pas besoin de savoir quels composants descendants utilisent les propriétés qu'il fournit🎜🎜🎜🎜Le composant descendant n'a pas besoin de savoir d'où viennent les propriétés injectées🎜
做这件事都是不够好的。如果你想要共享的这个属性是你的应用特有的,而不是通用化的,或者如果你想在祖先组件中更新所提供的数据,那么这意味着你可能需要换用一个像 Vuex 这样真正的状态管理方案了。Cependant, l’injection de dépendance a toujours des effets négatifs. Il couple les composants de votre application à la façon dont ils sont actuellement organisés, ce qui rend la refactorisation plus difficile. De plus, les propriétés fournies ne répondent pas. C'est intentionnel, car les utiliser pour créer une échelle centralisée de données et utiliser
$root
pour ce faire ne sont pas suffisants. Si la propriété que vous souhaitez partager est spécifique à votre application plutôt que générique, ou si vous souhaitez mettre à jour les données fournies dans un composant ancêtre, cela signifie que vous devrez peut-être utiliser quelque chose comme Vuex est une véritable solution de gestion d'état.$root
你可以在 API 参考文档学习更多关于依赖注入的知识。
程序化的事件侦听器
现在,你已经知道了 $emit
的用法,它可以被 v-on
侦听,但是 Vue 实例同时在其事件接口中提供了其它的方法。我们可以:
通过
$on(eventName, eventHandler)
侦听一个事件通过
$once(eventName, eventHandler)
一次性侦听一个事件通过
$off(eventName, eventHandler)
停止侦听一个事件
你通常不会用到这些,但是当你需要在一个组件实例上手动侦听事件时,它们是派得上用场的。它们也可以用于代码组织工具。例如,你可能经常看到这种集成一个第三方库的模式:
components: { TreeFolderContents: () => import('./tree-folder-contents.vue') }
这里有两个潜在的问题:
它需要在这个组件实例中保存这个
picker
,如果可以的话最好只有生命周期钩子可以访问到它。这并不算严重的问题,但是它可以被视为杂物。我们的建立代码独立于我们的清理代码,这使得我们比较难于程序化地清理我们建立的所有东西。
你应该通过一个程序化的侦听器解决这两个问题:
<my-component inline-template> <div> <p>These are compiled as the component's own template.</p> <p>Not parent's transclusion content.</p> </div> </my-component>
使用了这个策略,我甚至可以让多个输入框元素同时使用不同的 Pikaday,每个新的实例都程序化地在后期清理它自己:
<script type="text/x-template" id="hello-world-template"> <p>Hello hello hello</p> </script> Vue.component('hello-world', { template: '#hello-world-template' })
查阅这个 fiddle 可以了解到完整的代码。注意,即便如此,如果你发现自己不得不在单个组件里做很多建立和清理的工作,最好的方式通常还是创建更多的模块化组件。在这个例子中,我们推荐创建一个可复用的 <input-datepicker>
🎜
Écouteur d'événements programmatique h2>
🎜Maintenant, vous connaissez déjà l'utilisation de $emit
, il peut être écouté par v-on
, mais l'instance Vue est également dans son interface d'événements. D'autres méthodes sont fourni. On peut : 🎜- 🎜Écouter un événement via
$on(eventName, eventHandler)
🎜🎜 - 🎜via< code>$once(eventName, eventHandler) Écoutez un événement à la fois🎜🎜
- 🎜Arrêtez d'écouter un événement via
$off(eventName, eventHandler)
🎜🎜🎜🎜 Ils ne sont normalement pas utilisés, mais ils s'avèrent utiles lorsque vous devez écouter manuellement des événements sur une instance de composant. Ils peuvent également être utilisés dans les outils d’organisation du code. Par exemple, vous pouvez souvent voir ce modèle d'intégration d'une bibliothèque tierce : 🎜Vue.component('terms-of-service', {
template: `
<div v-once>
<h1>Terms of Service</h1>
... a lot of static content ...
</div>
`
})
🎜Il y a deux problèmes potentiels ici : 🎜- 🎜Cela nécessite Save ce
picker
dans cette instance de composant afin que seuls les hooks de cycle de vie puissent y accéder si possible. Ce n’est pas un problème grave, mais cela peut être considéré comme du désordre. 🎜🎜 - 🎜Notre code de build est indépendant de notre code de nettoyage, ce qui rend plus difficile pour nous de nettoyer par programme tout ce que nous construisons. 🎜🎜🎜🎜Vous devriez résoudre les deux problèmes avec un auditeur programmatique : 🎜rrreee🎜En utilisant cette stratégie, je peux même avoir plusieurs éléments de zone de saisie utilisant différents Pikadays en même temps, à chaque nouvelle instance par programme. Il se nettoie plus tard : 🎜rrreee 🎜 Consultez ce violon pour le code complet. Notez que même ainsi, si vous devez effectuer beaucoup de travaux de configuration et de nettoyage dans un seul composant, il est généralement préférable de créer des composants plus modulaires. Dans cet exemple, nous vous recommandons de créer un composant
<input-datepicker>
réutilisable. 🎜Pour en savoir plus sur les auditeurs programmatiques, veuillez consulter les API associées aux Méthodes/événements d'instance.
Notez que le système d'événements de Vue est différent de l'EventTarget API du navigateur. Bien qu'ils fonctionnent de la même manière, $emit
, $on
et $off
ne sont pas des dispatchEvent
, des alias pour addEventListener
et removeEventListener
. $emit
、$on
, 和 $off
并不是 dispatchEvent
、addEventListener
和 removeEventListener
的别名。
循环引用
递归组件
组件是可以在它们自己的模板中调用自身的。不过它们只能通过 name
选项来做这件事:
rrreee当你使用 Vue.component
全局注册一个组件时,这个全局的 ID 会自动设置为该组件的 name
选项。
rrreee稍有不慎,递归组件就可能导致无限循环:
rrreee类似上述的组件将会导致“max stack size exceeded”错误,所以请确保递归调用是条件性的 (例如使用一个最终会得到 false
的 v-if
)。
组件之间的循环引用
假设你需要构建一个文件目录树,像访达或资源管理器那样的。你可能有一个 <tree-folder>
组件,模板是这样的:
rrreee还有一个 <tree-folder-contents>
组件,模板是这样的:
rrreee当你仔细观察的时候,你会发现这些组件在渲染树中互为对方的后代和祖先——一个悖论!当通过 Vue.component
Référence circulaire
Composant récursif
le composant est OK S'appelant dans leurs propres modèles. Cependant, ils ne peuvent le faire que via l'option name
:
rrreee🎜Lorsque vous utilisez Vue.component
pour enregistrer globalement un composant, l'ID global sera automatiquement défini sur The Option name
pour ce composant. 🎜rrreee🎜Si vous ne faites pas attention, les composants récursifs peuvent provoquer des boucles infinies : 🎜rrreee🎜Des composants comme ceux ci-dessus provoqueront des erreurs "Taille maximale de la pile dépassée", alors assurez-vous que l'appel récursif est conditionnel (par exemple, en utilisant un < code>v-if de false
). 🎜🎜
🎜Références circulaires entre composants🎜🎜Hypothèse dont vous avez besoin pour créer une arborescence de répertoires de fichiers, comme un Finder ou un Explorateur. Vous pouvez avoir un composant <tree-folder>
, le modèle ressemble à ceci : 🎜rrreee🎜 Il existe également un composant <tree-folder-contents>
, le Le modèle ressemble à ceci : 🎜rrreee🎜 Lorsque vous regardez attentivement, vous verrez que ces composants sont les descendants et les ancêtres les uns des autres dans l'arbre de rendu - un paradoxe ! Ce paradoxe est automatiquement résolu lorsque le composant est globalement enregistré via Vue.component
. Si c'est ce que vous faites, vous pouvez ignorer cela. 🎜🎜Cependant, si vous utilisez un système de modules pour dépendre/importer des composants, comme via webpack ou Browserify, vous rencontrerez une erreur : 🎜rrreee🎜Pour expliquer ce qui se passe ici, appelons d'abord les deux composants A et B . Le système de modules découvre qu'il a besoin de A, mais d'abord A dépend de B, mais B dépend de A, mais A dépend de B, et ainsi de suite. Cela devient une boucle et je ne sais pas comment analyser complètement l'un des composants sans passer par l'autre. Pour résoudre ce problème, nous devons donner au système de modules un point où "A nécessite B de toute façon, mais nous n'avons pas besoin d'analyser B en premier 🎜".
Dans notre exemple, définissez le composant <tree-folder>
sur ce point. Nous savons que le composant enfant à l'origine du paradoxe est le composant <tree-folder-contents>
, nous allons donc attendre le hook de cycle de vie beforeCreate
pour l'enregistrer : <tree-folder>
组件设为了那个点。我们知道那个产生悖论的子组件是 <tree-folder-contents>
组件,所以我们会等到生命周期钩子 beforeCreate
时去注册它:
rrreee或者,在本地注册组件的时候,你可以使用 webpack 的异步 import
:
rrreee这样问题就解决了!
模板定义的替代品
内联模板
当 inline-template
这个特殊的特性出现在一个子组件上时,这个组件将会使用其里面的内容作为模板,而不是将其作为被分发的内容。这使得模板的撰写工作更加灵活。
rrreee内联模板需要定义在 Vue 所属的 DOM 元素内。
不过,inline-template
会让模板的作用域变得更加难以理解。所以作为最佳实践,请在组件内优先选择 template
选项或 .vue
文件里的一个 <template>
元素来定义模板。
X-Template
另一个定义模板的方式是在一个 <script>
元素中,并为其带上 text/x-template
rrreee
Ou, lors de l'enregistrement local de composants, vous pouvez utiliser l'import
asynchrone de webpack : rrreee
Ce problème est résolu !
Remplacement des définitions de modèles
inline-template
lorsque inline-template < /code> Lorsque cet attribut spécial apparaît sur un composant enfant, le composant utilisera le contenu qu'il contient comme modèle au lieu de l'utiliser comme contenu à distribuer. Cela rend l’écriture de modèles plus flexible. rrreee
Les modèles en ligne doivent être définis dans l'élément DOM auquel appartient Vue.
Cependant, inline-template
rendra la portée du modèle plus difficile à comprendre. Ainsi, à titre de bonne pratique, veuillez sélectionner l'option template
dans le composant ou un élément <template>
dans le fichier .vue
pour définir le modèle. .
X-Template
Une autre façon de définir un modèle est dans un élément <script>
et de lui donner Apportez le type de text/x-template
, puis référencez le modèle via un identifiant. Par exemple : rrreeex-template doit être défini en dehors de l'élément DOM auquel appartient Vue.
🎜🎜Ceux-ci peuvent être utilisés pour des démos ou de très petites applications où le modèle est particulièrement volumineux, mais sinon évitez de l'utiliser car cela séparerait le modèle des autres définitions du composant. 🎜🎜🎜🎜🎜🎜🎜🎜Contrôlez les mises à jour🎜🎜🎜🎜🎜Grâce au système réactif de Vue, il sait toujours quand mettre à jour (si vous l'utilisez correctement). Cependant, il existe certains cas extrêmes dans lesquels vous souhaitez forcer une mise à jour même si les données réactives semblent n'avoir pas changé. Il existe également des situations dans lesquelles vous souhaitez empêcher les mises à jour inutiles. 🎜🎜🎜🎜🎜🎜🎜🎜Mise à jour forcée🎜🎜🎜🎜🎜Si vous devez effectuer une mise à jour forcée dans Vue, 99,9 % du temps, vous faites quelque chose de mal quelque part. 🎜🎜🎜Vous n'avez peut-être pas remarqué les considérations de détection des changements pour les 🎜Arrays🎜 ou les 🎜Objects🎜, ou vous comptez peut-être sur un état qui n'est pas suivi par le système réactif de Vue. 🎜Cependant, si vous avez effectué ce qui précède et constatez toujours que, dans de rares occasions, vous devez forcer une mise à jour manuellement, vous pouvez le faire via $forceUpdate
. $forceUpdate
来做这件事。
通过 v-once
创建低开销的静态组件
渲染普通的 HTML 元素在 Vue 中是非常快速的,但有的时候你可能有一个组件,这个组件包含了大量静态内容。在这种情况下,你可以在根元素上添加 v-once
特性以确保这些内容只计算一次然后缓存起来,就像这样:
rrreee再说一次,试着不要过度使用这个模式。当你需要渲染大量静态内容时,极少数的情况下它会给你带来便利,除非你非常留意渲染变慢了,不然它完全是没有必要的——再加上它在后期会带来很多困惑。例如,设想另一个开发者并不熟悉 v-once
Créez des composants statiques à faible surcharge avec v-once
Le rendu d'éléments HTML ordinaires dans Vue est très rapide, mais parfois vous pouvez avoir un composant qui contient beaucoup de contenu statique. Dans ce cas, vous pouvez ajouter l'attribut v-once
sur l'élément racine pour garantir que le contenu n'est calculé qu'une seule fois puis mis en cache, comme ceci : 🎜rrreee🎜Encore une fois, essayez Don' N’abusez pas de ce modèle. Dans les rares occasions où vous avez besoin de restituer beaucoup de contenu statique, cela vous apportera du confort, mais à moins que vous ne fassiez très attention au ralentissement du rendu, cela est complètement inutile - et cela causera également beaucoup de problèmes en post-Perplexe. Par exemple, imaginez qu'un autre développeur ne soit pas familier avec v-once
ou qu'il ne soit pas présent dans le modèle. Il peut passer de nombreuses heures à essayer de comprendre pourquoi le modèle ne se met pas à jour correctement. 🎜🎜🎜🎜🎜
$on(eventName, eventHandler)
🎜🎜$off(eventName, eventHandler)
🎜🎜🎜🎜 Ils ne sont normalement pas utilisés, mais ils s'avèrent utiles lorsque vous devez écouter manuellement des événements sur une instance de composant. Ils peuvent également être utilisés dans les outils d’organisation du code. Par exemple, vous pouvez souvent voir ce modèle d'intégration d'une bibliothèque tierce : 🎜Vue.component('terms-of-service', { template: ` <div v-once> <h1>Terms of Service</h1> ... a lot of static content ... </div> ` })🎜Il y a deux problèmes potentiels ici : 🎜
- 🎜Cela nécessite Save ce
picker
dans cette instance de composant afin que seuls les hooks de cycle de vie puissent y accéder si possible. Ce n’est pas un problème grave, mais cela peut être considéré comme du désordre. 🎜🎜 - 🎜Notre code de build est indépendant de notre code de nettoyage, ce qui rend plus difficile pour nous de nettoyer par programme tout ce que nous construisons. 🎜🎜🎜🎜Vous devriez résoudre les deux problèmes avec un auditeur programmatique : 🎜rrreee🎜En utilisant cette stratégie, je peux même avoir plusieurs éléments de zone de saisie utilisant différents Pikadays en même temps, à chaque nouvelle instance par programme. Il se nettoie plus tard : 🎜rrreee 🎜 Consultez ce violon pour le code complet. Notez que même ainsi, si vous devez effectuer beaucoup de travaux de configuration et de nettoyage dans un seul composant, il est généralement préférable de créer des composants plus modulaires. Dans cet exemple, nous vous recommandons de créer un composant
<input-datepicker>
réutilisable. 🎜Pour en savoir plus sur les auditeurs programmatiques, veuillez consulter les API associées aux Méthodes/événements d'instance.
Notez que le système d'événements de Vue est différent de l'EventTarget API du navigateur. Bien qu'ils fonctionnent de la même manière,
$emit
,$on
et$off
ne sont pas desdispatchEvent
, des alias pouraddEventListener
etremoveEventListener
.$emit
、$on
, 和$off
并不是dispatchEvent
、addEventListener
和removeEventListener
的别名。循环引用
递归组件
组件是可以在它们自己的模板中调用自身的。不过它们只能通过
rrreeename
选项来做这件事:当你使用
rrreeeVue.component
全局注册一个组件时,这个全局的 ID 会自动设置为该组件的name
选项。稍有不慎,递归组件就可能导致无限循环:
rrreee类似上述的组件将会导致“max stack size exceeded”错误,所以请确保递归调用是条件性的 (例如使用一个最终会得到
false
的v-if
)。组件之间的循环引用
假设你需要构建一个文件目录树,像访达或资源管理器那样的。你可能有一个
rrreee<tree-folder>
组件,模板是这样的:还有一个
rrreee<tree-folder-contents>
组件,模板是这样的:当你仔细观察的时候,你会发现这些组件在渲染树中互为对方的后代和祖先——一个悖论!当通过
Vue.component
Référence circulaire
Composant récursif
le composant est OK S'appelant dans leurs propres modèles. Cependant, ils ne peuvent le faire que via l'option
rrreee🎜Lorsque vous utilisezname
:Vue.component
pour enregistrer globalement un composant, l'ID global sera automatiquement défini sur The Optionname
pour ce composant. 🎜rrreee🎜Si vous ne faites pas attention, les composants récursifs peuvent provoquer des boucles infinies : 🎜rrreee🎜Des composants comme ceux ci-dessus provoqueront des erreurs "Taille maximale de la pile dépassée", alors assurez-vous que l'appel récursif est conditionnel (par exemple, en utilisant un < code>v-if defalse
). 🎜🎜
🎜Références circulaires entre composants🎜🎜Hypothèse dont vous avez besoin pour créer une arborescence de répertoires de fichiers, comme un Finder ou un Explorateur. Vous pouvez avoir un composant
<tree-folder>
, le modèle ressemble à ceci : 🎜rrreee🎜 Il existe également un composant<tree-folder-contents>
, le Le modèle ressemble à ceci : 🎜rrreee🎜 Lorsque vous regardez attentivement, vous verrez que ces composants sont les descendants et les ancêtres les uns des autres dans l'arbre de rendu - un paradoxe ! Ce paradoxe est automatiquement résolu lorsque le composant est globalement enregistré viaVue.component
. Si c'est ce que vous faites, vous pouvez ignorer cela. 🎜🎜Cependant, si vous utilisez un système de modules pour dépendre/importer des composants, comme via webpack ou Browserify, vous rencontrerez une erreur : 🎜rrreee🎜Pour expliquer ce qui se passe ici, appelons d'abord les deux composants A et B . Le système de modules découvre qu'il a besoin de A, mais d'abord A dépend de B, mais B dépend de A, mais A dépend de B, et ainsi de suite. Cela devient une boucle et je ne sais pas comment analyser complètement l'un des composants sans passer par l'autre. Pour résoudre ce problème, nous devons donner au système de modules un point où "A nécessite B de toute façon, mais nous n'avons pas besoin d'analyser B en premier 🎜".Dans notre exemple, définissez le composant
rrreee<tree-folder>
sur ce point. Nous savons que le composant enfant à l'origine du paradoxe est le composant<tree-folder-contents>
, nous allons donc attendre le hook de cycle de viebeforeCreate
pour l'enregistrer :<tree-folder>
组件设为了那个点。我们知道那个产生悖论的子组件是<tree-folder-contents>
组件,所以我们会等到生命周期钩子beforeCreate
时去注册它:或者,在本地注册组件的时候,你可以使用 webpack 的异步
rrreeeimport
:这样问题就解决了!
模板定义的替代品
内联模板
当
rrreeeinline-template
这个特殊的特性出现在一个子组件上时,这个组件将会使用其里面的内容作为模板,而不是将其作为被分发的内容。这使得模板的撰写工作更加灵活。内联模板需要定义在 Vue 所属的 DOM 元素内。
不过,
inline-template
会让模板的作用域变得更加难以理解。所以作为最佳实践,请在组件内优先选择template
选项或.vue
文件里的一个<template>
元素来定义模板。X-Template
另一个定义模板的方式是在一个
Ou, lors de l'enregistrement local de composants, vous pouvez utiliser l'<script>
元素中,并为其带上text/x-template
rrreeeimport
asynchrone de webpack :rrreee
Ce problème est résolu !
Remplacement des définitions de modèlesinline-template
lorsqueinline-template < /code> Lorsque cet attribut spécial apparaît sur un composant enfant, le composant utilisera le contenu qu'il contient comme modèle au lieu de l'utiliser comme contenu à distribuer. Cela rend l’écriture de modèles plus flexible.
rrreee
Les modèles en ligne doivent être définis dans l'élément DOM auquel appartient Vue.Cependant,
inline-template
rendra la portée du modèle plus difficile à comprendre. Ainsi, à titre de bonne pratique, veuillez sélectionner l'optiontemplate
dans le composant ou un élément<template>
dans le fichier.vue
pour définir le modèle. .X-Template
Une autre façon de définir un modèle est dans un élément
🎜🎜Ceux-ci peuvent être utilisés pour des démos ou de très petites applications où le modèle est particulièrement volumineux, mais sinon évitez de l'utiliser car cela séparerait le modèle des autres définitions du composant. 🎜🎜🎜🎜🎜🎜🎜🎜Contrôlez les mises à jour🎜🎜🎜🎜🎜Grâce au système réactif de Vue, il sait toujours quand mettre à jour (si vous l'utilisez correctement). Cependant, il existe certains cas extrêmes dans lesquels vous souhaitez forcer une mise à jour même si les données réactives semblent n'avoir pas changé. Il existe également des situations dans lesquelles vous souhaitez empêcher les mises à jour inutiles. 🎜🎜🎜🎜🎜🎜🎜🎜Mise à jour forcée🎜🎜🎜🎜🎜Si vous devez effectuer une mise à jour forcée dans Vue, 99,9 % du temps, vous faites quelque chose de mal quelque part. 🎜🎜🎜Vous n'avez peut-être pas remarqué les considérations de détection des changements pour les 🎜Arrays🎜 ou les 🎜Objects🎜, ou vous comptez peut-être sur un état qui n'est pas suivi par le système réactif de Vue. 🎜<script>
et de lui donner Apportez le type detext/x-template
, puis référencez le modèle via un identifiant. Par exemple : rrreeex-template doit être défini en dehors de l'élément DOM auquel appartient Vue.Cependant, si vous avez effectué ce qui précède et constatez toujours que, dans de rares occasions, vous devez forcer une mise à jour manuellement, vous pouvez le faire via
$forceUpdate
.$forceUpdate
来做这件事。通过
v-once
创建低开销的静态组件渲染普通的 HTML 元素在 Vue 中是非常快速的,但有的时候你可能有一个组件,这个组件包含了大量静态内容。在这种情况下,你可以在根元素上添加
rrreeev-once
特性以确保这些内容只计算一次然后缓存起来,就像这样:再说一次,试着不要过度使用这个模式。当你需要渲染大量静态内容时,极少数的情况下它会给你带来便利,除非你非常留意渲染变慢了,不然它完全是没有必要的——再加上它在后期会带来很多困惑。例如,设想另一个开发者并不熟悉
v-once
Créez des composants statiques à faible surcharge avec
Le rendu d'éléments HTML ordinaires dans Vue est très rapide, mais parfois vous pouvez avoir un composant qui contient beaucoup de contenu statique. Dans ce cas, vous pouvez ajouter l'attributv-once
v-once
sur l'élément racine pour garantir que le contenu n'est calculé qu'une seule fois puis mis en cache, comme ceci : 🎜rrreee🎜Encore une fois, essayez Don' N’abusez pas de ce modèle. Dans les rares occasions où vous avez besoin de restituer beaucoup de contenu statique, cela vous apportera du confort, mais à moins que vous ne fassiez très attention au ralentissement du rendu, cela est complètement inutile - et cela causera également beaucoup de problèmes en post-Perplexe. Par exemple, imaginez qu'un autre développeur ne soit pas familier avec
v-once
ou qu'il ne soit pas présent dans le modèle. Il peut passer de nombreuses heures à essayer de comprendre pourquoi le modèle ne se met pas à jour correctement. 🎜🎜🎜🎜🎜