vue过渡以及动画
1自带类过渡动画<transition></transition>
,如果是列表即用v-for则用<transitiongroup></transitiongroup>
两个大阶段:v-enter-active和v-leave-active,
- 进入阶段分为v-enter进入前,v-enter-to进入后。
- 离开阶段分为v-leave离开前,v-leave-to离开后。
代码举例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
.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;
}
</style>
</head>
<body>
<div id="app">
<transition name="slide-fade">
<p v-if="flag">渐变过渡的效果</p>
</transition>
<button @click="change">点击</button>
</div>
</body>
<script>
var vm = new Vue({
el: "#app",
data: {
flag: true
},
methods: {
change() {
this.flag = (this.flag == true ? false : true)
}
}
})
</script>
</html>
<transsition><!-- 如果设置name属性,则样式的前缀可以自定义,
比如name="a"那么v-enter等要变成a-enter
如果有:duration="{ enter: 500, leave: 800 }"属性,可以设置动画及过渡效果的固定时长,
到达这个1000毫秒后就会强制隐藏或者移除元素-->
<div v-if="isShow">
asdasdasdasdasdasdasd
</div>
</transsition>
<input type="button" @click="isShow=!isShow" value="开始">
data:isShow: false
2自定义过渡动画
如果是自定义过渡动画格式,在<transition name ="my">
,style中v-就变成了my-。
导入animate.css包定义动画
- 导入包
<link rel="stylesheet" type="text/css" href="js/animate.css-main/animate.css-main/source/animate.css"/>
在transition中写入进入和离开阶段的动画类,在DOM中标上class
<transition enter-active-class="bounceIn" leave-active-class="bounceOut" :duration="{enter:500,leave:500}">
<h2 v-if="flag2" class="animated">你好呀!</h2>
</transition>
3.自定义过渡的类名
我们可以通过以下 attribute 来自定义过渡类名:
- enter-class
- enter-active-class
- enter-to-class (2.1.8+)
- leave-class
- leave-active-class
- leave-to-class (2.1.8+)
他们的优先级高于普通的类名,这对于 Vue 的过渡系统和其他第三方 CSS 动画库,如 Animate.css 结合使用十分有用。
举例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="lib/animate.css">
<script src="lib/vue-2.4.0.js"></script>
</head>
<body>
<div id="app">
<button @click="flag=!flag">点击</button>
<transition
name="fade"
enter-active-class="animated tada"
leave-active-class="animated bounceOutRight">
<p v-if="flag">ejw go jw go</p>
</transition>
</div>
</body>
<script>
var vm = new Vue({
el: "#app",
data: {
flag: true
}
})
</script>
</html>
4.同时使用过渡和动画
Vue 为了知道过渡的完成,必须设置相应的事件监听器。它可以是 transitionend 或 animationend,这取决于给元素应用的 CSS 规则。如果你使用其中任何一种,Vue 能自动识别类型并设置监听。
但是,在一些场景中,你需要给同一个元素同时设置两种过渡动效,比如 animation 很快的被触发并完成了,而 transition 效果还没结束。在这种情况中,你就需要使用 type attribute 并设置 animation 或 transition 来明确声明你需要 Vue 监听的类型。
- 显性的过渡持续时间
在很多情况下,Vue 可以自动得出过渡效果的完成时机。默认情况下,Vue 会等待其在过渡效果的根元素的第一个 transitionend 或 animationend 事件。然而也可以不这样设定——比如,我们可以拥有一个精心编排的一系列过渡效果,其中一些嵌套的内部元素相比于过渡效果的根元素有延迟的或更长的过渡效果。
在这种情况下你可以用 组件上的 duration prop 定制一个显性的过渡持续时间 (以毫秒计):
<transition :duration="1000">...</transition>
你也可以定制进入和移出的持续时间:
<transition :duration="{ enter: 500, leave: 800 }">...</transition>
5.动画钩子函数的使用
可以在 attribute 中声明 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 使用,也可以单独使用。
加入购物车案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="lib/vue-2.4.0.js"></script>
<style>
#ball {
width: 15px;
height: 15px;
background-color: brown;
border-radius: 50%;
}
</style>
</head>
<body>
<div id="app">
<button @click="flag=!flag">加入购物车</button>
<transition @befor-enter="beforEnter" @enter="enter" @after-enter="afterEnter">
<div id="ball" v-if="flag"></div>
</transition>
</div>
</body>
<script>
var vm = new Vue({
el: "#app",
data: {
flag: false
},
methods: {
beforEnter(el) {
el.style.transform = 'translate(0, 0)'
},
enter(el, done) {
el.offsetWidth
el.style.transform = 'translate(150px, 450px)'
el.style.transition = 'all 2s ease'
done()
},
afterEnter(el) {
this.flag = false
}
}
})
</script>
</html>
列表的进入/离开过渡
渲染整个列表,比如使用 v-for
在这种场景中,使用 <transition-group>
组件即可实现列表的过渡
特点:
- 不同于
<transition>
,它会以一个真实元素呈现:默认为一个<span>
。也可以通过tag attribute
更换为其他元素。 - 过渡模式不可用,因为我们不再相互切换特有的元素。
- 内部元素总是需要提供唯一的
key attribute
值。 - CSS 过渡的类将会应用在内部的元素中,而不是这个组/容器本身。
举例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="lib/vue-2.4.0.js"></script>
<style>
.slide-enter-active,
.slide-leave-active {
transition: opacity 0.5s;
}
.slide-enter,
.slide-leave-to
/* .fade-leave-active below version 2.1.8 */
{
opacity: 0;
}
table {
border: 1px solid purple;
}
</style>
</head>
<body>
<div id="app">
<button @click="add">添加</button>
<transition-group name="slide">
<table v-for="item in list" :key="item.id">
<tr>
<td>{{item.id}}</td>
<td>{{item.title}}</td>
</tr>
</table>
</transition-group>
</div>
</body>
<script>
var i = 3;
var vm = new Vue({
el: "#app",
data: {
id: 0,
title: "",
list: [{
id: 1,
title: "张三"
}, {
id: 2,
title: "李四"
}]
},
methods: {
add() {
this.list.push({
id: i++,
title: "王五" + "" + i
})
}
}
})
</script>
</html>
vue的自定义组件
什么是组件
组件是可复用的 Vue 实例,且带有一个名字。组件的出现是为了拆分 Vue 实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以去调用对应对的组件即可。
定义全局组件的方式
(1),使用 Vue.extend 创建全局的 Vue 组件:
- 使用 Vue.extend 创建全局组件;
- 使用 Vue.component (‘组件的名称’,创建出来的组件模板对象);
- 如果要使用组件,直接把组件的名称以 HTML 标签的形式,引用到页面中;
注意:如果使用 Vue.component 定义全局组件的时候,组件名称使用了
驼峰命名,则在引用组件的时候,需要把大写的驼峰改为小写字母,同时
两个单词之间使用 短横线(-)连接
Vue.component
- 第一个参数:组件的名称,将来在引用组件的时候,就是一个标签形式来引入它的;
- 第二个参数:
Vue.extend
创建的组件,其中template
就是组件将来要展示的 HTML 内容;
<div id='app'>
<!--3.如果要使用组件,直接把组件的名称以 HTML 标签的形式,引用到页面中-->
<mycom1></mycom1>
</div>
//1.使用 Vue.extend 创建全局组件
var com1 = Vue.extend({
//通过 template 属性,指定组件要展示的 HTML 结构。
template:'<h3>Vue.extend</h3>'
})
//2.使用 Vue.component('组件的名称',创建出来的组件模板对象)
Vue.component('mycom1',com1)
//如果不使用驼峰,则直接拿名称来使用即可
var vm = new Vue({
el:'#app',
data:{},
methods:{}
})
(2)直接使用 Vue.component
方法:
<div id='app'>
<!--如果要使用组件,直接把组件的名称以 HTML 标签的形式,引用到页面中-->
<mycom2></mycom2>
</div>
//使用 Vue.component('组件的名称',组件模板对象),第二个参数直接传入 对象字面量
Vue.component('mycom2',{
template:'<h3>Vue.component</h3>'
})
var vm = new Vue({
el:'#app',
data:{},
methods:{}
})
(3),将模板字符串,定义到 script
标签中:
在被控制的 #app 外面,使用 template 元素,定义组件的 HTML 模板结构。
注意:template 元素是 Vue 实例提供的标签
<div id='app'>
<mycom3></mycom3>
</div>
<template id="tmpl">
<div><!--必须有一个根元素-->
<h3>template Element</h3>
</div>
</template>
同时,需要使用 Vue.component 来定义组件:
//使用 Vue.component('组件的名称',组件模板对象)
Vue.component('mycom3',{
template:'#tmpl'
})
var vm = new Vue({
el:'#app',
data:{},
methods:{}
})
注意:组件中的 DOM 结构(组件的template 属性指向的模板内容),
有且只能有唯一的根元素(Root Element)来进行包裹!
(一般都是用 div 元素进行包裹)
(4)字面量方法直接定义组件
<div id="app">
<temp></temp>
</div>
var temp = {
template: "<h1>这是字面量创建组件的方法</h1>"
}
var vm = new Vue({
el: "#app",
data: {},
methods: {},
components: {
temp
}
})
定义私有组件
可以在 Vue 实例内部 定义私有组件 components
属性,表示只可以在该 Vue 实例中可用。
var vm = new Vue({
el:'#app',
data:{},
methods:{},
components:{
login:{
template:'<h1>vue私有组件</h1>'
}
}
})
组件中的 data 和 methods
组件可以有自己的 data 数据和 methods 方法,但组件中的 data 跟 Vue 实例中的不一样。实例中的 data 可以为一个对象,但组件中的 data 必须是一个 function函数,且要 return返回一个对象。
<div id="app">
<counter></counter>、
<counter></counter>
<counter></counter>
</div>
<template id="tmpl">
<div>
<input type="button" value="+1" @click="increment">
<h3>{{count}}</h3>
</div>
</template>
//定义全局组件
Vue.component('counter',{
template:'#tmpl',
data:function(){
return {count:0}
//data 数据可以在 template 模板上引用
},
methods:{
//组件中的方法
increment(){
this.count ++
}
}
})
var vm = new Vue({
el:'#app',
data:{},
methods:{},
})
当你在定义多个一样的组件时,你就会发现它们都是一起调用方法的,故组件中的 data 必须是一个函数。
组件切换
Vue 提供了 component 元素,来展示对应名称的组件。可看作是一个占位符。该元素下的 :is(这个属性有 v-bind 属性绑定) 属性,可以用来指定要展示的组件的名称
登录注册代码实例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="lib/bootstrap-3.3.7.css">
<link rel="stylesheet" href="lib/animate.css">
<script src="lib/vue-2.4.0.js"></script>
</head>
<body>
<div id="app">
<button @click="type='login'">登录</button>
<button @click="type='register'">注册</button>
<component :is="type"></component>
</div>
<template id="login">
<form action="#">
<label for="">账号:<input type="text"></label>
<label for="">密码:<input type="text"></label>
</form>
</template>
<template id="register">
<form action="#">
<label for="">手机号码:<input type="text"></label>
<label for="">验证码:<input type="text"></label>
</form>
</template>
</body>
<script>
Vue.component("login", {
template: "#login"
})
Vue.component("register", {
template: "#register"
})
var vm = new Vue({
el: "#app",
data: {
type: "",
flag: true
},
methods: {}
})
</script>
</html>
组件之间传值
组件之间的传值方式有:父组件向子组件传值,子组件向父组件传值,还有任意组件之间传值。
父子组件通信
父子组件通信,通过属性绑定(v-bind: 自定义属性)和 component 组件下的 props 属性(props 是一个数组对象)进行传值。
- 在父组件引用子组件的时候,通过属性绑定(v-bind:)的形式,把需要传递给子组件的数据,以属性绑定的形式,传递到子组件内部,供子组件使用;
- 把父组件传递过来的 parentmsg (自定义属性)属性,在 component 下的 props
数组中定义一下,这样才能使用这个数据;
<div id="app">
<!--自定义属性,属性值为父组件中的数据-->
<com1 :parentmsg="msg"></com1>
</div>
<script>
var vm = new Vue({
el:'#app',
data:{
msg:'father component data'
},
methods:{},
//子组件默认访问不到父组件的 data 中的数据和 methods 中的方法
components:{
com1:{
template:'<h1>child component {{parentmsg}}</h1>',
data(){
return {}
},
//在子组件中使用插值表达式输出父组件的数据
props:['parentmsg']
}
}
})
</script>
注意:组件中的所有 props 中的数据都是通过父组件传递给子组件的。
组件中的 data 和 props 的区别
- 子组件中的 props 中的数据是通过父组件传递过来的。子组件中的 data数据并不是通过父组件传递过来的,是子组件私有的,比如:子组件通过 Ajax,请求回来的数据,都可以放到data 身上;
- props中的数据是只读的,无法重新赋值;data中的数据都是可读可写的;
子父组件通信
子父组件通信,通过事件绑定机制(自定义事件)来进行传值。
- 先父组件传递一个方法到子组件,用自定义事件;
- 然后在子组件的内部定义一个方法,使用自定义事件的方法 $emit 调用自定义事件,父组件的方法;
- 可以用方法传参的方式,把子组件的 data 数据传递给父组件
传值实例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="lib/vue-2.4.0.js"></script>
</head>
<body>
<div id="app">
<p>{{msg}}</p>
<button @click="fun">点击</button>
<p>{{msgson}}</p>
<temp :parentmsg="msg" @add="fun"></temp>
</div>
<template id="templ">
<h1 @click="ale">这是子组件==={{parentmsg}}</h1>
</template>
</body>
<script>
var vm = new Vue({
el: "#app",
data: {
msgson: null,
msg: "这是父组件"
},
methods: {
fun(sonmsg) {
this.msgson = sonmsg;
console.log(this.msgson)
alert("这是父组件的弹窗")
}
},
components: {
temp: {
template: "#templ",
props: ['parentmsg'],
data() {
return {
sonmsg: {
id: 1,
title: "王麻子"
}
}
},
methods: {
ale() {
this.$emit("add", this.sonmsg)
}
}
}
}
})
</script>
</html>