Vue.js 过渡 & 动画和组件

本文详细介绍了Vue.js中的过渡效果和组件技术。Vue提供了多种过渡效果的实现方式,包括CSS过渡和动画、JavaScript钩子以及内置的过渡组件。文章详细解释了过渡的各个阶段和对应的类名,并展示了如何结合CSS动画库使用。此外,还阐述了Vue的组件复用概念,包括全局和局部注册组件,以及组件间的通信,如props、$emit和Vuex的使用。

过渡& 动画

Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。

Vue 提供了内置的过渡封装组件,该组件用于包裹要实现过渡效果的组件。

语法格式

<transition name = "nameoftransition">
   <div></div>
</transition>

实例:

<style>
    .fade-enter-active, .fade-leave-active {
         transition: opacity .5s;
    }
    .fade-enter, .fade-leave-to {
         opacity: 0;
    }
</style>

<body>
    <div id="app">
        <button @click='show=!show'>btn</button>
        <transition name="fade">
            <p v-if='show'>{{msg}}</p>
        </transition>
    </div>
    <script>
        new Vue({
            el:'#app',
            data:{
                show:true,
                msg:'holle'
            }
        })
    </script>
</body>

当插入或删除包含在 transition 组件中的元素时,Vue 将会做以下处理:

  • 自动嗅探目标元素是否应用了 CSS 过渡或动画,如果是,在恰当的时机添加/删除 CSS 类名。
  • 如果过渡组件提供了 JavaScript 钩子函数,这些钩子函数将在恰当的时机被调用。
  • 如果没有找到 JavaScript 钩子并且也没有检测到 CSS 过渡/动画,DOM 操作 (插入/删除)
    在下一帧中立即执行。(注意:此指浏览器逐帧动画机制,和 Vue 的 nextTick 概念不同)

过渡的类名

在进入/离开的过渡中,会有 6 个 class 切换。

  1. v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
  2. v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
  3. v-enter-to:2.1.8 版及以上定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter
    被移除),在过渡/动画完成之后移除。
  4. v-leave:定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
  5. v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
  6. v-leave-to:2.1.8 版及以上定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave
    被删除),在过渡/动画完成之后移除。

6个class的划分

进入类

v-enter进入过渡的开始状态
v-enter-active进入过渡的激活状态
v-enter-to进入过渡的结束状态

离开类

v-leave离开过渡的开始状态
v-leave-active离开过渡的激活状态
v-leave-to离开过渡的结束状态

在这里插入图片描述
自定义过渡的类名

vue提供了6个专门用于设置过渡效果的class选择器名

<transition 
	before-enter-class=''
	enter-class=''
	after-enter-class=''
	before-leave-class=''
	leave-class=''
	after-leave-class=''
	>
</transtition>

他们的优先级高于普通的类名,这对于 Vue 的过渡系统和其他第三方 CSS 动画库,如 Animate.css 结合使用十分有用。

示例:

<body>
    <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>
    <script>
        new Vue({
            el: '#example-3',
            data: {
                show: true
            }
        })
    </script>
</body>

同时使用过渡和动画

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>

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 使用,也可以单独使用。

当只用 JavaScript 过渡的时候,在 enter 和 leave 中必须使用 done 进行回调。否则,它们将被同步调用,过渡会立即完成。

推荐对于仅使用 JavaScript 过渡的元素添加 v-bind:css=“false”,Vue 会跳过 CSS 的检测。这也可以避免过渡过程中 CSS 的影响。

案例:

<style>
    .box{
        width: 50px;
        height: 50px;
        border-radius: 50%;
        background: red;
    }
</style>

<body>
    <div id="app">
        <button @click="show = !show">快到碗里来</button>
        // <!-- 1、使用transition 元素把小球包裹起来 -->
        <transition
            @before-enter="beforeEnter"
            @enter="enter"
            @after-enter='afterEnter'
        >
            <div class="box" v-show="show"></div>
        </transition>
    </div>
    <script>
        var app = new Vue({
            el:'#app',
            data: {
                show: false
            },
            methods:{
            //注意:动画钩子函数的第一个参数el 表示要执行动画的哪个DOM元素 是个原生的js DOM对象
           //大家可以认为 el是通过document.getElementById('')方式获取到的原生js DOM对象
                beforeEnter(el){
                // beforeEnter 表示动画入场前 此时 动画尚未开始 可以在beforeEnter中设置元素开始动画之前的起始样式
                    //设置小球开始动画之前的 起始位置
                    el.style.transform = "translate(0,0)";
                },
                enter(el,done){
               //这句话没有实际作用 但是如果不写 出不来动画效果
               //可以认为 el.offsetWidth 会强制动画刷新
                    el.offsetWidth;
                    el.style.transform = "translate(150px,450px)";
                    el.style.transition = "all 1s ease";
                 //这里的done 其实就是afterEnter这个函数 也就是说:done是afterEter函数的引用
                    done();
                },
                afterEnter(el){
                //动画完成之后 会调用afterEnter
                    this.show = !this.show;
                }
            }
        })
    </script>
