_posts 2016/12/13

vue 入门学习3

阅读时长 10 分钟

按照文档学习的思路继续进行中,本文是学习如何在数据的删除、新增、更新使用动画切换效果。

过渡效果

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

单元素/组件的过渡

vue封装了一个 transition 组件,源码中的平台组件,在一些情形中给元素和组件添加entering/leaving过渡。

  • 条件渲染(v-if)
  • 条件展示(v-show)
  • 动态组件
  • 组件根节点

一个例子:demo
这个例子中的 toggle 会有一个插入元素与删除元素的动作,会在合适的时候给元素添加css类名,并且自动嗅探目标元素是否有css过渡或动画。如果过渡组件还有js钩子函数,会在适应的阶段调用钩子函数。如果没有找到js钩子与css过渡、动画。dom操作会立即执行。

  • 过渡的css类名 - css过渡 enter/leave中存在四个状态,v-enter(准备进入), v-enter-active(进入过程中的过渡状态), v-leave(准备离开), v-leave-active(离开过程中的过渡状态)
  • v-enter:定义元素进入过渡的开始状态,在元素插入时生效,下一帧移除
  • v-enter-active:定义元素进入过渡的结束状态,在元素被插入时生效,在transition/animation完成之后移除
  • v-leave:定义元素离开时的开始状态,在离开过渡时生效,在下一个帧移除
  • v-leave-active:定义元素离开过渡的结束状态,在离开过渡被触发时生效,在transition/animation完成之后移除

v-是前缀,和上面的例子对应起来,v-就是上面的fade-

  • css动画 css动画也是使用类名来实现的,只是不是使用的css中的过渡变化的样式来实现,而是使用的animation动画来实现组件元素的过渡 一个例子:demo

  • 自定义过渡类名 自定义类名的优先级高于普通的类名,方便直接使用动画库动画

    • enter-class
    • enter-active-class
    • leave-class
    • leave-active-class

    一个组件同时存在自定义过渡类名元素与过渡的name为前缀的类名同时存在的时候,自定义类名的优先级更高。

  • 同时使用Transition 和 Animation 在例子中我同时使用了transition和animation的时候,元素可以设定type属性类默认一种动画优先方式 一个例子:demo

  • js钩子 内置了进入与离开时的事件,例如:beforeEnter/enter/afterEnter,beforeLeave/leave/afterLeave。

当只用 JavaScript 过渡的时候, 在 enter 和 leave 中,回调函数 done 是必须的 。 否则,它们会被同步调用,过渡会立即完成。 推荐对于仅使用 JavaScript 过渡的元素添加 v-bind:css="false",Vue 会跳过 CSS 的检测。这也可以避免过渡过程中 CSS 的影响。

文档demo中使用了 Velocity.js 来做。

初始渲染的过渡

可以通过 appear 来设置节点在初始渲染的过渡。

<transition appear>
  <!-- ... -->
</transition>

默认进入时状态一直,可以使用appear-class,appear-active-class来自定义样式。同理事件与name也可以。
一个例子:demo

多元素的过渡

开关切换的时候,我写了一个这样的 例子

<transition name="fade">
    <span v-if="show">off</span>
    <span v-else>on</span>
</transition>

例子实际上并没有实现渐隐渐现的效果,实际上只是值变化了一下。查看文档时有这样一段说明

当有相同标签名的元素切换时,需要通过 key 特性设置唯一的值来标记以让 Vue 区分它们,否则 Vue 为了效率只会替换相同标签内部的内容。即使在技术上没有必要,给在 组件中的多个元素设置 key 是一个更好的实践。

修改后的代码:

<transition name="fade">
    <span v-if="show" key="off">off</span>
    <span v-else key="on">on</span>
</transition>

因为只是一个状态的变化,所以再修改一下:

<transition name="fade">
    <span :key="key">
    {{key = show ? 'on' : 'off'}}  
    </span>
</transition>
  • 过渡模式 同时生效的进入和离开的过渡不能满足所有要求,所以 Vue 提供了 过渡模式

    • in-out: 新元素先进行过渡,完成之后当前元素过渡离开。
    • out-in: 当前元素先进行过渡,完成之后新元素过渡进入。
  • 组件过渡 动态组件的使用例子,一个例子:demo

  • 列表的进入与离开过渡 列表需要使用 transition-group 来使用,默认会被转换为实体标签 span,可以使用 tag来设置默认标签名。

