`

ReactTransitionGroup

 
阅读更多

ReactTransitionGroup模块通过ReactWithAddons模块提供外部接口,还被ReactCSSTransitionGroup模块调用;用于操控子节点componentWillAppear等方法的执行时机,以及由上层组件提供的childFactory方法劫持渲染子节点。

 

'use strict';

var _assign = require('object-assign');

// 构造函数作为普通函数调用报错
function _classCallCheck(instance, Constructor) { 
  if (!(instance instanceof Constructor)) { 
    throw new TypeError("Cannot call a class as a function"); 
  } 
}

function _possibleConstructorReturn(self, call) { 
  if (!self) { 
    throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); 
  } 
  return call && (typeof call === "object" || typeof call === "function") ? call : self; 
}

// 继承
function _inherits(subClass, superClass) { 
  if (typeof superClass !== "function" && superClass !== null) { 
    throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); 
  } 
  subClass.prototype = Object.create(superClass && superClass.prototype, 
    { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); 
  if (superClass) Object.setPrototypeOf ? 
    Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; 
}

var React = require('./React');

// getChildMapping方法将props.children扁平化处理
// mergeChildMappings方法将前后两次已经扁平化的数据props.children复合为一
var ReactTransitionChildMapping = require('./ReactTransitionChildMapping');

var emptyFunction = require('fbjs/lib/emptyFunction');

var ReactTransitionGroup = function (_React$Component) {
  _inherits(ReactTransitionGroup, _React$Component);

  function ReactTransitionGroup() {
    var _temp, _this, _ret;

    _classCallCheck(this, ReactTransitionGroup);

    for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
      args[_key] = arguments[_key];
    }

    return _ret = (_temp = (
      _this = _possibleConstructorReturn(this, _React$Component.call.apply(_React$Component, [this].concat(args))), _this), 
      
      // 将props.children扁平化后赋值给this.state
      // 在组件的componentDidAppear生命周期中,state.children包含前后两次props.children的所有子节点
      // 通过更新后的props.children判断state.children中的某个节点是否移除,触发该子节点componentWillLeave方法,及更新state
      _this.state = {
        children: ReactTransitionChildMapping.getChildMapping(_this.props.children)
      },

      // componentDidMount生命周期内执行,子节点一经挂载,即执行子组件的componentWillAppear、componentDidAppear方法
      _this.performAppear = function (key) {
        _this.currentlyTransitioningKeys[key] = true;

        var component = _this.refs[key];

        if (component.componentWillAppear) {
          component.componentWillAppear(_this._handleDoneAppearing.bind(_this, key));
        } else {
          // 子节点没有componentWillAppear方法,调用_handleDoneAppearing执行子节点的componentDidAppear方法
          // 当子节点componentDidAppear方法内促使ReactTransitionGroup的props.children删除该子节点时,调用performLeave
          // 何种代码书写方式下发生???
          _this._handleDoneAppearing(key);
        }
      }, 

      // 作为子节点componentWillAppear方法的回调,触发子节点的componentDidAppear方法
      // 当子节点componentWillAppear方法内促使ReactTransitionGroup的state.children不再包含该子节点时,调用performLeave
      _this._handleDoneAppearing = function (key) {
        var component = _this.refs[key];
        if (component.componentDidAppear) {
          component.componentDidAppear();
        }

        delete _this.currentlyTransitioningKeys[key];

        var currentChildMapping = ReactTransitionChildMapping.getChildMapping(_this.props.children);

        if (!currentChildMapping || !currentChildMapping.hasOwnProperty(key)) {
          _this.performLeave(key);
        }
      }, 

      // 组件props.children新增子节点引起重绘时,componentDidUpdate生命周期内触发performEnter方法
      _this.performEnter = function (key) {
        _this.currentlyTransitioningKeys[key] = true;

        var component = _this.refs[key];

        if (component.componentWillEnter) {
          component.componentWillEnter(_this._handleDoneEntering.bind(_this, key));
        } else {
          _this._handleDoneEntering(key);
        }
      }, 
      _this._handleDoneEntering = function (key) {
        var component = _this.refs[key];
        if (component.componentDidEnter) {
          component.componentDidEnter();
        }

        delete _this.currentlyTransitioningKeys[key];

        var currentChildMapping = ReactTransitionChildMapping.getChildMapping(_this.props.children);

        if (!currentChildMapping || !currentChildMapping.hasOwnProperty(key)) {
          _this.performLeave(key);
        }
      }, 

      // 组件props.children删除子节点引起重绘时,componentDidUpdate生命周期内触发performLeave方法
      // 最终删除时,调用setState方法移除state.children中的该节点
      _this.performLeave = function (key) {
        _this.currentlyTransitioningKeys[key] = true;

        var component = _this.refs[key];
        if (component.componentWillLeave) {
          component.componentWillLeave(_this._handleDoneLeaving.bind(_this, key));
        } else {
          _this._handleDoneLeaving(key);
        }
      }, 
      _this._handleDoneLeaving = function (key) {
        var component = _this.refs[key];

        if (component.componentDidLeave) {
          component.componentDidLeave();
        }

        delete _this.currentlyTransitioningKeys[key];

        var currentChildMapping = ReactTransitionChildMapping.getChildMapping(_this.props.children);

        if (currentChildMapping && currentChildMapping.hasOwnProperty(key)) {
          _this.performEnter(key);
        } else {
          _this.setState(function (state) {
            var newChildren = _assign({}, state.children);
            delete newChildren[key];
            return { children: newChildren };
          });
        }
      }, _temp), _possibleConstructorReturn(_this, _ret);
  }

  ReactTransitionGroup.prototype.componentWillMount = function componentWillMount() {
    this.currentlyTransitioningKeys = {};// 以键值对形式记录子节点的componentWillAppear等方法执行过程中信息
    this.keysToEnter = [];// 存储组件props变更引起重绘时的新增子节点key值
    this.keysToLeave = [];// 存储组件props变更引起重绘时的删除子节点key值
  };

  ReactTransitionGroup.prototype.componentDidMount = function componentDidMount() {
    var initialChildMapping = this.state.children;
    for (var key in initialChildMapping) {
      if (initialChildMapping[key]) {
        this.performAppear(key);
      }
    }
  };

  // props变更时,state.children存储props.children变更前后的两份扁平化数据
  // this.keysToEnter | keysToLeave存储props.children中增或删的子节点key值
  ReactTransitionGroup.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) {
    var nextChildMapping = ReactTransitionChildMapping.getChildMapping(nextProps.children);
    var prevChildMapping = this.state.children;

    // 将props.children变更前后的两份扁平化数据存入this.state.children
    // 通过componentDidUpdate生命周期内执行的performLeave方法剔除已删除的子节点
    this.setState({
      children: ReactTransitionChildMapping.mergeChildMappings(prevChildMapping, nextChildMapping)
    });

    var key;

    // props.children更新前没有key,更新后有key,将key推入this.keysToEnter
    for (key in nextChildMapping) {
      var hasPrev = prevChildMapping && prevChildMapping.hasOwnProperty(key);
      if (nextChildMapping[key] && !hasPrev && !this.currentlyTransitioningKeys[key]) {
        this.keysToEnter.push(key);
      }
    }

    // props.children更新后没有key,更新前有key,将key推入this.keysToLeave
    for (key in prevChildMapping) {
      var hasNext = nextChildMapping && nextChildMapping.hasOwnProperty(key);
      if (prevChildMapping[key] && !hasNext && !this.currentlyTransitioningKeys[key]) {
        this.keysToLeave.push(key);
      }
    }
  };

  // 依照props.children的增减项执行performEnter以及performLeave方法
  ReactTransitionGroup.prototype.componentDidUpdate = function componentDidUpdate() {
    var keysToEnter = this.keysToEnter;
    this.keysToEnter = [];
    keysToEnter.forEach(this.performEnter);

    var keysToLeave = this.keysToLeave;
    this.keysToLeave = [];
    keysToLeave.forEach(this.performLeave);
  };

  ReactTransitionGroup.prototype.render = function render() {
    // 设置ReactTransitionGroup的refs引用各子节点
    var childrenToRender = [];
    for (var key in this.state.children) {
      var child = this.state.children[key];
      if (child) {
        childrenToRender.push(React.cloneElement(this.props.childFactory(child), { ref: key, key: key }));
      }
    }

    var props = _assign({}, this.props);
    delete props.transitionLeave;
    delete props.transitionName;
    delete props.transitionAppear;
    delete props.transitionEnter;
    delete props.childFactory;
    delete props.transitionLeaveTimeout;
    delete props.transitionEnterTimeout;
    delete props.transitionAppearTimeout;
    delete props.component;

    // props.component作为容器节点
    // props.children扁平化后添加为ReactTransitionGroup的refs引用,作为props.component容器的子节点
    return React.createElement(this.props.component, props, childrenToRender);
  };

  return ReactTransitionGroup;
}(React.Component);

ReactTransitionGroup.displayName = 'ReactTransitionGroup';
ReactTransitionGroup.propTypes = {
  component: React.PropTypes.any,// 子节点的容器
  childFactory: React.PropTypes.func// 劫持渲染子节点的函数
};
ReactTransitionGroup.defaultProps = {
  component: 'span',
  childFactory: emptyFunction.thatReturnsArgument
};

// 操控子节点componentWillAppear等方法的执行时机,以及由上层组件提供的childFactory方法劫持渲染子节点
module.exports = ReactTransitionGroup;

 

0
0
分享到:
评论

相关推荐

    OSCHINA 2022年愚人节弹幕插件

    6. 动画框架:为了更高效地实现动画效果,开发者可能会利用现有的JavaScript动画库,如GreenSock Animation Platform (GSAP)或者React的`ReactTransitionGroup`等。 7. 异步编程:如果弹幕数据需要从服务器获取,...

    前端自定义动画.zip

    例如,React可以使用`ReactTransitionGroup`或`react-spring`库来实现动画效果。 在实践中,需要考虑性能优化,如使用硬件加速、避免重排和重绘,以及适配不同设备和浏览器的兼容性。此外,理解动画的基本原理,如...

    简单动画 web开发,动画函数的封装使用.zip

    3. 框架集成:现代前端框架如React、Vue、Angular都有内置或第三方支持的动画解决方案,如ReactTransitionGroup、Vue Transition等。 六、响应式动画 1. 媒体查询:根据设备屏幕尺寸和方向,使用媒体查询调整动画...

    仿微信聊天界面

    这些可以通过JavaScript库如jQuery或原生JavaScript实现,或者利用框架提供的动画库,如React的ReactTransitionGroup或Vue的vue2-animate。 在功能方面,聊天界面需要支持文本、图片、表情、语音等多种消息类型。这...

    react-React中的实验性尝试可视化Gitflow并产生动画

    ReactTransitionGroup提供了一套基础的进入/离开动画,而React Spring则提供了基于物理的动画效果,使动画更自然、逼真。 项目名称中的“gitflowanimated-master”可能是指项目的主分支名,这符合Git的命名规范,...

    翻页过渡效果

    例如,React中的`ReactTransitionGroup`组件可以方便地添加过渡效果;Vue.js的`&lt;transition&gt;`标签可以包裹需要过渡的元素,结合Vue的指令系统,能实现更为复杂的效果。 此外,还有一些工具和插件专门用于实现翻页...

    实现页面平滑过渡特效

    Vue.js的`&lt;transition&gt;`和React的`ReactTransitionGroup`库允许开发者定义进入和离开动画。 五、Web Animations API Web Animations API 是一个低级别的动画接口,可以直接操作动画的帧,提供更多的控制。它允许...

    react-为您的现代React应用更新了Windows95UI组件

    3. **动画效果**:实现平滑的过渡和动画,如窗口的打开和关闭、菜单的展开和收缩,这可能涉及`ReactTransitionGroup`或自定义CSS动画。 4. **性能优化**:由于React95可能会包含大量组件,性能优化就显得尤为重要。...

    飞入飞出效果动画

    在React中,可以使用`useState`或`useRef` hook来管理状态,结合`ReactTransitionGroup`库实现动画;在Vue中,可以利用`v-enter`, `v-leave-to`等过渡类名和`transition`组件来添加动画效果。 4. **性能优化**:在...

    JS网页特效大全下载

    - 动画框架:React的ReactTransitionGroup,Vue的vue-animate等。 4. **响应式设计**: - 适配不同设备:JS可以检测屏幕尺寸,调整布局和元素大小。 - 触屏事件:点击、滑动、缩放等事件处理,优化移动设备体验...

    为React开发的一个超级简单的动画引擎库

    因此,开发者通常需要借助额外的库来实现动画效果,如ReactTransitionGroup、ReactMotion或者自定义CSS动画等。 二、超简单动画引擎库的特点 1. **易用性**:库的核心设计理念是简化动画处理,使得即使是对动画编程...

    Javascript制作动画

    对于React这样的库,可以使用内置的`ReactTransitionGroup`或第三方库如`react-spring`来创建过渡和动画效果。 三、CSS3动画与JavaScript结合 1. CSS3关键帧动画 CSS3的`@keyframes`规则允许定义一个动画的过程,...

    JavaScript特效

    2. React:Facebook开发的用于构建用户界面的库,配合ReactTransitionGroup可实现组件级别的动画。 3. Vue.js:轻量级的MVVM框架,内置过渡效果,如v-enter、v-leave等。 4. GSAP(GreenSock Animation Platform):...

    google JS特效

    - React的`ReactTransitionGroup`和`ReactMotion`库可用于创建流畅的动画。 6. **动画库**: - GSAP(GreenSock Animation Platform)提供强大的时间轴管理和高级动画控制。 - anime.js是一个轻量级的动画库,...

    web页面切换动画

    例如,React的`ReactTransitionGroup`库可以方便地管理组件的进入和离开动画。 4. 性能优化:在实现页面切换动画时,注意性能优化,避免阻塞主线程。使用`will-change`属性提示浏览器预先准备渲染,合理使用CSS的`...

    Animation代码

    此外,还有许多库和框架如React的ReactTransitionGroup、Vue的transition组件、Unity3D等,它们提供了更高级的动画功能,简化了开发者的工作。在学习动画代码时,理解基础原理和掌握至少一种编程语言的动画API是至关...

    仿IOS底部弹窗

    3. **动画效果**:通过CSS动画或者JavaScript库(如ReactTransitionGroup)来实现弹窗的滑动动画。确保动画平滑且符合iOS原生风格。 4. **按钮处理**:为每个按钮创建子组件,并绑定点击事件。处理这些事件时,更新...

    JS模拟的图片动画特效

    - React、Vue等前端框架也有自己的动画解决方案,如ReactTransitionGroup和Vue transition。 9. **性能优化** - 避免在动画中频繁地读取和操作DOM,可以先将数据存储在变量中。 - 使用`requestAnimationFrame`...

    javascript函数库查询手册

    4. **动画效果**:JavaScript库如jQuery的`.animate()`, React的`ReactTransitionGroup`或Vue的`transition`组件,都能帮助创建平滑的过渡和动画效果。它们允许开发者自定义动画速度、缓动函数等参数,提高用户体验...

    各种JS动画

    - **React.js**: React的`ReactTransitionGroup`和`ReactMotion`库提供了用于组件过渡和动画的支持。 - **Vue.js**: Vue的`vue2-animate`或内置的`transition`组件可以方便地创建过渡和动画效果。 - **Angular**: ...

Global site tag (gtag.js) - Google Analytics