Maison  >  Article  >  interface Web  >  Une plongée approfondie dans les composants Vue.js et la communication entre les composants

Une plongée approfondie dans les composants Vue.js et la communication entre les composants

高洛峰
高洛峰original
2017-01-16 12:39:241708parcourir

En gros, tout a été trié selon le Guide sur le site officiel : http://vuejs.org/guide/index.html Ici, nous prenons une application Todo List comme exemple pour enchaîner toutes les choses liées. Tout cela. article Le code est entièrement sur github https://github.com/lihongxun945/vue-todolist

Instance Vue

Une application Vue est démarrée et démarrée par une instance racine de Vue, et Vue Instance est créée comme ceci :

var vm = new Vue({
 // options
})

Une instance est en fait une VM dans MVVM. Toutes les propriétés des données de l'objet de configuration transmis seront montées sur l'instance. Afin d'éviter les conflits de noms, les méthodes intégrées de Vue monteront les propriétés commençant par $ sur l'instance.

L'instance passera par le cycle de vie suivant, de la création à la destruction :

passe en gros par trois étapes lors de l'initialisation :
• Surveillance des données de liaison, c'est-à-dire la surveillance des données
• Compiler le modèle
• Insérer un document ou remplacer le dom correspondant
# Syntaxe de base de Vue

Liaison de données

Vue utilise une syntaxe de type mastache. La syntaxe de liaison couramment utilisée est divisée dans les catégories suivantes :
• syntaxe mastache, telle que {{ data }} {{ data | filter}}
  • attributs de liaison v-bind, tels que v-bind : href, v-bind :class
• Événement de liaison v-on, tel que v-on:click, v-on:submit

où v-* sont des directives

Exemple :
19de9f32bc61168916c704eb219bf5b9

Calcul de propriété

Vue prend en charge un calcul de propriété intéressant Syntaxe, vous pouvez spécifier un attribut à calculer à partir d'autres attributs, vous n'avez donc pas besoin d'utiliser $watch :

var vm = new Vue({
 el: '#example',
 data: {
 a: 1
 },
 computed: {
 // a computed getter
 b: function () {
 // `this` points to the vm instance
 return this.a + 1
 }
 }
})

## La syntaxe liée au contrôle de flux et aux listes inclut `v-if`, `v-show`, `v-else`, `v-for`

Formulaire

Liaison de données bidirectionnelle :

a47bd89bc0a63c736c9133163ce41aa3

428a92194d6993738a40e3b71632d673

## L'implémentation de l'animation est la même que celle d'Angular et de React, et est implémentée en ajoutant et en supprimant des classes. # Composant

Utilisation de base des composants

La définition du composant comprend deux parties :

1 Créer une classe de composant :

var Profile = Vue.extend({
 template: "<div> Lily </div>"
});

2 Enregistrez un nom de balise :

Vue.component("me-profile", Profile);

De cette façon, nous pouvons utiliser un tel composant via le nom de balise :

<div id="todo">
 <my-profile></my-profile>
 <form v-on:submit="add" v-on:submit.prevent>
 <input type="text" v-model="input"/>
 <input type="submit" value=&#39;add&#39; />
 </form>
 ...
</div>

Vue.component("me-profile", Profile); S'il n'est utilisé que dans une certaine page, vous pouvez l'enregistrer localement :

