├── examples ├── App.css ├── index.css ├── index.js ├── pages │ ├── bscroll-pullDown │ │ ├── main.css │ │ └── index.js │ ├── bscroll-pullup │ │ ├── main.css │ │ └── index.js │ ├── bscroll-vertical │ │ ├── main.css │ │ └── index.js │ ├── bscroll-multi │ │ ├── main.css │ │ └── index.js │ └── bscroll-sample │ │ ├── sample.css │ │ └── index.js └── App.js ├── public ├── favicon.ico ├── manifest.json └── index.html ├── src ├── loading │ ├── loading.gif │ ├── loading.css │ └── loading.js ├── scroll │ ├── betterScroll.css │ └── index.js └── bubble │ └── bubble.js ├── cli └── gh-pages.js ├── config ├── jest │ ├── fileTransform.js │ └── cssTransform.js ├── polyfills.js ├── paths.js ├── env.js ├── webpackDevServer.config.js ├── webpack.config.lib.js ├── webpack.config.dev.js └── webpack.config.prod.js ├── .gitignore ├── lib ├── react-scroll.css └── react-bscroll.js ├── package.json ├── .eslintrc ├── README.md └── scripts ├── dev.js ├── build-lib.js └── build-demo.js /examples/App.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soluteli/react-bscroll/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /examples/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /src/loading/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soluteli/react-bscroll/HEAD/src/loading/loading.gif -------------------------------------------------------------------------------- /examples/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | 6 | ReactDOM.render(, document.getElementById('root')); 7 | -------------------------------------------------------------------------------- /src/loading/loading.css: -------------------------------------------------------------------------------- 1 | .loading-container { 2 | width: 100%; 3 | } 4 | 5 | .loading-container img { 6 | display: block; 7 | width: 20px; 8 | height: 20px; 9 | margin: 0 auto; 10 | } -------------------------------------------------------------------------------- /cli/gh-pages.js: -------------------------------------------------------------------------------- 1 | var ghpages = require('gh-pages'); 2 | // var path = require('path'); 3 | 4 | ghpages.publish('dist', function(err) { 5 | if (err) { 6 | return console.log('gh pages error', err) 7 | } 8 | console.log('gh pages success') 9 | 10 | }); -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /config/jest/fileTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | 5 | // This is a custom Jest transformer turning file imports into filenames. 6 | // http://facebook.github.io/jest/docs/tutorial-webpack.html 7 | 8 | module.exports = { 9 | process(src, filename) { 10 | return `module.exports = ${JSON.stringify(path.basename(filename))};`; 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /config/jest/cssTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // This is a custom Jest transformer turning style imports into empty objects. 4 | // http://facebook.github.io/jest/docs/tutorial-webpack.html 5 | 6 | module.exports = { 7 | process() { 8 | return 'module.exports = {};'; 9 | }, 10 | getCacheKey() { 11 | // The output is always the same. 12 | return 'cssTransform'; 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | 23 | yarn.lock 24 | -------------------------------------------------------------------------------- /src/loading/loading.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | 3 | import './loading.css' 4 | 5 | const loadingImg = require('./loading.gif') 6 | 7 | class Loading extends Component { 8 | 9 | render () { 10 | return ( 11 |
12 | loading 13 |
14 | ) 15 | } 16 | } 17 | 18 | export default Loading 19 | -------------------------------------------------------------------------------- /examples/pages/bscroll-pullDown/main.css: -------------------------------------------------------------------------------- 1 | .container { 2 | position: relative; 3 | height: 400px; 4 | background: rgba(0,0,0,.3); 5 | border: 1px solid #000; 6 | } 7 | 8 | .content { 9 | /*width: 200%;*/ 10 | position: relative; 11 | margin: 0; 12 | } 13 | 14 | .content-item { 15 | height: 60px; 16 | line-height: 60px; 17 | font-size: 18px; 18 | padding-left: 20px; 19 | border-bottom: 1px solid #e5e5e5; 20 | } 21 | -------------------------------------------------------------------------------- /examples/pages/bscroll-pullup/main.css: -------------------------------------------------------------------------------- 1 | .container { 2 | position: relative; 3 | height: 400px; 4 | background: rgba(0,0,0,.3); 5 | border: 1px solid #000; 6 | } 7 | 8 | .content { 9 | /*width: 200%;*/ 10 | position: relative; 11 | margin: 0; 12 | } 13 | 14 | .content-item { 15 | height: 60px; 16 | line-height: 60px; 17 | font-size: 18px; 18 | padding-left: 20px; 19 | border-bottom: 1px solid #e5e5e5; 20 | } 21 | -------------------------------------------------------------------------------- /examples/pages/bscroll-vertical/main.css: -------------------------------------------------------------------------------- 1 | .container { 2 | position: relative; 3 | height: 400px; 4 | background: rgba(0,0,0,.3); 5 | border: 1px solid #000; 6 | } 7 | 8 | .content { 9 | /*width: 200%;*/ 10 | position: relative; 11 | margin: 0; 12 | } 13 | 14 | .content-item { 15 | height: 60px; 16 | line-height: 60px; 17 | font-size: 18px; 18 | padding-left: 20px; 19 | border-bottom: 1px solid #e5e5e5; 20 | } 21 | -------------------------------------------------------------------------------- /examples/pages/bscroll-multi/main.css: -------------------------------------------------------------------------------- 1 | .container { 2 | position: relative; 3 | height: 300px; 4 | background: rgba(0,0,0,.3); 5 | border: 1px solid #000; 6 | margin-bottom: 10px; 7 | } 8 | 9 | .content { 10 | /*width: 200%;*/ 11 | position: relative; 12 | margin: 0; 13 | } 14 | 15 | .content-item { 16 | height: 60px; 17 | line-height: 60px; 18 | font-size: 18px; 19 | padding-left: 20px; 20 | border-bottom: 1px solid #e5e5e5; 21 | } 22 | -------------------------------------------------------------------------------- /lib/react-scroll.css: -------------------------------------------------------------------------------- 1 | .loading-container{width:100%}.loading-container img{display:block;width:20px;height:20px;margin:0 auto}.b-wrapper{position:absolute;left:0;top:0;right:0;bottom:0;overflow:hidden;background:#fff}.b-pullup-wrapper{height:60px;line-height:60px}.b-pulldown-wrapper,.b-pullup-wrapper{width:100%;display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;-ms-flex-align:center;align-items:center}.b-pulldown-wrapper{position:absolute;top:0;left:0;-webkit-transition:all;-o-transition:all;transition:all;pointer-events:none}.b-pulldown-wrapper .after-trigger{margin-top:10px} -------------------------------------------------------------------------------- /config/polyfills.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if (typeof Promise === 'undefined') { 4 | // Rejection tracking prevents a common issue where React gets into an 5 | // inconsistent state due to an error, but it gets swallowed by a Promise, 6 | // and the user has no idea what causes React's erratic future behavior. 7 | require('promise/lib/rejection-tracking').enable(); 8 | window.Promise = require('promise/lib/es6-extensions.js'); 9 | } 10 | 11 | // fetch() polyfill for making API calls. 12 | require('whatwg-fetch'); 13 | 14 | // Object.assign() is commonly used with React. 15 | // It will use the native implementation if it's present and isn't buggy. 16 | Object.assign = require('object-assign'); 17 | -------------------------------------------------------------------------------- /src/scroll/betterScroll.css: -------------------------------------------------------------------------------- 1 | .b-wrapper { 2 | position: absolute; 3 | left: 0; 4 | top: 0; 5 | right: 0; 6 | bottom: 0; 7 | overflow: hidden; 8 | background: #fff; 9 | } 10 | 11 | .b-pullup-wrapper { 12 | width: 100%; 13 | display: flex; 14 | justify-content: center; 15 | align-items: center; 16 | height: 60px; 17 | line-height: 60px; 18 | } 19 | 20 | .b-pulldown-wrapper { 21 | position: absolute; 22 | width: 100%; 23 | top: 0; 24 | left: 0; 25 | display: flex; 26 | justify-content: center; 27 | align-items: center; 28 | transition: all; 29 | pointer-events: none; 30 | } 31 | 32 | .b-pulldown-wrapper .after-trigger { 33 | margin-top: 10px 34 | } 35 | -------------------------------------------------------------------------------- /examples/pages/bscroll-sample/sample.css: -------------------------------------------------------------------------------- 1 | .container { 2 | position: relative; 3 | height: 400px; 4 | background: rgba(0,0,0,.3); 5 | border: 1px solid #000; 6 | } 7 | 8 | .b-wrapper { 9 | position: absolute; 10 | left: 0; 11 | top: 0; 12 | right: 0; 13 | bottom: 0; 14 | overflow: hidden; 15 | background: #fff; 16 | } 17 | 18 | .b-content { 19 | /*width: 200%;*/ 20 | position: relative; 21 | margin: 0; 22 | } 23 | 24 | .b-content-item { 25 | /*height: 60px;*/ 26 | line-height: 60px; 27 | font-size: 18px; 28 | padding-left: 20px; 29 | border-bottom: 1px solid #e5e5e5; 30 | } 31 | 32 | .b-pullup-wrapper { 33 | width: 100%; 34 | display: flex; 35 | justify-content: center; 36 | align-items: center; 37 | height: 60px; 38 | line-height: 60px; 39 | } 40 | -------------------------------------------------------------------------------- /examples/pages/bscroll-vertical/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import Scroll from 'src/scroll' 3 | 4 | import './main.css' 5 | 6 | const Data = [] 7 | for (let i = 0; i < 10; i++) { 8 | Data.push(i) 9 | } 10 | class VerticalScrollPage extends Component { 11 | constructor (props, context) { 12 | super(props, context) 13 | 14 | this.state = { 15 | listData: Data, 16 | childData: 666 17 | } 18 | } 19 | 20 | componentDidMount () { 21 | for (let i = 10; i < 30; i++) { 22 | Data.push(i) 23 | } 24 | } 25 | 26 | clickItem (item) { 27 | console.log('clickEvent', item) 28 | } 29 | 30 | render () { 31 | return ( 32 |
33 |
34 | 35 |
    36 | {this.state.listData.map((item, index) => 37 | (
  • 41 | item:{item} 42 |
  • ), 43 | )} 44 |
45 |
46 |
47 |
48 | ) 49 | } 50 | } 51 | 52 | export default VerticalScrollPage 53 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /examples/pages/bscroll-multi/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import Scroll from 'src/scroll' 3 | 4 | import './main.css' 5 | 6 | let Data = [] 7 | for (let i = 0; i < 10; i++) { 8 | Data.push(i) 9 | } 10 | let Data2 = [] 11 | for (let i = 10; i < 20; i++) { 12 | Data2.push(i) 13 | } 14 | class BscrollMultiPage extends Component { 15 | constructor (props, context) { 16 | super(props, context) 17 | 18 | this.state = { 19 | listData: Data, 20 | listData2: Data2, 21 | childData: 666 22 | } 23 | } 24 | 25 | componentDidMount () { 26 | for (let i = 10; i < 30; i++) { 27 | Data.push(i) 28 | } 29 | } 30 | 31 | clickItem (item) { 32 | console.log('clickEvent', item) 33 | } 34 | 35 | render () { 36 | return ( 37 |
38 |
39 | 40 |
    41 | {this.state.listData.map((item, index) => 42 | (
  • 46 | item:{item} 47 |
  • ), 48 | )} 49 |
50 |
51 |
52 |
53 | 54 |
    55 | {this.state.listData2.map((item, index) => 56 | (
  • 60 | item:{item} 61 |
  • ), 62 | )} 63 |
64 |
65 |
66 |
67 | ) 68 | } 69 | } 70 | 71 | export default BscrollMultiPage 72 | -------------------------------------------------------------------------------- /examples/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { HashRouter as Router, Route, Link } from 'react-router-dom' 3 | 4 | // import BScrollSamplePage from './pages/bscroll-sample' 5 | import BScrollVertivalPage from './pages/bscroll-vertical/index' 6 | import BScrollPullupPage from './pages/bscroll-pullup/index' 7 | import BScrollPullDownPage from './pages/bscroll-pullDown/index' 8 | import BscrollMultiPage from './pages/bscroll-multi/index' 9 | 10 | class Home extends Component { 11 | render () { 12 | return ( 13 |
14 |
15 |

Demos

16 |

如果在pc端预览,请在打开移动调试工具后,先刷新后查看效果

17 |
18 | 19 | {/*
01: 使用原better-scroll
*/} 20 |
01: react-scroll -- 简单案例
21 |
02: react-scroll -- 上拉加载
22 |
03: react-scroll -- 下拉加载
23 |
04: react-scroll -- 多个scroll
24 |
25 | ) 26 | } 27 | } 28 | 29 | class App extends Component { 30 | render () { 31 | return ( 32 | 33 |
34 | {/* 导航 */} 35 | 36 | 37 | {/* better-scroll */} 38 | {/**/} 39 | 40 | 41 | 42 | 43 |
44 |
45 | ) 46 | } 47 | } 48 | 49 | export default App; 50 | -------------------------------------------------------------------------------- /examples/pages/bscroll-pullDown/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import Scroll from 'src/scroll' 3 | 4 | import './main.css' 5 | 6 | const Data = [] 7 | let NEWTOPDATAINDEX1 = 1 8 | for (let i = 0; i < 10; i++) { 9 | Data.push(i) 10 | } 11 | class PullDownScrollPage extends Component { 12 | constructor (props, context) { 13 | super(props, context) 14 | 15 | this.state = { 16 | listData: Data, 17 | childData: 666 18 | } 19 | } 20 | 21 | componentWillMount () { 22 | NEWTOPDATAINDEX1 = 1 23 | } 24 | 25 | componentDidMount () { 26 | } 27 | 28 | componentWillUnmount () { 29 | clearTimeout(this.timer) 30 | } 31 | 32 | pullDownFreshAction = () => { 33 | return new Promise((resolve) => { 34 | this.timer = setTimeout(() => { 35 | if (Math.random() > 0) { 36 | // 如果有新数据 37 | let newPage = [] 38 | for (let i = 0; i < 2; i++) { 39 | newPage.unshift(`我是顶部新数据${NEWTOPDATAINDEX1++}`) 40 | } 41 | this.setState({ 42 | listData: [ 43 | ...newPage, 44 | ...this.state.listData 45 | ], 46 | }) 47 | } 48 | resolve() 49 | }, 1000) 50 | }) 51 | } 52 | 53 | clickItem (item) { 54 | console.log('clickEvent', item) 55 | } 56 | 57 | render () { 58 | return ( 59 |
60 |
61 | 65 |
    66 | {this.state.listData.map((item, index) => 67 | (
  • 71 | item:{item} 72 |
  • ), 73 | )} 74 |
75 |
76 |
77 |
78 | ) 79 | } 80 | } 81 | 82 | export default PullDownScrollPage 83 | -------------------------------------------------------------------------------- /examples/pages/bscroll-pullup/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import Scroll from 'src/scroll' 3 | 4 | import './main.css' 5 | 6 | const Data = [] 7 | let NEWDATAINDEX = 1 8 | for (let i = 0; i < 10; i++) { 9 | Data.push(i) 10 | } 11 | class PullupScrollPage extends Component { 12 | constructor (props, context) { 13 | super(props, context) 14 | 15 | this.state = { 16 | listData: Data, 17 | childData: 666 18 | } 19 | } 20 | 21 | componentWillMount () { 22 | NEWDATAINDEX = 1 23 | } 24 | 25 | componentDidMount () { 26 | } 27 | 28 | componentWillUnmount () { 29 | console.log('compomentWillUnmount') 30 | console.log(this.timer) 31 | clearTimeout(this.timer) 32 | } 33 | 34 | loadMoreData = () => { 35 | // 更新数据 36 | return new Promise( resolve => { 37 | console.log('pulling up and load data') 38 | this.timer = setTimeout(() => { 39 | if (Math.random() > 0) { 40 | // 如果有新数据 41 | let newPage = [] 42 | for (let i = 0; i < 2; i++) { 43 | newPage.push(`我是新数据${NEWDATAINDEX++}`) 44 | } 45 | this.setState({ 46 | listData: [ 47 | ...this.state.listData, 48 | ...newPage 49 | ], 50 | }) 51 | } 52 | resolve() 53 | }, 1000) 54 | }) 55 | } 56 | 57 | clickItem (item) { 58 | console.log('clickEvent', item) 59 | } 60 | 61 | render () { 62 | return ( 63 |
64 |
65 | 70 |
    71 | {this.state.listData.map((item, index) => 72 | (
  • 76 | item:{item} 77 |
  • ), 78 | )} 79 |
80 |
81 |
82 |
83 | ) 84 | } 85 | } 86 | 87 | export default PullupScrollPage 88 | -------------------------------------------------------------------------------- /config/paths.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const fs = require('fs'); 5 | const url = require('url'); 6 | 7 | // Make sure any symlinks in the project folder are resolved: 8 | // https://github.com/facebookincubator/create-react-app/issues/637 9 | const appDirectory = fs.realpathSync(process.cwd()); 10 | const resolveApp = relativePath => path.resolve(appDirectory, relativePath); 11 | 12 | const envPublicUrl = process.env.PUBLIC_URL; 13 | 14 | function ensureSlash(path, needsSlash) { 15 | const hasSlash = path.endsWith('/'); 16 | if (hasSlash && !needsSlash) { 17 | return path.substr(path, path.length - 1); 18 | } else if (!hasSlash && needsSlash) { 19 | return `${path}/`; 20 | } else { 21 | return path; 22 | } 23 | } 24 | 25 | const getPublicUrl = appPackageJson => 26 | envPublicUrl || require(appPackageJson).homepage; 27 | 28 | // We use `PUBLIC_URL` environment variable or "homepage" field to infer 29 | // "public path" at which the app is served. 30 | // Webpack needs to know it to put the right