├── .babelrc
├── .jsconfig
├── doc
└── wechatpay.png
├── .gitignore
├── .travis.yml
├── demo
├── demo01
│ ├── images
│ │ ├── bg.jpg
│ │ ├── code.png
│ │ └── icon.png
│ ├── less
│ │ └── pages
│ │ │ └── variation.css
│ ├── js
│ │ └── index.js
│ ├── index.html
│ └── css
│ │ └── app.css
└── demo2
│ └── index.html
├── tea.yaml
├── .codeclimate.yml
├── .eslintrc
├── .editorconfig
├── src
├── index.js
├── fullpage.css
├── utils.js
├── events.js
├── init.js
└── page.js
├── webpack.config.js
├── LICENSE
├── package.json
├── readme.en-US.md
└── readme.md
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015"]
3 | }
--------------------------------------------------------------------------------
/.jsconfig:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES6"
4 | }
5 | }
--------------------------------------------------------------------------------
/doc/wechatpay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kisnows/fullpage/HEAD/doc/wechatpay.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .idea
3 | .tmp
4 | app.yaml
5 | bower_components
6 | .vscode
7 | *.less
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "12.16.0"
4 | script:
5 | - npm run deploy
6 |
--------------------------------------------------------------------------------
/demo/demo01/images/bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kisnows/fullpage/HEAD/demo/demo01/images/bg.jpg
--------------------------------------------------------------------------------
/demo/demo01/images/code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kisnows/fullpage/HEAD/demo/demo01/images/code.png
--------------------------------------------------------------------------------
/demo/demo01/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kisnows/fullpage/HEAD/demo/demo01/images/icon.png
--------------------------------------------------------------------------------
/tea.yaml:
--------------------------------------------------------------------------------
1 | # https://tea.xyz/what-is-this-file
2 | ---
3 | version: 1.0.0
4 | codeOwners:
5 | - '0xe8F5354FD744DD0b247ABe9C98033515Cc3Daf2B'
6 | quorum: 1
7 |
--------------------------------------------------------------------------------
/.codeclimate.yml:
--------------------------------------------------------------------------------
1 | engines:
2 | eslint:
3 | enabled: true
4 | ratings:
5 | paths:
6 | - src/**
7 | exclude_paths:
8 | - build/**/*
9 | - demo/**/*
10 |
--------------------------------------------------------------------------------
/demo/demo2/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | DEMO 2
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
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 |

86 |
87 |
94 |
95 |
96 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/readme.en-US.md:
--------------------------------------------------------------------------------
1 | # fullpage
2 | [](https://travis-ci.org/kisnows/fullpage)
3 | [](https://github.com/kisnows/fullpage/issues)
4 | [](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 | [](https://travis-ci.org/kisnows/fullpage)
3 | [](https://github.com/kisnows/fullpage/issues)
4 | [](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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------