var vm = new Vue({
 el: "#todo",
 components: {
 "my-profile": Profile
 },
 ...
}

Parce que notre instance Vue est liée à l'élément todo, il n'est pas valide de placer mon profil en dehors de cet élément. Ce n'est que lorsqu'il est placé à l'intérieur qu'il s'agira de cette instance de bootstraps Vue. initialisation.

Remarque :


Les paramètres qui peuvent être transmis au constructeur Vue peuvent essentiellement être utilisés dans Vue.extend, mais vous devez faire attention aux deux paramètres el et data, afin d'éviter des instances différentes Lors du partage du même objet, il est plus fiable de toujours renvoyer un nouvel objet via la fonction :

var MyComponent = Vue.extend({
 data: function () {
 return { a: 1 }
 }
})

Parce que les paramètres sont les mêmes, en fait ils C'est la même chose, mais un C'est un composant, un est utilisé pour guider Vue au démarrage.

Notes sur le modèle

Étant donné que Vue est le DOM natif, certaines balises personnalisées peuvent ne pas être conformes aux normes du DOM. Par exemple, si vous souhaitez personnaliser un tr dans le tableau, si vous insérez mon-. composant directement, non Il est conforme à la spécification, il doit donc être écrit comme ceci :

<table>
 <tr is="my-component"></tr>
</table>

Props transmet les données

Dans Vue, chaque composant est indépendant et ne peut pas et ne doit pas accéder directement aux données de classe. Nous transmettons donc les données aux sous-composants via des accessoires, est-ce similaire à React ?

Contrairement à React, les sous-composants de Vue doivent d'abord déclarer leurs propres accessoires :

var Profile = Vue.extend({
 props: ["name"],
 template: `
 <h2>{{name}}&#39;s Todo List</h2>
 <h4>{{name}} is a good girl</h4>
 `
});

Ensuite, nous pouvons transmettre des paramètres comme celui-ci lors de l'utilisation de Profile :

5262f07c1c15b67e64242fa6ad7262432ce8caae7ced446f67526b3e9d39dfa1

Il s'agit de transmettre les paramètres via des littéraux, donc la valeur transmise doit être une chaîne. Une autre façon consiste à transmettre dynamiquement les paramètres via v-bind, qui peut lier les données dans deux directions ou transmettre des paramètres autres que des chaînes :

1bb17a1f1b55d117ee6295fdbd893613b9c68978612d2bb2405a5ce3e24e00ae

v-bind S'il s'agit d'une chaîne, elle est liée au champ correspondant dans les données du composant parent. Par exemple, ce qui précède est la valeur de l'entrée qui est liée de manière bidirectionnelle. Si c'est un nombre, il est lié à un nombre.

Vue peut également spécifier explicitement une liaison de données unidirectionnelle ou bidirectionnelle :

<!-- default, one-way-down binding -->
<child :msg="parentMsg"></child>
 
<!-- explicit two-way binding -->
<child :msg.sync="parentMsg"></child>
 
<!-- explicit one-time binding -->
<child :msg.once="parentMsg"></child>

Vérification des accessoires

Un bon composant, vous devriez toujours vérifiez d'abord si les paramètres sont corrects. De plus, vous devrez peut-être également définir les valeurs par défaut de certains paramètres :

var Profile = Vue.extend({
 input: {
 type: String
 }
});

Communication des composants parent-enfant

上面讲到的 props 其实就是父组件向子组件传递消息的一种方式。 
在子组件中有一个 this.$parent 和 this.$root 可以用来方法父组件和根实例。不过,现在我们应该避免这么做。因为组件本身就是为了封装独立的逻辑,如果又去直接访问父组件的数据就破坏了组件的封装性。 
所以我们应该还是应该通过父组件向子组件传递 props 的方式来通信。

当然 props 其实只能做回调。在 React 中就探讨过这个问题,React 的做法就是通过 props 来做,传一个回调函数给子组件。其实我不是很喜欢这种把回调函数传来传去的方式,我更喜欢的是事件的方式。Vue 中子组件可以通过通过事件和父组件进行通信的。向父组件发消息是通过 this.$dispatch,而向子组件发送消息是通过 this.$boardcast,这里都是向所有的父亲和孩子发送消息,但是一旦执行一个回调之后就会停止,除非这个回调函数显式返回了 true。

我们把之前的Todo List拆成不同的组件来实现,这样可以体验下如何进行组件的双向通信,我们拆分出两个组件,分别是 List 和 Form 。

Form 负责处理用户输入,并在提交表单的时候向父组件发送一个 add 消息,代码如下:

var Form = Vue.extend({
 props: {
 username: {
 type: String,
 default: "Unnamed"
 }
 },
 data: function() {
 return {
 input: "",
 };
 },
 template: `
 <h1>{{username}}&#39;s Todo List</h1>
 <form v-on:submit="add" v-on:submit.prevent>
 <input type="text" v-model="input"/>
 <input type="submit" value=&#39;add&#39; />
 </form>
 `,
 methods: {
 add: function() {
 this.$dispatch("add", this.input); //这里就是向父组件发送消息
 this.input = "";
 }
 }
});

 List 只负责展示列表和处理用户勾选操作,它接收到 add 消息之后会在自己上添加一个条目:

var List = Vue.extend({
 template: `
 <ul>
 <li v-for=&#39;todo in list&#39;>
 <label v-bind:class="{ done : todo.done }" >
  <input type="checkbox" v-model="todo.done"/>
  {{todo.title}}
 </label>
 </li>
 </ul>`,
 props: {
 initList: {
 type: Array
 }
 },
 data: function() {
 return {
 list: []
 }
 },
 events: {
 add: function(input) {
 if(!input) return false;
 this.list.unshift({
 title: input,
 done: false
 });
 }
 }
});

 然后,因为这是两个组件,当然需要一个 Vue 实例来引导启动,我们的实例如下:

var vm = new Vue({
 el: "#todo",
 components: {
 "todo-form": Form,
 "todo-list": List
 },
 events: {
 add: function(input) {
 this.$broadcast("add", input);
 }
 }
});

 注意,其实 Form 和 List 在逻辑上是平级的组件,所以他们没有父子关系,他们共同都是 vm 的孩子。这里 vm 接到 Form 的消息之后会转发给 List。

html 代码就更简单了:

<div id="todo">
<todo-form username=&#39;Lily&#39;></todo-form>
<todo-list></todo-list>
</div>

 Slot

通过 Slot 可以实现把父组件渲染出来的HTML插入到子组件中,目前还不清楚什么时候会需要这样做,而且这么做对子组件的侵入性太大。

动态切换组件

这个功能感觉有点多余,感觉很多情况下我们应该是通过逻辑代码来实现切换,而不是通过Vue内置的动态组件来切换。不过用来实现一个类似 tab 切换的功能还是很方便的。

我们这里给 Todo List 增加一个 about 页面。那么首先我们需要把 vm 改成一个组件,这个组件叫 Todo,它就是整个 Todo 页面:

var Todo = Vue.extend({
 template: `
 <div id="todo">
 <todo-form username=&#39;Lily&#39;></todo-form>
 <todo-list></todo-list>
 <slot>not show</slot>
 </div>
 `,
 components: {
 "todo-form": Form,
 "todo-list": List
 },
 events: {
 add: function(input) {
 this.$broadcast("add", input);
 }
 }
});

 

 其实改动就第一行。

然后我们需要创建一个 About 组件:

var About = Vue.extend({
 template: `
 <div id="about">
 <p>About Todo List V0.1.0</p>
 <p>Content here</p>
 </div>`
});

 接下来是重点了,我们要创建一个实例 vm,这vm要负责切换这两个页面:

var vm = new Vue({
 el: "body",
 data: {
 currentView: "todo"
 },
 components: {
 "todo": Todo,
 "about": About
 }
});

 这里我们定义了一个 currentView 字段,当然可以是任意名称,然后通过特殊的 component 标签来进行组件切换:

<component :is="currentView"></component>
 <ul>
 <li><label><input type="radio" name=&#39;page&#39; value=&#39;todo&#39; v-model=&#39;currentView&#39;> Home</label></li>
 <li><label><input type="radio" name=&#39;page&#39; value=&#39;about&#39; v-model=&#39;currentView&#39;> About</label></li>
 </ul>

 上面的代码有两处需要注意:
 •通过 component这个特殊标签,然后用 :is 属性来进行组件的切换。
 •radio 通过双向绑定来修改 currentView 字段,从而实现点击之后就可以进行切换。

数据绑定的实现原理

Vue 把双向绑定称作 reactive,可以翻译为响应式数据绑定。内部是通过 ES5 定义的 getter 和 setter 方法实现的,所以不支持 IE8 及以下浏览器,这种实现方式有两个容易犯错的地方:
 •如果在 data 上直接添加和删除属性是无法被检测到的,一般删除是不会的,但是可能会动态添加,这个时候应该通过 vm.$set(“name”, value) 的方式来添加。
 •无法检测到对象内部的变化,也就是只能检测 data 的属性变化,如果 data.a 是一个对象,那么 data.a.b = 1 这种变化是无法被检测到的。这种情况下应该创建一个新的对象并赋值给 data.a 就行了。 

异步更新机制

Vue 对DOM的更新是异步的! 这个异步是在一个异步队列中进行的,不过这个异步队列会在当前的 Event Loop 中执行完,所以如果修改了 Data 立刻去DOM中做查询操作是不对的,这个时候DOM还没有更新,正确的做法是这样做:

vm.msg = &#39;new message&#39; // change data
vm.$el.textContent === &#39;new message&#39; // false
Vue.nextTick(function () {
 vm.$el.textContent === &#39;new message&#39; // true
})

 或者这样:

vm.$nextTick(function () {
 this.$el.textContent === &#39;new message&#39; // true
})

 花了半天时间才看完组件,下面应该去看一下另一个重点: Directive

本文已被整理到了《Vue.js前端组件学习教程》,欢迎大家学习阅读。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持PHP中文网。

更多X深入探讨Vue.js组件和组件通信相关文章请关注PHP中文网!


Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn