diff --git a/.travis.yml b/.travis.yml index f9c7145..2d72e5f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ notifications: - yiminghe@gmail.com node_js: -- 4.0.0 +- 6.0.0 before_install: - | diff --git a/README.md b/README.md index 131dce0..f9dc0c0 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ var React = require('react'); // ScrollOverPack support rc-animate,rc-queue-anim,rc-tween-one; -React.render( +React.render(
enter
enter
@@ -118,6 +118,7 @@ ScrollAnim.scrollScreen.unMount(); |-----------|----------------|---------|----------------| | component | string | `div` | - | | id | string | null | need to location the id,parallax the `location` or link the `to`, need to use | +| targetId | string | null | scroll target id, if don't window scroll, parent element is `overflow: scroll`, use parent id to do scroll; [demo refs](http://react-component.github.io/scroll-anim/examples/target.html) | | playScale | number / array | `0.5` | percentage of screen to start play, screen center is 0.5, if replay is true : [bottomEnter, topLeave], topLeave >= bottomEnter | | onChange | func | null | change callback({ mode, scrollName }); mode: `enter` or `leave` | | location | string | null | v0.6.0 above have,location, the parent id; | @@ -128,11 +129,13 @@ ScrollAnim.scrollScreen.unMount(); OverPack inherit Element; `component` `playScale` `onChange` `location` refer to `Element`; +> 1.0.0 remove hideProps; + | name | type | default | description | |-----------|----------------|---------|----------------| | always | boolean | `true` | back to top, enter replay,as `false` will only play it again, leave does not play | | replay | boolean | `false` | play every enter, do you want to animate each time you show the current, `false` only scroll to down play animate | -| hideProps | object | `null` | v0.3.0 children hideProps move here. If the child does not have, default: { children: null }. children be `rc-tween-one` { 'userKey': { reverse: true }} | +| appear | boolean | `true` | whether support appear the operation | ### Parallax | name | type | default | description | diff --git a/examples/link.js b/examples/link.js index 07dd9bc..15b3864 100644 --- a/examples/link.js +++ b/examples/link.js @@ -85,7 +85,7 @@ class Demo extends React.Component {
- + 默认进入与出场 @@ -102,7 +102,6 @@ class Demo extends React.Component { style={{ backgroundColor: '#0098CE' }} always={false} id="page2" - hideProps={{ 1: { reverse: true } }} >
只进入一次
@@ -121,7 +120,6 @@ class Demo extends React.Component { style={{ backgroundColor: '#174270' }} playScale={0.8} id="page3" - hideProps={{ title: { reverse: true }, 1: { reverse: true } }} > , - + 默认进入与出场 @@ -107,7 +107,6 @@ class Demo extends React.Component { style={{ backgroundColor: '#0098CE' }} always={false} id="page2" - hideProps={{ 1: { reverse: true } }} key="2" >
只进入一次
@@ -127,7 +126,6 @@ class Demo extends React.Component { style={{ backgroundColor: '#174270' }} playScale={0.8} id="page3" - hideProps={{ title: { reverse: true }, 1: { reverse: true } }} key="3" > @@ -116,7 +115,6 @@ class Demo extends React.Component { style={{ backgroundColor: '#174270', height: 500 }} id="page2" playScale={1} - hideProps={{ t: { reverse: true }, 1: { reverse: true } }} > 只从上往下时播放 @@ -138,7 +136,6 @@ class Demo extends React.Component { always={false} id="page3" playScale={1} - hideProps={{ t: { reverse: true }, 1: { reverse: true } }} > - 默认进入与出场 + 默认进入与出场, 顶部出场 + + +
+
+
+
+
+
+ + + + 默认出场直接出现
@@ -48,7 +63,6 @@ class Demo extends React.Component { className="pack-page page2" style={{ backgroundColor: '#0098CE' }} always={false} id="page2" - hideProps={{ title: { reverse: true } }} > 只进入一次 @@ -66,7 +80,6 @@ class Demo extends React.Component { className="pack-page page3" style={{ backgroundColor: '#174270' }} playScale={0.8} id="page3" - hideProps={{ title: { reverse: true }, 1: { reverse: true } }} > +
+ +
+

{_package.name}@{_package.version}

+
+
+

The simple demo

+
+
+
+ + + 默认进入与出场, 顶部出场 + + +
+
+
+
+
+
+ + + + 默认出场直接出现 + + +
+
+
+
+
+
+ + ); + } +} + +ReactDOM.render(, document.getElementById('__react-content')); diff --git a/package.json b/package.json index 5d5c451..abdafea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rc-scroll-anim", - "version": "0.6.5", + "version": "1.0.0", "description": "scroll-anim anim component for react", "keywords": [ "react", @@ -58,7 +58,7 @@ "dependencies": { "babel-runtime": "6.x", "raf": "3.x", - "rc-tween-one": "~0.11.6", + "rc-tween-one": "~1.1.2", "tween-functions": "1.x" } } diff --git a/src/EventDispatcher.js b/src/EventDispatcher.js index 44faaa6..b5b4930 100644 --- a/src/EventDispatcher.js +++ b/src/EventDispatcher.js @@ -3,9 +3,10 @@ function EventDispatcher(target) { this._listeners = {}; this._eventTarget = target || {}; this.recoverLists = []; + this._listFun = {}; } EventDispatcher.prototype = { - addEventListener(type, callback) { + addEventListener(type, callback, target) { const types = type.split('.'); const _type = types[0]; const namespaces = types[1]; @@ -26,16 +27,19 @@ EventDispatcher.prototype = { index = i + 1; } } - const func = this.dispatchEvent.bind(this, _type); - list.splice(index, 0, { c: callback, n: namespaces, t: _type, func }); - if (this._eventTarget.addEventListener) { - this._eventTarget.addEventListener(_type, func, false); - } else if (this._eventTarget.attachEvent) { - this._eventTarget.attachEvent(`on${_type}`, func); + + list.splice(index, 0, { c: callback, n: namespaces, t: _type }); + if (!this._listFun[_type]) { + this._listFun[_type] = this._listFun[_type] || this.dispatchEvent.bind(this, _type); + if (this._eventTarget.addEventListener) { + (target || this._eventTarget).addEventListener(_type, this._listFun[_type], false); + } else if (this._eventTarget.attachEvent) { + (target || this._eventTarget).attachEvent(`on${_type}`, this._listFun[_type]); + } } }, - removeEventListener(type, callback, force) { + removeEventListener(type, callback, target, force) { const types = type.split('.'); const _type = types[0]; const namespaces = types[1]; @@ -49,12 +53,17 @@ EventDispatcher.prototype = { i = list.length; while (--i > -1) { if (list[i].c === callback && (_force || list[i].n === namespaces)) { - if (this._eventTarget.removeEventListener) { - this._eventTarget.removeEventListener(list[i].t, list[i].func); - } else if (this._eventTarget.detachEvent) { - this._eventTarget.detachEvent(`on${list[i].t}`, list[i].func); - } list.splice(i, 1); + if (!list.length) { + const func = this._listFun[_type]; + delete this._listeners[_type]; + delete this._listFun[_type]; + if (this._eventTarget.removeEventListener) { + (target || this._eventTarget).removeEventListener(_type, func); + } else if (this._eventTarget.detachEvent) { + (target || this._eventTarget).detachEvent(`on${_type}`, func); + } + } if (!_force) { return; } @@ -80,7 +89,7 @@ EventDispatcher.prototype = { } } }, - removeAllType(type) { + removeAllType(type, target) { const types = type.split('.'); const _type = types[0]; const namespaces = types[1]; @@ -89,16 +98,16 @@ EventDispatcher.prototype = { item.n && item.n.match(namespaces) )); this.recoverLists.forEach(item => { - this.removeEventListener(`${item.t}.${item.n}`, item.c); + this.removeEventListener(`${item.t}.${item.n}`, item.c, target); }); }, - reAllType(type) { + reAllType(type, target) { const types = type.split('.'); const _type = types[0]; const namespaces = types[1]; this.recoverLists = this.recoverLists.map(item => { if (item.t === _type && item.n.match(namespaces)) { - this.addEventListener(`${item.t}.${item.n}`, item.c); + this.addEventListener(`${item.t}.${item.n}`, item.c, target); return null; } return item; diff --git a/src/ScrollElement.jsx b/src/ScrollElement.jsx index 2425fe5..7b5d253 100644 --- a/src/ScrollElement.jsx +++ b/src/ScrollElement.jsx @@ -16,10 +16,14 @@ class ScrollElement extends React.Component { mapped.register(this.props.id, this.dom); } const date = Date.now(); + const scrollTop = currentScrollTop(); + if (!scrollTop) { + this.scrollEventListener(); + } const length = EventListener._listeners.scroll ? EventListener._listeners.scroll.length : 0; this.eventType = `scroll.scrollEvent${date}${length}`; - this.scrollEventListener(); - EventListener.addEventListener(this.eventType, this.scrollEventListener); + this.target = this.props.targetId && document.getElementById(this.props.targetId); + EventListener.addEventListener(this.eventType, this.scrollEventListener, this.target); } componentWillReceiveProps(nextProps) { @@ -30,15 +34,15 @@ class ScrollElement extends React.Component { componentWillUnmount() { mapped.unRegister(this.props.id); - EventListener.removeEventListener(this.eventType, this.scrollEventListener); + EventListener.removeEventListener(this.eventType, this.scrollEventListener, this.target); } getParam = (e) => { - this.clientHeight = windowHeight(); - const scrollTop = currentScrollTop(); - // 屏幕缩放时的响应,所以放回这里,这个是pack,只处理子级里面的动画,所以marginTop无关系,所以不需减掉; + this.clientHeight = this.target ? this.target.getBoundingClientRect().height : windowHeight(); + const windowScrollTop = this.target ? currentScrollTop() : 0; + const scrollTop = this.target ? this.target.scrollTop : currentScrollTop(); const domRect = this.dom.getBoundingClientRect(); - const offsetTop = domRect.top + scrollTop; + const offsetTop = domRect.top + scrollTop + windowScrollTop; this.elementShowHeight = scrollTop - offsetTop + this.clientHeight; const playScale = transformArguments(this.props.playScale); this.playHeight = this.clientHeight * playScale[0]; @@ -60,7 +64,7 @@ class ScrollElement extends React.Component { render() { const { ...props } = this.props; - ['component', 'playScale', 'location'].forEach(key => delete props[key]); + ['component', 'playScale', 'location', 'targetId'].forEach(key => delete props[key]); return React.createElement(this.props.component, { ...props }); } } @@ -71,6 +75,7 @@ ScrollElement.propTypes = { id: React.PropTypes.string, onChange: React.PropTypes.func, location: React.PropTypes.string, + targetId: React.PropTypes.string, }; ScrollElement.defaultProps = { diff --git a/src/ScrollOverPack.jsx b/src/ScrollOverPack.jsx index b19af18..43d3faa 100644 --- a/src/ScrollOverPack.jsx +++ b/src/ScrollOverPack.jsx @@ -1,4 +1,5 @@ import React, { createElement } from 'react'; +import TweenOne from 'rc-tween-one'; import EventListener from './EventDispatcher'; import ScrollElement from './ScrollElement'; import { toArrayChildren } from './util'; @@ -9,36 +10,37 @@ function noop() { class ScrollOverPack extends ScrollElement { constructor(props) { super(props); - this.children = toArrayChildren(this.props.children); + this.children = toArrayChildren(props.children); this.oneEnter = false; this.enter = false; this.state = { show: false, - children: toArrayChildren(this.props.children), + children: toArrayChildren(props.children), }; } scrollEventListener = (e) => { this.getParam(e); - if (this.enter) { + const isTop = this.elementShowHeight > this.clientHeight + this.leavePlayHeight; + if (this.enter || !this.props.replay && isTop) { if (!this.state.show) { this.setState({ show: true, }); } if (!this.props.always) { - EventListener.removeEventListener(this.eventType, this.scrollEventListener); + EventListener.removeEventListener(this.eventType, this.scrollEventListener, this.target); } - } - const bottomLeave = this.elementShowHeight < this.playHeight; - // 设置往上时的出场点... - const topLeave = this.props.replay ? - this.elementShowHeight > this.clientHeight + this.leavePlayHeight : null; - if (topLeave || bottomLeave) { - if (this.state.show) { - this.setState({ - show: false, - }); + } else { + const bottomLeave = this.elementShowHeight < this.playHeight; + // 设置往上时的出场点... + const topLeave = this.props.replay ? isTop : null; + if (topLeave || bottomLeave) { + if (this.state.show) { + this.setState({ + show: false, + }); + } } } } @@ -51,12 +53,14 @@ class ScrollOverPack extends ScrollElement { 'component', 'always', 'scrollEvent', - 'hideProps', + 'appear', 'location', + 'targetId', ].forEach(key => delete placeholderProps[key]); let childToRender; - if (!this.oneEnter && !this.state.show) { - childToRender = createElement(this.props.component, { ...placeholderProps }, null); + if (!this.oneEnter) { + const children = !this.props.appear && this.props.children; + childToRender = createElement(this.props.component, { ...placeholderProps }, children); this.oneEnter = true; } else { if (!this.state.show) { @@ -65,9 +69,8 @@ class ScrollOverPack extends ScrollElement { return null; } let element; - const hideProps = this.props.hideProps[item.key]; - if (hideProps) { - element = React.cloneElement(item, { ...hideProps }); + if (item.type === TweenOne) { + element = React.cloneElement(item, { reverse: true }); return element; } element = React.cloneElement(item, {}, null); @@ -91,7 +94,7 @@ ScrollOverPack.propTypes = { style: React.PropTypes.any, replay: React.PropTypes.bool, onChange: React.PropTypes.func, - hideProps: React.PropTypes.object, + appear: React.PropTypes.bool, }; ScrollOverPack.defaultProps = { @@ -101,7 +104,7 @@ ScrollOverPack.defaultProps = { scrollEvent: noop, replay: false, onChange: noop, - hideProps: {}, + appear: true, }; export default ScrollOverPack;