Vue的入門知識我分紅了如上四個頂層概念。
vue實例、指令、組件、模板。
vue官方文檔已經很易懂了,可是我但願把個人理解以及一些容易疏忽的地方記下來,方便我往後更輕鬆的使用它。css
vue是一套構建用戶界面的漸進式框架。我對漸進式框架的理解是,你能夠充分的使用vue的功能,包括簡單的功能和複雜的功能,徹底按照vue的模式去構建程序。固然你也能夠只使用相似數據響應的單一功能。他不強制要求你按照某個模式去書寫,也就是說你能夠在原有的代碼基礎上將少許功能用vue去實現也是可行的。html
最喜歡的vue的兩個特色是,響應式數據和組件。響應式數據省去了不少監聽數據的代碼,能夠專一在構建界面上。而組件做爲模塊化思想下延伸出的一個手段,不只能夠很好的進行解耦使組件獨立存在便於管理,並且能夠很好的配合模塊化技術進行模塊化開發。ES6已經支持模塊化。前端
data = Model
模板 + 指令 = View
new Vue() = ViewModelvue
推薦一個言簡意賅的MVVM說明博文webpack
五種建立模板的方法:web
DOM元素模板(Vue實例用)chrome
script標籤 + x-templatesegmentfault
template屬性數組
.vue文件中template標籤緩存
inline-template
直接用DOM元素做爲模板的方式。僅限vue實例控制區域使用。下面四個是組件模板建立方式。
說明:受HTML限制,標籤名不能用駝峯(html大小寫不敏感)必須用aa-bb形式。另外受html標準影響,特殊元素內只容許存在特定元素,如tr內只能是td或th,若是想再相似tr裏解析組件,要用is屬性聲明組件。
將script內的內容做爲模板的方式。注意組件必須有一個根元素。好比下面那個無用div。並且模板與組件分離了,不在同一個位置,不便於管理。不推薦。
<script type="text/x-template" id="hello-world-template"> <div> <p>Hello hello hello</p> <p>Hello hello hello</p> </div> </script>
Vue.component('hello-world', { template: '#hello-world-template' })
最常規作法,也是最噁心的作法,在js語法環境寫html代碼,沒有代碼提示,沒有格式化,噁心程度可想而知。
Vue.component('my-component', { template: '<div>A custom component!</div>' })
<template> <div>This will be pre-compiled</div> </template>
直接在插入組件的位置,聲明模板。不過和script模板同樣,分離了,不便於管理。不推薦。
<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>
vue實例也就是MVVM中的VM(ViewModel)。負責鏈接view和model。
既然是VM,那麼vue實例主要做用是操做數據和自身。
vue實例提供了幾個用來操做數據的選項。
做爲MVVM中的M(Model),data屬性用來存儲未經處理的原始數據對象。
特性:
新添加的屬性不會被響應
這個特性包括兩點。
一點是指屬性必須在 data 對象上存在它纔是響應的。
var vm = new Vue({ data:{ a:1 } }) // `vm.a` 是響應的 vm.b = 2 // `vm.b` 是非響應的
一點是指Vue 不容許在已經建立的實例上動態添加新的根級響應式屬性。既不能將響應屬性添加到嵌套的對象上。
vm.a.b = 2
添加響應式新屬性的替代方案(2種)以下:
// 第一種 Vue.set(vm.a, 'b', 2) this.$set(this.a,'b',2) // 第二種 vm.a = Object.assign({}, vm.a, { b: 2 }) this.a = Object.assign({}, this.a, { b: 2 })
不能響應的數組操做及對應替代方法
// 不能響應 vm.items[indexOfItem] = newValue // 替代方法 Vue.set(example1.items, indexOfItem, newValue) // 不能響應 vm.items.length = newLength // 替代方法 example1.items.splice(indexOfItem, 1, newValue)
vue稱他爲計算屬性,用來對data數據進行處理。由於是對data進行計算,因此爲了便於維護和理解,計算屬性不要去修改data數據,僅僅引用便可。
特性:
用return的數據渲染view
數據是響應式的
基於依賴緩存計算結果。計算屬性只有在它的相關依賴發生改變時纔會從新求值。
好比兩個div都靠計算屬性A來渲染,那麼渲染第二個div時不會從新執行計算屬性A,而是直接返回渲染第一個div時計算的值
getter 和 setter。
默認只有一個getter,做用是依賴data變化來執行getter。能夠本身設一個setter,做用是直接給計算屬性賦值時會觸發setter。
區別於computed的方法,一般用來做爲事件的回調函數,或者不但願使用computed的緩存特性時做爲computed的替代品。methods方法一樣是數據響應式的。
特性:
用return的數據渲染view
數據是響應式的
計算結果不緩存
問題:
如何在methods函數內引用事件元素自己?
一般直接用this就能夠引用事件元素自己。
el.onclick = function(){ console.log(this) }
可是在Vue裏this指向實例或組件自身,因此在Vue裏這樣引用事件元素自己。
<li @click="warn('msg', $event)"></li>
warn: function (message, event) { // 如今咱們能夠訪問原生事件對象 if (event) event.preventDefault() alert(message) console.log(event.currentTarget) // 綁定事件的元素自己 }
這裏須要說明的是,引用的event對象是原生event對象,不是相似jQuery包裝過的event對象。並且之所在模板裏傳入$event是由於,event對象的兼容性問題。在IE和chrome內能夠經過window.event引用event對象,也就是不須要event形參,可是火狐不能夠,火狐必須有event形參,並且將event對象做爲實參傳入,固然只有一個event形參時不須要顯示的將event做爲實參傳入。問題在於event形參若是是非第一位參數,就必須將event對象顯示的做爲實參傳入。在原生JS中能夠以下實現。顯然vue提供了很好的解決方法。
asd.onclick = function(event) { var ee = event function a (msg, event) { console.log(event) alert(msg) } a(window.value,ee) }
當你想要在數據變化響應時,執行異步操做或開銷較大的操做時請使用watch
被用做一些常見的文本格式化。
vue實例從建立到銷燬的過程。在這個過程當中能夠經過配置生命週期鉤子來處理一些邏輯。
推薦一個說明生命週期的博文
vue實例建立後,爲了便於訪問數據,vue實例對象會代理一些數據。
如vm.a
直接訪問data數據、vm.$data直接訪問整個data對象
用來在view層代表數據的用途
v-show是條件顯示,只是切換display: none/block。
v-if是條件渲染。
用來聲明該模板是哪一個組件。解決兩個問題。
動態切換組件
<component v-bind:is="currentView"></component>
解決HTML元素限制
// bad <table> <my-row>...</my-row> </table> //good <table> <tr is="my-row"></tr> </table>
vue有一個最大限度複用原則,能夠複用的元素會通過少許修改繼續複用。
key屬性能夠屏蔽複用機制。有key屬性的元素,每次都會從新渲染。
說明:
key值相同的元素之間也會複用,可是綁定key的元素被從新渲染時(渲染了非相同key的元素)原來的緩存會被清除,再也不被複用
vue實例對象能夠經過變量名訪問。可是組件沒有變量名,因此沒有能夠訪問的接口。
ref提供了訪問組件的接口。
<child-comp ref="child"></child-comp>
訪問
vm.$refs.child
vue組件是實施前端組件化的一個手段。一個完整的前端組件應該包括屬於某一前端UI模塊HTML CSS JS部分。可是顯然入門教程裏的註冊方式有模板和JS,可是少了CSS,有點殘次品的感受。因此條件容許我仍是更喜歡.vue文件的方式封裝組件。
三種祖冊方式
全局註冊(不說了)
局部註冊(不說了)
用.vue文件封裝組件,並用做爲模塊進行require
給組件取個名
<child-comp ref="child"></child-comp>
訪問組件
var parent = new Vue({ el: '#parent' }) // 訪問子組件 var child = parent.$refs.child
簡單理解就是,父組件模板裏的內容應該如何處置。
內容分發規則有如下幾點:
沒有slot屬性的內容分發給匿名slot
有slot屬性的內容分發給對應有相同name屬性的slot
slot內的內容在沒有被分發內容時顯示,並不用任何標籤進行包裹
父子組件
遞歸組件
循環引用組件(A組件套了B組件,B組件裏又套了A,A引用B B引用A)
問題:
遞歸組件:組件遞歸調用自身時會進入死循環,因此須要用相似v-if,並最終v-if值最終返回false
循環引用組件:因爲互相引用,致使引用關係混亂。在用webpack構建時,webpack沒法判斷先引用誰。如A引用B B引用A時首先致使混亂的是B組件。Vue提供了一個解決方法。
beforeCreate: function () { this.$options.components.TreeFolderContents = require('./B.vue') }
vue組件最長提的是解耦。每一個組件只負責本身的部分,他只關心接收的數據。因此我以爲組件間的通信是vue組件最重要的部分。
父組件給子組件傳遞數據遵循一個模式。
在父組件模板中聲明傳入的數據
在子組件中用props屬性接收傳入的數據
這樣一來,子組件徹底解耦,他只負責接收。
父組件模板傳入
<child :message="hello!"></child>
在子組件接收
Vue.component('child', { // 聲明 props props: ['message'], template: '<span>{{ message }}</span>' })
說明:
傳入數據是基本類型時,在子組件修改props會報錯
傳入數據是對象時,在子組件修改props的狀況,由於對象是引用類型,修改props會同事修改到父組件
子組件給父組件傳遞數據遵循一個模式。
在父組件模板綁定並監聽一個事件,該事件觸發父組件方法。
在子組件觸發監聽的事件,進而觸發父組件方法,並把數據做爲參數傳入該方法。
具體實現:
在父組件模板監聽事件
<div id="counter-event-example"> <button-counter v-on:increment="incrementTotal"></button-counter> </div>
在子組件觸發事件
methods: { increment: function () { this.counter += 1 this.$emit('increment', data) } }
非父子組件通信,因爲兩個組件獨立存在,不能像父子間那樣在父模板傳入或監聽。
非父子組件通信經過eventBus也就是一個空的vue實例對象做爲中轉站進行通信。具體實現以下。
建立一個空的vue實例
在組件生命週期前期(一般是mounted)在中轉站上聲明一個事件監聽,表示誰觸發這個事件就至關於通知我了。
在另外一個組件,觸發這個事件,和子通知父同樣。
因此非父子和子傳父的區別在於,聲明監聽事件的方式不一樣。
具體實現:
建立一箇中轉站
var eventBus = new Vue()
在A組件聲明週期內,在中轉站監聽一個事件,並把該事件中的this指向自身(A組件自己)
mounted: function () { eventBus.$on('addBar', function () { this.a++ }.bind(this)) }
在B組件中觸發事件來通知A組件
methods: { aaaAdd: function () { eventBus.$emit('addBar') } }
與父傳子同樣的模式,在slot傳入,在分發內容接收。
具體實現:
傳入
<div class="child"> <slot :text="msg"></slot> </div>
接收,具備特殊屬性 scope 的 <template>
元素必須存在
<div class="parent"> <child> <template scope="props"> <span>hello from parent</span> <span>{{ props.text }}</span> </template> </child> </div>
有沒有發現?四種不一樣的通信方式各不相同,用了四種不一樣的模式,並且有些在html文檔裏聲明數據傳入,有些在js文檔裏。我覺的很不優雅也不易理解和管理。
原理很簡單,經過內置的component元素綁定is來實現切換。
<component v-bind:is="currentView"> <!-- 組件在 vm.currentview 變化時改變! --> </component>
可是切換出去的組件不會被緩存,從新切回來會從新渲染,若是想緩存。
<keep-alive> <component :is="currentView"> <!-- 非活動組件將被緩存! --> </component> </keep-alive>