VUE 入门基础(9)
十一,深入响应式原理
声明响应式属性
由于Vue不允许动态添加根级响应式属性,所以你必须在初始化实例钱声明根级响应式属性,哪怕只有一个空值。
var vm = new Vue({ data:{ // 声明 message 为一个空字符串 message: ' ' }, template: '<div>{{ message }}</div>' }) // vm.message = 'Hello!' vm.message = 'Hello!'
如果你在data 选项中未声明 message,Vue 将警告你渲染函数早试图访问的属性不存在。
异步更新队列
<div id="example">{{message}}</div> var vm = new Vue({ el:'#example', data: { message: '123' } }) vm.message = 'new message' // 更改数据 vm.$el.textContent === 'new message' // false Vue.nextTick(function() { vm.$el.textContent === 'new message' //true })
在组件内使用 vm.$nextTick() 实例方法特别方便,应为它不需要全局Vue ,并且回调函数中 this
将自动绑定到当前Vue
Vue.component('example', { template: '<span> {{ message }}</span>', data: function() { return { message: 'not updated' } }, methods: { updateMessage: function() { this.message = 'updated' console.log(this.$el.textContent) // => 'not updated' this.$nextTick(function () { console.log(this.$el.textContent) // => 'updated' }) } } })
十二,过度效果
在插入,更新或者移除DOM 时,提供多种不同方式的应用过度效果。
在css过度和动画中自动应用class
可以配合使用第三方css 动画库,如Animate.css
在过度钩子函数中使用JavaScript 直接操作DOM
可以配合使用第三方JavaScript 动画库,如velocity.js
单元素/组件的过度。
vue提供l了 transition 的封装组件,在下列情形中,可以给任何元素和组件添加entering/leaving过度
条件渲染使用(使用 v-if)
条件展示(使用 v-show)
动态组件
组件跟节点
例子:
<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 { opacity: 0 }
元素封装成过渡组件之后,在遇到插入或删除时,Vue 将
1.自动嗅探目标元素是否有 CSS 过渡或动画,并在合适时添加/删除 CSS 类名。
2.如果过渡组件设置了过渡的 JavaScript 钩子函数,会在相应的阶段调用钩子函数
3.如果没有找到 JavaScript 钩子并且也没有检测到 CSS 过渡/动画,DOM 操作(插入/删除)在下一帧中立即执行
#过度的-css-类名
会有4个css 类名在enter/leave 的过度中切换
1. v-enter: 定义进入过度的开始状态,在元素被插入的时生效,在下一个帧移除。
2.v-enter-actvie 定义进入过度的结束状态,在元素被插入时生效,在transition
/animation 完成之后移除。
3.v-leave: 定义离开过度的开始状态,在离开过度被触发时生效,在下一个帧移除。
4.v-leave-active: 定义离开过度的结束状态,在离开过度被处罚时生效,在transition/animation 完成之后移除。
css 过渡
常用的过度都是使用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-active{ transition: translateX(10px); opacity: 0; }
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">Look at me!</p> </transition> </div> new Vue({ el: '#example-2', data: { show: true } }) .bounce-enter-active { animation: bounce .5s; } .bounce-leave-active { animation: bounce .5s; } @keyframes bounce-in { 0%{ transeform: sceale(0); } 50%{ transeform: sceale(1.5); } 100%{ transeform: sceale(1); } } @keyframes bounce-out { 0%{ transeform: sceale(1); } 50%{ transeform: sceale(1.5); } 100%{ transeform: sceale(0); } }
自定义过渡名
我们可以通过以下特性来自定义过渡名:
enter-class
enter-active-class
leave-class
leace-active-class
他们的优先级别高于普通的类名,对于 Vue 的过渡系统和其他第三方 CSS 动画库,如 Animate.css 结合使用十分有用
实例
<div id="example-3"> <button @click="show = !show"> Toggle render </button> <transition name="custom-classes-transititon" enter-active-class="aniamated tada" leave-active-class="animated bounceOutRight" > <p v-if="show">hello</p> </transition> </div> new Vue({ el:'#example-3', data: { show: true } })
同时使用Transitions 和Animations
Vue 为了知道过渡的完成,必须设置相应的事件监听器
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() }, afterEnter: function ( el) { }, enterCancelled: function (el) { }, // 离开时 beforeLeave: function(el) { // }, // 此函数是可选项的设置 // 与 css 结合时使用 leave: function (el, done) { //... done() }, afterLeave: function (el) { //... }, // leaveCancelled 只用于v-show 中 leaveCancelled: function(el) { // ... } }
这些钩子函数可以结合 CSS transitions/animations 使用,也可以单独使用。
初始渲染的过度
可以通过 appear 特性设置节点的在初始渲染的过度。
<transition appear></transition> 这里默认的和进入和离开过度一样,同样也可以自定义css类名 <tranaition appear appear-class="custom-appear-class" appear-active-class="custom-appear-active-class" > </tranaition>
自定义 JavaScript 钩子:
<transition appear v-on:before-appear="customBeforAppearHook" v-on:appear="customAppearHook" v-on:after-appear="customAfterAppearHook" > </transition>
多个元素的过度
多个组件的过度很简单-我们不需要使用key 特性。我们只需要使用动态组件。
<transition name="component-fade" mode="out-in"> <component v-bind:is="view"></component> </transition> new Vue({ el: '#transition-components-demo', data: { view: 'v-a' }, components: { 'v-a': { template: '<div>Component A</div>' }, 'v-b': { template: '<div>Component B</div>' } } }) .component-fade-enter-active, .component-fade-leave-active { transition: opacity .3s ease; } .component-fade-enter, .component-fade-leave-active { opacity: 0; }
列表过度
目前为止,关于过度我们已经完成了:
单个节点
多个节点,其中每次只渲染一个
有一个完整的列表 v-for 我们如何做到同时渲染,我们将使用
<transition -group> 组件。
不同于 <transition> 他会以一个真实元素渲染。默认为<span>也可以通过 tag 属性更换为其他渲染元素。
他的元素必须具有为一个的key 属性
列表的进入和离开
进入和离开的过度使用之前一样的CSS 类名
<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"> <span v-for="item in items" v-bind:key="item" class="list-item" >{{ item }} </span> </transition-group> </div> new Vue({ el: '#list-demo', data: { items: [1,2,3,4,5,6,7,8,9], nextNum: 10 }, methods: { randomIndex: function() { return Math.floor(Math.random() * this.items.length) }, add: function () { this.items.splice(this.radomIndex(), 0,this.nextNum++) }, remove: function () { this.items.splice(this.randomIndex(), 1) } } }) .list-item { display: inline-balock; margin-right:10px; } .list-enter-active, .list-leave-active { transition: all ls; } .list-enter, .list-leave-active { opacity: 0; transform: translateY(30px); }
列表的位移过度
<transition-group> 组件还有一个特殊之处,不仅可以进入和离开动画,还可以改变定位,
要使用这个新功能 v-move 特性,它会在元素的改变定位的过程中应用。
可以通过 name 属性来定义前缀,也可以通过move-class 属性手动设置。
v-move 对于设置过度的过度的切换时机和过度曲线非常有用,
<div id="flip-list-demo" class="demo"> <button v-on:click="shuffle">Shuffle</button> <transition-group name="flip-list" tage="ul"> <li v-for="item in items" v-bind:key="item"> {{item}} </li> </transition-group> </div> new Vue({ el: '#flip-list-demo', data: { items: [1,2,3,4,5,6,7,8,9] }, methods: { shuffle: function () { this.items = _.shuffle(this.items) } } }) .flip-list-move { transition: transform 1s; }
列表的渐进过度
通过data 属性 与 JavaScript 通信,可以实现列表的渐进过度
<div id="staggered-list-demo"> <input v-mode="query"> <transition-group name="staggered-fade" tage="ul" v-bind:css= " false" v-on:before-enter="beforeEnter" v-on:enter = "enter" v-on:leave="l > <li v-for="{item, index} in computedList" v-bind:key = "item.msg" v-bind:data-index="index" >{{ item.msg}}</li> </transition-group> </div> new Vue({ el: '#staggered-list-demo', data: { query:' ', list: [ {msg: 'Bruce Lee'}, {msg: 'Jackie Chan'}, {msg: 'Chunck Norris'}, {msg: 'Jet Li'}, {msg: 'Kung Fury'} ] }, computed: { computedList: function () { var vm = this return this.list.filter(function (item) { return item.msg.toLowerCase().indexOf (vm.query.toLowerCase()) !=== -1 }) } }, methods: { beforeEnter: function (el) { el.style.opacity = 0 el.style.height = 0 }, enter: function (el,done) { var delay= el.dataset.index * 150 setTimeout(function () { Velocity( el, {opacity: 1, height: '1.6em'}, {complete: done} ) }, delay) }, leave: function (el, done) { var delay = el.dataset.index * 150 setTimeout(function () { Velocity( el, {opacity:0, height:0}, {complete: done} ) },delay) } } })
可复用的过度
过度可以通过 Vue 的组件系统实现复用,要创建一个可复用的过度组件,你需要做的就是
将 <transition> 或者 <transition-group> 作为一个跟=根组件,放置在其中就可以了
使用 template 的简单例子
Vue.component('my-special-transition', { template:`\ <transition\ name="very-special-transition"\ mode= "out-in"\ v-on:before-enter="beforeEnter"\ v-on:after-enter="afterEnter"\ >\ <slot></slot> </transition>\ \`, methods: { beforeEnter: function(el) { // ... }, afterEnter: function (el) { // ... } } })
函数组件更适合完成这个任务:
动态过渡
在Vue 中及时是过度也是数据驱动的,动态过度基本是通过name 特性来绑定动态值
<transition v-bind:name="transitionName"></transition>
所有的过渡特性都是动态绑定。它不仅是简单的特性,通过事件的钩子函数方法,可以在获取到相应上下文数据
<div id="dynmic-fade-"> Fade In: <input type="range" v-model="fadeInDuration" min="0" v-bind:max="maxFadeFuration"> Fade Out: <input type="range" v-model="fadeOtDuration" min="0" v-bind:max="maxFadeFuration"> <transition v-bind:css="false" v-on:before-enter="beforeEnter" v-on:enter="enter" v-on:leave="leave" > <p v-if="show">hello</p> </transition> <button v-on:click="stop = true">Stop it!</button> </div> new Vue({ el: '#dynamic-fade-demo', data: { show: true, fadeInDuration: 1000, fadeOutDuration: 1000, maxFadeDuration: 1500, stop: false }, mounted: function () { this.show = false }, methods: { beforeEnter: function (el) { el.style.opacity = 0 }, enter: function (el, done) { var vm = this Velocity(el, { opacity: 1 }, { duration: this.fadeInDuration, complete: function () { done() if (!vm.stop) vm.show = false } } ) }, leave: function (el, done) { var vm = this Velocity(el, { opacity: 0 }, { duration: this.fadeOutDuration, complete: function () { done() vm.show = true } } ) } } })