Vue筆記系列
一、Vue.js入門
二、Vue.js漸進
把一個普通 Javascript 對象傳給 Vue 實例的 data選項,Vue 將遍歷此對象全部的屬性,並使用 Object.defineProperty(中文版) 把這些屬性所有轉爲 getter/setter。
Object.defineProperty 是僅 ES5 支持,且沒法 shim(什麼是shim?) 的特性,這也就是爲何 Vue 不支持 IE8 以及更低版本瀏覽器的緣由。javascript
Vue 不能檢測到對象屬性的添加或刪除。因爲 Vue 會在初始化實例時對屬性執行 getter/setter 轉化過程,因此屬性必須在 data 對象上存在才能讓 Vue 轉換它,這樣才能讓它是響應的。
解決方法就是以前提到的,可使用 Vue.set(object, key, value)
方法將響應屬性添加到嵌套的對象上。還有就是以前提到的要注意,對象不能是 Vue 實例,或者 Vue 實例的根數據對象。css
因爲 Vue 不容許動態添加根級響應式屬性,乾脆在一開始就就把該加的屬性加上,因此你必須在初始化實例前聲明根級響應式屬性,哪怕只是一個空值。html
參考Vue.js漸進中的API和實例方法中的關於nextTick的介紹。前端
Vue 在插入、更新或者移除 DOM 時,提供多種不一樣方式的應用過渡效果。包括如下工具:vue
(1)單元素、組件的過渡java
Vue 提供了 transition 的封裝組件,在下列情形中,能夠給任何元素和組件添加 entering/leaving 過渡
條件渲染 (使用 v-if)
條件展現 (使用 v-show)
動態組件
組件根節點node
元素封裝成過渡組件以後,在遇到插入或刪除時,Vue 將
一、自動嗅探目標元素是否有 CSS 過渡或動畫,並在合適時添加/刪除 CSS 類名。
二、若是過渡組件設置了過渡的 JavaScript 鉤子函數,會在相應的階段調用鉤子函數。
三、若是沒有找到 JavaScript 鉤子而且也沒有檢測到 CSS 過渡/動畫,DOM 操做(插入/刪除)在下一幀中當即執行。git
過渡的-css-類名
會有 4 個(CSS)類名在 enter/leave 的過渡中切換v-enter
: 定義進入過渡的開始狀態。在元素被插入時生效,在下一個幀移除。v-enter-active
: 定義進入過渡的結束狀態。在元素被插入時生效,在 transition/animation 完成以後移除。v-leave
: 定義離開過渡的開始狀態。在離開過渡被觸發時生效,在下一個幀移除。v-leave-active
: 定義離開過渡的結束狀態。在離開過渡被觸發時生效,在 transition/animation 完成以後移除。
圖示:
github
過渡的-css-類名 例子 ,注意裏面星號部分
<!--css--> .fade-enter-active, .fade-leave-active { transition: opacity .5s } .fade-enter, .fade-leave-active { opacity: 0 } <!--html--> <div id="demo"> <button v-on:click="show = !show"> Toggle </button> <transition name="fade"> <p v-if="show">hello</p> </transition> </div> <!--js--> new Vue({ el: '#demo', data: { show: true } }) 若是<transition name="my-transition">中 name 沒有設置,對於這些在 enter/leave 過渡中切換的類名,v- 是這些類名的默認前綴。 <!--css--> .v-enter-active, .v-leave-active { transition: opacity .5s } .v-enter, .v-leave-active { opacity: 0 } <!--html--> ... <transition> <p v-if="show">hello</p> </transition>
CSS 動畫
CSS 動畫用法同 CSS 過渡,區別是在動畫中 v-enter 類名在節點插入 DOM 後不會當即刪除,而是在 animationend 事件觸發時刪除。web
對於 Vue 的過渡系統和其餘第三方 CSS 動畫庫,如過想跟 Animate.css 結合使用的話,Vue也準備了自定義過渡類名來控制,他們的優先級高於普通的類名。enter-class
enter-active-class
leave-class
leave-active-class
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 結合時使用 enter: function (el, done) { // ... done() //當只用 JavaScript 過渡的時候, 在 enter 和 leave 中,回調函數 done 是必須的 。 不然,它們會被同步調用,過渡會當即完成。 }, afterEnter: function (el) { // ... }, enterCancelled: function (el) { // ... }, // -------- // 離開時 // -------- beforeLeave: function (el) { // ... }, // 此回調函數是可選項的設置 // 與 CSS 結合時使用 leave: function (el, done) { // ... done() //當只用 JavaScript 過渡的時候, 在 enter 和 leave 中,回調函數 done 是必須的 。 不然,它們會被同步調用,過渡會當即完成。 }, afterLeave: function (el) { // ... }, // leaveCancelled 只用於 v-show 中 leaveCancelled: function (el) { // ... } }
JavaScript 鉤子的例子,注意裏面星號部分
<!-- html --> <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" ******推薦對於僅使用 JavaScript 過渡的元素添加 v-bind:css="false",Vue 會跳過 CSS 的檢測。這也能夠避免過渡過程當中 CSS 的影響。 > <p v-if="show"> Demo </p> </transition> </div>
//javascript 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 }) } } }) ******下面說一下,當只用 JavaScript 過渡的時候, 在 enter 和 leave 中,回調函數 done 是必須的 。 不然,它們會被同步調用,過渡會當即完成。 enter: function (el) { Velocity(el, { opacity: 1, fontSize: '1.4em' }, { duration: 300 }) Velocity(el, { fontSize: '1em' }) }, leave: function (el) { Velocity(el, { translateX: '15px', rotateZ: '50deg' }, { duration: 600 }) Velocity(el, { rotateZ: '100deg' }, { loop: 2 }) Velocity(el, { rotateZ: '45deg', translateY: '30px', translateX: '30px', opacity: 0 }) ******能夠看到done不僅是在Velocity的options中去掉了,並且參數中的done也去掉了。這是由於我嘗試只去掉options中的done無論用,仍是正常動畫,只有當參數中的done也去掉,元素離開的時候纔是當即完成的,可是進入的過渡仍是存在。
(2)多個元素的過渡
對於原生標籤可使用 v-if/v-else 。注意: 當有相同標籤名的元素切換時,須要經過 key 特性設置惟一的值來標記以讓 Vue 區分它們,不然 Vue 爲了效率只會替換相同標籤內部的內容。
例如:
<transition> <button v-if="isEditing" key="save"> Save </button> <button v-else key="edit"> Edit </button> </transition>
(3)過渡模式
默認是進入和離開的過渡同時生效。
in-out: 新元素先進行過渡,完成以後當前元素過渡離開。
out-in: 當前元素先進行過渡,完成以後新元素過渡進入。
(4)多個組件的過渡
須要使用動態組件
多個組件過渡的例子
<!--CSS--> <style type="text/css"> #app div{ position: absolute; top: 40px; left: 0px; margin-left: 20px; } #app .component-fade-enter,#app .component-fade-leave-active { opacity: 0; } #app .component-fade-enter { left: -30px; } #app .component-fade-enter-active { transition: all .5s; } #app .component-fade-leave-active { left: 30px; transition: all .5s; } </style> <!--html--> <div id="app"> <button type="button" @click="change">改變</button> <transition name="component-fade" mode="out-in"> <component v-bind:is="view"></component> </transition> </div> <!--javascript--> <script> new Vue({ el: '#app', data: { view: 'v-a' }, components: { 'v-a': { template: '<div>Component A</div>' }, 'v-b': { template: '<div>Component B</div>' } }, methods : { change : function (){ this.view == 'v-a'?this.view = 'v-b':this.view = 'v-a' } } }) </script>
(4)列表過渡
使用 <transition-group>
組件渲染列表。除了 mode,其餘特性和 <transition> 相同。<transition-group>
與<transition>
的不一樣點:
一、不一樣於 <transition>
, `<transition-group>會以一個真實元素呈現:默認爲一個 <span>。你也能夠經過 tag 特性更換爲其餘元素。
二、內部元素 老是須要 提供惟一的 key 屬性值
<div id="list-demo" class="demo"> <button v-on:click="add">Add</button> <button v-on:click="remove">Remove</button> <transition-group name="list" tag="p"> <!--元素是p,下面的key是數組的值--> <span v-for="item in items" v-bind:key="item" class="list-item"> {{ item }} </span> </transition-group> </div>
列表的位移過渡
<transition-group> 支持經過 CSS transform 過渡移動。當一個子節點被更新,從屏幕上的位置發生變化,它將會獲取應用 CSS 移動類(經過 name 屬性或配置 move-class 屬性自動生成)。
<div id="flip-list-demo" class="demo"> <button v-on:click="shuffle">Shuffle</button> <transition-group name="flip-list" tag="ul"> <li v-for="item in items" v-bind:key="item"> {{ item }} </li> </transition-group> </div> <!--沒有move-class,像以前的類名同樣,能夠經過 name 屬性來自定義前綴--> .flip-list-move { transition: transform 1s; } <transition-group name="flip-list" tag="ul" move-class="start"> ··· </transition-group> <!--經過 move-class 屬性手動設置--> .start { transition: transform 1s; } 也能夠這麼寫: <transition-group name="flip-list" tag="ul"> <li v-for="item in items" v-bind:key="item" class="start"> {{ item }} </li> </transition-group> <!--經過子元素的class 屬性手動設置--> .start { transition: transform 1s; }
Vue 使用了一個叫 FLIP 簡單的動畫隊列使用 transforms 將元素從以前的位置平滑過渡新的位置。
須要注意的是使用 FLIP 過渡的元素不能設置爲 display: inline 。做爲替代方案,能夠設置爲 display: inline-block 或者放置於 flex 中
Vue 的過渡系統提供了很是多簡單的方法設置進入、離開和列表的動效(上面提到的那些)。對於數據元素自己的動效,好比:
數字和運算
顏色的顯示
SVG 節點的位置
元素的大小和其餘的屬性**
全部的原始數字都被事先存儲起來,能夠直接轉換到數字。能夠結合 Vue 的響應式和組件系統,使用第三方庫來實現切換元素的過渡狀態。官方文檔中使用的是Tween.js,tween.js是一款可生成平滑動畫效果的js動畫庫,關於它的中文介紹可看一下這篇文章tween.js可生成平滑動畫效果的js動畫庫。
這裏面涉及到watch:
watch一個對象,鍵是須要觀察的表達式,值是對應回調函數。值也能夠是方法名,或者包含選項的對象。Vue 實例將會在實例化時調用 $watch(),遍歷 watch 對象的每個屬性。
var vm = new Vue({ data: { a: 1, b: 2, c: 3 }, watch: { a: function (val, oldVal) { console.log('new: %s, old: %s', val, oldVal) }, // 方法名 b: 'someMethod', // 深度 watcher c: { handler: function (val, oldVal) { /* ... */ }, deep: true } } }) vm.a = 2 // -> new: 2, old: 1
順便再說一下實例方法vm.$watch( expOrFn, callback, [options] )
觀察 Vue 實例變化的一個表達式或計算屬性函數。回調函數獲得的參數爲新值和舊值。表達式只接受監督的鍵路徑。對於更復雜的表達式,用一個函數取代。
注意:在變異(不是替換)對象或數組時,舊值將與新值相同,由於它們的引用指向同一個對象/數組。Vue 不會保留變異以前值的副本。(試了一下,沒有進回調函數)
例子:
// 監督的鍵路徑 vm.$watch('a.b.c', function (newVal, oldVal) { // 作點什麼 }) // 更復雜的表達式==>函數 vm.$watch( function () { return this.a + this.b }, function (newVal, oldVal) { // 作點什麼 } )
vm.$watch 返回一個取消觀察函數,用來中止觸發回調:
var unwatch = vm.$watch('a', cb) // 以後取消觀察 unwatch()
選項:deep
爲了發現對象內部值的變化,能夠在選項參數中指定 deep: true 。注意監聽數組的變更不須要這麼作。
vm.$watch('someObject', callback, { deep: true }) vm.someObject.nestedValue = 123 // callback is fired???
選項:immediate
在選項參數中指定 immediate: true 將當即以表達式的當前值觸發回調:
vm.$watch('a', callback, { immediate: true }) // 當即以 `a` 的當前值觸發回調
Vue 推薦在絕大多數狀況下使用 template 來建立你的 HTML。在某些狀況須要用到比template 更接近編譯器的render函數。
render 函數接收一個 createElement 方法做爲第一個參數用來建立 VNode。
若是組件是一個函數組件,Render 函數還會接收一個額外的 context 參數,爲沒有實例的函數組件提供上下文信息。
createElement
接受的參數:
// @returns {VNode} createElement( // {String | Object | Function} // 一個 HTML 標籤字符串,組件選項對象,或者一個返回值類型爲String/Object的函數,必要參數 'div', // {Object} // 一個包含模板相關屬性的數據對象 // 這樣,您能夠在 template 中使用這些屬性.可選參數. { }, // {String | Array} // 子節點(VNodes),能夠是一個字符串或者一個數組. 可選參數. [ createElement('h1', 'hello world'), createElement(MyComponent, { props: { someProp: 'foo' } }), 'bar' ] )
createElement的第二個屬性data Object參數詳解
{ // 和`v-bind:class`同樣的 API 'class': { foo: true, bar: false }, // 和`v-bind:style`同樣的 API style: { color: 'red', fontSize: '14px' }, // 正常的 HTML 特性 attrs: { id: 'foo' }, // 組件 props props: { myProp: 'bar' }, // DOM 屬性 domProps: { innerHTML: 'baz' }, // 事件監聽器基於 "on" // 因此再也不支持如 v-on:keyup.enter 修飾器 // 須要手動匹配 keyCode。 on: { click: this.clickHandler }, // 僅對於組件,用於監聽原生事件,而不是組件內部使用 vm.$emit 觸發的事件。 nativeOn: { click: this.nativeClickHandler }, // 自定義指令. 注意事項:不能對綁定的舊值設值 // Vue 會爲您持續追蹤 directives: [ { name: 'my-custom-directive', value: '2' expression: '1 + 1', arg: 'foo', modifiers: { bar: true } } ], // Scoped slots in the form of // { name: props => VNode | Array<VNode> } scopedSlots: { default: props => h('span', props.text) }, // 若是組件是其餘組件的子組件,需爲slot指定名稱 slot: 'name-of-slot' // 其餘特殊頂層屬性 key: 'myKey', ref: 'myRef' }
函數化組件
標記組件爲 functional, 組件無狀態(沒有 data),無實例(沒有 this 上下文)。
Vue.component('my-component', { functional: true, // 爲了彌補缺乏的實例 // 提供第二個參數做爲上下文 render: function (createElement, context) { // ... }, // Props 可選 props: { // ... } })
組件須要的一切都是經過上下文傳遞,包括:
props: 提供props 的對象
children: VNode 子節點的數組
slots: slots 對象
data: 傳遞給組件的 data 對象
parent: 對父組件的引用
注意:slots() 和 children 對比
<my-functional-component> <p slot="foo"> first </p> <p>second</p> </my-functional-component>
對於這個組件,children 會給你兩個段落標籤,而 slots().default 只會傳遞第二個匿名段落標籤,slots().foo 會傳遞第一個具名段落標籤。同時擁有 children 和 slots() ,所以你能夠選擇讓組件經過 slot() 系統分發或者簡單的經過 children 接收,讓其餘組件去處理。
Vue.directive( id, [definition] )
註冊或獲取全局指令。
// 註冊 Vue.directive('my-directive', { bind: function () {}, inserted: function () {}, update: function () {}, componentUpdated: function () {}, unbind: function () {} }) // 註冊(傳入一個簡單的指令函數) Vue.directive('my-directive', function () { // 這裏將會被 `bind` 和 `update` 調用 }) // getter,返回已註冊的指令 var myDirective = Vue.directive('my-directive')
鉤子函數
指令定義函數提供了幾個鉤子函數(可選):
鉤子函數參數
鉤子函數被賦予瞭如下參數:
binding: 一個對象,包含如下屬性:
注意:除了 el以外,其它參數都應該是隻讀的,儘可能不要修改他們。若是須要在鉤子之間共享數據,建議經過元素的 dataset 來進行。
例子:
html <div id="hook-arguments-example" v-demo:hello.a.b="message"></div> javascript 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!' } })
這個demo放到了github上,有時間會把它整理到個人github主頁的一個小欄目裏,那樣就是方便看了。
從github上用各類方法下載到本地,找到index.html文件,雙擊就能看到效果
推薦一下微信公衆號:《web前端教程》的一篇vue實戰案例,你們能夠關注一下這個公衆號,他的教程都是挺新的,並且很基礎很基礎,個人這個demo就是在根據他的例子(特別是樣式),增長了計數,增長了本地存儲。
最後,這三篇文章是從個人簡書裏面搬來的。