4.深入理解Vue组件
4.1使用组件的细节点(is、自定义组件中data、ref)
vue中is的属性引入是为了解决dom结构中对放入html的元素有限制的问题,例如上图不正确渲染就会出现上图所示结果,譬如ul里面要接上li的标签或者tbody下要接上tr时,引入is的属性后,你完全可以写成这样
//我这个是li标签,同时使用row组件
<div class="language-html">
<ul>
<li is="row"></li>
</ul>
</div>
这样会保证dom结构在浏览器的正常渲染,也保证可以使用组件,尽量避免在不正确的结构中直接使用组件
<script>
Vue.component('row', {
template: '<li>this is a row</li>'
})
</script>
Vue.component中得data:
//不是New vue里面data,组件data后面要是函数,New Vue中data可以定义是对象
Vue.component('row',{
data:function(){
return {
content:'this is content'
}
},
template:'<tr><td>{{content}}</td></tr>'
})
ref:引用,获取dom节点,同样也可以获取一个组件
<!--//ref引用-->
//此时this.$refs获取的是dom元素
<div
ref='hello'
@click='handleClick'>
hello world
</div>
handleClick:function(){
console.log(this.$refs.hello.innerHTML) //this.$refs.hello获取所有引用中的hello这个,获取dom节点, 输出结果是hello world
}
//此时this.$refs是对组件的引用,然后再获取组件的dom节点/数据/methods等
<div>
<counter ref="one" @change="handleChange"></counter>
<counter ref="two" @change="handleChange"></counter>
<div>{{total}}</div>
</div>
Vue.component('counter',{
template:'<div @click="handleClick01">{{number}}</div>',
data:function(){
return {
number:0
}
},
methods:{
handleClick01:function(){
this.number ++
this.$emit('change')
}
}
})
methods:{
handleChange:function(){
//针对每次得变化进行求和
this.total = this.$refs.one.number + this.$refs.two.number
}
}
ref调用组件完整代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
</style>
<script type="text/javascript" src="https://cdn.bootcss.com/vue/2.6.3/vue.min.js"></script>
</head>
<body>
<!--Vue中is/ref的示例-->
<div id="app">
<ul>
<li is="row"></li>
</ul>
<counter ref="one" @change="handleClick"></counter>
<counter ref="two" @change="handleClick"></counter>
<div>{{total}}</div>
</div>
<script>
Vue.component('row',{
data:function(){
return {
content:'this is content'
}
},
template:'<li>{{content}}</li>'
})
Vue.component('counter',{
data:function(){
return {
number:0
}
},
template:'<div @click="handleClick01">{{number}}</div>',
methods:{
handleClick01:function(){
this.number++;
this.$emit('change')
}
}
})
var app = new Vue({
el:"#app",
data:{
total:''
},
methods:{
handleClick:function(){
this.total = this.$refs.one.number + this.$refs.two.number;
}
}
})
</script>
</body>
</html>
4.2父子组件间的数据传递(建议是子组件不直接修改父组件传来的值,可以通过拷贝进行修改)
父组件通过属性的方式向子组件传递数据。
props和emit
单向数据流:父组件可以向子组件直接传值,子组件不能直接修改父组件传递过来的数据,但是可以通过在子组件中拷贝一个副本处理props:['count'] number:this.count
进行处理,类似下面代码。
<counter :count="2" @count="countNum"></counter>
Vue.component('counter',{
props:['count'],
template:'<div @click="handleClick01">{{number}} | {{count}}</div>',
data:function(){
return {
number:this.count //从父组件传递过来的值拷贝一个副本进行处理
}
},
methods:{
handleClick01:function(){
this.number ++
this.$emit('count')
}
}
})
methods:{
countNum:function(){
}
}
可以看上面ref对组件引用的完整代码,了解$emit。
上面这种子组件不直接修改父组件传过来的值,通过拷贝进行修改,就是Vue中的单向数据流,但是Vue中数据是双向绑定的。
参考文章:
https://juejin.im/entry/59e8b8a8518825579d131e51
https://www.jianshu.com/p/1ebc15645abe
https://blog.csdn.net/LeonBec/article/details/78019486
附注:父组件向子组件传值,count前加不加:区别
//加:表示后面是JavaScript表达式,此时是number类型,不加:此时"1"是字符串类型
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
<div id="app">
<runoob :count="0"></runoob>
</div>
<script>
// 注册
Vue.component('runoob', {
props:["count"],
template: '<h1 @click="handleClick">{{count}}自定义组件!</h1>',
methods:{
handleClick:function(){
console.log(typeof this.count);
}
}
})
// 创建根实例
new Vue({
el: '#app'
})
</script>
</body>
</html>
4.3组件参数校验与非props特性
参数校验,是子组件对父组件传递的值进行一些约束。
<!--f父组件向子组件传递content-->
<child content="hello world"></child>
Vue.component('child',{
props:{ //上面不约束时候props后面是数组,此时props是对象
content:String //规定content必须是字符串类型,这就是参数校验
// content:[Number,String] 字符串或者数字类型,还可以更复杂
},
template: '<div>Child | {{content}}</div>'
})
//更复杂形式
content:{
type:String,
required:false,
default:'default value',
validator:function(value){ //检验器,长度大于5
return (value.length > 5)
}
}
props特性:
父组件传递的值,如果子组件有对应接收,就是props特性,传递的值(content=“hell”)不会显示在源代码中,不会显示在DOM树中。
<child content=''hell'></child>
Vue.component('child',{
props:{
content:String //规定content必须是字符串类型,这就是参数校验
},
template: '<div>Child | {{content}}</div>'
})
非props特性:
父组件传,子组件不接,要传递的属性值(content=“hell”)会显示在DOM树中。
重点记住:
Vue中的:
加的时候代表是一个变量,不加代表是一个字符串。
4.4给组件绑定原生事件
本来点击组件触发事件要通过组件内部,然后$emit传递到父组件,然后在new Vue中书写函数,但是我们能不能直接在组件中书写函数,而不是通过两次事件传递。
可以这么理解,在组件上的监听是自定义事件,在元素上绑定是原生事件。
// 通过添加修饰符.native
<child @click.native = "handleClick"></child>
Vue.component('child',{
template:'<div>Child</div>'
})
new Vue({
el:'#root',
methods:{
handleClick:function(){
alert('click')
}
}
})
//之前的写法
<child></child>
Vue.component('child',{
template:"<div @click="handleClick">Child</div>",
methods:{
handle:function(){
}
}
})
4.5非父子组件间的传值
非父子组件间的传值:
- Vuex
- 总线机制(Bus / 发布订阅模式 / 观察者模式):
Vue.prototype.bus = new Vue();
让原型属性 bus 指向一个 Vue 实例,让其充当非父子组件之间传值的桥梁,相当于计算机各种功能部件之间传送信息的公共通信干线(总线 Bus)- 给 Vue 类加上原型属性 bus, 这样每个 Vue 实例都能访问到原型属性 bus
- 利用 bus 的实例方法 $emit 触发事件
- 再利用生命周期方法(钩子) mounted 给 bus 绑定监听函数, 在事件触发时执行
懂原型的自然就懂bus了,所有的Vue实例都有一些共用的属性和方法,存放这些属性和方法的对象叫原型。相当于Vue实例1把数据传入这个共用的属性bus上,其他Vue实例就自然可以享用这个数据,因为它们的原型地址指向同一块堆内存。
相当于一辆公交车,一些数据从某一个站通过bus传到另一个站,完成信息传输。
通俗的说整个过程:
在vue的prototype上创建一个bus,用于数据运输想要获取什么数据,就在该子组件创建点击事件,通过触发实现数据传输,以emit将属性上传给bus,实现属性共有,再在另一个子组件,通过this.bus.$on的方式在mounted的时候获取到数据,并新建一个值去接受它。(传输的数据通过emit传输到bus,需要的组件通过on在mounted时候获取到数据。)
子组件的的this指的时子组件本身,通过proptype把所有的vue都有了bus属性,所有的vue都可以调用这个属性,同时这个bus属性是个new Vue(),所以有$emit()事件,通过此次挂载,实现非父子组件之间的事件触发,实现传值的目的。
父组件通过props向子组件传值,子组件通过事件触发向父组件传值。
比较复杂的传值:
两种解决方法:
1.vuex
2.发布订阅模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document(Bus/总线/发布订阅模式/观察者模式)</title>
<script type="text/javascript" src="https://cdn.bootcss.com/vue/2.6.3/vue.min.js"></script>
</head>
<body>
<div id="root">
<child content="Dell"></child>
<child content="Lee"></child>
</div>
<script type="text/javascript">
//js代码中先将prototype的bus挂载在vue实例中
//然后每一次的this(vue实例)都将挂载有这个bus属性
//就是让这个vue实例被所有vue实例所共享
Vue.prototype.bus = new Vue()
Vue.component('child',{
data:function(){
return {
selfContent: this.content
}
},
props:{
content:String
},
template:'<div @click=handleClick"">{{content}}</div>',
methods:{
handleClick:function(){
this.bus.$emit('change',this.selfContent)
}
},
mounted:function(){ //this.bus.$on() 里面的函数中的 this 指的是属性 bus 指向的 vue 实例。而函数外部的 this 指的是 vue 组件。所以使用var this_ = this 处理下
var this_ = this
this.bus.$on('change',function(msg){ //change事件这个函数,不一定自什么时候被谁调用,所以this是说不准会指向哪里的,所以要想指向外部的this,就要提前保存着。
this_.selfContent = msg
})
}
})
var vm = new Vue({
el:'#root'
})
</script>
</body>
</html>
this.bus.$on() 里面的函数中的 this 指的是属性 bus 指向的 vue 实例。而函数外部的 this 指的是 vue 组件。
关于上面代码中var _this = this;中this的指向问题可以看:https://coding.imooc.com/learn/questiondetail/52358.html
还可以查看文章:
https://cloud.tencent.com/developer/article/1352108
https://juejin.im/post/5c778631f265da2ddf789d69
https://blog.csdn.net/xiasohuai/article/details/80664605
https://segmentfault.com/a/1190000012555128
https://noobakong.cn/2018/12/06/vue%E4%B8%AD%E7%88%B6%E5%AD%90%E7%BB%84%E4%BB%B6%E4%BC%A0%E5%80%BC%E5%92%8CBus%E6%80%BB%E7%BA%BF%E4%BC%A0%E5%80%BC/
4.6在Vue中使用插槽
一句话:插槽内可以是任意内容
<div id="app">
<child-component>你好</child-component>
</div>
<script>
Vue.component('child-component',{
template:`
<div>Hello,World!</div>
`
})
let vm = new Vue({
el:'#app',
data:{
}
})
</script>
输出内容还是在组件中的内容,在<child-component>
内写的内容没起作用。
这时候就需有插槽了。
Vue.component('child-component',{
template:`
<div>
Hello,World!
<slot></slot> //我们还可以在slot中写默认值,当上面调用组件时候没有写入值,会填入默认值
</div>
`
})
我们现在给组件增加一个<slot></slot>
插槽
我们在<child-component></child-component>
内写的"你好"起作用了!!!
到现在,我们知道了什么是插槽:
插槽就是Vue实现的一套内容分发的API,将<slot></slot>
元素作为承载分发内容的出口。
具名插槽,就是给这个插槽起个名字
在组件中,我给插槽起个名字,一个名字叫"girl",一个名字叫"boy",还有一个不起名字。
然后再<child-component></child-component>
内,slot属性对应的内容都会和组件中name一一对应。
而没有名字的,就是默认插槽!!
<div id="app">
<child-component>
<div slot="girl">
漂亮、美丽、购物、逛街
</idv>
<div slot="boy">
帅气、才实
</div>
<div>
我是一类人,
我是默认的插槽
</div>
</child-component>
</div>
<script>
Vue.component('child-component',{
template:`
<div>
<h4>这个世界不仅有男人和女人</h4>
<slot name="girl"></slot>
<div style="height:1px;background-color:red;"></div>
<slot name="boy"></slot>
<div style="height:1px;background-color:red;"></div>
<slot></slot>
</div>
`
})
let vm = new Vue({
el:'#app',
data:{
}
})
</script>
4.7作用域插槽
作用域插槽:说白了就是我在组件上的属性,可以在组件元素内使用!
作用域插槽的使用场景:
子组件循环并且是从父组件传入HTML元素的时候,
或者说,同一个组件在不同地方使用,需要展现不同的样子,这时候就需要作用域插槽。
先看一个最简单的例子!!
我们给<slot></slot>
元素上定义一个属性say(随便定义的!),接下来在使用组件child,然后在template元素上添加属性slot-scope!!随便起个名字a
我们把a打印一下发现是 {“say” : “你好”},也就是slot上面的属性和值组成的键值对!!!(也就是a是slot上面的键值对(属性和值))
这就是作用域插槽!
<div id="app">
<child :lists="nameList">
<template slot-scope="a">
{{a}}
</template>
</child>
</div>
<script>
Vue.component('child',{
props:['lists'],
template:`
<div>
<ul>
<li v-for="list in lists">
<slot :bbbbb="list"></slot>
</li>
</ul>
</div>
`
})
let vm = new Vue({
el:'#app',
data:{
nameList:[
{id:1,name:'孙悟空'},
{id:2,name:'猪八戒'},
{id:3,name:'沙和尚'},
{id:4,name:'唐僧'},
{id:5,name:'小白龙'},
]
}
})
</script>
更多可以参考文章:https://www.cnblogs.com/chinabin1993/p/9115396.html
子组件循环遍历的item,父组件得到放在props里,然后props.item进行获取。这样每一项显示什么,是由子组件决定,子组件从父组件获取属性,下面的格式是固定的。
<template slot-scope=" ">
</template>
也就是相对默认插槽,可以传递值和在子组件修改样式。
作用域插槽进一步理解
参考文章:https://juejin.im/post/5d5b9b2fe51d4561f64a080c
为什么要有作用域插槽?我们调用插槽时候,想在父组件中的插槽中调用子组件的数据,就可以使用作用域插槽。
<script src="https://unpkg.com/vue"></script>
<div id="app">
//然后就可以接收传过来的值,绑定在 <slot> 元素上的特性被称为插槽 prop。在父组件中,我们可以用 v-slot 设置一个值来定义我们提供的插槽 prop 的名字,然后直接使用就好了
<child v-slot:default="slotProps">
{{slotProps.usertext.firstName}}
</child>
</div>
<script>
Vue.component('child',{
data(){
return{
user:{
firstName:"Fan",
lastName:"Jun"
}
}
},
template:`
<div>
<!-- 设置默认值:{{user.lastName}}获取 Jun -->
<!-- 如果home.vue中给这个插槽值的话,则不显示 Jun -->
<!-- 设置一个 usertext 然后把user绑到设置的 usertext 上 -->
<slot v-bind:usertext="user">{{user.lastName}}</slot>
</div>
`
})
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
</script>
4.8动态组件与v-once指令
<div id="app">
//1.第一种方法,利用v-if判断切换
<child-one v-if = "type === 'child-one' "></child-one>
<child-two v-if = "type === 'child-two' "></child-two>
//2.第二种方法,利用动态组件切换,component 是Vue自带的标签,表示是一个动态组件
//根据type的值加载对应的组件
<component :is="type"></component>
<button @click="handleBtnClick">Change</button>
</div>
<script>
Vue.component('child-one',{
template:'<div v-once>child-one</div>'
})
Vue.component('child-two',{
template:'<div v-once>chile-two</div>'
})
var app = new Vue({
el:"#app",
data:{
type:'child-one'
},
methods:{
handleBtnClick:function(){
this.type =
this.type === 'child-one' ? 'child-two' : 'child-one';
}
}
})
</script>
加入v-once后,从内存读取,所以可以利用v-once指令可以提高一些静态内容的展示效率。
v-once:只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。
5.Vue中的动画特效
本章将讲解 Vue 中的 Css 及 Js 动画原理,以及在 Vue 中如使用 Animate.css 及Velocity.js 动画库,在理解了基础动画原理后,本章还扩展了 Vue 中多元素及列表过渡效果实现的知识,并会带同学们学习如何对通用动画效果进行代码封装。
关于本节动画笔记还可以参考:https://blog.csdn.net/cckevincyh/article/details/87903552
5.1Vue动画-Vue中CSS动画原理
动画开始前有fade-enter、fade-enter-active两个class,当动画执行一帧后,fade-enter消失,fade-enter-to添加。
下面为什么是fade-enter-active呢?因为fade-enter消失后,fade-enter-active会一直存在整个动画过程,也就是下面6s之间,opacity从0到1.当运行第一帧的时候,fade-enter、fade-enter-active同时存在,处于隐藏状态,第二帧fade-enter消失,整个6s动画过程都是fade-enter-active在起作用。
不同过程中会添加/删除不同样式。
<style type="text/css">
.fade-enter{
opacity: 0
}
.fade-enter-active{
transition: opacity 6s;
}
/*
*刚刚开始,两个都存在,动画开始时fade-enter消失,所以是从消失到显示
*fade是因为name是fade,默认情况是v(没有name时候),其他名字也可以
*下面是从显示到消失(注意是fade-leave-to)
*/
.fade-leave-to{
opacity: 0;
}
.fade-leave-active{
transition:opacity 6s;
}
</style>
<div id="root">
<transition name="fade">
<div v-if="show">hello world</div>
</transition>
<button @click="handleClick">点击</button>
</div>
<script type="text/javascript">
var vm = new Vue({
el:'#root',
data:{
show:true
},
methods:{
handleClick:function(){
this.show = ! this.show
}
}
})
</script>
Vue中一般称上面为过渡动画。
注意:v-leave和v-leave-to相当于动画开始和最终的状态,v-leave-active用来实现两个状态过渡的方式,比如设置时间什么的,enter同理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello World</title>
<script type="text/javascript" src="./vue.js"></script>
<style>
/*隐藏到现实*/
.fade-enter{ /*第一帧存在,第二帧就移除了,所以是opacity从0到1的过程*/
opacity: 0
}
.fade-enter-active{
transition: opacity 1s;
}
.fade-enter-to{
}
/*显示到隐藏*/
.fade-leave-to{/*opacity从1到0,fade-leave-active一直在监听*/
opacity:0;
}
.fade-leave-active{
transition:opacity 1s;
}
</style>
</head>
<body>
<div id="app">
<transition name="fade">
<div v-if="show">hello world</div>
</transition>
<button @click="handleClick">切换</button>
</div>
<script>
var app = new Vue({
el:'#app',
data:{
show:true
},
methods:{
handleClick:function(){
this.show = !this.show
}
}
})
</script>
</body>
</html>
Vue中css动画:
在需要设置动画标签外部用<transition></transition>
包裹,可以添加name属性
1.没有name属性,css 默认前缀是v,类名:
隐藏到显示:第一帧加载v-enter;v-enter-cative,第二帧将v-enter清除,添加v-enter-to,最后一帧将所有类名删掉
显示到隐藏:第一帧加载v-leave,v-leace-active,第二帧将v-leave清除,添加v-leave-to,最后一帧将所有类名删掉
2.有name属性时,css前缀为name的属性值
通过在某一时刻,向div元素自动添加class的底层原理,vue实现动画
5.2在Vue中使用animate.css库
我们可以通过以下特性来自定义过渡类名:
1.enter-class
2.enter-active-class
3.enter-to-class (2.1.8+)
4.leave-class
5.leave-active-class
6.leave-to-class (2.1.8+)
使用@keyframes形式动画:
<style type="text/css">
@keyframes bounce-in {
0%{
transform: scale(0); /*2D/3D转换transform*/
}
50%{
transform: scale(1.5);
}
100%{
transform: scale(1);
}
}
.active{
transform-origin:left center;
animation: bounce-in 1s;
}
.active{
transform-origin:left center;
animation: bounce-in 1s reverse;
}
</style>
<div id="root">
<!--可以自定义class-->
<transition name="fade"
enter-active-class="active"
leave-active-class="leave">
<div v-if="show">hello world</div>
</transition>
<button @click="handleClick">点击</button>
</div>
<script type="text/javascript">
var vm = new Vue({
el:'#root',
data:{
show:true
},
methods:{
handleClick:function(){
this.show = ! this.show
}
}
})
</script>
使用animate.css:
<body>
<div id="root">
<!--可以自定义class-->
<transition name="fade"
enter-active-class="animated swing"
leave-active-class="animated shake">
<div v-if="show">hello world</div>
</transition>
<button @click="handleClick">点击</button>
</div>
<script type="text/javascript">
var vm = new Vue({
el:'#root',
data:{
show:true
},
methods:{
handleClick:function(){
this.show = !this.show
}
}
})
</script>
</body>
animate.css中提供的动画效果和CSS3中的@keyframes动画效果一样。
还可以参考链接:https://www.jianshu.com/p/fd861af247e5
5.3在Vue中同时使用过渡和动画
可以通过 appear 特性设置节点的在初始渲染的过渡。
<transition
appear
appear-class="custom-appear-class"
appear-active-class="custom-appear-active-class"
>
</transition>
.custom-appear-class{
font-size: 40px;
color: red;
background: green;
}
.custom-appear-active-class{
background: green;
}
也就是当前transition
元素第一次渲染时的过渡动画,它也提供了两个css动画钩子:
appear
:表示是否开启此特性
appear-class
:表示元素渲染完毕后应用的css样式,它里面的css样式会参与整个动画的过渡
appear-active-class
:也表示元素渲染完毕后应用的css样式,它不参与整个动画的过渡
同时使用过渡和动画(添加fade-enter-active和fade-leave-active):
<style type="text/css">
.fade-enter, .fade-leave-to{
opacity: 0;
}
.fade-enter-active, .fade-leave-active{
transition: opacity 3s;
}
</style>
<body>
<div id="root">
<!--可以自定义class-->
<transition
type="transition"
//:duration="10000"
name="fade"
appear
enter-active-class="animated swing fade-enter-active"
leave-active-class="animated shake fade-leave-active"
appear-active-class="animated swing"
>
<div v-if="show">hello world</div>
</transition>
<button @click="handleClick">点击</button>
</div>
<script type="text/javascript">
var vm = new Vue({
el:'#root',
data:{
show:true
},
methods:{
handleClick:function(){
this.show = !this.show
}
}
})
</script>
</body>
还有一个问题:animate.css动画默认是1秒,过渡动画我们设置是3秒,那么时间是怎么样?
有两种解决方法:
1.我们可以设置type==“transition”
2.设置:duration=“10000” / duration="{enter:10000,leave:10000}"
5.4Vue中Js动画与Velocity.js的结和
JavaScript钩子:
beforeEnter、enter、afterEnter、enterCancelled
beforeLeave、leave、afterLeave、leaveCancelled
JS动画:
<!--JS动画效果-->
<!--handleBeforeEnter在显示之前触发该事件-->
<div id="root">
<transition
name="fade"
@before-enter="handleBeforeEnter"
@enter="handleEnter"
@after-enter="handleAfterEnter"
>
<div v-if="show">hello world</div>
</transition>
<button @click="handleClick">点击</button>
</div>
<script type="text/javascript">
var vm = new Vue({
el:'#root',
data:{
show:true
},
methods:{
handleClick:function(){
this.show = ! this.show
},
handleBeforeEnter: function(el){
//el事transition包裹的标签div
el.style.color = 'red'
},
handleEnter:function(el,done){
setTimeout(()=>{
el.style.color = 'green'
},2000)
setTimeout(()=>{
done()
},40000)
},
handleAfterEnter:function(el){
el.style.color = '#000'
}
}
})
</script>
Velocity.js:
<body>
<!--JS动画效果-->
<!--handleBeforeEnter在显示之前触发该事件-->
<div id="root">
<transition
name="fade"
@before-enter="handleBeforeEnter"
@enter="handleEnter"
@after-enter="handleAfterEnter"
>
<div v-if="show">hello world</div>
</transition>
<button @click="handleClick">点击</button>
</div>
<script type="text/javascript">
var vm = new Vue({
el:'#root',
data:{
show:true
},
methods:{
handleClick:function(){
this.show = ! this.show
},
handleBeforeEnter: function(el){
el.style.opacity = 0;
},
handleEnter:function(el,done){
Velocity(el,{opacity:1},
{duration:1000,
complete:done
})
},
handleAfterEnter:function(el){
}
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello World</title>
<script type="text/javascript" src="./vue.js"></script>
<link href="./animate.css" rel="stylesheet">
<style>
/*
transition 补间动画
type="transition" 指定以transition动画时长为准
:duration="10000" 指定自定义动画时长
:duration="{enter:5000,leave:10000}" 更复杂的自定义;
*/
.fade-enter {
opacity: 0;
}
.fade-enter-active{
transition: opacity 3s;
}
.fade-leave-to{
opacity: 0;
}
.fade-enter-active{
transition: opacity 3s;
}
</style>
</head>
<body>
<div id="app">
<!--type="transition" -->
<transition
:duration="10000"
name="fade"
appear
enter-active-class="animated swing fade-enter-active"
leave-active-class="animated shake fade-leave-active"
appear-active-class="animated swing">
<div v-if="show">hello world</div>
</transition>
<button @click="handleClick">切换</button>
</div>
<script>
var app = new Vue({
el:'#app',
data:{
show:true
},
methods:{
handleClick:function(){
this.show = !this.show
}
}
})
</script>
</body>
5.5Vue中多个元素或组件的过渡
在vue更新DOM时,如果key值相同则会对原有组件进行复用,如果不同,则会重新生成。
可以参考文章:
https://blog.csdn.net/qq_41861679/article/details/80659278
https://www.jianshu.com/p/7838e1e765ae
多个元素的过渡:
<style type="text/css">
.v-enter, .v-leave-to{
opacity: 0;
}
.v-enter-active, .v-leave-active{
transition: opacity 1s;
}
</style>
<body>
<div id="root">
<!--在vue更新DOM时,如果key值相同则会对原有组件进行复用,如果不同,则会重新生成。
-->
<transition mode="in-out">
<div v-if="show" key="hello">hello world</div>
<div v-else key="bye">Bye World</div>
</transition>
<button @click="handleClick">点击</button>
</div>
<script type="text/javascript">
var vm = new Vue({
el:'#root',
data:{
show:true
},
methods:{
handleClick:function(){
this.show = !this.show
}
}
})
</script>
</body>
我们还要了解一个概念:过渡模式
Vue 提供了 过渡模式:
1.in-out:新元素先进行过渡,完成之后当前元素过渡离开。
2.out-in:当前元素先进行过渡,完成之后新元素过渡进入。
用 out-in 重写之前的开关按钮过渡:
<transition name="fade" mode="out-in">
<!-- ... the buttons ... -->
</transition>
多个组件的过渡:
<style type="text/css">
.v-enter, .v-leave-to{
opacity: 0;
}
.v-enter-active, .v-leave-active{
transition: opacity 1s;
}
</style>
<transition mode="out-in">
<child></child>
<child-one></child-one>
</transition>
//通过动态组件实现过渡
<style type="text/css">
.v-enter, .v-leave-to{
opacity: 0;
}
.v-enter-active, .v-leave-active{
transition: opacity 1s;
}
</style>
<transition>
<component :is="type"></component>
</transition>
<button @click="handleClick">toggle</button>
data:{
type:'child'
}
methods:{
handleClick:function(){
this.type=
this.type === 'child' ? 'child-one' : 'child';
}
}
5.6Vue中的列表过渡
<style type="text/css">
.v-enter, .v-leave-to{
opacity: 0;
}
.v-enter-active, .v-leave-active{
transition: opacity 1s;
}
</style>
<body>
<div id="root">
<transition-group>
<div v-for="item of list" :key="item.id">
{{item.title}}
</div>
</transition-group>
<button @click="handleBtnClick">Add</button>
</div>
<script type="text/javascript">
var count=0;
var vm = new Vue({
el:'#root',
data:{
list:[]
},
methods:{
handleBtnClick:function(){
this.list.push({
id:count++,
title:"hello world"
})
}
}
})
</script>
</body>
5.7Vue中的动画封装
利用组件封装,把一个动画封装在一个组件里面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script type="text/javascript" src="https://cdn.bootcss.com/vue/2.6.3/vue.min.js"></script>
<style type="text/css">
</style>
</head>
<body>
<div id="root">
<fade :show="show">
<div>hello world</div>
</fade>
<button @click="handleClick">点击</button>
</div>
<script type="text/javascript">
Vue.component('fade',{
props:['show'],
template:`
<transition @before-enter="handleBeforeEnter"
@enter="handleEnter">
<slot v-show="show"></slot>
</transition>`,
methods:{
handleBefore:function(el){
el.style.color = 'red'
},
handleEnter:function(el,done){
setTimeout(()=>{
el.style.color = 'green'
done()
},2000)
}
}
})
var vm = new Vue({
el:'#root',
data:{
show:true
}
})
</script>
</body>
</html>
5.8本章小结
更多动画学习可以去官网查看资料。