基本是按照官網的Guide 全部梳理了一遍:http://vuejs.org/guide/index.html 這裡我們以一個Todo List 應用為例來把相關的只是都串起來,這篇裡面的全部代碼都在github上https://github.com/lihongxun945/vue-todolist
Vue 實例
一個Vue 應用是由一個root vue instance 引導啟動的,而Vue instance 是這麼創建的:
var vm = new Vue({ // options})一個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
例子:
<div v-bind:class="[classA, isB ? classB : '']">
屬性計算
Vue 支持一個很有意思的屬性計算語法,可以指定一個屬性由其他屬性計算出來,這樣就不用通過$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 } }})## 流程控制和列表相關的語法包括`v-if`, `v-show`, `v-else`, `v-for`
表單
雙向數據綁定:
<input type="text" v-model="message" placeholder="edit me">
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
## 動畫動畫的實現方式和Angular 以及React 都是一樣的,都是通過添加和刪除class 來實現的。 # Component
組件的基本用法
Component 的定義包括兩部分:
1 創建component類:
var Profile = Vue.extend({ template: "<div> Lily </div>"});2 註冊一個tagname:
Vue.component("me-profile", Profile);
這樣我們就可以通過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='add' /> </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}}'s Todo List</h2> <h4>{{name}} is a good girl</h4> `});然後我們可以在使用Profile 的時候這樣傳遞參數:
<my-profile name='Lily'></my-profile>
這種是通過字面量傳遞參數,所以傳遞的值一定是字符串。還有一種方式是動態傳參,通過v-bind 來傳遞參數,可以雙向綁定數據或者傳非字符串參數:
<my-profile v-bind:name='input'></my-profile>
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}}'s Todo List</h1> <form v-on:submit="add" v-on:submit.prevent> <input type="text" v-model="input"/> <input type="submit" value='add' /> </form> `, methods: { add: function() { this.$dispatch("add", this.input); //這裡就是向父組件發送消息this.input = ""; } }});List 只負責展示列表和處理用戶勾選操作,它接收到add 消息之後會在自己上添加一個條目:
var List = Vue.extend({ template: ` <ul> <li v-for='todo in list'> <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='Lily'></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='Lily'></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='page' value='todo' v-model='currentView'> Home</label></li> <li><label><input type="radio" name='page' value='about' v-model='currentView'> About</label></li> </ul>
上面的代碼有兩處需要注意:
•通過component這個特殊標籤,然後用:is 屬性來進行組件的切換。
•radio 通過雙向綁定來修改currentView 字段,從而實現點擊之後就可以進行切換。
數據綁定的實現原理
Vue 把雙向綁定稱作reactive,可以翻譯為響應式數據綁定。內部是通過ES5 定義的getter 和setter 方法實現的,所以不支持IE8 及以下瀏覽器,這種實現方式有兩個容易犯錯的地方:
•如果在data 上直接添加和刪除屬性是無法被檢測到的,一般刪除是不會的,但是可能會動態添加,這個時候應該通過vm.$set(“name”, value) 的方式來添加。
•無法檢測到對象內部的變化,也就是只能檢測data 的屬性變化,如果data.a 是一個對象,那麼data.ab = 1 這種變化是無法被檢測到的。這種情況下應該創建一個新的對象並賦值給data.a 就行了。
異步更新機制
Vue 對DOM的更新是異步的! 這個異步是在一個異步隊列中進行的,不過這個異步隊列會在當前的Event Loop 中執行完,所以如果修改了Data 立刻去DOM中做查詢操作是不對的,這個時候DOM還沒有更新,正確的做法是這樣做:
vm.msg = 'new message' // change datavm.$el.textContent === 'new message' // falseVue.nextTick(function () { vm.$el.textContent === 'new message' // true})或者這樣:
vm.$nextTick(function () { this.$el.textContent === 'new message' // true})花了半天時間才看完組件,下面應該去看一下另一個重點: Directive
本文已被整理到了《Vue.js前端組件學習教程》,歡迎大家學習閱讀。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。