1、有關於Vue.js特性的例子css
1.第一個特性是數據綁定。綁定用戶輸入的數據,視圖會隨着用戶的輸入而變化。前端
<div id="app"> <h1>Your input is {{message}}</h1> <input type="text" v-model="message"> </div>
2.第二個特性是組件化,簡單來講咱們能夠本身定義HTML標籤,並在模板中使用它。vue
<div id="app"> <message content="Hello World"></message> </div> <script> var Message = Vue.extend({ props: ['content'], template: '<h1>{{content}}</h1>' }) Vue.component('message', Message); new Vue({ el: '#app', }) </script> HTML結果爲: <div id="app"> <h1>Hello World</h1> </div>
1、數據node
Vue.js實例中能夠經過data屬性定義數據,若是傳入data的是一個對象,Vue實例會代理起data對象裏的全部屬性,而不會對傳入的對象進行深拷貝。另外,咱們能夠引用Vue實例vm中的$data來獲取聲明的數據,例如:webpack
var data = { a: 1 }; var vm = new Vue({ data: data }); console.log(vm.$data === data); // true console.log(vm.$data.a === data.a); // true console.log(vm.a === data.a); // true // 設置屬性也會影響到原始數據 vm.a = 2; console.log(data.a); // 2 // 反之亦然 data.a = 3; console.log(vm.a); // 3
在模板中使用{{a}}就會輸出vm.a的值,而且修改vm.a的值,模板中的值會隨之改變。咱們稱這個數據爲響應式數據。
注意:只有初始化時傳入的對象纔是響應式的,即在生命完實例後,再加上vm.$data.b = '2',並在模板中使用{{b}},是不會輸出字符串'2'的。例如:web
<div id="app"> <p>{{a}}</p> <p>{{b}}</p> </div> <script> var vm = new Vue({ el: '#app', data: { a: 1 } }); vm.$data.b = 2; // 報錯 </script>
若是須要在實例化以後加入響應式變量,須要調用實例方法$set,例如:vm.$set('b',2);不過Vue.js並不推薦這麼作,會拋出異常。因此咱們應儘可能在初始化的時候,把全部的變量都設定好,若是沒有值,能夠用undefined或null佔位。
另外,組件類型的實例也能夠經過props獲取數據,同data同樣,也須要在初始化時預設好。例如:ajax
<div id="app"> <my-component title="myTitle" content="myContent"></my-component> </div> <script> var MyComponent = Vue.component('my-component', { props: ['title', 'content'], template: '<h1>{{title}}</h1><p>{{content}}</p>' }); </script>
也能夠在上述組件類型實例中同時使用data,但需注意: 1.data的值必須是一個函數,而且返回值不是原始對象。若是傳給組件的data是一個原始對象,則在建議多個組件實例時它們就會共用這個data對象,修改其中一個組件實例的數據就會影響到其餘組件實例的數據,這顯然不是咱們所指望的。 2.data中的屬性和props中的不能重名。 這二者均會拋出異常。 正確使用方法:
var MyComponent = Vue.component('my-component', { props: ['title', 'content'], data: function () { return { desc: '描述' } }, template: `<div> <h1>{{title}}</h1> <p>{{content}}</p> <p>{{desc}}</p> </div>` });
2、生命週期
經過一個簡單的demo來清楚地瞭解內部的運行機制,代碼以下:正則表達式
var vm = new Vue({ el: '#app', init: function () { // 在實例開始初始化時同步調用。此時數據觀測、事件等都還沒有初始化。2.0中改名爲beforeCreate console.log('init'); }, created: function () { // 在實例建立以後調用。此時已完成數據綁定、事件方法,但還沒有開始DOM編譯,即未掛載到document中。 console.log('created'); }, beforeCompile: function () { // 在DOM編譯前調用。2.0廢棄了該方法,推薦使用created。 console.log('beforeCompile'); }, beforeMount: function () { // 2.0新增的生命週期鉤子,在mounted以前運行。 console.log('beforeMount'); }, compiled: function () { // 在編譯結束時調用。此時全部指令已生效,數據變化已能觸發DOM更新,但不保證$el已插入文檔。2.0中改名爲mounted。 console.log('compiled'); }, mounted: function () { // 2.0中compiled改名。 console.log('mounted'); }, attached: function () { // 在vm.$el插入DOM時調用,ready會在第一次attached後調用。操做$el必須使用指令或實例方法(例如$appendTo()),直接操做$el不會觸發這個鉤子。2.0廢棄了該方法,推薦在其它鉤子中自定義方法檢查是否已掛載。 console.log('attached'); }, dettached: function () { // 同attached相似,該鉤子在vm.$el從DOM刪除時調用,並且必須是指令或實例方法。2.0中一樣廢棄了該方法。 console.log('dettached'); }, beforeDestroy: function () { // 在開始銷燬實例時調用,此時實例仍然有效。 console.log('beforeDestory'); }, destroyed: function () { // 在實例被銷燬以後調用。此時全部綁定和實例指令都已經解綁,子實例也被銷燬。 console.log('destroyed'); }, ready: function () { // 在編譯結束和$el第一次插入文檔以後調用。2.0廢棄了該方法,推薦使用mounted。這個變化其實已經改變了ready這個生命週期狀態,至關於取消了在$el首次插入文檔後的鉤子函數。 console.log('ready'); // 組件完成後調用$destroy()函數,進行銷燬 this.$destroy(); }, beforeUpdate: function () { // 2.0新增的生命週期鉤子,在實例掛載以後,再次更新實例(例如更新data)時會調用該方法,此時還沒有更新DOM結構。 console.log('beforeUpdate'); }, update: function () { // 2.0新增的生命週期鉤子,在實例掛載以後,再次更新實例並更新完DOM結構後調用。 console.log('update'); }, activated: function () { // 2.0新增的生命週期鉤子,須要配合動態組件keep-live屬性使用。在動態組件初始化渲染的過程當中調用該方法。 console.log('activated'); }, deactivated: function () { // 2.0新增的生命週期鉤子,須要配合動態組件keep-live屬性使用。在動態組件移出的過程當中調用該方法。 console.log('deactivated'); } });
3、數據綁定
Vue.js做爲數據驅動視圖的框架,核心是一個響應式的數據綁定系統,創建綁定後,DOM將和數據保持同步,這樣就無需手動維護DOM,使代碼能給更加簡潔易懂、提高效率。
數據綁定語法:
js代碼:express
var vm = new Vue({ el: '#app', data: { id: 1, index: 0, name: 'Vue', avatar: 'http://...', count: [1, 2, 3, 4, 5], names: ['Vue1.0', 'Vue2.0'], items: [ {name: 'Vue1.0', version: '1.0'}, {name: 'Vue2.0', version: '2.0'} ] } });
1.文本插值npm
<span>Hello {{name}}</span> // Hello Vue
修改數據對象中的name屬性,DOM也會隨之更新。// console中修改name屬性爲Vue2.0後輸出 Hello Vue2.0
模板語法同時也支持單次插值,即首次賦值後再更改vm實例屬性值不會引發DOM變化,例如:
<span>Hello {{* name}}</span>
Vue.js 2.0去除了{{*}}這種寫法,採用v-once代替。
<span>Hello {{* name}}</span> // console中修改name屬性後依然輸出 Hello Vue
2.HTML屬性
Mustache標籤也一樣適用於HTML屬性中,例如:
<div id="id-{{id}}"></div> // <div id="id-1"></div>
Vue.js 2.0廢棄了這種寫法,用v-bind指令代替。
<div v-bind:id="'id-' + id"></div> // <div id="id-1"></div> 或簡寫爲: <div :id="'id-' + id"></div> // <div id="id-1"></div>
3.綁定表達式
放在Mustache標籤內的文本內容稱爲綁定表達式。除了直接輸出屬性值以外,一段綁定表達式能夠由一個簡單的JavaScript表達式和可選的一個或多個過濾器構成。例如:
<div>{{index + 1}}</div> // <div>1</div> <div>{{index == 0 ? 'a' : 'b'}}</div> // <div>a</div> <div>{{name.split('').join('|')}}</div> // <div>V|u|e</div>
每一個綁定中只能包含單個表達式,並不支持JavaScript語句,不然Vue.js就會拋出warning異常。而且綁定表達式裏不支持正則表達式,若是須要進行復雜的轉換,可使用過濾器或者計算屬性來進行處理。
4.過濾器
Vue.js容許在表達式後添加可選的過濾器,以管道符""指示。示例:
<div>{{name | uppercase}}</div> // VUE
Vue.js將name的值傳入給uppercase這個過濾器中(本質是一個函數),返回字符串中的大寫值。同時也容許多個過濾器鏈式使用。例如:
<div>{{name | filterA | filterB}}</div> // VUE
也容許入多個參數,例如:
<div>{{name | filterA arg1 arg2}}</div> // VUE
注意:Vue.js 2.0中已經去除了內置的過濾器,不過能夠聲明自定義過濾器。
5.指令
修飾符:修飾符(Modifiers)是以半角句號.開始的特殊後綴,用於表示指令應該以特殊方式綁定。
<button v-on:click.stop="doClick"></button>
v-on的做用是在對應的DOM元素上綁定事件監聽器,doClick爲函數名,而stop即爲修飾符,做用是中止冒泡,至關於調用了e.stopPropagation()。
2、計算屬性
在項目開發中,展現的數據每每須要通過一些處理。除了在模板中綁定表達式或者利用過濾器外,Vue.js還提供了計算屬性方法。
1.基礎例子
<div id="app"> <div>{{firstName}}</div> <div>{{lastName}}</div> <div>{{fullName}}</div> </div> <script> var vm = new Vue({ el: '#app', data: { firstName: 'Gavin', lastName: 'CLY' }, computed: { fullName: function () { return this.firstName + ' ' + this.lastName } } }); </script> 輸出結果: Gavin CLY Gavin CLY
對vm.firstName和vm.lastName進行修改,始終會影響vm.fulllName。
2.Setter
計算屬性的Setter方法,在更新屬性時帶來了便利。例如:
<div id="app"> <div>¥{{price}}</div> </div> <script> var vm = new Vue({ el: '#app', data: { cents: 100 }, computed: { price: { set: function (newValue) { this.cents = newValue * 100; }, get: function () { return (this.cents / 100).toFixed(2); } } } }); </script> 輸出結果:¥1.00
在處理商品價格的時候,後端每每會把價錢定義成以分爲單位的整型,避免在處理浮點類型數據時產生的問題。而前端則須要把價錢再轉成元進行展現,若是須要對價錢進行修改,要把輸入的價格再恢復到分傳給後端,很繁瑣。使用Vue.js的計算屬性,能夠將vm.cents設置爲後端所存的數據,計算屬性price爲前端展現和更新的數據。
此時更改vm.price=2,vm.cents會被更新爲200,在傳遞給後端時無需再手動轉化一遍數據。
3、表單控件
Vue.js中提供v-model指令對錶單元素進行雙向數據綁定。
js代碼:
var vm = new Vue({ el: '#app', data: { message: '', gender: '', checked: '', multiChecked: [], selected: '', multiSelected: [], a: 'checked', b: 'checked' } });
1.Text 輸入框示例,用戶輸入的內容和vm.message直接綁定:
<input type="text" v-model="message"> <div>Your input is : {{message}}</div>
2.Radio 單選框示例:
<label><input type="radio" value="male" v-model="gender">男</label> <label><input type="radio" value="female" v-model="gender">女</label> <div>{{gender}}</div>
gener值即爲選擇的radio元素的value值。
3.Checkbox 分兩種狀況:單個勾選框和多個勾選框。
單個勾選框,v-model即爲布爾值,此時input的value值並不影響v-model的值。
<input type="checkbox" v-model="checked"> <div>checked: {{ checked }}</div>
多個勾選框,v-model使用相同的屬性名稱,且屬性爲數組。
<label><input type="checkbox" value="1" v-model="multiChecked">1</label> <label><input type="checkbox" value="2" v-model="multiChecked">2</label> <label><input type="checkbox" value="3" v-model="multiChecked">3</label> <div>multiChecked: {{ multiChecked }}</div>
請輸入代碼
4.Select 同checkbox元素同樣,也分單選和多選兩種,多選的時候也須要綁定到一個數組。
單選:
<select v-model="selected"> <option>A</option> <option>B</option> <option>C</option> </select> <div>selected: {{ selected }}</div>
多選:
<select v-model="multiSelected" multiple> <option>A</option> <option>B</option> <option>C</option> </select> <div>multiSelected: {{ multiSelected }}</div>
注意:multiple 屬性規定可同時選擇多個選項。
在不一樣操做系統中,選擇多個選項的差別:
對於 windows:按住 Ctrl 按鈕來選擇多個選項 對於 Mac:按住 command 按鈕來選擇多個選項
因爲上述差別的存在,同時因爲須要告知用戶可使用多項選擇,對用戶更友好的方式是使用複選框。
提示:能夠把 multiple 屬性與 size 屬性配合使用,來定義可見選項的數目。
5.參數特性
默認狀況下,v-model在input事件中同步輸入框值與數據,加lazy屬性後會在change事件中同步。number會自動將用戶輸入轉爲Number類型,若是原值轉換結果爲NaN則返回原值。不過Vue.js 2.0中取消了lazy和number做爲參數,用修飾符來代替。新增了trim修飾符,去掉輸入值首尾空格。
<input type="text" v-model.lazy="message" @change="changeFn"> <input type="text" v-model.number="message"> <input type="text" v-model.trim="message">
4、模板渲染
1.先後端渲染對比:兩種方式各有本身的優缺點,須要根據本身的業務場景來選擇技術方案。
前端渲染的優勢在於:
① 業務分離,後端只須要提供數據接口,前端在開發時也不須要部署對應的後端環境,經過一些代理服務器工具就能遠程獲取後端數據進行開發,可以提高開發效率。
② 計算量轉移,本來須要後端渲染的任務轉移給了前端,減輕了服務器的壓力。
後端渲染的優勢在於:
① 對搜索引擎友好。
② 首頁加載時間短,後端渲染加載完成後就直接顯示HTML,但前端渲染在加載完成後還須要有段js渲染的時間。
Vue.js 2.0開始支持服務端渲染,從而讓開發者在使用上有了更多的選擇。
2.v-if vs v-show
當v-if和v-show的條件發生變化時,v-if引發了dom操做級別的變化,而v-show僅發生了樣式的變化,從切換的角度考慮v-show消耗的性能要比v-if小。
除此以外,v-if切換時,Vue.js會有一個局部編譯/卸載的過程,由於v-if中的模板也可能包括數據綁定或子組件。v-if會確保條件塊在切換當中適當地銷燬與中間內部的事件監聽器和子組件。並且v-if是惰性的,若是在初始化條件爲假時,v-if自己什麼都不會作,而v-show則仍會進行正常的操做,而後吧css樣式設置爲display:none。
總的來講,v-if有更高的切換消耗,而v-show有更高的初始渲染消耗,咱們須要根據實際的使用場景來選擇合適的指令。
3.列表渲染v-for指令
Vue.js對data中數組的原生方法進行了封裝,因此在改變數時能觸發視圖更新,但如下兩種狀況是沒法觸發視圖更新的:
① 經過索引直接修改數組元素,例如 vm.items[0] = { title: 'title-changed' };
對於這種狀況,Vue.js提供了$set方法,在修改數據的同時進行視圖更新,能夠寫成:vm.items.$set(0, {title: 'title-changed'}) 或者 vm.$set('items[0]', {title: 'title-changed'}),兩種方式皆能夠達到效果。
② 沒法直接修改「修改數組」的長度,例如 vm.items.length = 0;
在列表渲染的時候,有個性能方面的小技巧,若是數組中有惟一標識id,經過track-by給數組設定惟一標識,這樣Vue.js在渲染過程當中會盡可能複用原有對象的做用域及DOM元素。
<li v-for="item in items" track-by="id"></li>
track-by已經替換爲key,它的工做方式與其餘屬性同樣,沒有v-bind或者:前綴,它會被做爲一個字符串處理。多數狀況下,須要使用具備完整表達式的動態綁定來替換靜態的key。如今應寫爲:
<li v-for="item in items" v-bind:key="item.id"></li>
5、事件綁定與監聽
1.在直接綁定methods函數和內聯JavaScript語句時,都有可能須要獲取原生DOM事件對象,如下兩種方式均可以獲取:
<div id="app"> <button v-on:click="showEvent">showEvent</button> <button v-on:click="showEvent($event)">showEvent</button> <!--下面這樣寫獲取不到event showEvent方法中輸出undefined--> <button v-on:click="showEvent()">showEvent</button> </div> <script> var vm = new Vue({ el: '#app', methods: { showEvent(event) { console.log(event); } } }); </script>
同一個元素上也能夠經過v-on綁定多個相同事件函數,執行順序爲順序執行,例如:
<div v-on:click="sayFrom('first')" v-on:click="sayFrom('second')">say</div> // 執行參數爲first的
2.修飾符
Vue.js爲指令v-on提供了多個修飾符,方便出來一些DOM時間的細節,而且修飾符能夠串聯使用。主要修飾符以下:
.stop 等同於調用event.stopPropagation()
.prevent 等同於調用event.preventDefault()
.capture 使用capture模式添加事件監聽器
.self 只當事件是從監聽元素自己觸發時才觸發回調
使用方式以下:
<a v-on:click.stop="doThis">say</a> <!--阻止表單默認提交事件--> <form v-on:submit.prevent="onSubmit"></form> <!--阻止默認提交事件且阻止冒泡--> <form v-on:submit.stop.prevent="onSubmit"></form> <!--也能夠只有修飾符,並不綁定事件--> <form v-on:submit.stop.prevent></form>
嘗試運行如下這個例子,更好地理解修飾符的做用。
<div id="app"> <!--只點擊紅色div,彈出'click from inner',點擊藍色div,彈出'click from inner'和'click from self'--> <div v-on:click="saySelf('click from inner')" v-on:click.self="saySelf('click from self')" style="width:600px;border:1px solid blue;"> <div style="width:100px;border:1px solid red;">div</div> </div> <!--點擊button 觸發button以及父元素div的saySelf事件 彈出'just button click'和'div'--> <div v-on:click="saySelf('div')"> <button v-on:click="saySelf('button click')">button</button> </div> <!--點擊button 觸發button的saySelf事件 彈出'just button click'--> <div v-on:click="saySelf('div')"> <button v-on:click.stop="saySelf('just button click')">button</button> </div> </div> <script> var vm = new Vue({ el: '#app', methods: { saySelf(msg) { alert(msg); } } }); </script>
除了事件修飾符以外,v-on還提供了按鍵修飾符,方便咱們監聽鍵盤事件中的按鍵。例如:
<div id="app"> <!--監聽input的輸入,當輸入回車時觸發saySelf函數(回車的keyCode值爲13),用於處理常見的用戶輸入完直接按回車鍵提交--> <input type="text" v-on:keyup.13="saySelf('回車鍵')"> </div> <script> var vm = new Vue({ el: '#app', methods: { saySelf(msg) { alert(msg); } } }); </script>
Vue.js給一些經常使用的按鍵名提供了別稱,這樣就省去了記一些keyCode。所有按鍵別名爲:enter,tab,delete,esc,space,up,down,left,right。例如:
<input type="text" v-on:keyup.enter="saySelf('回車鍵')">
Vue.js也容許咱們本身定義按鍵別名,例如:
<input type="text" v-on:keyup.f1="saySelf(112)"> Vue.directive('on').keyCodes.f1 = 112;
Vue.js 2.0中能夠直接在Vue.config.keyCodes裏添加自定義按鍵別名,無需修改v-on指令,例如:
<input type="text" v-on:keyup.13="saySelf('回車鍵')"> Vue.config.keyCodes.f1 = 13; <input type="text" @keyup.media-play-pause="method"> Vue.config.keyCodes = { v: 86, f1: 112, // camelCase 不可用 mediaPlayPause: 179, // 取而代之的是 kebab-case 且用雙引號括起來 "media-play-pause": 179, up: [38, 87] }
1、內置指令
1.v-bind
擁有三種修飾符,分別爲.sync .once .camel。在Vue.js 2.0中修飾符.sync .once均被廢棄,規定組件間僅能單向傳遞,若是子組件須要修改父組件,則必須使用事件機制來進行處理。
.camel 將綁定的特性名字轉回駝峯命名。之鞥呢用於普通HTML屬性的綁定,一般會用於svg標籤下的屬性,例如:<svg width='400' height='300' :view-box.camel='viewBox'></svg>,輸出結果即爲<svg width='400' height='300' :viewBox='viewBox'></svg>
2.v-for
Vue.js 2.0中作了些細微的調整,大體包括如下幾個方面:
① 參數順序變化
當包含參數index或key時,對象參數修改成(item, index)或(value, key),這樣與JS Array對象的新方法forEach和map,以及一些對象迭代器(例如lodash)的參數能保持一致。
② v-bind:key
屬性track-by被v-bind:key代替,<li v-for="item in items" track-by="id"></li>須要改寫爲<li v-for="item in items" v-bind:key="item.id"></li>
③ n in 10
v-for="n in 10"中的n由原來的0 ~ 9迭代變成1 ~ 10迭代。
3.v-el 和 v-ref
v-el指令爲DOM元素註冊了一個索引,使得咱們能夠直接訪問DOM元素。語法上說能夠經過所屬實例的$els屬性調用。
v-ref指令與v-el類型,只不過v-ref做用於子組件上,實例能夠經過$refs訪問子組件。命名方式也類型,想使用駝峯命名的話用「-」來作鏈接。
注意:Vue.js 2.0中,v-el和v-ref合併爲一個ref屬性了,能夠在組件實例中經過$refs來調用。這意味着 v-el:my-element 將寫成這樣:ref="myElement",v-ref:my-component 變成了這樣:ref="myComponent"。綁定在通常元素上時,ref 指 DOM 元素,綁定在組件上時,ref 爲一組件實例。
<div id="app"> <div ref="demo">there is a el demo</div> </div> <script> var vm = new Vue({ el: '#app', methods: { saySelf(msg) { alert(msg); }, } }); console.log(vm.$refs.demo.innerText); // there is a el demo </script>
由於 v-ref 再也不是一個指令了而是一個特殊的屬性,它也能夠被動態定義了。這樣在和v-for 結合的時候是頗有用的:
<p v-for="item in items" v-bind:ref="'item' + item.id"></p>
之前 v-el/v-ref 和 v-for 一塊兒使用將產生一個 DOM 數組或者組件數組,由於無法給每一個元素一個特定名字。如今你還仍然能夠這樣作,給每一個元素一個一樣的ref:
<p v-for="item in items" ref="items"></p>
和 1.x 中不一樣,$refs 不是響應的,由於它們在渲染過程當中註冊/更新。只有監聽變化並重復渲染才能使它們響應。
另外一方面,設計$refs主要是提供給 js 程序訪問的,並不建議在模板中過分依賴使用它。由於這意味着在實例以外去訪問實例狀態,違背了 Vue 數據驅動的思想。
4.v-pre
v-pre指令就是跳過編譯這個元素和子元素,顯示原始的{{}}Mustache標籤,用來減小編譯時間。例如:
<div id="app"> <div v-pre>{{ uncompiled }}</div> </div> <script> var vm = new Vue({ el: '#app', data: { uncompiled: 'There is an uncompiled element' } }); </script> 輸出結果爲:<div>{{ uncompiled }}</div>
5.v-cloak
v-cloak指令至關於在元素上添加了一個[v-cloak]的屬性,直到關聯的實例結束編譯。官方推薦能夠和css規則[v-cloak]{display:none}一塊兒使用,能夠隱藏未編譯的Mustache標籤直到實例準備完畢。例如:
<div v-cloak>{{ msg}}</div>
6.v-once
v-once指令是Vue.js 2.0中新增的內置指令,用於標明元素或組件只渲染一次,即便隨後發生綁定數據的變化或更新,該元素或組件以及包含的子元素都不會再次被編譯和渲染。至關於明確標註了這些元素不須要被更新,因此v-once的做用是最大程度地提高了更新行爲中頁面的性能,能夠略過一些明確不須要變化的步驟。使用方式以下:
<div v-once>{{ uncompiled }}</div> <my-component v-once :msg="msg"></my-component>
2、自定義指令基礎
一、指令的註冊
能夠經過Vue.directive(id, definition)方法註冊一個全局自定義指令,接收參數id和定義對象。id是指令的惟一標識,定義對象則是指令的相關屬性及鉤子函數。例如:
Vue.directive('global-directive', definition); // 只註冊了這個指令,並無賦予這個指令任何功能 <div v-global-directive></div> // 能夠在模板中這麼使用
除了在全局註冊指令外,也能夠經過在組件的directives選項註冊一個局部的自定義指令。例如:
var comp = Vue.extend({ directives: { 'localDirective': {} // 能夠採用駝峯式命名 } }); // 該指令就只能在當前組件內經過v-local-directive的方式調用,而沒法被其餘組件調用。
2.指令的定義對象
註冊指令的同時,能夠傳入definition定義對象,對指令賦予一些特殊功能。一個指令定義對象主提供以下幾個鉤子函數(均爲可選):
bind:只被調用一次,在指令第一個綁定到元素上時調用。
inserted:被綁定元素插入父節點時調用 (僅保證父節點存在,但不必定已被插入文檔中)。
update:Vue.js 1.0指令在bind以後以初始值爲參數進行第一次調用,以後每次當綁定值發生變化時調用,update接收到的參數爲newValue和oldValue。Vue.js 2.0中變化:
指令綁定bind函數執行後不直接調用update函數。 只要組件發生重繪,不管指令接受的值是否發生變化,均會調用update函數。若是須要過濾沒必要要的更新,則可使用binding.value == binding.oldValue來判斷。
componentUpdated:指令所在組件的 VNode 及其子 VNode 所有更新後調用。
unbind:指令從元素上解綁時調用,只調用一次。
鉤子函數參數(即 el、binding、vnode 和 oldVnode)
指令鉤子函數會被傳入如下參數:
el:指令所綁定的元素,能夠用來直接操做 DOM 。
binding:一個對象,包含如下屬性:
name:指令名,不包括 v- 前綴。
value:指令的綁定值,例如:v-my-directive="1 + 1" 中,綁定值爲 2。
oldValue:指令綁定的前一個值,僅在 update 和 componentUpdated 鉤子中可用。不管值是否改變均可用。
expression:字符串形式的指令表達式。例如 v-my-directive="1 + 1" 中,表達式爲 "1 + 1"。
arg:傳給指令的參數,可選。例如 v-my-directive:foo 中,參數爲 "foo"。
modifiers:一個包含修飾符的對象。例如:v-my-directive.foo.bar 中,修飾符對象爲 { foo: true, bar: true }。
vnode:Vue 編譯生成的虛擬節點。移步 VNode API 來了解更多詳情。
oldVnode:上一個虛擬節點,僅在 update 和 componentUpdated 鉤子中可用。
除了 el 以外,其它參數都應該是隻讀的,切勿進行修改。若是須要在鉤子之間共享數據,建議經過元素的 dataset 來進行。
使用了這些屬性的自定義鉤子樣例:
<div id="hook-arguments-example" v-demo:foo.a.b="message"></div> Vue.directive('demo', { bind: function (el, binding, vnode) { var s = JSON.stringify el.innerHTML = 'name: ' + s(binding.name) + '<br>' + 'value: ' + s(binding.value) + '<br>' + 'expression: ' + s(binding.expression) + '<br>' + 'argument: ' + s(binding.arg) + '<br>' + 'modifiers: ' + s(binding.modifiers) + '<br>' + 'vnode keys: ' + Object.keys(vnode).join(', ') } }) new Vue({ el: '#hook-arguments-example', data: { message: 'hello!' } }) 輸出結果: name: "demo" value: "hello!" expression: "message" argument: "foo" modifiers: {"a":true,"b":true} vnode keys: tag, data, children, text, elm, ns, context, functionalContext, key, componentOptions, componentInstance, parent, raw, isStatic, isRootInsert, isComment, isCloned, isOnce
鉤子函數實例和參數變化
<div id="demo" v-my-msg:console.log="content"></div> <script> Vue.directive('my-msg', { bind: function (el, binding, vnode) { console.log('el', el); console.log('binding', binding); console.log('vnode', vnode); } }); var vm = new Vue({ el: '#demo', data: { content: 'there is the content' } }); </script>
函數簡寫
在不少時候,可能想在bind和update時觸發相同行爲,不關心其它的鉤子。能夠直接傳入一個函數代替定義對象:
<div id="demo" v-color-swatch="red">ddd</div> <div v-color-swatch="red">ddd</div> <script> Vue.directive('color-swatch', function (el, binding) { el.style.backgroundColor = binding.value; }); var vm = new Vue({ el: '#demo', data: { red: 'red' } }); </script>
對象字面量
若是指令須要多個值,能夠傳入一個 JavaScript 對象字面量。指令函數可以接受全部合法的 JavaScript 表達式。
<div v-demo="{ color: 'white', text: 'hello!' }"></div> Vue.directive('demo', function (el, binding) { console.log(binding.value.color) // => "white" console.log(binding.value.text) // => "hello!" });
Vue.js 容許自定義過濾器,可被用於一些常見的文本格式化。過濾器能夠用在兩個地方:雙花括號插值和 v-bind 表達式 (後者從 2.1.0+ 開始支持)。過濾器應該被添加在 JavaScript 表達式的尾部,由「管道」符號指示:
<!-- 在雙花括號中 --> {{ message | capitalize }} <!-- 在 `v-bind` 中 --> <div v-bind:id="rawId | formatId"></div>
能夠在一個組件的選項中定義本地的過濾器:
filters: { capitalize: function (value) { if (!value) return '' value = value.toString() return value.charAt(0).toUpperCase() + value.slice(1) } }
或者在建立 Vue 實例以前全局定義過濾器:
Vue.filter('capitalize', function (value) { if (!value) return '' value = value.toString() return value.charAt(0).toUpperCase() + value.slice(1) }) new Vue({ // ... })
過濾器函數總接收表達式的值 (以前的操做鏈的結果) 做爲第一個參數。在上述例子中,capitalize 過濾器函數將會收到 message 的值做爲第一個參數。
過濾器能夠串聯:
{{ message | filterA | filterB }}
在這個例子中,filterA 被定義爲接收單個參數的過濾器函數,表達式 message 的值將做爲參數傳入到函數中。而後繼續調用一樣被定義爲接收單個參數的過濾器函數 filterB,將 filterA 的結果傳遞到 filterB 中。
過濾器是 JavaScript 函數,所以能夠接收參數:
{{ message | filterA('arg1', arg2) }}
這裏,filterA 被定義爲接收三個參數的過濾器函數。其中 message 的值做爲第一個參數,普通字符串 'arg1' 做爲第二個參數,表達式 arg2 的值做爲第三個參數。
日期格式化過濾器:
<div id="app"> {{date | date('yyyy-MM-dd hh:mm:ss')}} </div> <script> // 日期格式化 Vue.filter('date', function (value, format) { var o = { 'M+': value.getMonth() + 1, // 月份 'd+': value.getDate(), // 日 'h+': value.getHours(), // 小時 'm+': value.getMinutes(), // 分 's+': value.getSeconds(), // 秒 }; if (/(y+)/.test(format)) format = format.replace(RegExp.$1, (value.getFullYear() + '').substr(4 - RegExp.$1.length)); for (var k in o) { if (new RegExp('('+ k + ')').test(format)) format = format.replace(RegExp.$1, (RegExp.$1.length == 1) ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)); } return format; }); var vm = new Vue({ el: '#app', data: { date: new Date() } }); // 顯示結果:2019-04-10 17:19:17 </script>
概述
Vue 在插入、更新或者移除 DOM 時,提供多種不一樣方式的應用過渡效果。
包括如下工具:
1、單元素/組件的過渡
Vue 提供了 transition 的封裝組件,在下列情形中,能夠給任何元素和組件添加進入/離開過渡
直接使用transition標籤並設定其屬性來定義一個過渡效果。例如:
<div id="demo"> <button v-on:click="show = !show"> Toggle </button> <transition name="fade"> <p v-if="show">hello</p> </transition> </div>
new Vue({ el: '#demo', data: { show: true } })
.fade-enter-active, .fade-leave-active { transition: opacity .5s; } .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ { opacity: 0; }
1.過渡的類名
在進入/離開的過渡中,會有 6 個 class 切換。
對於這些在過渡中切換的類名來講,若是你使用一個沒有名字的 <transition>,則 v- 是這些類名的默認前綴。若是你使用了 <transition name="my-transition">,那麼 v-enter 會替換爲 my-transition-enter。
經常使用的過渡都是使用 CSS 過渡。下面是一個簡單例子:
<div id="example-1"> <button @click="show = !show"> Toggle render </button> <transition name="slide-fade"> <p v-if="show">hello</p> </transition> </div>
new Vue({ el: '#example-1', data: { show: true } })
/* 能夠設置不一樣的進入和離開動畫 */ /* 設置持續時間和動畫函數 */ .slide-fade-enter-active { transition: all .3s ease; } .slide-fade-leave-active { transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0); } .slide-fade-enter, .slide-fade-leave-to /* .slide-fade-leave-active for below version 2.1.8 */ { transform: translateX(10px); opacity: 0; }
2.CSS 動畫
CSS 動畫用法同 CSS 過渡,區別是在動畫中 v-enter 類名在節點插入 DOM 後不會當即刪除,而是在 animationend 事件觸發時刪除。
<div id="example-2"> <button @click="show = !show">Toggle show</button> <transition name="bounce"> <p v-if="show">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis enim libero, at lacinia diam fermentum id. Pellentesque habitant morbi tristique senectus et netus.</p> </transition> </div>
new Vue({ el: '#example-2', data: { show: true } })
.bounce-enter-active { animation: bounce-in .5s; } .bounce-leave-active { animation: bounce-in .5s reverse; } @keyframes bounce-in { 0% { transform: scale(0); } 50% { transform: scale(1.5); } 100% { transform: scale(1); } }
3.自定義過渡的類名
能夠經過如下特性來自定義過渡類名:
他們的優先級高於普通的類名,這對於 Vue 的過渡系統和其餘第三方 CSS 動畫庫,如 Animate.css 結合使用十分有用。示例:
<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css"> <div id="example-3"> <button @click="show = !show"> Toggle render </button> <transition name="custom-classes-transition" enter-active-class="animated tada" leave-active-class="animated bounceOutRight" > <p v-if="show">hello</p> </transition> </div> new Vue({ el: '#example-3', data: { show: true } })
JavaScript 鉤子
能夠在屬性中聲明 JavaScript 鉤子
<transition v-on:before-enter="beforeEnter" v-on:enter="enter" v-on:after-enter="afterEnter" v-on:enter-cancelled="enterCancelled" v-on:before-leave="beforeLeave" v-on:leave="leave" v-on:after-leave="afterLeave" v-on:leave-cancelled="leaveCancelled" > <!-- ... --> </transition>
// ... methods: { // -------- // 進入中 // -------- beforeEnter: function (el) { // ... }, // 當與 CSS 結合使用時 // 回調函數 done 是可選的 enter: function (el, done) { // ... done() }, afterEnter: function (el) { // ... }, enterCancelled: function (el) { // ... }, // -------- // 離開時 // -------- beforeLeave: function (el) { // ... }, // 當與 CSS 結合使用時 // 回調函數 done 是可選的 leave: function (el, done) { // ... done() }, afterLeave: function (el) { // ... }, // leaveCancelled 只用於 v-show 中 leaveCancelled: function (el) { // ... } }
這些鉤子函數能夠結合 CSS transitions/animations 使用,也能夠單獨使用。
注意:
一個使用 Velocity.js 的簡單例子:
<!-- Velocity是一款高校的動畫引擎,能夠單獨使用也能夠配合jQuery使用。 和 jQuery.animate 的工做方式相似,也是用來實現 JavaScript 動畫的一個很棒的選擇 --> <script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script> <div id="example-4"> <button @click="show = !show"> Toggle </button> <transition v-on:before-enter="beforeEnter" v-on:enter="enter" v-on:leave="leave" v-bind:css="false" > <p v-if="show"> Demo </p> </transition> </div>
new Vue({ el: '#example-4', data: { show: false }, methods: { beforeEnter: function (el) { el.style.opacity = 0 el.style.transformOrigin = 'left' }, enter: function (el, done) { Velocity(el, { opacity: 1, fontSize: '1.4em' }, { duration: 300 }) Velocity(el, { fontSize: '1em' }, { complete: done }) }, leave: function (el, done) { Velocity(el, { translateX: '15px', rotateZ: '50deg' }, { duration: 600 }) Velocity(el, { rotateZ: '100deg' }, { loop: 2 }) Velocity(el, { rotateZ: '45deg', translateY: '30px', translateX: '30px', opacity: 0 }, { complete: done }) } } })
2、初始渲染的過渡
能夠經過 appear 特性設置節點在初始渲染的過渡
<transition appear> <!-- ... --> </transition>
這裏默認和進入/離開過渡同樣,一樣也能夠自定義 CSS 類名。
<transition appear appear-class="custom-appear-class" appear-to-class="custom-appear-to-class" (2.1.8+) appear-active-class="custom-appear-active-class" > <!-- ... --> </transition>
自定義 JavaScript 鉤子:
<transition appear v-on:before-appear="customBeforeAppearHook" v-on:appear="customAppearHook" v-on:after-appear="customAfterAppearHook" v-on:appear-cancelled="customAppearCancelledHook" > <!-- ... --> </transition>
appear主要用於元素的首次渲染,若是同時聲明瞭enter和appear的相關鉤子函數,元素首次渲染的時候會使用appear系鉤子函數,再次渲染的時候才使用enter系鉤子函數。
2、多個元素的過渡
咱們以後討論多個組件的過渡,對於原生標籤可使用 v-if/v-else 。最多見的多標籤過渡是一個列表和描述這個列表爲空消息的元素:
<transition> <table v-if="items.length > 0"> <!-- ... --> </table> <p v-else>Sorry, no items found.</p> </transition>
能夠這樣使用,可是有一點須要注意:當有相同標籤名的元素切換時,須要經過 key 特性設置惟一的值來標記以讓 Vue 區分它們,不然 Vue 爲了效率只會替換相同標籤內部的內容。即便在技術上沒有必要,給在 <transition> 組件中的多個元素設置 key 是一個更好的實踐。示例:
<transition> <button v-if="isEditing" key="save"> Save </button> <button v-else key="edit"> Edit </button> </transition>
在一些場景中,也能夠經過給同一個元素的 key 特性設置不一樣的狀態來代替 v-if 和 v-else,上面的例子能夠重寫爲:
<transition> <button v-bind:key="isEditing"> {{ isEditing ? 'Save' : 'Edit' }} </button> </transition>
使用多個 v-if 的多個元素的過渡能夠重寫爲綁定了動態屬性的單個元素過渡。例如:
<transition> <button v-if="docState === 'saved'" key="saved"> Edit </button> <button v-if="docState === 'edited'" key="edited"> Save </button> <button v-if="docState === 'editing'" key="editing"> Cancel </button> </transition>
能夠重寫爲:
<transition> <button v-bind:key="docState"> {{ buttonMessage }} </button> </transition>
// ... computed: { buttonMessage: function () { switch (this.docState) { case 'saved': return 'Edit' case 'edited': return 'Save' case 'editing': return 'Cancel' } } }
過渡模式mode
同時生效的進入和離開的過渡不能知足全部要求,因此 Vue 提供了過渡模式,控制過渡插入/移除的前後順序,主要用於元素切換時。可供選擇的值有「out-in」 「in-out」,若是不設置,則同時調用。
<div id="app"> <button @click="show = !show"> Toggle </button> <transition name="fade" mode="out-in"> <div :key="show">{{show}}</div> </transition> </div> <script> var vm = new Vue({ el: '#app', data: { show: true } }); </script>
當show在true和false切換時,mode="out-in"決定先移除<div>true</div>,等過渡結束後,再插入<div>true</div>元素,mode="in-out"則相反。
列表過渡
怎麼同時渲染整個列表,好比使用 v-for ?在這種場景中,使用 <transition-group> 組件。這個組件的特色:
列表的進入/離開過渡
<div id="app"> <button @click="pushFn">push</button> <transition-group name="list" appear tag="ul"> <li v-for="item in items" :key="item.id" class="list-li">{{item.text}}</li> </transition-group> </div> <script> var vm = new Vue({ el: '#app', data: { items: [ {id: 1, text: '11'}, {id: 2, text: '22'}, {id: 3, text: '33'} ] }, methods: { pushFn() { this.items.push({id: 4, text: '44'}); } } }); </script> <style> .list-li{ width: 100px; height: 20px; transform: translate(0, 0); } .list-enter,.list-leave-active{ opacity: 0; transform: translate(-30px, 0); } .list-enter-active, .list-leave-active{ transition: all 0.5s ease; } </style>
列表的排序過渡
列表的交錯過渡
可複用的過渡
動態過渡
1、組件註冊
Vue.js提供了兩種註冊方式,分別是全局註冊和局部註冊。
全局註冊須要確保在根實例初始化以前註冊,這樣才能使組件在任意實例中被使用,示例:
Vue.component('my-component-name', { // ... 選項 ... }) // 這條語句須要寫在new Vue({ el: '#app' })以前。 Vue.component('component-a', { /* ... */ }) Vue.component('component-b', { /* ... */ }) Vue.component('component-c', { /* ... */ }) new Vue({ el: '#app' }) <div id="app"> <component-a></component-a> <component-b></component-b> <component-c></component-c> </div> // 這三個組件在各自內部也均可以相互使用。
若是你使用一個像 webpack 這樣的構建系統,全局註冊全部的組件意味着即使你已經再也不使用一個組件了,它仍然會被包含在你最終的構建結果中。這形成了用戶下載的 JavaScript 的無謂的增長。
局部註冊則限定了組件只能在被註冊的組件中使用,而沒法在其餘組件中使用,示例:
var ComponentA = { /* ... */ } var ComponentB = { /* ... */ } var ComponentC = { /* ... */ } new Vue({ el: '#app', components: { 'component-a': ComponentA, 'component-b': ComponentB } })
對於 components 對象中的每一個屬性來講,其屬性名就是自定義元素的名字,其屬性值就是這個組件的選項對象。
注意局部註冊的組件在其子組件中不可用。例如,若是你但願 ComponentA 在 ComponentB 中可用,則你須要這樣寫:
var ComponentA = { /* ... */ } var ComponentB = { components: { 'component-a': ComponentA }, // ... }
或者若是你經過 Babel 和 webpack 使用 ES2015 模塊,:
import ComponentA from './ComponentA.vue' export default { components: { ComponentA }, // ... }
注意在 ES2015+ 中,在對象中放一個相似 ComponentA 的變量名實際上是 ComponentA: ComponentA 的縮寫,即這個變量名同時是:
構造器寫法:Vue.extend({})
<div id="app"> <my-component></my-component> <parent></parent> </div> <script> // 全局註冊 var MyComponent = Vue.extend({ template: '<p>This is a component</p>' }); Vue.component('my-component', MyComponent); // 局部註冊 var Parent = Vue.extend({ template: `<div><p>This is a parent component</p> <my-child></my-child> </div>`, components: { 'my-child': { template: '<p>This is a child component</p>' } } }); var vm = new Vue({ el: '#app', components: { parent: Parent } }); </script>
Vue 組件的基本示例:
<div id="app"> <button-counter></button-counter> </div> <script> // 組件是可複用的 Vue 實例,因此它們與 new Vue 接收相同的選項,例如 data、computed、watch、methods 以及生命週期鉤子等。僅有的例外是像 el 這樣根實例特有的選項。 Vue.component('button-counter', { // 一個組件的 data 選項必須是一個函數,所以每一個實例能夠維護一份被返回對象的獨立的拷貝: data: function () { return { count: 0 } }, template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>' }); var vm = new Vue({ el: '#app' }); </script>