后续暂时就先不继续按照文档学习了,觉得应该用实际的例子来巩固一下知识点,要不就又忘记了怎么完成的项目了。

计划

  1. 再次熟悉webpack
  2. 按照情况看看是否使用vue-router,vuex
  3. 文档手册 / weibo

更多的是帮助自己学习之前的知识点,以及对于平时的知识点的一个总结。本周主要还是熟悉第一点与第二点,下周开始项目演练。太多的时候是把时间用在了不紧急的地方,对于时间管理这块还需要加强。

var platformComponents = {
    Transition: Transition,
    TransitionGroup: TransitionGroup
};

Transition


var Transition = {
  name: 'transition',
  props: transitionProps,
  abstract: true,
  render: function render (h) {
    var this$1 = this;

    var children = this.$slots.default;
    if (!children) {
      return
    }

    // filter out text nodes (possible whitespaces)
    children = children.filter(function (c) { return c.tag; });
    /* istanbul ignore if */
    if (!children.length) {
      return
    }

    // warn multiple elements
    if ("development" !== 'production' && children.length > 1) {
      warn(
        '<transition> can only be used on a single element. Use ' +
        '<transition-group> for lists.',
        this.$parent
      );
    }

    var mode = this.mode;

    // warn invalid mode
    if ("development" !== 'production' &&
        mode && mode !== 'in-out' && mode !== 'out-in') {
      warn(
        'invalid <transition> mode: ' + mode,
        this.$parent
      );
    }

    var rawChild = children[0];

    // if this is a component root node and the component's
    // parent container node also has transition, skip.
    if (hasParentTransition(this.$vnode)) {
      return rawChild
    }

    // apply transition data to child
    // use getRealChild() to ignore abstract components e.g. keep-alive
    var child = getRealChild(rawChild);
    /* istanbul ignore if */
    if (!child) {
      return rawChild
    }

    if (this._leaving) {
      return placeholder(h, rawChild)
    }

    var key = child.key = child.key == null || child.isStatic
      ? ("__v" + (child.tag + this._uid) + "__")
      : child.key;
    var data = (child.data || (child.data = {})).transition = extractTransitionData(this);
    var oldRawChild = this._vnode;
    var oldChild = getRealChild(oldRawChild);

    // mark v-show
    // so that the transition module can hand over the control to the directive
    if (child.data.directives && child.data.directives.some(function (d) { return d.name === 'show'; })) {
      child.data.show = true;
    }

    if (oldChild && oldChild.data && oldChild.key !== key) {
      // replace old child transition data with fresh one
      // important for dynamic transitions!
      var oldData = oldChild.data.transition = extend({}, data);

      // handle transition mode
      if (mode === 'out-in') {
        // return placeholder node and queue update when leave finishes
        this._leaving = true;
        mergeVNodeHook(oldData, 'afterLeave', function () {
          this$1._leaving = false;
          this$1.$forceUpdate();
        }, key);
        return placeholder(h, rawChild)
      } else if (mode === 'in-out') {
        var delayedLeave;
        var performLeave = function () { delayedLeave(); };
        mergeVNodeHook(data, 'afterEnter', performLeave, key);
        mergeVNodeHook(data, 'enterCancelled', performLeave, key);
        mergeVNodeHook(oldData, 'delayLeave', function (leave) {
          delayedLeave = leave;
        }, key);
      }
    }

    return rawChild
  }
};

/*  */

// Provides transition support for list items.
// supports move transitions using the FLIP technique.

// Because the vdom's children update algorithm is "unstable" - i.e.
// it doesn't guarantee the relative positioning of removed elements,
// we force transition-group to update its children into two passes:
// in the first pass, we remove all nodes that need to be removed,
// triggering their leaving transition; in the second pass, we insert/move
// into the final disired state. This way in the second pass removed
// nodes will remain where they should be.

var props = extend({
  tag: String,
  moveClass: String
}, transitionProps);

delete props.mode;