Heim  >  Artikel  >  Web-Frontend  >  Ein tiefer Einblick in die Komponenten und Komponentenkommunikation von Vue.js

Ein tiefer Einblick in die Komponenten und Komponentenkommunikation von Vue.js

高洛峰
高洛峰Original
2017-01-16 12:39:241667Durchsuche

Im Grunde alles gemäß dem Leitfaden auf der offiziellen Website sortiert: http://vuejs.org/guide/index.html Hier nehmen wir eine Todo-Listen-Anwendung als Beispiel, um alle zugehörigen Dinge darin zusammenzufassen Artikel Der Code ist vollständig auf Github https://github.com/lihongxun945/vue-todolist

Vue-Instanz

Eine Vue-Anwendung wird von einer Root-Vue-Instanz gebootet und gestartet. und eine Vue-Instanz wird wie folgt erstellt:

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

Eine Instanz ist eigentlich eine VM in MVVM. Alle Eigenschaften in den Daten im übergebenen Konfigurationsobjekt werden in die Instanz eingebunden. Um Namenskonflikte zu vermeiden, mounten die integrierten Methoden von Vue Eigenschaften, die mit $ beginnen, in die Instanz.

Instanz durchläuft den folgenden Lebenszyklus von der Erstellung bis zur Zerstörung:

durchläuft während der Initialisierung ungefähr drei Schritte:
• Bindungsdatenüberwachung, d. h. Überwachung von Daten
• Vorlage kompilieren
• Dokument einfügen oder entsprechenden Dom ersetzen
# Vue-Grundsyntax

Datenbindung

Vue verwendet eine Mastache-ähnliche Syntax. Die häufig verwendete Bindungssyntax ist in die folgenden Kategorien unterteilt:
•mastache-Syntax, wie z. B. {{ data }} {{ data | v-bind :class
• v-on-Bindungsereignisse, wie z. B. v-on:click, v-on:submit

wobei v-* Anweisungen sind


Beispiel:

19de9f32bc61168916c704eb219bf5b9

Eigenschaftsberechnung

Vue unterstützt eine interessante Eigenschaftsberechnung Syntax: Sie können ein Attribut angeben, das aus anderen Attributen berechnet werden soll, sodass Sie $watch nicht verwenden müssen:

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

## Syntax im Zusammenhang mit Flusskontrolle und Listen-Includes „v- if“, „v-show“, „v-else“, „v-for“


Formular

Zwei-Wege-Datenbindung:


a47bd89bc0a63c736c9133163ce41aa3

428a92194d6993738a40e3b71632d673


## Die Implementierung der Animation ist die gleiche wie bei Angular und React und wird durch Hinzufügen und Löschen von Klassen implementiert. # Komponente


Grundlegende Verwendung von Komponenten

Die Definition von Komponente umfasst zwei Teile:

1 Komponentenklasse erstellen:

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

2 Registrieren Sie einen Tagnamen:


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

Auf diese Weise können wir eine solche Komponente über Tagname:

<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", Profil); Wenn es nur auf einer bestimmten Seite verwendet wird, können Sie es lokal registrieren:

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

Da unsere Vue-Instanz an das todo-Element gebunden ist, ist es ungültig, my-profile außerhalb dieses Elements zu platzieren. Nur wenn es innerhalb dieses Elements platziert wird, handelt es sich um diese Instanz von Vue-Bootstraps Initialisierung.

Hinweis:


Die Parameter, die an den Vue-Konstruktor übergeben werden können, können grundsätzlich in Vue.extend verwendet werden, Sie müssen jedoch auf die beiden Parameter el und data achten. Um unterschiedliche Instanzen zu vermeiden, ist es zuverlässiger, bei der gemeinsamen Nutzung desselben Objekts immer ein neues Objekt über die Funktion zurückzugeben:

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

Da die Parameter tatsächlich gleich sind sind dasselbe, aber eine Es ist eine Komponente, eine wird verwendet, um Vue beim Start zu unterstützen.

Vorlagennotizen

Da Vue das native DOM ist, entsprechen einige benutzerdefinierte Tags möglicherweise nicht den DOM-Standards. Wenn Sie beispielsweise ein tr in der Tabelle anpassen möchten, fügen Sie my- ein. Komponente direkt, nein Es entspricht der Spezifikation, daher sollte es so geschrieben werden:

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

Props übergibt Daten

In Vue ist jede Komponente unabhängig und kann und sollte nicht direkt auf die Daten der übergeordneten Klasse zugreifen. Wir übergeben also Daten über Requisiten an Unterkomponenten. Ist das ähnlich wie bei React?

Im Gegensatz zu React müssen Unterkomponenten in Vue zuerst ihre eigenen Requisiten deklarieren:

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

Dann können wir bei Verwendung von Profile Parameter wie diesen übergeben:

5262f07c1c15b67e64242fa6ad7262432ce8caae7ced446f67526b3e9d39dfa1


Hiermit werden Parameter über Literale übergeben, daher muss der übergebene Wert eine Zeichenfolge sein. Eine andere Möglichkeit besteht darin, Parameter dynamisch über v-bind zu übergeben, das Daten in zwei Richtungen binden oder Nicht-String-Parameter übergeben kann:

1bb17a1f1b55d117ee6295fdbd89361350d5c14ea3d37db8443f419b867978cc


v-bind Wenn es sich um eine Zeichenfolge handelt, ist sie an das entsprechende Feld in den Daten der übergeordneten Komponente gebunden. Das Obige ist beispielsweise der Wert der Eingabe, der bidirektional gebunden ist. Wenn es eine Zahl ist, ist sie an eine Zahl gebunden.

Vue kann auch explizit eine unidirektionale oder bidirektionale Datenbindung angeben:

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

Props-Verifizierung

Eine gute Komponente, die Sie immer haben sollten Überprüfen Sie zunächst, ob die Parameter korrekt sind. Darüber hinaus müssen Sie möglicherweise auch die Standardwerte einiger Parameter festlegen:

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

Kommunikation zwischen Eltern-Kind-Komponenten

上面讲到的 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中文网!


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn