Коммит
14cb562c76
|
@ -5,7 +5,7 @@
|
||||||
<p align="center">Official React wrapper for the <a target="_blank" href="https://github.com/alvarotrigo/fullPage.js/">fullpage.js library</a></p>
|
<p align="center">Official React wrapper for the <a target="_blank" href="https://github.com/alvarotrigo/fullPage.js/">fullpage.js library</a></p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="https://img.shields.io/badge/react--fullpage-v0.1.2-brightgreen.svg" alt="react-fullpage version" />
|
<img src="https://img.shields.io/badge/react--fullpage-v0.1.3-brightgreen.svg" alt="react-fullpage version" />
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
- [Demo online](https://alvarotrigo.com/react-fullpage/) | [CodeSandbox](https://codesandbox.io/s/m34yq5q0qx)
|
- [Demo online](https://alvarotrigo.com/react-fullpage/) | [CodeSandbox](https://codesandbox.io/s/m34yq5q0qx)
|
||||||
|
|
|
@ -25,52 +25,44 @@ class ReactFullpage extends React.Component {
|
||||||
throw new Error('must provide render prop to <ReactFullpage />');
|
throw new Error('must provide render prop to <ReactFullpage />');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.state = { initialized: false };
|
this.state = {
|
||||||
|
initialized: false,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { $, v2compatible = false } = this.props;
|
|
||||||
const opts = this.buildOptions();
|
const opts = this.buildOptions();
|
||||||
|
|
||||||
if (v2compatible) {
|
if (Fullpage) {
|
||||||
if (!$ || $ instanceof window.jQuery === false) {
|
|
||||||
throw new Error('Must provide $ (jQuery) as a prop if using v2 API');
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).ready(() => {
|
|
||||||
// eslint-disable-line
|
|
||||||
$('#fullpage').fullpage(opts);
|
|
||||||
});
|
|
||||||
} else if (Fullpage) {
|
|
||||||
this.init(opts);
|
this.init(opts);
|
||||||
this.markInitialized();
|
this.markInitialized();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps, prevState) {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
if (prevState.initialized === this.state.initialized) {
|
const newSectionCount = this.getSectionCount();
|
||||||
|
const newSlideCount = this.getSlideCount();
|
||||||
|
const { sectionCount, slideCount } = this.state;
|
||||||
|
|
||||||
|
/* TODO: add a list of fullpage.js specific props to subscribe too
|
||||||
|
similar to how callbacks are handled)
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (this.props.sectionsColor !== prevProps.sectionsColor) {
|
||||||
|
console.log('rebuilding due to a change in fullpage.js props');
|
||||||
|
// NOTE: if fullpage props have changed we need to rebuild
|
||||||
|
this.destroy();
|
||||||
|
this.init(this.buildOptions());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { props, fpUtils } = this;
|
if (sectionCount === newSectionCount && slideCount === newSlideCount) {
|
||||||
const slideSelector = props.slideSelector || '.slide';
|
return;
|
||||||
const sectionSelector = props.sectionSelector || '.section';
|
}
|
||||||
|
|
||||||
const activeSection = document.querySelector(`${sectionSelector}.active`);
|
|
||||||
const activeSectionIndex = activeSection ? fpUtils.index(activeSection): -1;
|
|
||||||
const activeSlide = document.querySelector(`${sectionSelector}.active${slideSelector}.active`);
|
|
||||||
const activeSlideIndex = activeSlide ? fpUtils.index(activeSlide) : -1;
|
|
||||||
|
|
||||||
|
console.log('rebuilding due to a change in fullpage.js sections/slides');
|
||||||
|
// NOTE: if sections have changed we need to rebuild
|
||||||
this.destroy();
|
this.destroy();
|
||||||
|
|
||||||
if (activeSectionIndex > -1) {
|
|
||||||
fpUtils.addClass(document.querySelectorAll(sectionSelector)[activeSectionIndex], 'active');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (activeSlideIndex > -1) {
|
|
||||||
fpUtils.addClass(activeSlide, 'active');
|
|
||||||
}
|
|
||||||
|
|
||||||
this.init(this.buildOptions());
|
this.init(this.buildOptions());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,6 +70,20 @@ class ReactFullpage extends React.Component {
|
||||||
this.destroy();
|
this.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getSectionCount() {
|
||||||
|
const { sectionSelector = '.section' } = this.props;
|
||||||
|
return document
|
||||||
|
.querySelectorAll(sectionSelector)
|
||||||
|
.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
getSlideCount() {
|
||||||
|
const { slideSelector = '.slide' } = this.props;
|
||||||
|
return document
|
||||||
|
.querySelectorAll(slideSelector)
|
||||||
|
.length;
|
||||||
|
}
|
||||||
|
|
||||||
init(opts) {
|
init(opts) {
|
||||||
new Fullpage('#fullpage', opts); // eslint-disable-line
|
new Fullpage('#fullpage', opts); // eslint-disable-line
|
||||||
this.fullpageApi = window.fullpage_api;
|
this.fullpageApi = window.fullpage_api;
|
||||||
|
@ -87,22 +93,34 @@ class ReactFullpage extends React.Component {
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
// NOTE: need to check for init to support SSR
|
// NOTE: need to check for init to support SSR
|
||||||
if (!this.state.initialized) return;
|
if (typeof window !== 'undefined') {
|
||||||
|
this
|
||||||
this.fullpageApi.destroy('all');
|
.fullpageApi
|
||||||
|
.destroy('all');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
markInitialized() {
|
markInitialized() {
|
||||||
this.setState({ initialized: true });
|
this.setState({
|
||||||
|
initialized: true,
|
||||||
|
sectionCount: this.getSectionCount(),
|
||||||
|
slideCount: this.getSlideCount(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
buildOptions() {
|
buildOptions() {
|
||||||
const filterCb = key => !!Object.keys(this.props).find(cb => cb === key);
|
const filterCb = key => !!Object
|
||||||
|
.keys(this.props)
|
||||||
|
.find(cb => cb === key);
|
||||||
const registered = fullpageCallbacks.filter(filterCb);
|
const registered = fullpageCallbacks.filter(filterCb);
|
||||||
const listeners = registered.reduce((result, key) => {
|
const listeners = registered.reduce((result, key) => {
|
||||||
const agg = { ...result };
|
const agg = {
|
||||||
|
...result,
|
||||||
|
};
|
||||||
agg[key] = (...args) => {
|
agg[key] = (...args) => {
|
||||||
const newArgs = [key, ...args];
|
const newArgs = [
|
||||||
|
key, ...args,
|
||||||
|
];
|
||||||
this.update(...newArgs);
|
this.update(...newArgs);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -116,10 +134,10 @@ class ReactFullpage extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
update(lastEvent, ...args) {
|
update(lastEvent, ...args) {
|
||||||
const { v2compatible = false } = this.props;
|
|
||||||
|
|
||||||
let state = {
|
let state = {
|
||||||
...this.state,
|
...this.state,
|
||||||
|
sectionCount: this.getSectionCount(),
|
||||||
|
getSlideCount: this.getSlideCount(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const makeState = callbackParameters => ({
|
const makeState = callbackParameters => ({
|
||||||
|
@ -128,89 +146,43 @@ class ReactFullpage extends React.Component {
|
||||||
lastEvent,
|
lastEvent,
|
||||||
});
|
});
|
||||||
|
|
||||||
const fromArgs = argList =>
|
const fromArgs = argList => argList.reduce((result, key, i) => {
|
||||||
argList.reduce((result, key, i) => {
|
const value = args[i];
|
||||||
const value = args[i];
|
result[key] = value; // eslint-disable-line
|
||||||
result[key] = value; // eslint-disable-line
|
return result;
|
||||||
return result;
|
}, {});
|
||||||
}, {});
|
|
||||||
|
|
||||||
// TODO: change all fromArgs to constants After-*
|
// NOTE: remapping callback args to v3
|
||||||
if (v2compatible) {
|
// https://github.com/alvarotrigo/fullPage.js#callbacks
|
||||||
// NOTE: remapping callback args for v2
|
switch (lastEvent) {
|
||||||
// https://github.com/alvarotrigo/fullPage.js#callbacks
|
// After-*
|
||||||
switch (lastEvent) {
|
case 'afterLoad':
|
||||||
// After-*
|
state = makeState(fromArgs(['origin', 'destination', 'direction']));
|
||||||
case 'afterLoad':
|
break;
|
||||||
state = makeState(fromArgs(['anchorLink', 'index']));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'afterResponsive':
|
case 'afterResize':
|
||||||
state = makeState(fromArgs(['isResponsive']));
|
state = makeState(fromArgs(['']));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'afterSlideLoad':
|
case 'afterResponsive':
|
||||||
state = makeState(fromArgs(['anchorLink', 'index', 'slideAnchor', 'slideIndex']));
|
state = makeState(fromArgs(['isResponsive']));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'afterSlideLoad':
|
||||||
|
state = makeState(fromArgs(['section', 'origin', 'destination', 'direction']));
|
||||||
|
break;
|
||||||
|
|
||||||
// On-*
|
// On-*
|
||||||
case 'onLeave':
|
case 'onLeave':
|
||||||
state = makeState(fromArgs(['index', 'nextIndex', 'direction']));
|
state = makeState(fromArgs(['origin', 'destination', 'direction']));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'onSlideLeave':
|
case 'onSlideLeave':
|
||||||
state = makeState(fromArgs([
|
state = makeState(fromArgs(['section', 'origin', 'slideIndex', 'destination', 'direction']));
|
||||||
'anchorLink',
|
break;
|
||||||
'index',
|
|
||||||
'slideIndex',
|
|
||||||
'direction',
|
|
||||||
'nextSlideIndex',
|
|
||||||
]));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// NOTE: remapping callback args to v3
|
|
||||||
// https://github.com/alvarotrigo/fullPage.js#callbacks
|
|
||||||
switch (lastEvent) {
|
|
||||||
// After-*
|
|
||||||
case 'afterLoad':
|
|
||||||
state = makeState(fromArgs(['origin', 'destination', 'direction']));
|
|
||||||
break;
|
|
||||||
|
|
||||||
// TODO: update accoding to new API
|
|
||||||
case 'afterResize':
|
|
||||||
state = makeState(fromArgs(['']));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'afterResponsive':
|
|
||||||
state = makeState(fromArgs(['isResponsive']));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'afterSlideLoad':
|
|
||||||
state = makeState(fromArgs(['section', 'origin', 'destination', 'direction']));
|
|
||||||
break;
|
|
||||||
|
|
||||||
// On-*
|
|
||||||
case 'onLeave':
|
|
||||||
state = makeState(fromArgs(['origin', 'destination', 'direction']));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'onSlideLeave':
|
|
||||||
state = makeState(fromArgs([
|
|
||||||
'section',
|
|
||||||
'origin',
|
|
||||||
'slideIndex',
|
|
||||||
'destination',
|
|
||||||
'direction',
|
|
||||||
]));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState(state, () => {
|
this.setState(state, () => {
|
||||||
|
@ -221,10 +193,7 @@ class ReactFullpage extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div id="fullpage">
|
<div id="fullpage">
|
||||||
{this.state.initialized
|
{this.props.render(this)}
|
||||||
? this.props.render(this)
|
|
||||||
: <div className="section fp-section active" />
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,6 @@
|
||||||
|
|
||||||
import React, { Fragment } from 'react';
|
import React, { Fragment } from 'react';
|
||||||
|
|
||||||
const Wrapper = ({ children }) => <Fragment>{children}</Fragment>;
|
const Wrapper = ({ children }) => <Fragment>{children}</Fragment>
|
||||||
|
|
||||||
export default Wrapper;
|
export default Wrapper;
|
||||||
|
|
|
@ -11,7 +11,6 @@ export default (() => {
|
||||||
exported = require('./ReactFullpageShell').default;
|
exported = require('./ReactFullpageShell').default;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log({ exported })
|
|
||||||
exported.Wrapper = Wrapper;
|
exported.Wrapper = Wrapper;
|
||||||
|
|
||||||
return exported;
|
return exported;
|
||||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -9,9 +9,6 @@
|
||||||
<meta name="keywords" content="fullpage, react wrapper,react.js,react-fullpage,react-component,adapter,component,react,sections,slides,scrolling,snap,snapping,scroll">
|
<meta name="keywords" content="fullpage, react wrapper,react.js,react-fullpage,react-component,adapter,component,react,sections,slides,scrolling,snap,snapping,scroll">
|
||||||
<meta name="Resource-type" content="Document" />
|
<meta name="Resource-type" content="Document" />
|
||||||
|
|
||||||
<!-- fullpage.js stylesheet -->
|
|
||||||
<link rel="stylesheet" type="text/css" href="https://unpkg.com/fullpage.js@3.0.1/dist/fullpage.min.css">
|
|
||||||
|
|
||||||
<!-- custom styles for the example -->
|
<!-- custom styles for the example -->
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -14,7 +14,9 @@
|
||||||
"babel-loader": "^7.1.5",
|
"babel-loader": "^7.1.5",
|
||||||
"babel-preset-env": "^1.7.0",
|
"babel-preset-env": "^1.7.0",
|
||||||
"babel-preset-react": "^6.24.1",
|
"babel-preset-react": "^6.24.1",
|
||||||
|
"css-loader": "^1.0.1",
|
||||||
"html-loader": "^0.5.5",
|
"html-loader": "^0.5.5",
|
||||||
|
"style-loader": "^0.23.1",
|
||||||
"webpack": "^4.20.2",
|
"webpack": "^4.20.2",
|
||||||
"webpack-cli": "^3.1.1"
|
"webpack-cli": "^3.1.1"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,47 +1,110 @@
|
||||||
/* eslint-disable import/no-extraneous-dependencies */
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import ReactFullpage from '../../components';
|
import ReactFullpage from '../../components';
|
||||||
|
|
||||||
import 'fullpage.js/vendors/scrolloverflow'; // Optional. When using scrollOverflow:true
|
//import 'fullpage.js/vendors/scrolloverflow'; // Optional. When using scrollOverflow:true
|
||||||
|
|
||||||
|
const originalColors = ['#282c34', '#ff5f45', '#0798ec'];
|
||||||
|
|
||||||
|
class App extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
sectionsColor: [...originalColors],
|
||||||
|
fullpages: [
|
||||||
|
{
|
||||||
|
text: 'section 1',
|
||||||
|
id: Math.random(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
class Fullpage extends React.Component {
|
|
||||||
onLeave(origin, destination, direction) {
|
onLeave(origin, destination, direction) {
|
||||||
// arguments are mapped in order of fullpage.js callback arguments
|
console.log('onLeave', { origin, destination, direction });
|
||||||
// do something with the event
|
// arguments are mapped in order of fullpage.js callback arguments do something
|
||||||
|
// with the event
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChangeColors() {
|
||||||
|
const newColors = this.state.sectionsColor[0] === 'yellow' ? [...originalColors] : ['yellow', 'blue', 'white']
|
||||||
|
this.setState({
|
||||||
|
sectionsColor: newColors,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleAddSection() {
|
||||||
|
this.setState((state) => {
|
||||||
|
const { fullpages } = state;
|
||||||
|
const { length } = fullpages;
|
||||||
|
fullpages.push({
|
||||||
|
text: `section ${length + 1}`,
|
||||||
|
id: Math.random(),
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
fullpages: [...fullpages],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleRemoveSection() {
|
||||||
|
this.setState((state) => {
|
||||||
|
const { fullpages } = state;
|
||||||
|
const newPages = [...fullpages];
|
||||||
|
newPages.pop();
|
||||||
|
|
||||||
|
return { fullpages: newPages };
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
const { fullpages } = this.state;
|
||||||
<ReactFullpage
|
|
||||||
anchors={['firstPage', 'secondPage', 'thirdPage']}
|
|
||||||
sectionsColor={['#282c34', '#ff5f45', '#0798ec']}
|
|
||||||
onLeave={this.onLeave.bind(this)}
|
|
||||||
render={({ state, fullpageApi }) => {
|
|
||||||
console.log('render prop change', state);
|
|
||||||
|
|
||||||
return (
|
if (!fullpages.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Menu = () => (
|
||||||
|
<div
|
||||||
|
className="menu"
|
||||||
|
style={{
|
||||||
|
position: 'fixed',
|
||||||
|
top: 0,
|
||||||
|
zIndex: 100,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<button onClick={() => this.handleAddSection()}>+ Section</button>
|
||||||
|
<button onClick={() => this.handleRemoveSection()}>- Section</button>
|
||||||
|
<button onClick={() => this.handleChangeColors()}>Change colors</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="App">
|
||||||
|
<Menu />
|
||||||
|
<ReactFullpage
|
||||||
|
navigation
|
||||||
|
onLeave={this.onLeave.bind(this)}
|
||||||
|
sectionsColor={this.state.sectionsColor}
|
||||||
|
render={comp => console.log('render prop change') || (
|
||||||
<ReactFullpage.Wrapper>
|
<ReactFullpage.Wrapper>
|
||||||
<div className="section">
|
{fullpages.map(({ text, id }) => (
|
||||||
<h3>Section 1</h3>
|
<div key={id} className="section">
|
||||||
<button onClick={() => fullpageApi.moveSectionDown()}>
|
<h1>{text}</h1>
|
||||||
Move down
|
</div>
|
||||||
</button>
|
))}
|
||||||
</div>
|
|
||||||
<div className="section">
|
|
||||||
<div className="slide"> Slide 1 </div>
|
|
||||||
<div className="slide"> Slide 2 </div>
|
|
||||||
<div className="slide"> Slide 3 </div>
|
|
||||||
</div>
|
|
||||||
<div className="section">
|
|
||||||
<h3>Section 3</h3>
|
|
||||||
</div>
|
|
||||||
</ReactFullpage.Wrapper>
|
</ReactFullpage.Wrapper>
|
||||||
);
|
)}
|
||||||
}}
|
/>
|
||||||
/>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReactDOM.render(<Fullpage />, document.getElementById('react-root'));
|
const rootElement = document.getElementById('react-root');
|
||||||
|
ReactDOM.render(<App />, rootElement);
|
|
@ -14,6 +14,8 @@ module.exports = {
|
||||||
|
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
|
|
||||||
|
// BABEL
|
||||||
{
|
{
|
||||||
test: /\.js$/,
|
test: /\.js$/,
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
|
@ -21,6 +23,20 @@ module.exports = {
|
||||||
loader: 'babel-loader',
|
loader: 'babel-loader',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// STYLES
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
use: [
|
||||||
|
'style-loader',
|
||||||
|
{
|
||||||
|
loader: 'css-loader',
|
||||||
|
options: {
|
||||||
|
sourceMap: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@fullpage/react-fullpage",
|
"name": "@fullpage/react-fullpage",
|
||||||
"version": "0.1.2",
|
"version": "0.1.3",
|
||||||
"description": "Official react wrapper for fullPage.js",
|
"description": "Official react wrapper for fullPage.js",
|
||||||
"author": "cmswalker",
|
"author": "cmswalker",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
|
|
Загрузка…
Ссылка в новой задаче