vue 如何判断是否含有子组件_细谈 vue - transition 篇

418339af6f56922bae30e9607b134a4f.png

本篇文章是细谈 vue 系列的第三篇,这篇文章主要会介绍一下 vue 的内置组件 transition 。前几篇链接如下

qiangdada:细谈 vue 核心- vdom 篇​zhuanlan.zhihu.com
26b5972a70fa42971717af1c573317ba.png
qiangdada:细谈 vue - slot 篇​zhuanlan.zhihu.com
d5b4e889a2dad7cb75e89eb039259074.png

开始之前,我们先看下官方对 transition 的定义

  1. 自动嗅探目标元素是否使用了 CSS 过渡或动画,如果使用,会在合适的时机添加/移除 CSS 过渡 class。
  2. 如果过渡组件设置了 JavaScript 钩子函数,这些钩子函数将在合适的时机调用。
  3. 如果没有检测到 CSS 过渡/动画,并且也没有设置 JavaScript 钩子函数,插入和/或删除 DOM 的操作会在下一帧中立即执行

一、抽象组件

vue 中,对于 options 有一条属性叫 abstract ,类型为 boolean ,他代表组件是否为抽象组件。但找寻了有关 options 的类型定义,却只找到这么一条

static options: Object;

但实际上,vue 还是有对 abstract 属性进行处理的,在 lifecycle.jsinitLifecycle() 方法中有这么一段逻辑

let parent = options.parent
if (parent && !options.abstract) {
    
  while (parent.$options.abstract && parent.$parent) {
    
    parent = parent.$parent
  }
  parent.$children.push(vm)
}
vm.$parent = parent

从这段逻辑我们能看出,vue 会一层一层往上找父节点是否拥有 abstract 属性,找到之后则直接将 vm 丢到其父节点的 $children 中,其本身的父子关系是直接被忽略的

然后在create-component.jscreateComponent() 方法中对其处理如下

if (isTrue(Ctor.options.abstract)) {
    
  // abstract components do not keep anything
  // other than props & listeners & slot

  // work around flow
  const slot = data.slot
  data = {}
  if (slot) {
    
    data.slot = slot
  }
}

二、举个例子

分析之前,先看个官方 transition 的例子

<template>
  <div id="example">
    <button @click="show = !show">
      Toggle render
    </button>
    <transition name="slide-fade">
      <p v-if="show">hello</p>
    </transition>
  </div>
</template>

<script>
export default {
    
  data () {
    
    return {
    
      show: true
    }
  }
}
</script>

<style lang="scss">
.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 {
    
  transform: translateX(10px);
  opacity: 0;
}
</style>

当点击按钮切换显示状态时,被 transition 包裹的元素会有一个 css 过渡效果。接下来,我们将分析具体它是如何做到这种效果的。

三、transition 实现

从上面的用法中,我们应该能感知出,对于 <transition>vue 给我们提供了一整套 css 以及 js 的钩子,这些钩子本身都已经帮我定义好并绑定在实例上面,剩下的就是需要我们自己去重写 css 或者 js 钩子函数。其实这和 vue 本身的 hooks 实现非常类似,都会在不同的钩子帮我们做好对应的不同的事情。

这种编程思维非常像函数式编程中的思想,或者说它就是。

函数式编程关心数据的映射,函数式编程中的 lambda 可以看成是两个类型之间的关系,一个输入类型和一个输出类型。你给它一个输入类型的值,则可以得到一个输出类型的值。

其实这个反映到这块,在其不同的钩子里面进行不同程度的重写,即可得到不同的输出结果,当然这里的输出其实就是过渡效果,而这种方式不恰好是 输入 => 输出 的方式吗?接下来我们就讲一下这块的具体实现。

<transtion> 组件的实现是 export 出 一个对象,从这里我们能看出它会将预先设定好的 props 绑定到 transition 上,而后我们只需对其中的点进行输入即可得到对应的样式输出,具体如何进行的过程,就不需要我们去考虑了

export default {
    
  name: 'transition',
  props: transitionProps,
  abstract: true,
  render (h: Function) {
    
    // 具体 render 等会再看
  }
}

其中支持的 props 如下,你可以对 enterleave 的样式进行任意形式的重写

export const transitionProps = {
    
  name: String,
  appear: Boolean,
  css: Boolean,
  mode: String,
  type: String,
  enterClass: String,
  leaveClass: String,
  enterToClass: String,
  leaveToClass: String,
  enterActiveClass: String,
  leaveActiveClass: String,
  appearClass: String,
  appearActiveClass: String,
  appearToClass: String,
  duration: [Number, String, Object]
}

接下来我们来看看 render 里面的内容是如何对我们预先绑定好的东西进行 输入 => 输出 的一个转换的

  • children 处理逻辑:首先从默认插槽中获取到 <transition> 包裹的子节点,随后对其进行 filter 过滤,将文本节点以及空格给过滤掉。如果不存在子节点则直接 return,如果子节点为多个,则报错,因为 <transition> 组件只能有一个子节点
let children: any = this.$slots.default
if (!children) {
    
  return
}
children = children.filter(isNotTextNode)
if (!children.length) {
    
  return
}
if (process.env.NODE_ENV !== 'production' && children.length > 1) {
    
  warn(
    '<transition> can only be used on a single element. Use ' +
    '<transition-group> for lists.',
    this.$parent
  )
}
  • mod
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值