首頁 web前端 js教程 深入探討Vue.js組件和組件通信

深入探討Vue.js組件和組件通信

Jan 16, 2017 pm 12:39 PM

基本上是按照官網的Guide 全部梳理了一遍:http://vuejs.org/guide/index.html 這裡我們以一個Todo List 應用為例來把相關的只是都串起來,這篇裡面的全部代碼都在github上 https://github.com/lihongxun945/vue-todolist

 Vue 實例

一個Vue 應用是由一個root vue instance 開機啟動的,而Vue instance 是這麼創建的​​:instance 是這麼一個創的: instance 其實就是MVVM 中的一個VM。 傳入的設定物件中data裡的所有屬性都會被掛載到 instance上,而為了避免命名衝突,Vue 內建方法都會以 $ 開頭的屬性掛載到 instance 上。

instance 從創建到銷毀會經歷如下生命週期:

在初始化的時候大致經過三步:

 •綁定資料監聽,即對data 的監聽

 •編譯模板

 •插入document或替換對應dom🎠 Vue 基本語法 



資料綁定

Vue 使用的是一種類別mastache 語法。常用綁定語法分這麼幾類:
 •mastache 語法,如{{ data }} {{ data | filter}}

 •v-bind 綁定屬性,如v-bind: href, v-bind:class

 • v-on 綁定事件, 例如v-on:click, v-on:submit 


其中v-* 都是directive 


範例:


 屬性計算

Vue 支援一個很有趣的屬性計算語法,可以指定一個屬性由其他屬性計算出來,這樣就不用透過$watch 來實現了:

var vm = new Vue({
 // options
})
登入後複製

 ## 流程# 流程#控制和清單相關的語法包括`v-if`, `v-show`, `v-else`, `v-for` 

表單

雙向資料綁定:


 ## 動畫動畫的實作方式和Angular 以及React 都是一樣的,都是透過新增和刪除class 來實現的。 # Component 


元件的基本使用

Component 的定義包括兩個部分:

1 建立component類別:

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
 }
 }
})
登入後複製

 2 註冊一個名稱:
var Profile = Vue.extend({
 template: "<div> Lily </div>"
});
登入後複製

;

 這樣我們就可以透過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", Profile); 屬於全域註冊,如果只是在某頁內使用,可以透過局部註冊的方式:

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

 其中因為我們的Vue 實例是綁定在todo 元素上的,所以如果把my-profile 放在這個元素外面是無效的,只有放在這個裡面才會被Vue 的這個實例引導初始化。

注意事項: 

Vue 構造函數可以傳的參數基本上可以用在Vue.extend 上,但是對el 和data 兩個參數需要注意,為了避免不同實例間共享同一個對象,總是要通過function 回傳一個新的物件比較可靠:

var MyComponent = Vue.extend({
 data: function () {
 return { a: 1 }
 }
})
登入後複製

 因為參數都一樣,其實他們兩個就是同一個東西,不過一個是元件,一個是用來引導Vue啟動的。

模板注意事項

因為Vue 就是原生的DOM,所以有些自訂標籤可能不符合DOM標準,例如想在table 中自訂一個tr,如果直接插入my-component 不符合規範,所以應該這樣寫:

<table>
 <tr is="my-component"></tr>
</table>
登入後複製

 Props 傳遞資料

在Vue 中每個元件都是獨立的,不能也不應該直接存取父類別的data。所以我們透過 props 來向子元件傳遞數據,是不是跟 React 的方式很像?

不同於React,在Vue 中子元件需要先宣告自己的props 才行:

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

 然後我們可以在使用Profile 的時候這樣傳遞參數:

 這種是透過字面量傳遞參數,所以傳遞的值一定是字串。還有一種方式是動態傳參,透過v-bind 來傳遞參數,可以雙向綁定資料或傳非字串參數:

 v-bind 如果是一個字串,則是綁定父組件的data中對應的字段,例如上面就是雙向綁定了input 的值。如果是一個數字則就是綁定了一個數字。


Vue 還可以明確指定單向還是雙向的資料綁定:

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

一個好的元件總是應該先驗證參數是否正確,另外可能還需要設定一些參數的預設值:

var Profile = Vue.extend({
 input: {
 type: String
 }
});
登入後複製

 父子組件通訊

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


本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1665
14
CakePHP 教程
1424
52
Laravel 教程
1321
25
PHP教程
1269
29
C# 教程
1249
24
JavaScript引擎:比較實施 JavaScript引擎:比較實施 Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

Python vs. JavaScript:學習曲線和易用性 Python vs. JavaScript:學習曲線和易用性 Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

從C/C到JavaScript:所有工作方式 從C/C到JavaScript:所有工作方式 Apr 14, 2025 am 12:05 AM

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

JavaScript和Web:核心功能和用例 JavaScript和Web:核心功能和用例 Apr 18, 2025 am 12:19 AM

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

JavaScript在行動中:現實世界中的示例和項目 JavaScript在行動中:現實世界中的示例和項目 Apr 19, 2025 am 12:13 AM

JavaScript在現實世界中的應用包括前端和後端開發。 1)通過構建TODO列表應用展示前端應用,涉及DOM操作和事件處理。 2)通過Node.js和Express構建RESTfulAPI展示後端應用。

了解JavaScript引擎:實施詳細信息 了解JavaScript引擎:實施詳細信息 Apr 17, 2025 am 12:05 AM

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

Python vs. JavaScript:社區,圖書館和資源 Python vs. JavaScript:社區,圖書館和資源 Apr 15, 2025 am 12:16 AM

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

Python vs. JavaScript:開發環境和工具 Python vs. JavaScript:開發環境和工具 Apr 26, 2025 am 12:09 AM

Python和JavaScript在開發環境上的選擇都很重要。 1)Python的開發環境包括PyCharm、JupyterNotebook和Anaconda,適合數據科學和快速原型開發。 2)JavaScript的開發環境包括Node.js、VSCode和Webpack,適用於前端和後端開發。根據項目需求選擇合適的工具可以提高開發效率和項目成功率。

See all articles