├── .babelrc ├── .codeclimate.yml ├── .editorconfig ├── .eslintrc ├── .gitignore ├── .jsconfig ├── .travis.yml ├── LICENSE ├── build ├── fullpage.css ├── fullpage.js └── fullpage.min.js ├── demo ├── demo01 │ ├── css │ │ └── app.css │ ├── images │ │ ├── bg.jpg │ │ ├── code.png │ │ └── icon.png │ ├── index.html │ ├── js │ │ └── index.js │ └── less │ │ └── pages │ │ └── variation.css └── demo2 │ └── index.html ├── doc └── wechatpay.png ├── package-lock.json ├── package.json ├── readme.en-US.md ├── readme.md ├── src ├── events.js ├── fullpage.css ├── index.js ├── init.js ├── page.js └── utils.js ├── tea.yaml └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"] 3 | } -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | engines: 2 | eslint: 3 | enabled: true 4 | ratings: 5 | paths: 6 | - src/** 7 | exclude_paths: 8 | - build/**/* 9 | - demo/**/* 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | charset = utf-8 6 | trim_trailing_whitespace = true 7 | insert_final_newline = true 8 | indent_style = space 9 | indent_size = 2 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "standard", 3 | "env": { 4 | "browser": true, 5 | "node": true, 6 | "es6": true 7 | }, 8 | "ecmaFeatures": { 9 | "modules": true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea 3 | .tmp 4 | app.yaml 5 | bower_components 6 | .vscode 7 | *.less -------------------------------------------------------------------------------- /.jsconfig: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES6" 4 | } 5 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "12.16.0" 4 | script: 5 | - npm run deploy 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) <2016> <抹桥 yq12315@gmail.com> 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /build/fullpage.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | overflow: hidden; 4 | margin: 0; 5 | padding: 0; 6 | width: 100%; 7 | height: 100%; 8 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 9 | } 10 | 11 | .fp-section-content { 12 | margin: 0; 13 | padding: 0; 14 | transition: all 0.5s ease-in-out; 15 | } 16 | 17 | .fp-section-content .fp-section { 18 | height: 100%; 19 | position: relative; 20 | overflow: hidden; 21 | } 22 | 23 | .fp-section-content .fp-section .fp-slide-wrap { 24 | transition: all 0.5s ease-in-out; 25 | -webkit-transition: all 0.5s ease-in-out; 26 | -moz-transition: all 0.5s ease-in-out; 27 | height: 100%; 28 | width: auto; 29 | position: relative; 30 | } 31 | 32 | .fp-section-content .fp-section .fp-slide-wrap .fp-slide { 33 | display: inline-block; 34 | height: 100%; 35 | float: left; 36 | } 37 | 38 | .fp-controller { 39 | position: fixed; 40 | right: 10px; 41 | width: 10px; 42 | height: 200px; 43 | top: 50%; 44 | -webkit-transform: translateY(-50%); 45 | transform: translateY(-50%); 46 | } 47 | 48 | .fp-controller .fp-controller-dotted { 49 | width: 10px; 50 | height: 10px; 51 | margin-bottom: 10px; 52 | border-radius: 50%; 53 | background: #fff; 54 | border: 1px solid #000; 55 | transition: all 0.5s ease-in-out; 56 | } 57 | 58 | .fp-controller .fp-controller-dotted.active { 59 | background: #000; 60 | border-color: #fff; 61 | } 62 | -------------------------------------------------------------------------------- /build/fullpage.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * 3 | * fullpage 1.5.0 4 | * Author: 抹桥 (http://www.kisnows.com) 5 | * Homepage: https://github.com/kisnows/fullpage#readme 6 | * Release under MIT. 7 | * update 2016-04-29 8 | * 9 | */ 10 | /******/ (function(modules) { // webpackBootstrap 11 | /******/ // The module cache 12 | /******/ var installedModules = {}; 13 | 14 | /******/ // The require function 15 | /******/ function __webpack_require__(moduleId) { 16 | 17 | /******/ // Check if module is in cache 18 | /******/ if(installedModules[moduleId]) 19 | /******/ return installedModules[moduleId].exports; 20 | 21 | /******/ // Create a new module (and put it into the cache) 22 | /******/ var module = installedModules[moduleId] = { 23 | /******/ exports: {}, 24 | /******/ id: moduleId, 25 | /******/ loaded: false 26 | /******/ }; 27 | 28 | /******/ // Execute the module function 29 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 30 | 31 | /******/ // Flag the module as loaded 32 | /******/ module.loaded = true; 33 | 34 | /******/ // Return the exports of the module 35 | /******/ return module.exports; 36 | /******/ } 37 | 38 | 39 | /******/ // expose the modules object (__webpack_modules__) 40 | /******/ __webpack_require__.m = modules; 41 | 42 | /******/ // expose the module cache 43 | /******/ __webpack_require__.c = installedModules; 44 | 45 | /******/ // __webpack_public_path__ 46 | /******/ __webpack_require__.p = "D:\\Github\\fullpage-light.js\\static"; 47 | 48 | /******/ // Load entry module and return exports 49 | /******/ return __webpack_require__(0); 50 | /******/ }) 51 | /************************************************************************/ 52 | /******/ ([ 53 | /* 0 */ 54 | /***/ function(module, exports, __webpack_require__) { 55 | 56 | eval("'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _init = __webpack_require__(1);\n\nvar _page = __webpack_require__(4);\n\nvar _page2 = _interopRequireDefault(_page);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nvar fullpage = {\n init: _init.init,\n scrollPage: _page2.default.scrollPage,\n scrollSlide: _page2.default.scrollSlide,\n moveTo: _page2.default.moveTo,\n moveToNext: _page2.default.move.next,\n moveToPre: _page2.default.move.pre,\n slideToNext: _page2.default.slide.next,\n slideToPre: _page2.default.slide.pre\n};\n\n(function (global) {\n global.fullpage = fullpage;\n})(window);\n\nexports.default = fullpage;\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/index.js\n ** module id = 0\n ** module chunks = 0\n **/\n//# sourceURL=webpack:///./src/index.js?"); 57 | 58 | /***/ }, 59 | /* 1 */ 60 | /***/ function(module, exports, __webpack_require__) { 61 | 62 | eval("'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.options = exports.sections = exports.sectionContent = exports.stepWidth = exports.stepHeight = exports.init = undefined;\n\nvar _utils = __webpack_require__(2);\n\nvar _utils2 = _interopRequireDefault(_utils);\n\nvar _events = __webpack_require__(3);\n\nvar _events2 = _interopRequireDefault(_events);\n\nvar _page = __webpack_require__(4);\n\nvar _page2 = _interopRequireDefault(_page);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nvar sectionContent = undefined;\nvar sections = undefined;\nvar options = undefined;\nvar stepHeight = undefined;\nvar stepWidth = undefined;\nvar defaults = {\n threshold: 50, // 触发滚动事件的阈值,越小越灵敏\n pageSpeed: 500, // 滚屏速度,单位为毫秒 ms\n autoScroll: 0, // 自动播放事件间隔,如果为 0 则不自动播放\n loopSection: true, // Section 循环滚动\n hasSectionPagination: true, // Section 编码页\n loopSlide: true, // Slide 循环滑动\n hasSlidePagination: true, // Slide 编码页\n afterLoad: null, // 页面载入事件\n beforeLeave: null, // 页面离开事件\n afterSlideLoad: null, // slide 载入事件\n beforeSlideLeave: null // slide 离开事件\n};\n\nfunction init(ele, Customize) {\n exports.sectionContent = sectionContent = _utils2.default.$$(ele)[0];\n exports.sections = sections = _utils2.default.$$('.fp-section');\n exports.options = options = Object.assign({}, defaults, Customize);\n exports.stepHeight = stepHeight = _utils2.default.$$(ele)[0].offsetHeight;\n exports.stepWidth = stepWidth = _utils2.default.$$(ele)[0].offsetWidth;\n initEle();\n (0, _events2.default)(options, _page2.default, sectionContent);\n}\n\nfunction initEle() {\n function init() {\n initSection();\n initSlide();\n pageController();\n customize();\n }\n\n init();\n /**\n * 初始化 Section\n */\n function initSection() {\n _utils2.default.setCss(sectionContent, {\n 'transform': 'translate3d(0,0,0)',\n '-webkit-transform': 'translate3d(0,0,0)',\n 'transitionDuration': options.pageSpeed + 'ms',\n '-webkit-transitionDuration': options.pageSpeed + 'ms',\n 'display': 'block'\n });\n\n sectionContent.addEventListener(_utils2.default.transitionEvent, function () {\n _page2.default.isScrolling = false;\n }, false);\n\n for (var i = sections.length - 1; i >= 0; i--) {\n sections[i].style.height = stepHeight + 'px';\n }\n\n sections[_page2.default.nowPage].classList.add('active');\n }\n\n /**\n * 初始化 Slide\n */\n function initSlide() {\n var slideWrap = _utils2.default.$$('.fp-slide-wrap');\n var slides = undefined;\n\n function slideWrapInitHandle() {\n _page2.default.isScrolling = false;\n }\n\n for (var i = slideWrap.length - 1; i >= 0; i--) {\n slides = _utils2.default.$$('.fp-slide', slideWrap[i]);\n for (var j = slides.length - 1; j >= 0; j--) {\n slides[j].style.width = stepWidth + 'px';\n }\n slideWrap[i].style.width = slides.length * stepWidth + 'px';\n slideWrap[i].dataset.x = '0';\n slideWrap[i].dataset.index = '0';\n slideWrap[i].addEventListener(_utils2.default.transitionEvent, slideWrapInitHandle, false);\n }\n }\n\n /**\n * 初始化翻页控制点\n */\n function pageController() {\n function init() {\n createControllerNode();\n bindEvent();\n initController();\n }\n\n init();\n // 插入控制点\n function createControllerNode() {\n var controllerWrap = document.createElement('div');\n var controllerText = '';\n controllerWrap.className = 'fp-controller';\n for (var i = sections.length; i--; i > 0) {\n controllerText += \"
\";\n }\n controllerWrap.innerHTML = controllerText;\n document.body.appendChild(controllerWrap);\n }\n\n // 给控制点绑定切换事件\n function bindEvent() {\n var controllers = _utils2.default.$$('.fp-controller-dotted');\n for (var i = controllers.length - 1; i >= 0; i--) {\n controllers[i].addEventListener('click', helper(i + 1), false);\n }\n function helper(i) {\n return function () {\n _utils2.default.addClassToOneEle(controllers, i - 1);\n _page2.default.moveTo(i);\n };\n }\n }\n\n // 获取控制点初试状态\n function initController() {\n var controllers = _utils2.default.$$('.fp-controller-dotted');\n controllers[_page2.default.nowPage].classList.add('active');\n }\n }\n\n /**\n * 初始化定制内容\n */\n function customize() {\n var prop = {\n autoScroll: function autoScroll() {\n /* eslint-disable */\n var timer = null;\n /* eslint-enable */\n if (options.autoScroll) {\n timer = setInterval(function () {\n _page2.default.move.next();\n }, options.autoScroll);\n }\n }\n };\n\n for (var key in prop) {\n if (prop.hasOwnProperty(key)) {\n prop[key]();\n }\n }\n }\n}\n\nexports.init = init;\nexports.stepHeight = stepHeight;\nexports.stepWidth = stepWidth;\nexports.sectionContent = sectionContent;\nexports.sections = sections;\nexports.options = options;\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/init.js\n ** module id = 1\n ** module chunks = 0\n **/\n//# sourceURL=webpack:///./src/init.js?"); 63 | 64 | /***/ }, 65 | /* 2 */ 66 | /***/ function(module, exports) { 67 | 68 | eval("'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nvar utils = {\n $$: function $$(el, parent) {\n if (!parent) {\n return document.querySelectorAll(el);\n } else {\n return parent.querySelectorAll(el);\n }\n },\n setCss: function setCss(el, props) {\n var prop = undefined;\n for (prop in props) {\n if (props.hasOwnProperty(prop)) {\n el.style[prop] = props[prop];\n }\n }\n return el;\n },\n translate: function translate(el, value, direction) {\n if (direction === 'y') {\n this.setCss(el, {\n 'transform': 'translate3d(0,' + value + 'px,0)',\n '-webkit-transform': 'translate3d(0,' + value + 'px,0)'\n });\n // console.log('setAttr Done')\n } else if (direction === 'x') {\n this.setCss(el, {\n 'transform': 'translate3d(' + value + 'px,0,0)',\n '-webkit-transform': 'translate3d(' + value + 'px,0,0)'\n });\n }\n },\n\n /**\n * 只给一组元素中的某一个元素添加class\n * @param els 一组元素\n * @param theOne 要添加元素的index值\n */\n addClassToOneEle: function addClassToOneEle(els, theOne) {\n for (var j = els.length - 1; j >= 0; j--) {\n els[j].classList.remove('active');\n }\n els[theOne].classList.add('active');\n },\n\n transitionEvent: whichTransitionEvent()\n\n};\n\nfunction whichTransitionEvent() {\n var t = undefined;\n var el = document.createElement('fakeelement');\n var transitions = {\n 'transition': 'transitionend',\n 'OTransition': 'oTransitionEnd',\n 'MozTransition': 'transitionend',\n 'WebkitTransition': 'webkitTransitionEnd',\n 'MsTransition': 'msTransitionEnd'\n };\n\n for (t in transitions) {\n if (el.style[t] !== undefined) {\n return transitions[t];\n }\n }\n}\n\nexports.default = Object.create(utils);\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/utils.js\n ** module id = 2\n ** module chunks = 0\n **/\n//# sourceURL=webpack:///./src/utils.js?"); 69 | 70 | /***/ }, 71 | /* 3 */ 72 | /***/ function(module, exports) { 73 | 74 | eval("'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nfunction bindEvent(options, page, el) {\n var Events = [];\n\n /**\n * 绑定触摸事件\n */\n function bindTouchMove() {\n var startPos = {};\n var movePos = {};\n var diffX = undefined;\n var diffY = undefined;\n var touch = undefined;\n var onceTouch = false; // 判断是否为一次触摸,保证一次触摸只触发一次事件\n\n var threshold = options.threshold; // 阈值,灵敏度,越小越灵敏\n var isVertical = undefined; // 是否为垂直滚动事件\n\n function touchstartHandle(event) {\n // onceTouch首先置为true,表明开始了一次触摸\n onceTouch = true;\n // 初始化 x,y 值,防止点击一次后出现假 move 事件\n startPos = {};\n if (event.target.tagName.toLowerCase() !== 'a') {\n event.preventDefault();\n }\n touch = event.touches[0];\n startPos.x = touch.pageX;\n startPos.y = touch.pageY;\n }\n\n function touchmoveHandle(event) {\n event.preventDefault();\n touch = event.touches[0];\n movePos.x = touch.pageX;\n movePos.y = touch.pageY;\n diffX = startPos.x - movePos.x;\n diffY = startPos.y - movePos.y;\n\n // 如果页面正在滚动或者不是一次滚动事件,则直接return掉\n if (page.isScrolling || !onceTouch) {\n return false;\n }\n\n isVertical = Math.abs(diffX) - Math.abs(diffY) <= 0;\n // 如果diff大于阈值,则事件触发,将onceTouch置为false\n onceTouch = Math.max(diffX, diffY) <= threshold;\n if (!isVertical) {\n if (diffX > threshold) {\n // Move to left\n page.slide.next();\n } else if (diffX < -threshold) {\n // Move to right\n page.slide.pre();\n }\n } else {\n // isVertical = true\n if (diffY > threshold) {\n // Move to top\n page.move.next();\n } else if (diffY < -threshold) {\n // Move to bottom\n page.move.pre();\n }\n }\n }\n\n function touchendHandle(event) {\n if (event.target.tagName.toLowerCase() !== 'a') {\n event.preventDefault();\n }\n // 重置onceTouch为true\n onceTouch = true;\n }\n\n el.addEventListener('touchstart', touchstartHandle, false);\n\n el.addEventListener('touchmove', touchmoveHandle, false);\n\n el.addEventListener('touchend', touchendHandle, false);\n }\n\n /**\n * 绑定鼠标滚动事件\n */\n function bindMouseWheel() {\n // FIXME change the way binding event.\n var type = undefined;\n var deltaY = undefined;\n\n if (navigator.userAgent.toLowerCase().indexOf('firefox') !== -1) {\n type = 'DOMMouseScroll';\n } else {\n type = 'mousewheel';\n }\n\n function mouseWheelHandle(event) {\n if (page.isScrolling) {\n return false;\n }\n deltaY = event.detail || -event.wheelDelta || event.deltaY;\n if (deltaY > 0) {\n page.move.next();\n // console.log('next')\n } else if (deltaY < 0) {\n page.move.pre();\n // console.log('pre')\n }\n }\n\n el.addEventListener(type, mouseWheelHandle, false);\n }\n\n /**\n * 绑定键盘事件\n */\n function bindKeyboard() {\n function keyboardHandle(event) {\n var key = event.keyCode || event.which;\n switch (key) {\n case 37:\n page.slide.pre();\n break;\n case 38:\n page.move.pre();\n break;\n case 39:\n page.slide.next();\n break;\n case 40:\n page.move.next();\n break;\n }\n }\n // in order to bind key event to a normal element,we should add a tabindex attribute on it.\n el.setAttribute('tabindex', '1');\n el.focus();\n el.addEventListener('keydown', keyboardHandle, false);\n }\n\n Events.push(bindTouchMove, bindKeyboard, bindMouseWheel);\n\n Events.forEach(function (now) {\n now();\n });\n}\n\nexports.default = bindEvent;\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/events.js\n ** module id = 3\n ** module chunks = 0\n **/\n//# sourceURL=webpack:///./src/events.js?"); 75 | 76 | /***/ }, 77 | /* 4 */ 78 | /***/ function(module, exports, __webpack_require__) { 79 | 80 | eval("'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _utils = __webpack_require__(2);\n\nvar _utils2 = _interopRequireDefault(_utils);\n\nvar _init = __webpack_require__(1);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nvar page = {\n nowPage: 0,\n isScrolling: false,\n translate3dY: 0,\n /**\n * Scroll to a specified page.\n * @param pageIndex {number} The page index you want scroll to.\n * @returns {boolean}\n */\n scrollPage: function scrollPage(pageIndex) {\n var pageDiff = pageIndex - page.nowPage;\n var leaveSection = _init.sections[page.nowPage];\n var nowSection = _init.sections[pageIndex];\n var controllers = _utils2.default.$$('.fp-controller-dotted');\n if (pageIndex >= 0 && pageIndex <= _init.sections.length - 1 && !page.isScrolling && pageDiff) {\n if (typeof _init.options.beforeLeave === 'function') {\n /**\n * leaveSection 函数内部 this 指向,为将要离开的 section\n * page.nowPage 将要离开页面的 index\n * pageIndex 将要载入页面的 index\n */\n _init.options.beforeLeave.call(leaveSection, page.nowPage, pageIndex);\n }\n\n leaveSection.classList.remove('active');\n _utils2.default.addClassToOneEle(controllers, pageIndex);\n page.translate3dY -= pageDiff * _init.stepHeight;\n _utils2.default.translate(_init.sectionContent, page.translate3dY, 'y');\n page.isScrolling = true;\n page.nowPage = pageIndex;\n nowSection.classList.add('active');\n\n if (typeof _init.options.afterLoad === 'function') {\n _init.options.pageSpeed = _init.options.pageSpeed ? 500 : _init.options.pageSpeed;\n setTimeout(function () {\n /**\n * nowSection 函数内部 this 指向,为载入后的 section\n * pageIndex 载入后的 index\n */\n _init.options.afterLoad.call(nowSection, pageIndex);\n }, _init.options.pageSpeed);\n }\n return true;\n } else {\n return false;\n }\n },\n /**\n * Scroll to a specified slide.\n * @param slideIndex {number} The slide index you want scroll to.\n * @returns {boolean}\n */\n scrollSlide: function scrollSlide(slideIndex) {\n // 获取slide包裹层\n var slideWrap = _utils2.default.$$('.fp-slide-wrap', _init.sections[page.nowPage])[0];\n\n if (!slideWrap) {\n console.log('This page has no slide');\n return false;\n }\n\n // 当前页面下所有的slide\n var slide = _init.sections[page.nowPage].querySelectorAll('.fp-slide');\n\n // 当前页面上存储的数据\n var slideData = slideWrap.dataset;\n\n // 当前页面上slide的index\n var slideNowIndex = parseInt(slideData.index, 10);\n\n // 当前页面上slide的x轴偏移值\n var slideX = slideData.x;\n\n var slideDiff = slideIndex - slideNowIndex;\n\n if (slideIndex >= 0 && slideIndex <= slide.length - 1 && !page.isScrolling) {\n if (typeof _init.options.beforeSlideLeave === 'function') {\n /**\n * leaveSlide 函数内部 this 指向,将要离开的 slide\n * page.nowPage 将要离开 section 的 index\n * slideNowIndex 将要离开 slide 的 index\n * slideIndex 将要载入 slide 的 index\n */\n _init.options.beforeSlideLeave.call(slide[slideNowIndex], page.nowPage, slideNowIndex, slideIndex);\n }\n\n slide[slideNowIndex].classList.remove('active');\n slideX -= slideDiff * _init.stepWidth;\n _utils2.default.translate(slideWrap, slideX, 'x');\n page.isScrolling = true;\n slideData.x = slideX;\n slideData.index = slideIndex;\n slide[slideIndex].classList.add('active');\n\n if (typeof _init.options.afterSlideLoad === 'function') {\n _init.options.pageSpeed = _init.options.pageSpeed ? 500 : _init.options.pageSpeed;\n setTimeout(function () {\n /**\n * nowSection 函数内部 this 指向,载入后的 section\n * page.nowPage 将要载入 section 的 index\n * pageIndex 载入后的 Slide 的 index\n */\n _init.options.afterSlideLoad.call(slide[slideIndex], page.nowPage, slideIndex);\n }, _init.options.pageSpeed);\n }\n return true;\n }\n return false;\n },\n /**\n * Scroll to a specified section and slide.\n * @param pageIndex {number}\n * @param slideIndex {number}\n * @returns {boolean}\n */\n moveTo: function moveTo(pageIndex, slideIndex) {\n // DONE move to a specify section or slide\n if (page.nowPage === pageIndex || page.scrollPage(pageIndex)) {\n if (typeof slideIndex !== 'undefined') {\n // DONE move to a specify slide\n return !!page.scrollSlide(slideIndex);\n }\n return true;\n } else {\n return false;\n }\n },\n move: {\n next: function next(callback) {\n if (page.scrollPage(page.nowPage + 1)) {\n var arg = Array.prototype.slice.call(arguments, 1);\n\n if (typeof callback === 'function') {\n callback(arg);\n }\n return true;\n } else if (_init.options.loopSection) {\n page.moveTo(0);\n\n return true;\n } else {\n return false;\n }\n },\n pre: function pre(callback) {\n if (page.scrollPage(page.nowPage - 1)) {\n var arg = Array.prototype.slice.call(arguments, 1);\n\n if (typeof callback === 'function') {\n callback(arg);\n }\n return true;\n } else {\n return false;\n }\n }\n },\n slide: {\n /**\n * slide move 方法,移动到上一个或下一个 slide\n * @param {string} direction 要移动的方向,next 为下一个, pre 为上一个\n * @returns {boolean}\n */\n move: function move(direction) {\n var slideWrap = _utils2.default.$$('.fp-slide-wrap', _init.sections[page.nowPage])[0];\n var slide = _init.sections[page.nowPage].querySelectorAll('.fp-slide');\n // slideNowIndexChange slideNowIndex 将要的变化\n var slideNowIndexChange = undefined;\n // slideWillBe 将要滚到slide的index\n var slideWillBe = undefined;\n if (direction === 'next') {\n slideNowIndexChange = 1;\n slideWillBe = 0;\n } else if (direction === 'pre') {\n slideNowIndexChange = -1;\n slideWillBe = slide.length - 1;\n }\n if (!slideWrap) {\n return false;\n } else {\n var slideData = slideWrap.dataset;\n var slideNowIndex = parseInt(slideData.index, 10);\n\n if (page.scrollSlide(slideNowIndex + slideNowIndexChange)) {\n slideData.index = slideNowIndex + slideNowIndexChange;\n return true;\n } else if (_init.options.loopSlide && page.scrollSlide(slideWillBe)) {\n slideData.index = slideWillBe;\n return true;\n }\n return false;\n }\n },\n next: function next() {\n page.slide.move('next');\n },\n pre: function pre() {\n page.slide.move('pre');\n }\n }\n};\n\nexports.default = page;\n\n/*****************\n ** WEBPACK FOOTER\n ** ./src/page.js\n ** module id = 4\n ** module chunks = 0\n **/\n//# sourceURL=webpack:///./src/page.js?"); 81 | 82 | /***/ } 83 | /******/ ]); -------------------------------------------------------------------------------- /build/fullpage.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * 3 | * fullpage 1.5.0 4 | * Author: 抹桥 (http://www.kisnows.com) 5 | * Homepage: https://github.com/kisnows/fullpage#readme 6 | * Release under MIT. 7 | * update 2016-04-29 8 | * 9 | */ 10 | !function(e){function t(o){if(n[o])return n[o].exports;var i=n[o]={exports:{},id:o,loaded:!1};return e[o].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var i=n(1),a=n(2),r=o(a),s={init:i.init,scrollPage:r["default"].scrollPage,scrollSlide:r["default"].scrollSlide,moveTo:r["default"].moveTo,moveToNext:r["default"].move.next,moveToPre:r["default"].move.pre,slideToNext:r["default"].slide.next,slideToPre:r["default"].slide.pre};!function(e){e.fullpage=s}(window),t["default"]=s},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,n){t.sectionContent=f=s["default"].$$(e)[0],t.sections=p=s["default"].$$(".fp-section"),t.options=v=Object.assign({},m,n),t.stepHeight=g=s["default"].$$(e)[0].offsetHeight,t.stepWidth=h=s["default"].$$(e)[0].offsetWidth,a(),(0,d["default"])(v,c["default"],f)}function a(){function e(){t(),n(),o(),i()}function t(){s["default"].setCss(f,{transform:"translate3d(0,0,0)","-webkit-transform":"translate3d(0,0,0)",transitionDuration:v.pageSpeed+"ms","-webkit-transitionDuration":v.pageSpeed+"ms",display:"block"}),f.addEventListener(s["default"].transitionEvent,function(){c["default"].isScrolling=!1},!1);for(var e=p.length-1;e>=0;e--)p[e].style.height=g+"px";p[c["default"].nowPage].classList.add("active")}function n(){function e(){c["default"].isScrolling=!1}for(var t=s["default"].$$(".fp-slide-wrap"),n=void 0,o=t.length-1;o>=0;o--){n=s["default"].$$(".fp-slide",t[o]);for(var i=n.length-1;i>=0;i--)n[i].style.width=h+"px";t[o].style.width=n.length*h+"px",t[o].dataset.x="0",t[o].dataset.index="0",t[o].addEventListener(s["default"].transitionEvent,e,!1)}}function o(){function e(){t(),n(),o()}function t(){var e=document.createElement("div"),t="";e.className="fp-controller";for(var n=p.length;n--;n>0)t+="
";e.innerHTML=t,document.body.appendChild(e)}function n(){function e(e){return function(){s["default"].addClassToOneEle(t,e-1),c["default"].moveTo(e)}}for(var t=s["default"].$$(".fp-controller-dotted"),n=t.length-1;n>=0;n--)t[n].addEventListener("click",e(n+1),!1)}function o(){var e=s["default"].$$(".fp-controller-dotted");e[c["default"].nowPage].classList.add("active")}e()}function i(){var e={autoScroll:function(){var e=null;v.autoScroll&&(e=setInterval(function(){c["default"].move.next()},v.autoScroll))}};for(var t in e)e.hasOwnProperty(t)&&e[t]()}e()}Object.defineProperty(t,"__esModule",{value:!0}),t.options=t.sections=t.sectionContent=t.stepWidth=t.stepHeight=t.init=void 0;var r=n(3),s=o(r),l=n(4),d=o(l),u=n(2),c=o(u),f=void 0,p=void 0,v=void 0,g=void 0,h=void 0,m={threshold:50,pageSpeed:500,autoScroll:0,loopSection:!0,hasSectionPagination:!0,loopSlide:!0,hasSlidePagination:!0,afterLoad:null,beforeLeave:null,afterSlideLoad:null,beforeSlideLeave:null};t.init=i,t.stepHeight=g,t.stepWidth=h,t.sectionContent=f,t.sections=p,t.options=v},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var i=n(3),a=o(i),r=n(1),s={nowPage:0,isScrolling:!1,translate3dY:0,scrollPage:function(e){var t=e-s.nowPage,n=r.sections[s.nowPage],o=r.sections[e],i=a["default"].$$(".fp-controller-dotted");return e>=0&&e<=r.sections.length-1&&!s.isScrolling&&t?("function"==typeof r.options.beforeLeave&&r.options.beforeLeave.call(n,s.nowPage,e),n.classList.remove("active"),a["default"].addClassToOneEle(i,e),s.translate3dY-=t*r.stepHeight,a["default"].translate(r.sectionContent,s.translate3dY,"y"),s.isScrolling=!0,s.nowPage=e,o.classList.add("active"),"function"==typeof r.options.afterLoad&&(r.options.pageSpeed=r.options.pageSpeed?500:r.options.pageSpeed,setTimeout(function(){r.options.afterLoad.call(o,e)},r.options.pageSpeed)),!0):!1},scrollSlide:function(e){var t=a["default"].$$(".fp-slide-wrap",r.sections[s.nowPage])[0];if(!t)return console.log("This page has no slide"),!1;var n=r.sections[s.nowPage].querySelectorAll(".fp-slide"),o=t.dataset,i=parseInt(o.index,10),l=o.x,d=e-i;return e>=0&&e<=n.length-1&&!s.isScrolling?("function"==typeof r.options.beforeSlideLeave&&r.options.beforeSlideLeave.call(n[i],s.nowPage,i,e),n[i].classList.remove("active"),l-=d*r.stepWidth,a["default"].translate(t,l,"x"),s.isScrolling=!0,o.x=l,o.index=e,n[e].classList.add("active"),"function"==typeof r.options.afterSlideLoad&&(r.options.pageSpeed=r.options.pageSpeed?500:r.options.pageSpeed,setTimeout(function(){r.options.afterSlideLoad.call(n[e],s.nowPage,e)},r.options.pageSpeed)),!0):!1},moveTo:function(e,t){return s.nowPage===e||s.scrollPage(e)?"undefined"!=typeof t?!!s.scrollSlide(t):!0:!1},move:{next:function(e){if(s.scrollPage(s.nowPage+1)){var t=Array.prototype.slice.call(arguments,1);return"function"==typeof e&&e(t),!0}return r.options.loopSection?(s.moveTo(0),!0):!1},pre:function(e){if(s.scrollPage(s.nowPage-1)){var t=Array.prototype.slice.call(arguments,1);return"function"==typeof e&&e(t),!0}return!1}},slide:{move:function(e){var t=a["default"].$$(".fp-slide-wrap",r.sections[s.nowPage])[0],n=r.sections[s.nowPage].querySelectorAll(".fp-slide"),o=void 0,i=void 0;if("next"===e?(o=1,i=0):"pre"===e&&(o=-1,i=n.length-1),t){var l=t.dataset,d=parseInt(l.index,10);return s.scrollSlide(d+o)?(l.index=d+o,!0):r.options.loopSlide&&s.scrollSlide(i)?(l.index=i,!0):!1}return!1},next:function(){s.slide.move("next")},pre:function(){s.slide.move("pre")}}};t["default"]=s},function(e,t){"use strict";function n(){var e=void 0,t=document.createElement("fakeelement"),n={transition:"transitionend",OTransition:"oTransitionEnd",MozTransition:"transitionend",WebkitTransition:"webkitTransitionEnd",MsTransition:"msTransitionEnd"};for(e in n)if(void 0!==t.style[e])return n[e]}Object.defineProperty(t,"__esModule",{value:!0});var o={$$:function(e,t){return t?t.querySelectorAll(e):document.querySelectorAll(e)},setCss:function(e,t){var n=void 0;for(n in t)t.hasOwnProperty(n)&&(e.style[n]=t[n]);return e},translate:function(e,t,n){"y"===n?this.setCss(e,{transform:"translate3d(0,"+t+"px,0)","-webkit-transform":"translate3d(0,"+t+"px,0)"}):"x"===n&&this.setCss(e,{transform:"translate3d("+t+"px,0,0)","-webkit-transform":"translate3d("+t+"px,0,0)"})},addClassToOneEle:function(e,t){for(var n=e.length-1;n>=0;n--)e[n].classList.remove("active");e[t].classList.add("active")},transitionEvent:n()};t["default"]=Object.create(o)},function(e,t){"use strict";function n(e,t,n){function o(){function o(e){c=!0,r={},"a"!==e.target.tagName.toLowerCase()&&e.preventDefault(),u=e.touches[0],r.x=u.pageX,r.y=u.pageY}function i(e){return e.preventDefault(),u=e.touches[0],s.x=u.pageX,s.y=u.pageY,l=r.x-s.x,d=r.y-s.y,t.isScrolling||!c?!1:(p=Math.abs(l)-Math.abs(d)<=0,c=Math.max(l,d)<=f,void(p?d>f?t.move.next():-f>d&&t.move.pre():l>f?t.slide.next():-f>l&&t.slide.pre()))}function a(e){"a"!==e.target.tagName.toLowerCase()&&e.preventDefault(),c=!0}var r={},s={},l=void 0,d=void 0,u=void 0,c=!1,f=e.threshold,p=void 0;n.addEventListener("touchstart",o,!1),n.addEventListener("touchmove",i,!1),n.addEventListener("touchend",a,!1)}function i(){function e(e){return t.isScrolling?!1:(i=e.detail||-e.wheelDelta||e.deltaY,void(i>0?t.move.next():0>i&&t.move.pre()))}var o=void 0,i=void 0;o=-1!==navigator.userAgent.toLowerCase().indexOf("firefox")?"DOMMouseScroll":"mousewheel",n.addEventListener(o,e,!1)}function a(){function e(e){var n=e.keyCode||e.which;switch(n){case 37:t.slide.pre();break;case 38:t.move.pre();break;case 39:t.slide.next();break;case 40:t.move.next()}}n.setAttribute("tabindex","1"),n.focus(),n.addEventListener("keydown",e,!1)}var r=[];r.push(o,a,i),r.forEach(function(e){e()})}Object.defineProperty(t,"__esModule",{value:!0}),t["default"]=n}]); -------------------------------------------------------------------------------- /demo/demo01/css/app.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */ 2 | html { 3 | font-family: sans-serif; 4 | -ms-text-size-adjust: 100%; 5 | -webkit-text-size-adjust: 100%; 6 | } 7 | body { 8 | margin: 0; 9 | } 10 | article, 11 | aside, 12 | details, 13 | figcaption, 14 | figure, 15 | footer, 16 | header, 17 | hgroup, 18 | main, 19 | menu, 20 | nav, 21 | section, 22 | summary { 23 | display: block; 24 | } 25 | audio, 26 | canvas, 27 | progress, 28 | video { 29 | display: inline-block; 30 | vertical-align: baseline; 31 | } 32 | audio:not([controls]) { 33 | display: none; 34 | height: 0; 35 | } 36 | [hidden], 37 | template { 38 | display: none; 39 | } 40 | a { 41 | background-color: transparent; 42 | } 43 | a:active, 44 | a:hover { 45 | outline: 0; 46 | } 47 | abbr[title] { 48 | border-bottom: 1px dotted; 49 | } 50 | b, 51 | strong { 52 | font-weight: bold; 53 | } 54 | dfn { 55 | font-style: italic; 56 | } 57 | h1 { 58 | font-size: 2em; 59 | margin: 0.67em 0; 60 | } 61 | mark { 62 | background: #ff0; 63 | color: #000; 64 | } 65 | small { 66 | font-size: 80%; 67 | } 68 | sub, 69 | sup { 70 | font-size: 75%; 71 | line-height: 0; 72 | position: relative; 73 | vertical-align: baseline; 74 | } 75 | sup { 76 | top: -0.5em; 77 | } 78 | sub { 79 | bottom: -0.25em; 80 | } 81 | img { 82 | border: 0; 83 | } 84 | svg:not(:root) { 85 | overflow: hidden; 86 | } 87 | figure { 88 | margin: 1em 40px; 89 | } 90 | hr { 91 | -moz-box-sizing: content-box; 92 | box-sizing: content-box; 93 | height: 0; 94 | } 95 | pre { 96 | overflow: auto; 97 | } 98 | code, 99 | kbd, 100 | pre, 101 | samp { 102 | font-family: monospace, monospace; 103 | font-size: 1em; 104 | } 105 | button, 106 | input, 107 | optgroup, 108 | select, 109 | textarea { 110 | color: inherit; 111 | font: inherit; 112 | margin: 0; 113 | } 114 | button { 115 | overflow: visible; 116 | } 117 | button, 118 | select { 119 | text-transform: none; 120 | } 121 | button, 122 | html input[type="button"], 123 | input[type="reset"], 124 | input[type="submit"] { 125 | -webkit-appearance: button; 126 | cursor: pointer; 127 | } 128 | button[disabled], 129 | html input[disabled] { 130 | cursor: default; 131 | } 132 | button::-moz-focus-inner, 133 | input::-moz-focus-inner { 134 | border: 0; 135 | padding: 0; 136 | } 137 | input { 138 | line-height: normal; 139 | } 140 | input[type="checkbox"], 141 | input[type="radio"] { 142 | box-sizing: border-box; 143 | padding: 0; 144 | } 145 | input[type="number"]::-webkit-inner-spin-button, 146 | input[type="number"]::-webkit-outer-spin-button { 147 | height: auto; 148 | } 149 | input[type="search"] { 150 | -webkit-appearance: textfield; 151 | -moz-box-sizing: content-box; 152 | -webkit-box-sizing: content-box; 153 | box-sizing: content-box; 154 | } 155 | input[type="search"]::-webkit-search-cancel-button, 156 | input[type="search"]::-webkit-search-decoration { 157 | -webkit-appearance: none; 158 | } 159 | fieldset { 160 | border: 1px solid #c0c0c0; 161 | margin: 0 2px; 162 | padding: 0.35em 0.625em 0.75em; 163 | } 164 | legend { 165 | border: 0; 166 | padding: 0; 167 | } 168 | textarea { 169 | overflow: auto; 170 | } 171 | optgroup { 172 | font-weight: bold; 173 | } 174 | table { 175 | border-collapse: collapse; 176 | border-spacing: 0; 177 | } 178 | td, 179 | th { 180 | padding: 0; 181 | } 182 | /** 183 | * mixin.less 184 | * A set of useful LESS mixins 185 | * version: 1.0.1 186 | */ 187 | .purple { 188 | color: #c694ff; 189 | } 190 | .blue { 191 | color: #00fcff; 192 | } 193 | .red { 194 | color: #ff7791; 195 | } 196 | .yellow { 197 | color: #f4ce74; 198 | } 199 | .white { 200 | color: #fff; 201 | } 202 | .pink { 203 | color: #6DAEBC; 204 | } 205 | html { 206 | font-size: 62.5%; 207 | height: 100%; 208 | } 209 | body { 210 | font-family: Arial, "微软雅黑", sans-serif; 211 | color: #fff; 212 | background-image: url('../images/bg.jpg'); 213 | background-size: 100% 100%; 214 | font-size: 1.6rem; 215 | margin: 0; 216 | padding: 0; 217 | width: 100%; 218 | height: 100%; 219 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 220 | transition: all 0.5s ease-in-out; 221 | } 222 | .fp-wrap { 223 | width: 100%; 224 | height: 100%; 225 | } 226 | * { 227 | -webkit-box-sizing: border-box; 228 | -moz-box-sizing: border-box; 229 | box-sizing: border-box; 230 | } 231 | @media screen and (min-width: 600px) { 232 | * { 233 | text-align: center; 234 | } 235 | } 236 | ul { 237 | list-style: none; 238 | padding: 0; 239 | margin: 0; 240 | } 241 | a { 242 | color: #fff; 243 | } 244 | .section .wrap { 245 | width: 100%; 246 | height: 100%; 247 | position: absolute; 248 | top: 0; 249 | left: 0; 250 | } 251 | .fp-controlArrow { 252 | display: none !important; 253 | } 254 | .loading { 255 | width: 100%; 256 | height: 100%; 257 | background-color: #fff; 258 | } 259 | .wrong-dialog { 260 | width: 100%; 261 | height: 100%; 262 | background: #777779; 263 | position: absolute; 264 | z-index: 99999; 265 | top: 0; 266 | left: 0; 267 | } 268 | .wrong-dialog .error-msg { 269 | width: 100%; 270 | text-align: center; 271 | font-size: 18px; 272 | height: 50px; 273 | line-height: 50px; 274 | position: absolute; 275 | color: #fff; 276 | left: 0; 277 | right: 0; 278 | top: 0; 279 | bottom: 0; 280 | margin: auto; 281 | } 282 | i.icon { 283 | display: inline-block; 284 | width: 30px; 285 | height: 20px; 286 | background: url(../images/icon.png); 287 | background-size: 44px auto; 288 | vertical-align: middle; 289 | margin-left: 20px; 290 | margin-right: 8px; 291 | } 292 | .icon.icon-monthstart { 293 | background-position: 34px -92px; 294 | } 295 | .icon.icon-income { 296 | width: 30px; 297 | height: 16px; 298 | background-position: 34px -112px; 299 | } 300 | .icon.icon-takeout { 301 | width: 30px; 302 | height: 26px; 303 | background-position: 38px 2px; 304 | margin-bottom: 6px; 305 | } 306 | .icon.icon-monthend { 307 | background-position: 34px -92px; 308 | } 309 | .split-line { 310 | font-size: 2rem; 311 | margin: 20px auto 26px; 312 | text-align: center; 313 | } 314 | .split-line:before { 315 | content: ''; 316 | display: inline-block; 317 | width: calc(50% - 60px); 318 | margin-right: 10px; 319 | border-top: 1px solid #6DAEBC; 320 | vertical-align: middle; 321 | } 322 | .split-line:after { 323 | content: ''; 324 | display: inline-block; 325 | width: calc(50% - 60px); 326 | margin-left: 10px; 327 | border-top: 1px solid #6DAEBC; 328 | vertical-align: middle; 329 | } 330 | .balloon-pink { 331 | position: absolute; 332 | width: 8rem; 333 | height: 8rem; 334 | -webkit-border-radius: 50%; 335 | -moz-border-radius: 50%; 336 | border-radius: 50%; 337 | -webkit-background-clip: padding-box; 338 | -moz-background-clip: padding-box; 339 | background-clip: padding-box; 340 | text-align: center; 341 | line-height: 8rem; 342 | background-color: #F868B6; 343 | } 344 | .balloon-pink:before { 345 | content: ''; 346 | position: absolute; 347 | width: 4px; 348 | height: 4px; 349 | background-color: #F868B6; 350 | bottom: -2px; 351 | left: 50%; 352 | margin-left: -4px; 353 | } 354 | .balloon-pink:after { 355 | content: ''; 356 | position: absolute; 357 | display: inline-block; 358 | width: 0; 359 | height: 0; 360 | font-size: 0; 361 | line-height: 0; 362 | overflow: hidden; 363 | border-color: transparent transparent #F868B6 transparent; 364 | border-style: dashed dashed solid dashed; 365 | border-width: 0 4px 4px 4px; 366 | bottom: -4px; 367 | left: 50%; 368 | margin-left: -6px; 369 | } 370 | .balloon-pink .balloon-line { 371 | width: 16px; 372 | height: 76px; 373 | background: url(../images/icon.png) 0 0 no-repeat; 374 | background-size: auto 100px; 375 | position: absolute; 376 | left: 50%; 377 | margin-left: -6px; 378 | top: 8rem; 379 | z-index: -9999; 380 | } 381 | .balloon-purple { 382 | position: absolute; 383 | width: 8rem; 384 | height: 8rem; 385 | -webkit-border-radius: 50%; 386 | -moz-border-radius: 50%; 387 | border-radius: 50%; 388 | -webkit-background-clip: padding-box; 389 | -moz-background-clip: padding-box; 390 | background-clip: padding-box; 391 | text-align: center; 392 | line-height: 8rem; 393 | background-color: #E27DFC; 394 | } 395 | .balloon-purple:before { 396 | content: ''; 397 | position: absolute; 398 | width: 4px; 399 | height: 4px; 400 | background-color: #E27DFC; 401 | bottom: -2px; 402 | left: 50%; 403 | margin-left: -4px; 404 | } 405 | .balloon-purple:after { 406 | content: ''; 407 | position: absolute; 408 | display: inline-block; 409 | width: 0; 410 | height: 0; 411 | font-size: 0; 412 | line-height: 0; 413 | overflow: hidden; 414 | border-color: transparent transparent #E27DFC transparent; 415 | border-style: dashed dashed solid dashed; 416 | border-width: 0 4px 4px 4px; 417 | bottom: -4px; 418 | left: 50%; 419 | margin-left: -6px; 420 | } 421 | .balloon-purple .balloon-line { 422 | width: 16px; 423 | height: 76px; 424 | background: url(../images/icon.png) 0 0 no-repeat; 425 | background-size: auto 100px; 426 | position: absolute; 427 | left: 50%; 428 | margin-left: -6px; 429 | top: 8rem; 430 | z-index: -9999; 431 | } 432 | .balloon-purple .balloon-line { 433 | transform: rotateY(180deg); 434 | margin-left: -14px; 435 | } 436 | .balloon-green { 437 | position: absolute; 438 | width: 8rem; 439 | height: 8rem; 440 | -webkit-border-radius: 50%; 441 | -moz-border-radius: 50%; 442 | border-radius: 50%; 443 | -webkit-background-clip: padding-box; 444 | -moz-background-clip: padding-box; 445 | background-clip: padding-box; 446 | text-align: center; 447 | line-height: 8rem; 448 | background-color: #61D6C8; 449 | } 450 | .balloon-green:before { 451 | content: ''; 452 | position: absolute; 453 | width: 4px; 454 | height: 4px; 455 | background-color: #61D6C8; 456 | bottom: -2px; 457 | left: 50%; 458 | margin-left: -4px; 459 | } 460 | .balloon-green:after { 461 | content: ''; 462 | position: absolute; 463 | display: inline-block; 464 | width: 0; 465 | height: 0; 466 | font-size: 0; 467 | line-height: 0; 468 | overflow: hidden; 469 | border-color: transparent transparent #61D6C8 transparent; 470 | border-style: dashed dashed solid dashed; 471 | border-width: 0 4px 4px 4px; 472 | bottom: -4px; 473 | left: 50%; 474 | margin-left: -6px; 475 | } 476 | .balloon-green .balloon-line { 477 | width: 16px; 478 | height: 76px; 479 | background: url(../images/icon.png) 0 0 no-repeat; 480 | background-size: auto 100px; 481 | position: absolute; 482 | left: 50%; 483 | margin-left: -6px; 484 | top: 8rem; 485 | z-index: -9999; 486 | } 487 | .balloon-orange { 488 | position: absolute; 489 | width: 8rem; 490 | height: 8rem; 491 | -webkit-border-radius: 50%; 492 | -moz-border-radius: 50%; 493 | border-radius: 50%; 494 | -webkit-background-clip: padding-box; 495 | -moz-background-clip: padding-box; 496 | background-clip: padding-box; 497 | text-align: center; 498 | line-height: 8rem; 499 | background-color: #F99F64; 500 | } 501 | .balloon-orange:before { 502 | content: ''; 503 | position: absolute; 504 | width: 4px; 505 | height: 4px; 506 | background-color: #F99F64; 507 | bottom: -2px; 508 | left: 50%; 509 | margin-left: -4px; 510 | } 511 | .balloon-orange:after { 512 | content: ''; 513 | position: absolute; 514 | display: inline-block; 515 | width: 0; 516 | height: 0; 517 | font-size: 0; 518 | line-height: 0; 519 | overflow: hidden; 520 | border-color: transparent transparent #F99F64 transparent; 521 | border-style: dashed dashed solid dashed; 522 | border-width: 0 4px 4px 4px; 523 | bottom: -4px; 524 | left: 50%; 525 | margin-left: -6px; 526 | } 527 | .balloon-orange .balloon-line { 528 | width: 16px; 529 | height: 76px; 530 | background: url(../images/icon.png) 0 0 no-repeat; 531 | background-size: auto 100px; 532 | position: absolute; 533 | left: 50%; 534 | margin-left: -6px; 535 | top: 8rem; 536 | z-index: -9999; 537 | } 538 | .circle-line { 539 | list-style: none; 540 | padding: 0; 541 | font-size: 1.6rem; 542 | margin-top: -20px; 543 | } 544 | .circle-line .item { 545 | width: 80%; 546 | margin: 26px auto 0; 547 | height: 28px; 548 | line-height: 28px; 549 | } 550 | .circle-line .item span { 551 | display: inline-block; 552 | vertical-align: middle; 553 | } 554 | .circle-line .item .white { 555 | margin-right: 10px; 556 | } 557 | .circle-line .item .number { 558 | width: 64%; 559 | text-align: right; 560 | font-size: 2rem; 561 | float: right; 562 | } 563 | .circle-line .item .number i { 564 | font-style: normal; 565 | font-size: 2.4rem; 566 | } 567 | .circle-line .circle-purple { 568 | margin-right: 10px; 569 | width: 20px; 570 | height: 20px; 571 | -webkit-border-radius: 50%; 572 | -moz-border-radius: 50%; 573 | border-radius: 50%; 574 | -webkit-background-clip: padding-box; 575 | -moz-background-clip: padding-box; 576 | background-clip: padding-box; 577 | position: relative; 578 | background-color: rgba(255, 255, 255, 0.08); 579 | } 580 | .circle-line .circle-purple:after { 581 | content: ''; 582 | display: inline-block; 583 | width: 6px; 584 | height: 6px; 585 | -webkit-border-radius: 50%; 586 | -moz-border-radius: 50%; 587 | border-radius: 50%; 588 | -webkit-background-clip: padding-box; 589 | -moz-background-clip: padding-box; 590 | background-clip: padding-box; 591 | position: absolute; 592 | top: 50%; 593 | left: 50%; 594 | -webkit-transform: translate(-50%, -50%); 595 | -moz-transform: translate(-50%, -50%); 596 | -ms-transform: translate(-50%, -50%); 597 | transform: translate(-50%, -50%); 598 | background-color: #c694ff; 599 | } 600 | .circle-line .circle-blue { 601 | margin-right: 10px; 602 | width: 20px; 603 | height: 20px; 604 | -webkit-border-radius: 50%; 605 | -moz-border-radius: 50%; 606 | border-radius: 50%; 607 | -webkit-background-clip: padding-box; 608 | -moz-background-clip: padding-box; 609 | background-clip: padding-box; 610 | position: relative; 611 | background-color: rgba(255, 255, 255, 0.08); 612 | } 613 | .circle-line .circle-blue:after { 614 | content: ''; 615 | display: inline-block; 616 | width: 6px; 617 | height: 6px; 618 | -webkit-border-radius: 50%; 619 | -moz-border-radius: 50%; 620 | border-radius: 50%; 621 | -webkit-background-clip: padding-box; 622 | -moz-background-clip: padding-box; 623 | background-clip: padding-box; 624 | position: absolute; 625 | top: 50%; 626 | left: 50%; 627 | -webkit-transform: translate(-50%, -50%); 628 | -moz-transform: translate(-50%, -50%); 629 | -ms-transform: translate(-50%, -50%); 630 | transform: translate(-50%, -50%); 631 | background-color: #00fcff; 632 | } 633 | .circle-line .circle-yellow { 634 | margin-right: 10px; 635 | width: 20px; 636 | height: 20px; 637 | -webkit-border-radius: 50%; 638 | -moz-border-radius: 50%; 639 | border-radius: 50%; 640 | -webkit-background-clip: padding-box; 641 | -moz-background-clip: padding-box; 642 | background-clip: padding-box; 643 | position: relative; 644 | background-color: rgba(255, 255, 255, 0.08); 645 | } 646 | .circle-line .circle-yellow:after { 647 | content: ''; 648 | display: inline-block; 649 | width: 6px; 650 | height: 6px; 651 | -webkit-border-radius: 50%; 652 | -moz-border-radius: 50%; 653 | border-radius: 50%; 654 | -webkit-background-clip: padding-box; 655 | -moz-background-clip: padding-box; 656 | background-clip: padding-box; 657 | position: absolute; 658 | top: 50%; 659 | left: 50%; 660 | -webkit-transform: translate(-50%, -50%); 661 | -moz-transform: translate(-50%, -50%); 662 | -ms-transform: translate(-50%, -50%); 663 | transform: translate(-50%, -50%); 664 | background-color: #f4ce74; 665 | } 666 | .circle-line .circle-pink { 667 | margin-right: 10px; 668 | width: 20px; 669 | height: 20px; 670 | -webkit-border-radius: 50%; 671 | -moz-border-radius: 50%; 672 | border-radius: 50%; 673 | -webkit-background-clip: padding-box; 674 | -moz-background-clip: padding-box; 675 | background-clip: padding-box; 676 | position: relative; 677 | background-color: rgba(255, 255, 255, 0.08); 678 | } 679 | .circle-line .circle-pink:after { 680 | content: ''; 681 | display: inline-block; 682 | width: 6px; 683 | height: 6px; 684 | -webkit-border-radius: 50%; 685 | -moz-border-radius: 50%; 686 | border-radius: 50%; 687 | -webkit-background-clip: padding-box; 688 | -moz-background-clip: padding-box; 689 | background-clip: padding-box; 690 | position: absolute; 691 | top: 50%; 692 | left: 50%; 693 | -webkit-transform: translate(-50%, -50%); 694 | -moz-transform: translate(-50%, -50%); 695 | -ms-transform: translate(-50%, -50%); 696 | transform: translate(-50%, -50%); 697 | background-color: #6DAEBC; 698 | } 699 | .distribution { 700 | color: #fff; 701 | width: 100%; 702 | } 703 | .distribution .fp-slide-wrap .fp-slide { 704 | text-align: center; 705 | margin-top: 20px; 706 | } 707 | .distribution .box { 708 | width: 92%; 709 | height: 86%; 710 | height: calc(100% - 74px); 711 | background: rgba(255, 255, 255, 0.08); 712 | border-radius: 8px; 713 | position: absolute; 714 | top: 64px; 715 | left: 50%; 716 | -webkit-transform: translate(-50%, 0); 717 | -moz-transform: translate(-50%, 0); 718 | -ms-transform: translate(-50%, 0); 719 | transform: translate(-50%, 0); 720 | padding: 20px 10px; 721 | } 722 | .distribution .box .month-bottom { 723 | padding: 0 30px; 724 | margin-top: -20px; 725 | position: relative; 726 | overflow: hidden; 727 | -webkit-transition: all 0.4s; 728 | -moz-transition: all 0.4s; 729 | transition: all 0.4s; 730 | } 731 | .distribution .box .circle-percent { 732 | position: absolute; 733 | -webkit-transition: all .6s; 734 | -moz-transition: all .6s; 735 | -o-transition: all .6s; 736 | transition: all .6s; 737 | } 738 | .distribution .box .triangle { 739 | display: inline-block; 740 | width: 0; 741 | height: 0; 742 | font-size: 0; 743 | line-height: 0; 744 | overflow: hidden; 745 | border-color: transparent transparent rgba(255, 255, 255, 0.08) transparent; 746 | border-style: dashed dashed solid dashed; 747 | border-width: 0 14px 14px 14px; 748 | position: absolute; 749 | left: 50%; 750 | margin-left: -14px; 751 | top: -14px; 752 | } 753 | .keywords { 754 | background-size: 100% 100%; 755 | background: url(../images/last-bg.png) no-repeat; 756 | } 757 | .keywords .balloon-pink, 758 | .keywords .balloon-purple, 759 | .keywords .balloon-green, 760 | .keywords .balloon-orange { 761 | top: 100%; 762 | } 763 | .keywords .balloon-pink { 764 | left: 26%; 765 | z-index: 1; 766 | transition-delay: .3s; 767 | } 768 | .keywords .balloon-purple { 769 | left: 60%; 770 | z-index: 2; 771 | transition-delay: .6s; 772 | } 773 | .keywords .balloon-green { 774 | left: 20%; 775 | z-index: 3; 776 | transition-delay: .8s; 777 | } 778 | .keywords .balloon-orange { 779 | left: 50%; 780 | z-index: 4; 781 | transition-delay: 1s; 782 | } 783 | .keywords.active .balloon-pink { 784 | top: 14%; 785 | transition: all 1.4s ease-in-out; 786 | -webkit-animation: balloon-move 5s linear 0.1s infinite normal; 787 | -moz-animation: balloon-move 5s linear 0.1s infinite normal; 788 | animation: balloon-move 5s linear 0.1s infinite normal; 789 | } 790 | .keywords.active .balloon-purple { 791 | top: 10%; 792 | transition: all 1.4s ease-in-out; 793 | -webkit-animation: balloon-move-reversed 5s linear 0.1s infinite normal; 794 | -moz-animation: balloon-move-reversed 5s linear 0.1s infinite normal; 795 | animation: balloon-move-reversed 5s linear 0.1s infinite normal; 796 | } 797 | .keywords.active .balloon-green { 798 | top: 40%; 799 | transition: all 1.4s ease-in-out; 800 | -webkit-animation: balloon-move-reversed 5s linear 0.1s infinite normal; 801 | -moz-animation: balloon-move-reversed 5s linear 0.1s infinite normal; 802 | animation: balloon-move-reversed 5s linear 0.1s infinite normal; 803 | } 804 | .keywords.active .balloon-orange { 805 | top: 34%; 806 | transition: all 1.4s ease-in-out; 807 | -webkit-animation: balloon-move 5s linear 0.1s infinite normal; 808 | -moz-animation: balloon-move 5s linear 0.1s infinite normal; 809 | animation: balloon-move 5s linear 0.1s infinite normal; 810 | } 811 | .keywords .btn-wrap { 812 | position: absolute; 813 | width: 100%; 814 | bottom: 10px; 815 | } 816 | .keywords .btn-wrap .btn { 817 | margin: 0 auto 18px; 818 | display: block; 819 | width: 82%; 820 | height: 48px; 821 | line-height: 48px; 822 | border: 1px solid #fff; 823 | border-radius: 48px; 824 | text-align: center; 825 | font-size: 2rem; 826 | } 827 | .keywords .btn-wrap .btn-yellow { 828 | background: #F8E261; 829 | color: #c9723d; 830 | border: none; 831 | } 832 | .keywords .btn-wrap a.btn { 833 | color: #fff; 834 | text-decoration: none; 835 | } 836 | .keywords .cover { 837 | width: 20%; 838 | height: 40px; 839 | background: #44396a; 840 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #443769), color-stop(1, #433A6B)); 841 | background: -moz-linear-gradient(center top, #443769 0%, #433A6B 100%); 842 | background: -ms-linear-gradient(top, #443769, #433A6B); 843 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#443769', endColorstr='#433A6B', GradientType=0); 844 | position: absolute; 845 | left: 50%; 846 | transform: translate(-50%, 0); 847 | bottom: 4px; 848 | } 849 | @-webkit-keyframes balloon-move { 850 | 0% { 851 | -webkit-transform: translate(-10%, 0); 852 | -moz-transform: translate(-10%, 0); 853 | -ms-transform: translate(-10%, 0); 854 | transform: translate(-10%, 0); 855 | } 856 | 33% { 857 | -webkit-transform: translate(0, 10%); 858 | -moz-transform: translate(0, 10%); 859 | -ms-transform: translate(0, 10%); 860 | transform: translate(0, 10%); 861 | } 862 | 66% { 863 | -webkit-transform: translate(0, -10%); 864 | -moz-transform: translate(0, -10%); 865 | -ms-transform: translate(0, -10%); 866 | transform: translate(0, -10%); 867 | } 868 | 100% { 869 | -webkit-transform: translate(-10%, 0); 870 | -moz-transform: translate(-10%, 0); 871 | -ms-transform: translate(-10%, 0); 872 | transform: translate(-10%, 0); 873 | } 874 | } 875 | @-webkit-keyframes balloon-move-reversed { 876 | 0% { 877 | -webkit-transform: translate(0, -10%); 878 | -moz-transform: translate(0, -10%); 879 | -ms-transform: translate(0, -10%); 880 | transform: translate(0, -10%); 881 | } 882 | 33% { 883 | -webkit-transform: translate(10%, 0); 884 | -moz-transform: translate(10%, 0); 885 | -ms-transform: translate(10%, 0); 886 | transform: translate(10%, 0); 887 | } 888 | 66% { 889 | -webkit-transform: translate(-10%, 0); 890 | -moz-transform: translate(-10%, 0); 891 | -ms-transform: translate(-10%, 0); 892 | transform: translate(-10%, 0); 893 | } 894 | 100% { 895 | -webkit-transform: translate(0, -10%); 896 | -moz-transform: translate(0, -10%); 897 | -ms-transform: translate(0, -10%); 898 | transform: translate(0, -10%); 899 | } 900 | } 901 | .variation { 902 | transition: all 0.6s ease-in-out; 903 | } 904 | .variation.active { 905 | transform: rotate(360deg); 906 | } 907 | .variation .des .ht-user { 908 | list-style: circle; 909 | padding-left: 20px; 910 | margin-bottom: 20px; 911 | } 912 | -------------------------------------------------------------------------------- /demo/demo01/images/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kisnows/fullpage/eee68c572b44da9c9474b0c3ac43e06643d7e742/demo/demo01/images/bg.jpg -------------------------------------------------------------------------------- /demo/demo01/images/code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kisnows/fullpage/eee68c572b44da9c9474b0c3ac43e06643d7e742/demo/demo01/images/code.png -------------------------------------------------------------------------------- /demo/demo01/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kisnows/fullpage/eee68c572b44da9c9474b0c3ac43e06643d7e742/demo/demo01/images/icon.png -------------------------------------------------------------------------------- /demo/demo01/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Fullpage 6 | 7 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 |
20 |
21 |
Slide1
22 |
Slide2
23 |
Slide3
24 |
25 |
26 |
27 |
    28 |
  • 29 | 独立不依赖任何库 32 |
  • 33 |
  • 34 | 轻巧gzip后不足1K 37 |
  • 38 |
  • 39 | 简单非常易于使用 42 |
  • 43 |
44 |
简介
45 |
46 |

47 | FullPage-light v1.3.0 53 |

54 | 55 |

一个轻巧的fullpage框架,不依赖其他任何库

56 | 57 |

主要针对移动端设备(同时也支持桌面端),压缩后不到4kb。

58 | 59 |

轻松创建炫酷的单页滑动网站。

60 |
61 |

尝试左右滑动,或者使用方向键控制

62 | 63 |

64 | 当前Slide位于:Slide1 67 |

68 |
69 |
70 |
71 |
72 |
使用方法
73 |
74 |
    75 |
  • 引入 JavaScript 文件 fullpage.min.js
  • 76 |
  • 77 | 引入 css 文件 78 | fullpage.css(如果你使用less,则可以在less主文件中引入fullpage.less) 79 |
  • 80 |
  • 81 | 按照下面格式书写html代码(其中 id 为 sectionContent 82 | 的为包裹层,你可以自定义修改其id) 83 |
  • 84 |
85 | code 86 | 87 |

88 | 详细使用方法请点击 93 |

94 |
95 |
96 |
97 |
98 |
给我意见
99 | 嘻 101 | 102 | 103 | 嘻 105 | 106 | 107 | 哈 109 | 110 | 111 | 哈 113 | 114 | 115 | 116 | 125 |
126 |
127 |
128 |
129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /demo/demo01/js/index.js: -------------------------------------------------------------------------------- 1 | /* global fullpage */ 2 | "use strict"; 3 | window.onload = function() { 4 | function fire() { 5 | fullpage.init("#sectionContent", { 6 | pageSpeed: 500, 7 | beforeLeave: function(leaveIndex, nowIndex) { 8 | if (nowIndex === 2) { 9 | //console.log('You will leave page 2'); 10 | } 11 | //console.log(this, leaveIndex, nowIndex); 12 | }, 13 | afterLoad: function(afterIndex) { 14 | if (afterIndex === 2) { 15 | //console.log('You will go to page 2'); 16 | } 17 | //console.log(this, afterIndex); 18 | }, 19 | beforeSlideLeave: function(pageIndex, slideNow, slideAfter) { 20 | var _this = this; 21 | var SlideNow = document.querySelector("#nowSlide"); 22 | SlideNow.innerHTML = "Slide" + slideAfter; 23 | }, 24 | afterSlideLoad: function(pageIndex, slideIndex) { 25 | var _this = this; 26 | } 27 | }); 28 | } 29 | fire(); 30 | window.addEventListener("resize", () => { 31 | fire(); 32 | }); 33 | }; 34 | -------------------------------------------------------------------------------- /demo/demo01/less/pages/variation.css: -------------------------------------------------------------------------------- 1 | .variation { 2 | transition: all 0.6s ease-in-out; 3 | } 4 | .variation.active { 5 | transform: rotate(360deg); 6 | } 7 | .variation .des .ht-user { 8 | list-style: circle; 9 | padding-left: 20px; 10 | margin-bottom: 20px; 11 | } 12 | -------------------------------------------------------------------------------- /demo/demo2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DEMO 2 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /doc/wechatpay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kisnows/fullpage/eee68c572b44da9c9474b0c3ac43e06643d7e742/doc/wechatpay.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fullpage", 3 | "version": "1.5.0", 4 | "description": "A light JavaScript framework to build fullpage site in a simple way, write with pure JavaScript.", 5 | "scripts": { 6 | "lint": "eslint src test ./src/**.js", 7 | "dev": "webpack-dev-server", 8 | "deploy": "set NODE_ENV=production & webpack" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/kisnows/fullpage.git" 13 | }, 14 | "keywords": [ 15 | "fullpage, slide" 16 | ], 17 | "author": "抹桥 (http://blog.kisnows.com)", 18 | "license": "MIT", 19 | "bugs": { 20 | "url": "https://github.com/kisnows/fullpage/issues" 21 | }, 22 | "homepage": "https://github.com/kisnows/fullpage#readme", 23 | "devDependencies": { 24 | "babel-core": "^6.26.3", 25 | "babel-loader": "^7.x", 26 | "babel-preset-es2015": "^6.24.1", 27 | "eslint": "^6.8.0", 28 | "eslint-config-standard": "^14.1.0", 29 | "eslint-plugin-standard": "^4.0.1", 30 | "webpack": "^4.41.6", 31 | "webpack-cli": "^3.3.11", 32 | "webpack-dev-server": "^3.10.3" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /readme.en-US.md: -------------------------------------------------------------------------------- 1 | # fullpage 2 | [![Build Status](https://travis-ci.org/kisnows/fullpage.svg?branch=master)](https://travis-ci.org/kisnows/fullpage) 3 | [![GitHub issues](https://img.shields.io/github/issues/kisnows/fullpage.svg)](https://github.com/kisnows/fullpage/issues) 4 | [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/kisnows/fullpage/master/LICENSE) 5 | 6 | 一个轻巧的`fullpage`框架,不依赖其他任何库,gzip 后不到1kb。 7 | 轻松创建炫酷的单页滑动网站。 8 | 9 | [一个简单的DEMO](http://github.kisnows.com/fullpage/) 10 | ## 功能 11 | * 触摸/键盘/鼠标滚轮控制 12 | * 垂直/水平翻页 13 | 14 | ## 兼容性 15 | | Android 4.1+ | Safari 7.1+ | IE 11 | Opera | Chrome | firefox | 16 | | ------------ | ----------- | ----- | ----- | ------ | ------- | 17 | 18 | ## 使用方法 19 | 通过 npm 下载 fullpage 文件 20 | ```bash 21 | npm install fullpage 22 | ``` 23 | * 引入位于 build 目录下的 `fullpage.min.js`(或 fullpage.js 做为开发环境) 24 | * 引入 css 文件 `fullpage.css` 25 | * 按照下面格式书写`html`代码(其中 id 为 `sectionContent` 的为包裹层,你可以自定义修改其id) 26 | 27 | ```html 28 | 29 | 30 | 31 | 32 | 33 |
34 |
35 |
36 |
37 |
1
38 |
2
39 |
3
40 |
41 |
42 |
2
43 |
3
44 |
45 |
46 | 47 | ``` 48 | 49 | ## 初始化 50 | 简单使用,只要在页面加载完成后执行: 51 | ```javascript 52 | fullpage.init('#sectionContent'); 53 | ``` 54 | 如果需要定制化,则需要如下方法: 55 | ```javascript 56 | fullpage.init('#sectionContent',{ 57 | threshold: 10, // 触发滚动事件的阈值,越小越灵敏 58 | pageSpeed: 600, // 滚屏速度,单位为毫秒 ms 59 | autoScroll: 0, // 自动播放时间间隔,如果为 0 则不自动播放,单位 ms 60 | loopSection: true, // Section循环滚动 61 | loopSlide: true, // Slide循环滑动 62 | afterLoad: null, // 页面载入事件,具体查看下面的 afterLoad 函数 63 | beforeLeave: null, // 页面离开事件,具体查看下面的 beforeLeave 函数 64 | afterSlideLoad: null, // slide 载入事件 65 | beforeSlideLeave: null // slide 离开事件 66 | }); 67 | ``` 68 | ### beforeLeave(leaveIndex,nowIndex) 69 | 离开当前页面时触发的事件,函数中 `this` 指向当前页面的 **section**,`leaveIndex`为要**离开**页面的 `index` ,`nowIndex` 为要**载入**页面的 `Index` 70 | ### afterLoad(afterIndex) 71 | 载入下一张页面后触发的事件,函数中 `this` 指向将要**载入**页面的 `section`, `afterIndex` 为要**载入**页面的 `index` 72 | ### beforeSlideLeave(pageIndex, slideNow, slideAfter) 73 | 离开当前 Slide 时触发的事件,`pageIndex`是**当前**`section`的`index`,`slideNow`是**当前**`slide`的`index`,`slideAfter`是要**载入**`slide`的`index` 74 | ### afterSlideLoad(pageIndex, slideIndex) 75 | 载入下一个`slide`后触发的事件,`pageIndex`是**当前**`section`的`index`,`slideIndex`是要**载入**`slide`的`index` 76 | ```javascript 77 | fullpage.init('#sectionContent', { 78 | beforeLeave: function (leaveIndex, nowIndex) { // 如果现在在第1个页面,向下滚动后 79 | if (nowIndex === 2) { // leaveIndex = 1,nowIndex = 2 80 | console.log('You will leave page 2') // 这条语句会执行 81 | } 82 | console.log(this, leaveIndex, nowIndex) // 这里的 this 指向将要离开的页面元素,即第一个页面 83 | }, 84 | afterLoad: function (afterIndex) { // afterIndex = 2 85 | if (afterIndex === 2) { 86 | console.log('You will go to page 2') // 这条语句会执行 87 | } 88 | console.log(this, afterIndex) // 此处 this 指向当前载入的页面,即第二个页面 89 | }, 90 | beforeSlideLeave: function (pageIndex, slideNow, slideAfter) { 91 | var _this = this; 92 | console.log(_this, 'beforeSlideLeave:', pageIndex, slideNow, slideAfter); 93 | }, 94 | afterSlideLoad: function (pageIndex, slideIndex) { 95 | var _this = this; 96 | console.log(_this, 'afterSlideLoad:', pageIndex, slideIndex); 97 | } 98 | }); 99 | ``` 100 | ## 方法 101 | ### init(el,options) 102 | 页面初始化,`el`为最外包裹层选择器,`options`是要定制的参数。具体同[初始化](#初始化) 103 | ### moveTo(index,slideIndex) 104 | 滚动到指定页面,`index` 为必选参数,`slideIndex`为可选参数 105 | ```javascript 106 | fullpage.moveTo(1) // 滚动到第一个页面 107 | fullpage.moveTo(3,2) // 滚动到第三个页面的第二个slider 108 | ``` 109 | ### moveToNext(callback) 110 | 垂直滚动到下一个页面,`callback`为回掉函数,可选。 111 | ```javascript 112 | fullpage.moveToNext(); // 滚动到下一个页面 113 | fullpage.moveToNext(callback) // 滚动到下一个页面后,执行 callback 114 | fullpage.moveToNext(callback,params...) // 滚动到下一个页面后,执行 callback,params为callback的参数,根据情况传入 115 | function foo(a,b){ 116 | console.log(a,b) 117 | } 118 | fullpage.moveToNext(foo,1,2) // 滚动到下一个页面,并输出 1,2 119 | ``` 120 | ### moveToPre(callback) 121 | 垂直滚动到上一个页面,用法同 `moveToNext(callback)` 122 | ### slideToNext() 123 | 水平滚动到下一个页面(页面向左滚动) 124 | ### slideToPre() 125 | 水平滚动到上一个页面(页面向右滚动) 126 | 127 | 128 | ## LICENSE 129 | The MIT License (MIT) 130 | Copyright (c) 2015-2016 [抹桥](mailto:yq12315@gmail.com) 131 | 132 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 133 | 134 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 135 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # fullpage 2 | [![Build Status](https://travis-ci.org/kisnows/fullpage.svg?branch=master)](https://travis-ci.org/kisnows/fullpage) 3 | [![GitHub issues](https://img.shields.io/github/issues/kisnows/fullpage.svg)](https://github.com/kisnows/fullpage/issues) 4 | [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/kisnows/fullpage/master/LICENSE) 5 | 6 | 一个轻巧的`fullpage`框架,不依赖其他任何库,gzip 后不到1kb。 7 | 轻松创建炫酷的单页滑动网站。 8 | 9 | [一个简单的DEMO](http://github.kisnows.com/fullpage/) 10 | ## 功能 11 | * 触摸/键盘/鼠标滚轮控制 12 | * 垂直/水平翻页 13 | 14 | ## 兼容性 15 | | Android 4.1+ | Safari 7.1+ | IE 11 | Opera | Chrome | firefox | 16 | | ------------ | ----------- | ----- | ----- | ------ | ------- | 17 | 18 | ## 使用方法 19 | 通过 npm 下载 fullpage 文件 20 | ```bash 21 | npm install fullpage 22 | ``` 23 | * 引入位于 build 目录下的 `fullpage.min.js`(或 fullpage.js 做为开发环境) 24 | * 引入 css 文件 `fullpage.css` 25 | * 按照下面格式书写`html`代码(其中 id 为 `sectionContent` 的为包裹层,你可以自定义修改其id) 26 | 27 | ```html 28 | 29 | 30 | 31 | 32 | 33 |
34 |
35 |
36 |
37 |
1
38 |
2
39 |
3
40 |
41 |
42 |
2
43 |
3
44 |
45 |
46 | 47 | ``` 48 | 49 | ## 初始化 50 | 简单使用,只要在页面加载完成后执行: 51 | ```javascript 52 | fullpage.init('#sectionContent'); 53 | ``` 54 | 如果需要定制化,则需要如下方法: 55 | ```javascript 56 | fullpage.init('#sectionContent',{ 57 | threshold: 10, // 触发滚动事件的阈值,越小越灵敏 58 | pageSpeed: 600, // 滚屏速度,单位为毫秒 ms 59 | autoScroll: 0, // 自动播放时间间隔,如果为 0 则不自动播放,单位 ms 60 | loopSection: true, // Section循环滚动 61 | loopSlide: true, // Slide循环滑动 62 | afterLoad: null, // 页面载入事件,具体查看下面的 afterLoad 函数 63 | beforeLeave: null, // 页面离开事件,具体查看下面的 beforeLeave 函数 64 | afterSlideLoad: null, // slide 载入事件 65 | beforeSlideLeave: null // slide 离开事件 66 | }); 67 | ``` 68 | ### beforeLeave(leaveIndex,nowIndex) 69 | 离开当前页面时触发的事件,函数中 `this` 指向当前页面的 **section**,`leaveIndex`为要**离开**页面的 `index` ,`nowIndex` 为要**载入**页面的 `Index` 70 | ### afterLoad(afterIndex) 71 | 载入下一张页面后触发的事件,函数中 `this` 指向将要**载入**页面的 `section`, `afterIndex` 为要**载入**页面的 `index` 72 | ### beforeSlideLeave(pageIndex, slideNow, slideAfter) 73 | 离开当前 Slide 时触发的事件,`pageIndex`是**当前**`section`的`index`,`slideNow`是**当前**`slide`的`index`,`slideAfter`是要**载入**`slide`的`index` 74 | ### afterSlideLoad(pageIndex, slideIndex) 75 | 载入下一个`slide`后触发的事件,`pageIndex`是**当前**`section`的`index`,`slideIndex`是要**载入**`slide`的`index` 76 | ```javascript 77 | fullpage.init('#sectionContent', { 78 | beforeLeave: function (leaveIndex, nowIndex) { // 如果现在在第1个页面,向下滚动后 79 | if (nowIndex === 2) { // leaveIndex = 1,nowIndex = 2 80 | console.log('You will leave page 2') // 这条语句会执行 81 | } 82 | console.log(this, leaveIndex, nowIndex) // 这里的 this 指向将要离开的页面元素,即第一个页面 83 | }, 84 | afterLoad: function (afterIndex) { // afterIndex = 2 85 | if (afterIndex === 2) { 86 | console.log('You will go to page 2') // 这条语句会执行 87 | } 88 | console.log(this, afterIndex) // 此处 this 指向当前载入的页面,即第二个页面 89 | }, 90 | beforeSlideLeave: function (pageIndex, slideNow, slideAfter) { 91 | var _this = this; 92 | console.log(_this, 'beforeSlideLeave:', pageIndex, slideNow, slideAfter); 93 | }, 94 | afterSlideLoad: function (pageIndex, slideIndex) { 95 | var _this = this; 96 | console.log(_this, 'afterSlideLoad:', pageIndex, slideIndex); 97 | } 98 | }); 99 | ``` 100 | ## 方法 101 | ### init(el,options) 102 | 页面初始化,`el`为最外包裹层选择器,`options`是要定制的参数。具体同[初始化](#初始化) 103 | ### moveTo(index,slideIndex) 104 | 滚动到指定页面,`index` 为必选参数,`slideIndex`为可选参数 105 | ```javascript 106 | fullpage.moveTo(1) // 滚动到第一个页面 107 | fullpage.moveTo(3,2) // 滚动到第三个页面的第二个slider 108 | ``` 109 | ### moveToNext(callback) 110 | 垂直滚动到下一个页面,`callback`为回掉函数,可选。 111 | ```javascript 112 | fullpage.moveToNext(); // 滚动到下一个页面 113 | fullpage.moveToNext(callback) // 滚动到下一个页面后,执行 callback 114 | fullpage.moveToNext(callback,params...) // 滚动到下一个页面后,执行 callback,params为callback的参数,根据情况传入 115 | function foo(a,b){ 116 | console.log(a,b) 117 | } 118 | fullpage.moveToNext(foo,1,2) // 滚动到下一个页面,并输出 1,2 119 | ``` 120 | ### moveToPre(callback) 121 | 垂直滚动到上一个页面,用法同 `moveToNext(callback)` 122 | ### slideToNext() 123 | 水平滚动到下一个页面(页面向左滚动) 124 | ### slideToPre() 125 | 水平滚动到上一个页面(页面向右滚动) 126 | 127 | ## 捐赠 128 | 如果你觉得本项目对你有帮助,可以考虑请我喝咖啡。 129 | 130 | 131 | 132 | ## LICENSE 133 | The MIT License (MIT) 134 | Copyright (c) 2015-2016 [抹桥](mailto:yq12315@gmail.com) 135 | 136 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 137 | 138 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 139 | -------------------------------------------------------------------------------- /src/events.js: -------------------------------------------------------------------------------- 1 | function bindEvent (options, page, el) { 2 | const Events = [] 3 | 4 | /** 5 | * 绑定触摸事件 6 | */ 7 | function bindTouchMove () { 8 | let startPos = {} 9 | let movePos = {} 10 | let diffX 11 | let diffY 12 | let touch 13 | let onceTouch = false // 判断是否为一次触摸,保证一次触摸只触发一次事件 14 | 15 | let threshold = options.threshold // 阈值,灵敏度,越小越灵敏 16 | let isVertical // 是否为垂直滚动事件 17 | 18 | function touchstartHandle (event) { 19 | // onceTouch首先置为true,表明开始了一次触摸 20 | onceTouch = true 21 | // 初始化 x,y 值,防止点击一次后出现假 move 事件 22 | startPos = {} 23 | if (event.target.tagName.toLowerCase() !== 'a') { 24 | event.preventDefault() 25 | } 26 | touch = event.touches[0] 27 | startPos.x = touch.pageX 28 | startPos.y = touch.pageY 29 | } 30 | 31 | function touchmoveHandle (event) { 32 | event.preventDefault() 33 | touch = event.touches[0] 34 | movePos.x = touch.pageX 35 | movePos.y = touch.pageY 36 | diffX = startPos.x - movePos.x 37 | diffY = startPos.y - movePos.y 38 | 39 | // 如果页面正在滚动或者不是一次滚动事件,则直接return掉 40 | if (page.isScrolling || !onceTouch) { 41 | return false 42 | } 43 | 44 | isVertical = Math.abs(diffX) - Math.abs(diffY) <= 0 45 | // 如果diff大于阈值,则事件触发,将onceTouch置为false 46 | onceTouch = Math.max(diffX, diffY) <= threshold 47 | if (!isVertical) { 48 | if (diffX > threshold) { 49 | // Move to left 50 | page.slide.next() 51 | } else if (diffX < -threshold) { 52 | // Move to right 53 | page.slide.pre() 54 | } 55 | } else { 56 | // isVertical = true 57 | if (diffY > threshold) { 58 | // Move to top 59 | page.move.next() 60 | } else if (diffY < -threshold) { 61 | // Move to bottom 62 | page.move.pre() 63 | } 64 | } 65 | } 66 | 67 | function touchendHandle (event) { 68 | if (event.target.tagName.toLowerCase() !== 'a') { 69 | event.preventDefault() 70 | } 71 | // 重置onceTouch为true 72 | onceTouch = true 73 | } 74 | 75 | let bindOptions = { 76 | capture: false, 77 | passive: false 78 | } 79 | 80 | document.addEventListener('touchstart', touchstartHandle, bindOptions) 81 | 82 | document.addEventListener('touchmove', touchmoveHandle, bindOptions) 83 | 84 | document.addEventListener('touchend', touchendHandle, bindOptions) 85 | } 86 | 87 | /** 88 | * 绑定鼠标滚动事件 89 | */ 90 | function bindMouseWheel () { 91 | // FIXME change the way binding event. 92 | let type 93 | let deltaY 94 | 95 | if (navigator.userAgent.toLowerCase().indexOf('firefox') !== -1) { 96 | type = 'DOMMouseScroll' 97 | } else { 98 | type = 'mousewheel' 99 | } 100 | 101 | function mouseWheelHandle (event) { 102 | if (page.isScrolling) { 103 | return false 104 | } 105 | deltaY = event.detail || -event.wheelDelta || event.deltaY 106 | if (deltaY > 0) { 107 | page.move.next() 108 | // console.log('next') 109 | } else if (deltaY < 0) { 110 | page.move.pre() 111 | // console.log('pre') 112 | } 113 | } 114 | 115 | el.addEventListener(type, mouseWheelHandle, false) 116 | } 117 | 118 | /** 119 | * 绑定键盘事件 120 | */ 121 | function bindKeyboard () { 122 | function keyboardHandle (event) { 123 | let key = event.keyCode || event.which 124 | switch (key) { 125 | case 37: 126 | page.slide.pre() 127 | break 128 | case 38: 129 | page.move.pre() 130 | break 131 | case 39: 132 | page.slide.next() 133 | break 134 | case 40: 135 | page.move.next() 136 | break 137 | } 138 | } 139 | // in order to bind key event to a normal element,we should add a tabindex attribute on it. 140 | el.setAttribute('tabindex', '1') 141 | el.focus() 142 | el.addEventListener('keydown', keyboardHandle, false) 143 | } 144 | 145 | Events.push(bindTouchMove, bindKeyboard, bindMouseWheel) 146 | 147 | Events.forEach(function (now) { 148 | now() 149 | }) 150 | } 151 | 152 | export default bindEvent 153 | -------------------------------------------------------------------------------- /src/fullpage.css: -------------------------------------------------------------------------------- 1 | .fp-wrap { 2 | overflow: hidden; 3 | margin: 0; 4 | padding: 0; 5 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 6 | } 7 | 8 | .fp-section-content { 9 | width: 100%; 10 | height: 100%; 11 | margin: 0; 12 | padding: 0; 13 | outline: none; 14 | } 15 | 16 | .fp-section-content .fp-section { 17 | height: 100%; 18 | position: relative; 19 | overflow: hidden; 20 | } 21 | 22 | .fp-section-content .fp-section .fp-slide-wrap { 23 | -webkit-transition: all 0.5s ease-in-out; 24 | transition: all 0.5s ease-in-out; 25 | width: auto; 26 | height: 100%; 27 | position: relative; 28 | overflow: hidden; 29 | } 30 | 31 | .fp-section-content .fp-section .fp-slide-wrap .fp-slide { 32 | float: left; 33 | } 34 | 35 | .fp-controller { 36 | position: fixed; 37 | right: 10px; 38 | width: 10px; 39 | height: 200px; 40 | top: 50%; 41 | -webkit-transform: translateY(-50%); 42 | transform: translateY(-50%); 43 | } 44 | 45 | .fp-controller .fp-controller-dotted { 46 | width: 10px; 47 | height: 10px; 48 | margin-bottom: 10px; 49 | border-radius: 50%; 50 | background: #fff; 51 | border: 1px solid #000; 52 | -webkit-transition: all 0.5s ease-in-out; 53 | transition: all 0.5s ease-in-out; 54 | } 55 | 56 | .fp-controller .fp-controller-dotted.active { 57 | background: #000; 58 | border-color: #fff; 59 | } 60 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import {init} from './init' 2 | import page from './page' 3 | 4 | let fullpage = { 5 | init: init, 6 | scrollPage: page.scrollPage, 7 | scrollSlide: page.scrollSlide, 8 | moveTo: page.moveTo, 9 | moveToNext: page.move.next, 10 | moveToPre: page.move.pre, 11 | slideToNext: page.slide.next, 12 | slideToPre: page.slide.pre 13 | }; 14 | 15 | (function (global) { 16 | global.fullpage = fullpage 17 | })(window) 18 | 19 | export default fullpage 20 | -------------------------------------------------------------------------------- /src/init.js: -------------------------------------------------------------------------------- 1 | import utils from './utils' 2 | import bindEvent from './events' 3 | import page from './page' 4 | 5 | let sectionContent 6 | let sections 7 | let options 8 | let stepHeight 9 | let stepWidth 10 | const defaults = { 11 | threshold: 50, // 触发滚动事件的阈值,越小越灵敏 12 | pageSpeed: 500, // 滚屏速度,单位为毫秒 ms 13 | autoScroll: 0, // 自动播放事件间隔,如果为 0 则不自动播放 14 | loopSection: true, // Section 循环滚动 15 | hasSectionPagination: true, // Section 编码页 16 | loopSlide: true, // Slide 循环滑动 17 | hasSlidePagination: true, // Slide 编码页 18 | afterLoad: null, // 页面载入事件 19 | beforeLeave: null, // 页面离开事件 20 | afterSlideLoad: null, // slide 载入事件 21 | beforeSlideLeave: null // slide 离开事件 22 | } 23 | 24 | function init (ele, Customize) { 25 | sectionContent = utils.$$(ele)[0] 26 | sections = utils.$$('.fp-section') 27 | options = Object.assign({}, defaults, Customize) 28 | stepHeight = utils.$$(ele)[0].offsetHeight 29 | stepWidth = utils.$$(ele)[0].offsetWidth 30 | initEle() 31 | bindEvent(options, page, sectionContent) 32 | } 33 | 34 | function initEle () { 35 | function init () { 36 | initSection() 37 | initSlide() 38 | pageController() 39 | customize() 40 | } 41 | 42 | init() 43 | /** 44 | * 初始化 Section 45 | */ 46 | function initSection () { 47 | utils.setCss(sectionContent, { 48 | 'transform': 'translate3d(0,0,0)', 49 | '-webkit-transform': 'translate3d(0,0,0)', 50 | 'transitionDuration': options.pageSpeed + 'ms', 51 | '-webkit-transitionDuration': options.pageSpeed + 'ms', 52 | 'display': 'block' 53 | }) 54 | 55 | sectionContent.addEventListener(utils.transitionEvent, function () { 56 | page.isScrolling = false 57 | }, false) 58 | 59 | for (let i = sections.length - 1; i >= 0; i--) { 60 | sections[i].style.height = stepHeight + 'px' 61 | } 62 | 63 | sections[page.nowPage].classList.add('active') 64 | } 65 | 66 | /** 67 | * 初始化 Slide 68 | */ 69 | function initSlide () { 70 | let slideWrap = utils.$$('.fp-slide-wrap') 71 | let slides 72 | 73 | function slideWrapInitHandle () { 74 | page.isScrolling = false 75 | } 76 | 77 | for (let i = slideWrap.length - 1; i >= 0; i--) { 78 | slides = utils.$$('.fp-slide', slideWrap[i]) 79 | for (let j = slides.length - 1; j >= 0; j--) { 80 | slides[j].style.width = stepWidth + 'px' 81 | } 82 | slideWrap[i].style.width = slides.length * stepWidth + 'px' 83 | slideWrap[i].dataset.x = '0' 84 | slideWrap[i].dataset.index = '0' 85 | slideWrap[i].addEventListener(utils.transitionEvent, slideWrapInitHandle, false) 86 | } 87 | } 88 | 89 | /** 90 | * 初始化翻页控制点 91 | */ 92 | function pageController () { 93 | function init () { 94 | createControllerNode() 95 | bindEvent() 96 | initController() 97 | } 98 | 99 | init() 100 | // 插入控制点 101 | function createControllerNode () { 102 | let controllerWrap = document.createElement('div') 103 | let controllerText = '' 104 | controllerWrap.className = 'fp-controller' 105 | for (let i = sections.length; i--; i > 0) { 106 | controllerText += "
" 107 | } 108 | controllerWrap.innerHTML = controllerText 109 | document.body.appendChild(controllerWrap) 110 | } 111 | 112 | // 给控制点绑定切换事件 113 | function bindEvent () { 114 | let controllers = utils.$$('.fp-controller-dotted') 115 | for (let i = controllers.length - 1; i >= 0; i--) { 116 | controllers[i].addEventListener('click', helper(i + 1), false) 117 | } 118 | function helper (i) { 119 | return function () { 120 | utils.addClassToOneEle(controllers, i - 1) 121 | page.moveTo(i) 122 | } 123 | } 124 | } 125 | 126 | // 获取控制点初试状态 127 | function initController () { 128 | let controllers = utils.$$('.fp-controller-dotted') 129 | controllers[page.nowPage].classList.add('active') 130 | } 131 | } 132 | 133 | /** 134 | * 初始化定制内容 135 | */ 136 | function customize () { 137 | let prop = { 138 | autoScroll: function () { 139 | /* eslint-disable */ 140 | let timer = null 141 | /* eslint-enable */ 142 | if (options.autoScroll) { 143 | timer = setInterval(function () { 144 | page.move.next() 145 | }, options.autoScroll) 146 | } 147 | } 148 | } 149 | 150 | for (let key in prop) { 151 | if (prop.hasOwnProperty(key)) { 152 | prop[key]() 153 | } 154 | } 155 | } 156 | } 157 | 158 | export { 159 | init, 160 | stepHeight, 161 | stepWidth, 162 | sectionContent, 163 | sections, 164 | options 165 | } 166 | -------------------------------------------------------------------------------- /src/page.js: -------------------------------------------------------------------------------- 1 | import utils from './utils' 2 | import {stepHeight, stepWidth, sectionContent, sections, options} from './init' 3 | 4 | let page = { 5 | nowPage: 0, 6 | isScrolling: false, 7 | translate3dY: 0, 8 | /** 9 | * Scroll to a specified page. 10 | * @param pageIndex {number} The page index you want scroll to. 11 | * @returns {boolean} 12 | */ 13 | scrollPage: function (pageIndex) { 14 | let pageDiff = pageIndex - page.nowPage 15 | let leaveSection = sections[page.nowPage] 16 | let nowSection = sections[pageIndex] 17 | let controllers = utils.$$('.fp-controller-dotted') 18 | if (pageIndex >= 0 && pageIndex <= sections.length - 1 && !page.isScrolling && pageDiff) { 19 | if (typeof options.beforeLeave === 'function') { 20 | /** 21 | * leaveSection 函数内部 this 指向,为将要离开的 section 22 | * page.nowPage 将要离开页面的 index 23 | * pageIndex 将要载入页面的 index 24 | */ 25 | options.beforeLeave.call(leaveSection, page.nowPage, pageIndex) 26 | } 27 | 28 | leaveSection.classList.remove('active') 29 | utils.addClassToOneEle(controllers, pageIndex) 30 | page.translate3dY -= pageDiff * stepHeight 31 | utils.translate(sectionContent, page.translate3dY, 'y') 32 | page.isScrolling = true 33 | page.nowPage = pageIndex 34 | nowSection.classList.add('active') 35 | 36 | if (typeof options.afterLoad === 'function') { 37 | options.pageSpeed = options.pageSpeed ? 500 : options.pageSpeed 38 | setTimeout(function () { 39 | /** 40 | * nowSection 函数内部 this 指向,为载入后的 section 41 | * pageIndex 载入后的 index 42 | */ 43 | options.afterLoad.call(nowSection, pageIndex) 44 | }, options.pageSpeed) 45 | } 46 | return true 47 | } else { 48 | return false 49 | } 50 | }, 51 | /** 52 | * Scroll to a specified slide. 53 | * @param slideIndex {number} The slide index you want scroll to. 54 | * @returns {boolean} 55 | */ 56 | scrollSlide: function (slideIndex) { 57 | // 获取slide包裹层 58 | let slideWrap = utils.$$('.fp-slide-wrap', sections[page.nowPage])[0] 59 | 60 | if (!slideWrap) { 61 | console.log('This page has no slide') 62 | return false 63 | } 64 | 65 | // 当前页面下所有的slide 66 | let slide = sections[page.nowPage].querySelectorAll('.fp-slide') 67 | 68 | // 当前页面上存储的数据 69 | let slideData = slideWrap.dataset 70 | 71 | // 当前页面上slide的index 72 | let slideNowIndex = parseInt(slideData.index, 10) 73 | 74 | // 当前页面上slide的x轴偏移值 75 | let slideX = slideData.x 76 | 77 | let slideDiff = slideIndex - slideNowIndex 78 | 79 | if (slideIndex >= 0 && slideIndex <= slide.length - 1 && !page.isScrolling) { 80 | if (typeof options.beforeSlideLeave === 'function') { 81 | /** 82 | * leaveSlide 函数内部 this 指向,将要离开的 slide 83 | * page.nowPage 将要离开 section 的 index 84 | * slideNowIndex 将要离开 slide 的 index 85 | * slideIndex 将要载入 slide 的 index 86 | */ 87 | options.beforeSlideLeave.call(slide[slideNowIndex], page.nowPage, slideNowIndex, slideIndex) 88 | } 89 | 90 | slide[slideNowIndex].classList.remove('active') 91 | slideX -= slideDiff * stepWidth 92 | utils.translate(slideWrap, slideX, 'x') 93 | page.isScrolling = true 94 | slideData.x = slideX 95 | slideData.index = slideIndex 96 | slide[slideIndex].classList.add('active') 97 | 98 | if (typeof options.afterSlideLoad === 'function') { 99 | options.pageSpeed = options.pageSpeed ? 500 : options.pageSpeed 100 | setTimeout(function () { 101 | /** 102 | * nowSection 函数内部 this 指向,载入后的 section 103 | * page.nowPage 将要载入 section 的 index 104 | * pageIndex 载入后的 Slide 的 index 105 | */ 106 | options.afterSlideLoad.call(slide[slideIndex], page.nowPage, slideIndex) 107 | }, options.pageSpeed) 108 | } 109 | return true 110 | } 111 | return false 112 | }, 113 | /** 114 | * Scroll to a specified section and slide. 115 | * @param pageIndex {number} 116 | * @param slideIndex {number} 117 | * @returns {boolean} 118 | */ 119 | moveTo: function (pageIndex, slideIndex) { 120 | // DONE move to a specify section or slide 121 | if (page.nowPage === pageIndex || page.scrollPage(pageIndex)) { 122 | if (typeof slideIndex !== 'undefined') { 123 | // DONE move to a specify slide 124 | return !!page.scrollSlide(slideIndex) 125 | } 126 | return true 127 | } else { 128 | return false 129 | } 130 | }, 131 | move: { 132 | next: function (callback) { 133 | if (page.scrollPage(page.nowPage + 1)) { 134 | let arg = Array.prototype.slice.call(arguments, 1) 135 | 136 | if (typeof callback === 'function') { 137 | callback(arg) 138 | } 139 | return true 140 | } else if (options.loopSection) { 141 | page.moveTo(0) 142 | 143 | return true 144 | } else { 145 | return false 146 | } 147 | }, 148 | pre: function (callback) { 149 | if (page.scrollPage(page.nowPage - 1)) { 150 | let arg = Array.prototype.slice.call(arguments, 1) 151 | 152 | if (typeof callback === 'function') { 153 | callback(arg) 154 | } 155 | return true 156 | } else { 157 | return false 158 | } 159 | } 160 | }, 161 | slide: { 162 | /** 163 | * slide move 方法,移动到上一个或下一个 slide 164 | * @param {string} direction 要移动的方向,next 为下一个, pre 为上一个 165 | * @returns {boolean} 166 | */ 167 | move: function (direction) { 168 | let slideWrap = utils.$$('.fp-slide-wrap', sections[page.nowPage])[0] 169 | let slide = sections[page.nowPage].querySelectorAll('.fp-slide') 170 | // slideNowIndexChange slideNowIndex 将要的变化 171 | let slideNowIndexChange 172 | // slideWillBe 将要滚到slide的index 173 | let slideWillBe 174 | if (direction === 'next') { 175 | slideNowIndexChange = 1 176 | slideWillBe = 0 177 | } else if (direction === 'pre') { 178 | slideNowIndexChange = -1 179 | slideWillBe = slide.length - 1 180 | } 181 | if (!slideWrap) { 182 | return false 183 | } else { 184 | let slideData = slideWrap.dataset 185 | let slideNowIndex = parseInt(slideData.index, 10) 186 | 187 | if (page.scrollSlide(slideNowIndex + slideNowIndexChange)) { 188 | slideData.index = slideNowIndex + slideNowIndexChange 189 | return true 190 | } else if (options.loopSlide && page.scrollSlide(slideWillBe)) { 191 | slideData.index = slideWillBe 192 | return true 193 | } 194 | return false 195 | } 196 | }, 197 | next: function () { 198 | page.slide.move('next') 199 | }, 200 | pre: function () { 201 | page.slide.move('pre') 202 | } 203 | } 204 | } 205 | 206 | export default page 207 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | let utils = { 2 | $$ (el, parent) { 3 | if (!parent) { 4 | return document.querySelectorAll(el) 5 | } else { 6 | return parent.querySelectorAll(el) 7 | } 8 | }, 9 | 10 | setCss (el, props) { 11 | let prop 12 | for (prop in props) { 13 | if (props.hasOwnProperty(prop)) { 14 | el.style[prop] = props[prop] 15 | } 16 | } 17 | return el 18 | }, 19 | 20 | translate (el, value, direction) { 21 | if (direction === 'y') { 22 | this.setCss(el, { 23 | 'transform': 'translate3d(0,' + value + 'px,0)', 24 | '-webkit-transform': 'translate3d(0,' + value + 'px,0)' 25 | }) 26 | // console.log('setAttr Done') 27 | } else if (direction === 'x') { 28 | this.setCss(el, { 29 | 'transform': 'translate3d(' + value + 'px,0,0)', 30 | '-webkit-transform': 'translate3d(' + value + 'px,0,0)' 31 | }) 32 | } 33 | }, 34 | 35 | /** 36 | * 只给一组元素中的某一个元素添加class 37 | * @param els 一组元素 38 | * @param theOne 要添加元素的index值 39 | */ 40 | addClassToOneEle (els, theOne) { 41 | for (let j = els.length - 1; j >= 0; j--) { 42 | els[j].classList.remove('active') 43 | } 44 | els[theOne].classList.add('active') 45 | }, 46 | transitionEvent: whichTransitionEvent() 47 | 48 | } 49 | 50 | function whichTransitionEvent () { 51 | let t 52 | let el = document.createElement('fakeelement') 53 | let transitions = { 54 | 'transition': 'transitionend', 55 | 'OTransition': 'oTransitionEnd', 56 | 'MozTransition': 'transitionend', 57 | 'WebkitTransition': 'webkitTransitionEnd', 58 | 'MsTransition': 'msTransitionEnd' 59 | } 60 | 61 | for (t in transitions) { 62 | if (el.style[t] !== undefined) { 63 | return transitions[t] 64 | } 65 | } 66 | } 67 | 68 | export default Object.create(utils) 69 | -------------------------------------------------------------------------------- /tea.yaml: -------------------------------------------------------------------------------- 1 | # https://tea.xyz/what-is-this-file 2 | --- 3 | version: 1.0.0 4 | codeOwners: 5 | - '0xe8F5354FD744DD0b247ABe9C98033515Cc3Daf2B' 6 | quorum: 1 7 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | var pkg = require('./package.json'); 4 | var date = new Date(); 5 | var banner = ` 6 | ${pkg.name} ${pkg.version} 7 | Author: ${pkg.author} 8 | Homepage: ${pkg.homepage} 9 | Release under ${pkg.license}. 10 | update ${date.toLocaleDateString()} 11 | `; 12 | 13 | var config = { 14 | devtool: 'cheap-module-eval-source-map', 15 | entry: './src/index.js', 16 | output: { 17 | path: path.resolve(__dirname, 'build'), 18 | filename: 'fullpage.js', 19 | publicPath: path.resolve(__dirname, 'build'), 20 | }, 21 | plugins: [new webpack.BannerPlugin(banner)], 22 | module: { 23 | rules: [{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' }], 24 | }, 25 | }; 26 | 27 | if (process.env.NODE_ENV === 'production') { 28 | config.devtool = null; 29 | config.output = { 30 | path: path.resolve(__dirname, 'build'), 31 | filename: 'fullpage.min.js', 32 | }; 33 | config.plugins.push(new webpack.optimize.UglifyJsPlugin()); 34 | } 35 | 36 | module.exports = config; 37 | --------------------------------------------------------------------------------