</body>

列表的排序过渡

<transition-group> 组件还有一个特殊之处。不仅可以进入和离开动画,还可以改变定位。要使用这个新功能只需了解新增的 v-move 特性,它会在元素的改变定位的过程中应用。eg:删除上面的行,下面的行会渐渐的飘上来

v-move 和 v-leave-active 结合使用,能够让列表的过渡更加平缓柔和:

.v-move{
    transition: all 0.8s ease;
}
.v-leave-active{
    position: absolute;
}

组件

Vue中的组件技术类似于后端开发中常用的一些工具类或方法,如果一个方法或功能在多个地方要用到,我们就需要将其进行抽离出来,在Vue中,组件就是一种很好的复用一个功能的手段。比如页面上的按钮、输入框等都可以以组件的形态存在,以供多个页面去复用使用。

注册组件

  • 创建组件放在后面讲,先看下注册组件。首先假设存在一个已经开发好的组件M(可能是个人开发的,也可能是别人开发的,亦可能是通过npm
    install安装的第三方库的组件),在我们的项目中如何去注册。
  • 组件注册主要分全局注册和局部注册
  • 全局组件通常使用 Vue.component(tagName, {options})的格式注册;
  • 局部组件则在实例中的components中注册。

注意:
要确保在初始化根实例之前注册了组件,即:先注册组件,再初始化Vue实例;
建议将组件提取出来放在单独js文件中,按需引用。

组件传值

如果页面A上使用某个组件M,统一称呼的口径,全文约束调用方页面A为父组件,被调用方组件M称之为子组件。
组件使用和开发的核心就是父子组件的数据传递(通信)问题,按照数据传递方向可分为三类:

  • 父组件(调用方)与子组件(被调用方)的数据传递:props
  • 子组件向父组件传递数据:$emit()
  • 子组件与子组件(兄弟组件)数据传递:vuex

父–>子组件 props:

<template>
    <div>
      <p>我是子组件,父组件通过props传递过来的值是</p>
      {{postTitle}}
    </div>
</template>

<script>
export default {
  name: 'parent-child',
  // props: ['postTitle'],
  props: {
    'postTitle': String
  }
}
</script>

<style scoped>
</style>

注意:
1.子组件中的驼峰命名的 prop 名在父组件赋值的时候需要使用其等价的短横线分隔命名;
2.props如果不加类型校验则是一个数组;若加上类型校验则是一个对象。

子–>父组件 :$emit()
props里面的属性字段值是单向的,只能是父组件传递给子组件,如果在子组件对其进行修改父组件是无感知的。子组件如果想跟父组件进行反馈,通过在子组件利用emit()定义一个事件回调函数。

<template>
    <div>
      <button v-on:click="btnClickEvent">
        子组件的按钮
      </button>
    </div>
</template>

<script>
export default {
  name: 'child-parent',

  methods: {
    // 在子组件内部通过emit定义btn-click事件,在父组件中去监听btn-click事件并实现对其的响应
    btnClickEvent: function () {
      this.$emit('btn-click')
    }
  }
}
</script>

<style scoped>
</style>
------------------- 分割线: 以下是调用上面子组件的父组件 ---------------------
<!-- 子组件通过emit注册的事件回调父组件的事件响应函数 -->
<template>
  <div>
    <!-- 监听子组件预定义的btn-click事件 -->
    <child-parent @btn-click="callback_fn"></child-parent>
  </div>
</template>

<script>
import childParent from '@/components/child-parent'
export default {
  name: 'emit',
  methods: {
    callback_fn () {
      alert('父组件预定义的供子组件回调的函数 ==> (由子组件触发)')
    }
  },
  components: {
    childParent
  }
}
</script>

<style scoped>
</style>

子组件与子组件(兄弟组件)数据传递:vuex

把各组件间用到的共享数据,抽离出到一个全局共享变量中,交由vuex进行集中管理。

1.将vuex引入到当前工程:

安装:npm install vuex --save
定义Vuex对象:在src/store/store.js文件(若无则新建)中定义一个new Vuex.Store对象
在src/main.js中的Vue实例中引入vuex store

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值