├── .babelrc ├── .eslintrc ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── examples-dist ├── carousel.9540da0e7b385842da32.bundle.js ├── carousel.9540da0e7b385842da32.bundle.js.map ├── carousel.html ├── css │ ├── carousel.d7c89e08b5abfb774f54.css │ ├── carousel.d7c89e08b5abfb774f54.css.map │ ├── header-footer.aa697a21f7857d4c1560.css │ ├── header-footer.aa697a21f7857d4c1560.css.map │ ├── index.36fbdaffa0fdd50aa664.css │ ├── index.36fbdaffa0fdd50aa664.css.map │ ├── pull-carousel.168d7ef0a8deaade6c73.css │ ├── pull-carousel.168d7ef0a8deaade6c73.css.map │ ├── pull-carousel2.d50988f2dea6085f1002.css │ ├── pull-carousel2.d50988f2dea6085f1002.css.map │ ├── pull.1cdce4fcd519ccb16612.css │ ├── pull.1cdce4fcd519ccb16612.css.map │ ├── simple.cd5bd1d575b7cc335111.css │ ├── simple.cd5bd1d575b7cc335111.css.map │ ├── tabs-carousel.65b224ba332c3c8c1bb4.css │ └── tabs-carousel.65b224ba332c3c8c1bb4.css.map ├── eruda.min.js ├── header-footer.9540da0e7b385842da32.bundle.js ├── header-footer.9540da0e7b385842da32.bundle.js.map ├── header-footer.html ├── index.9540da0e7b385842da32.bundle.js ├── index.9540da0e7b385842da32.bundle.js.map ├── index.html ├── pull-carousel.9540da0e7b385842da32.bundle.js ├── pull-carousel.9540da0e7b385842da32.bundle.js.map ├── pull-carousel.html ├── pull-carousel2.9540da0e7b385842da32.bundle.js ├── pull-carousel2.9540da0e7b385842da32.bundle.js.map ├── pull-carousel2.html ├── pull.9540da0e7b385842da32.bundle.js ├── pull.9540da0e7b385842da32.bundle.js.map ├── pull.html ├── simple.9540da0e7b385842da32.bundle.js ├── simple.9540da0e7b385842da32.bundle.js.map ├── simple.html ├── tabs-carousel.9540da0e7b385842da32.bundle.js ├── tabs-carousel.9540da0e7b385842da32.bundle.js.map └── tabs-carousel.html ├── examples ├── carousel.js ├── eruda.min.js ├── header-footer.js ├── index.js ├── pull-carousel.js ├── pull-carousel2.js ├── pull.js ├── sass │ └── example.scss ├── simple.js ├── tabs-carousel.js └── templates │ └── layout.html ├── gulp ├── example.babel.js ├── publish.babel.js └── scss.babel.js ├── gulpfile.babel.js ├── js ├── AlloyTouch.js ├── ReactAlloyTouch.js ├── ReactCarousel.js ├── ReactPull.js ├── ReactSwiper.js └── index.js ├── package-lock.json ├── package.json ├── publish └── package.json ├── sass ├── carousel.scss ├── index.scss └── pull.scss ├── webpack.config.babel.js ├── webpack.config.example.babel.js └── webpack.config.example.dist.babel.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "targets": { 5 | "browsers": ["last 2 versions"] 6 | } 7 | }], 8 | "react" 9 | ], 10 | "plugins": [ 11 | "transform-object-rest-spread", // 支持对象 rest 预发 12 | "transform-class-properties" //解析类属性,静态和实例的属性 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | /** 2 | "off" or 0 - turn the rule off 3 | "warn" or 1 - turn the rule on as a warning (doesn’t affect exit code) 4 | "error" or 2 - turn the rule on as an error (exit code is 1 when triggered) 5 | **/ 6 | { 7 | "rules": { 8 | // Possible Errors 9 | "no-await-in-loop": 2, // Disallow await inside of loops 10 | "no-compare-neg-zero": 2, // 不要出现负零,即 -0 11 | "no-cond-assign": 2, // 条件语句中,不应该出现 = ,比如 if (x = 2) { } 是会报错的 12 | "no-console": 0, // 是否允许 console 13 | "no-constant-condition": 2, // 是否允许使用常量式表达式 if (false) { } 14 | "no-control-regex": 2, // 是否允许在正则表达式中使用控制字符 15 | "no-debugger": 2, // 是否允许使用 debugger 16 | "no-dupe-args": 2, // 函数参数是否允许有重复的,如果设置了严格模式,可以不用设置该选项 17 | "no-dupe-keys": 2, // 是否允许对象中有相同的key 18 | "no-duplicate-case": 2, // 检测case语句中,是否有重复的case变量值 19 | "no-empty": 2, // 是否允许空的表达式,if (foo) {} 20 | "no-empty-character-class": 2, // 是否允许空的正则表达式,比如 var foo = /^abc[]/; 21 | /** 22 | 异常时给ex赋值是不允许的 23 | try { 24 | // code 25 | } catch (e) { 26 | e = 12; //error Do not assign to the exception parameter. 27 | } 28 | **/ 29 | "no-ex-assign": 2, 30 | "no-extra-boolean-cast": 2, // 在条件语句中不允许使用!! 比如 if (!!foo) { } /*error Redundant double negation in an if statement condition.*/ 31 | "no-extra-parens": 0, // 不要使用冗余的括号,比如 a = (b * c); 32 | "no-extra-semi": 2, // 不要使用多余的分号; 比如 var x = 5;; 33 | "no-func-assign": 2, // 不允许给函数重新赋值 function foo() {} foo = bar; /*error 'foo' is a function.*/ 34 | "no-inner-declarations": 2, // 不要在函数体或程序块(if或循环)中声明函数 35 | "no-invalid-regexp": 2, // 不允许定义无效的正则表达式 36 | "no-irregular-whitespace": 2, // 不允许使用除空格和制表位意外的空白字符,比如 \u222B 37 | "no-obj-calls": 2, // 不允许调用全局的函数对象,比如 Math 和 JSON var x = Math(); /*error 'Math' is not a function.*/ var y = JSON(); /*error 'JSON' is not a function.*/ 38 | "no-prototype-builtins": 0, // 不建议直接使用 Object.prototypes ,而使用 call 来调用,比如 var hasBarProperty = {}.hasOwnProperty.call(foo, "bar"); 39 | "no-regex-spaces": 2, // 正则表达式中不允许有空格 40 | "no-sparse-arrays": 2, // 此开关控制是否可以用稀疏数组 41 | "no-template-curly-in-string": 2, // 不允许字符串的模板,比如 "Hello ${name}!" 会报错 42 | "no-unexpected-multiline": 2, // 避免多行的表达式 43 | "no-unreachable": 2, // 避免书写不可达的代码,比如在return后添加新的代码,或抛出异常,中断语句后 44 | "no-unsafe-finally": 2, // 不用在 finally 语句中使用 return 或抛出异常(throw) 45 | "no-unsafe-negation": 2, // 在in 或 instanceof表达式中不要否定变量 if(!a in b) {} 是错误的,应该写成 if(!(a in b)){} 46 | "use-isnan": 2, // 不要用NaN跟变量作比较,而是应该调用 isNaN() 47 | "valid-jsdoc": 0, // 如果我们使用jsdoc[http://usejsdoc.org/]来生成js文档,可以开启该规则来检测注释的正确性 48 | "valid-typeof": 2, // 验证typeof与比较的值,是否为以下几种情况,"undefined", "object", "boolean", "number", "string", and "function" 49 | 50 | // Best Practices 51 | "accessor-pairs": 2, // 定义对象属性时,setter和getter应该成对出现,如果不是成对的,会出现警告信息的 52 | "array-callback-return": 2, // 在数组方法中,回调函数应该加上 return,比如在 array.reduce中 53 | "block-scoped-var": 2, // 在快作用于中不允许使用var来定义变量 54 | "class-methods-use-this": 0, //在 class 定义的方法中,没有使用 this,会认为是不应该的 55 | "complexity": 2, // 判断语句复杂度,关闭该规则 56 | "consistent-return": 0, // 不同的分支返回的类型应该一样 57 | "curly": [2, "multi-line"], // 在循环或判断语句中是否需要加花括号 58 | "default-case": 2, // 在 switch语句中,检测是否有默认分支 59 | "dot-location": [2, "property"], // 在换行时,用来检测对象的点是换行之前还是之后,这里设为放在下一行 60 | "dot-notation": 2, // 对于对象属性应该用点表达式,不应该用[] var x = foo["bar"]; 是错误的,应该 var x = foo.bar; 但 var x = foo[bar]; 是正确的,因为bar是变量 61 | "eqeqeq": [2, "allow-null"], // 使用恒等来比较两个变量 62 | "guard-for-in": 2, // 在 for in 表达式中需要调用 hasOwnProperty 来判断是否为自有的属性 63 | "no-alert": 2, // 不允许用alert语句 64 | "no-caller": 2, // 不允许用 arguments.caller 和 arguments.callee 65 | "no-case-declarations": 2, // 在 case 语句中使用声明式语句时,需要用 {} 括起来 66 | "no-div-regex": 0, // 消除除法运算符迷惑用户使用 例如 return /=foo/; 应该写成 return /\=foo/; 67 | "no-else-return": 2, // 如果在if语句中有return,则在else中可以不用return,可以放到最外面返回 68 | "no-empty-function": 0, //不要定义空函数 69 | "no-empty-pattern": 2, // 不允许空的解构赋值,例如 var {a: {}} = foo; 70 | "no-eq-null": 0, // 对于null比较也应该使用 === 来比较 71 | "no-eval": 2, // 不允许使用 eval() 72 | "no-extend-native": 2, // 不允许修改扩展内置对象的属性,比如 Object.prototype.a = "a"; 73 | "no-extra-bind": 0, // 可以规范代码,防止滥用 bind 方法 74 | "no-extra-label": 2, // 当使用 label 表达式时,检测不必要的 label 表达式 75 | "no-fallthrough": 2, // 是否检测switch语句中 case 后没有break,return或throw 76 | "no-floating-decimal": 2, // 对于浮点数,不能省略.前或.后的数字2 77 | "no-global-assign": [2, {"exceptions": ["Object"]}], // 不要给全局变量赋值,需要先定义在赋值 78 | "no-implicit-coercion": [2, {"string": false}], // 不要使用隐身转换,应该使用直接转换,如果针对 boolean number string ,比如 var n = +foo; 应该为 var n = Number(foo); 代替 79 | "no-implicit-globals": 0, 80 | "no-implied-eval": 2, // 不要使用隐式调用eval的语句,比如 setInterval("alert('Hi!');", 122); 81 | "no-invalid-this": 0, // 用来检测 this 关键字使用的地方是否正确,我们可以设置关闭该规则 82 | "no-iterator": 2, // 在ES6中有__iterator__属性,建议不要修改该属性值 83 | "no-labels": 2, // 不建议使用 label 表达式 84 | "no-lone-blocks": 2, // 禁止内部不必要的嵌套块 85 | "no-loop-func": 2, // 不要在循环中定义函数,并且该函数中调用了循环变量 86 | "no-magic-numbers": [0, { // 一些系数最好定义为常量 87 | "ignore": [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 16], 88 | "ignoreArrayIndexes": true 89 | } 90 | ], 91 | "no-multi-spaces": [0, { // 表达式中是否允许有多余的空格 92 | "exceptions": { 93 | "AssignmentExpression": true, 94 | "ArrowFunctionExpression": true, 95 | "CallExpression": true, 96 | "VariableDeclarator": true 97 | } 98 | } 99 | ], 100 | "no-multi-str": 2, // 是否允许多行字符串 101 | "no-new": 0, // 不允许实例化类,而没有赋给任何变量 102 | "no-new-func": 2, // 不建议使用 new Function 来声明函数 103 | "no-new-wrappers": 2, // 对于String, Number, 和 Boolean,不建议使用 new,即 new String 等 104 | "no-octal": 2, // 不允许使用八进制数字 105 | "no-octal-escape": 2, // 不允许使用八进制转义字符串 106 | "no-param-reassign": 0, // 如果开启,则不允许重新修改函数参数值,或者参数属性值 107 | "no-proto": 2, // 不建议使用该属性 __proto__ 108 | "no-redeclare": 2, // 不允许重复声明同一个变量 109 | "no-restricted-properties": [2, { // 定义不允许的对象属性 110 | "object": "disallowedObjectName", 111 | "property": "disallowedPropertyName", 112 | "message": "Please use allowedObjectName.allowedPropertyName." 113 | }], 114 | "no-return-assign": 2, // 不允许在return语句中有赋值语句 115 | "no-return-await": 2, // disallow unnecessary return await 116 | "no-script-url": 2, // 不要使用javascript:url,比如 location.href = "scripts:void(2)";是错误的 117 | "no-self-assign": [2, {"props": false}],// 不建议自己给自己赋值,比如 foo = foo 118 | "no-self-compare": 2, // 不允许变量自己跟自己做比较 119 | "no-sequences": 2, // 需要正确的使用逗号操作符 120 | "no-throw-literal": 2, // 抛出异常时,请使用 new Error() 121 | "no-unmodified-loop-condition": 2, // 用来检测循环中的条件值始终没有改变 122 | "no-unused-expressions": 2, // 不允许出现未使用的表达式 123 | "no-unused-labels": 2, // 定义了 label 而没有被调用 124 | "no-useless-call": 2, // 对于不必要使用call或apply,建议不要使用,直接调用即可 125 | "no-useless-concat": 2, // 不必要的字符串连接最好去掉,写在一起 126 | "no-useless-escape": 2, // 不必要的转义就不要转义了 127 | "no-useless-return": 2, // 不允许出现不必要的 return 语句 128 | "no-void": 2, // 不建议使用void操作符 129 | "no-warning-comments": 0, // 对于注释中的 TODO FIXME XXX 等,是否给出提示,建议开发中设置为1,部署的时候设置为 2 130 | "no-with": 2, // 不允许使用with表达式语句 131 | "prefer-promise-reject-errors": 2, // 对于Promise.reject,参数必须是一个 Error 对象,比如 Promise.reject(5); 是不允许的,应该写成 Promise.reject(new Error("something bad happened")); 132 | "radix": 2, // 在调用 parseInt 应该指定基数 133 | "require-await": 2, // 对于 async 表达式,必须有对应的 await 表达式 134 | "vars-on-top": 0, // 所有变量声明是否都放在函数最上面或过程快最上面 135 | "wrap-iife": [2, "any"], // 立即执行函数是里面包裹还是外面包裹,默认是外面包裹,即 outside 136 | "yoda": 2, // 不允许使用 yoda 条件表达式,常量值在前的比较表达式,比如: if(1 === a){ } 137 | 138 | // Variables 139 | "init-declarations": 0, // 声明变量的时候赋值,还是在其他地方赋值,我们可以关闭该规则 140 | "no-catch-shadow": 2, // 在IE8或更早的浏览器中,在catch语句中引入的变量 e 会调用全局已定义的变量 e 141 | "no-delete-var": 2, // 不能删除变量,而只能删除属性 142 | "no-label-var": 2, // 使用标签label语句时,不要跟变量同名,建议不要使用标签 143 | "no-restricted-globals": 2, // 不要使用全局变量 144 | "no-shadow": 0, // 全局和局部变量名不要用相同的名称 145 | "no-shadow-restricted-names": 2, // 不要使用 NaN, Infinity, undefined 等内部定义的变量来声明变量 146 | "no-undef": 2, // 不要使用还没有定义的变量或函数,如果引用第三方定义的变量,可以用 /*global */ 来标注,例如 /*global require define:true*/ 147 | "no-undef-init": 2, // 定义变量的时候,如果没有合适的赋值,不用显式设置 undefined ,因为默认声明而未赋值的变量,其默认值为 undefined 148 | "no-undefined": 0, // 代码中不建议使用 undefined ,包括命令和赋值等 149 | /** 150 | 定义了,但没有使用该变量,vars 有两种选择 all 和 local;args 有三种选择,all after-used 和 none 151 | 我们可以只检测变量而不检测函数参数,可以把 args 设为 none 152 | **/ 153 | "no-unused-vars": [0, {"vars": "all", "args": "none"}], 154 | "no-use-before-define": [0, "nofunc"], // 变量和函数的声明需要在使用之前,可以设置 [2, "nofunc"],只检测变量,而不检测函数 155 | 156 | //Node.scripts and CommonJS 157 | "callback-return": 0, // 调用callback时需要加上return语句 158 | "global-require": 0, // require加载依赖应该放在代码最上边显示,比如 var fs = require("fs"); 159 | "handle-callback-err": 2, // 如果回调函数中有错误变量(比如err),我们需要判断处理错误的情况 160 | "no-mixed-requires": 2, // require与其他变量声明应该不要放在一起 161 | "no-new-require": 2, // 不用对表达式 require 直接使用 new,例如 var appHeader = new require('app-header'); 162 | "no-path-concat": 2, // 不要使用 __dirname 或 __filename 与字符串连接生成路径,应该使用 path.join(__dirname, "foo.scripts"); 或 path.resolve(__dirname, "foo.scripts"); 163 | "no-process-env": 0, // 在node环境中,不建议使用 process.env ,而使用 config 来配置 164 | "no-process-exit": 2, // 不要直接调用 process.exit(); 165 | "no-restricted-modules": 2, // 限制使用某些模块,比如 no-restricted-modules: [2, "fs"] ,不能使用fs模块 166 | "no-sync": 2, // 我们尽量使用异步方法来代替同步方法,比如操作文件等, 167 | 168 | // Stylistic Issues 169 | "array-bracket-spacing": 2, // 数组元素前后是否要加一空格,默认为不必要加,如 var arr = [ 'foo', 'bar' ]; 是不正确的写法 170 | "block-spacing": 2, // 花括号与语句间应该有空格 171 | "brace-style": 2, // 条件或循环语句中,花括号是另起一行,还是与当前语句在同一行,默认跟当前语句在同一行 172 | "camelcase": 2, // 驼峰式命名变量或属性 173 | "capitalized-comments": 0, // 注释的大小写格式限制 174 | "comma-dangle": 0, // 对象最后一个属性,是否需要逗号 175 | "comma-spacing": 2, // 逗号表达式前后空格情况,默认前面没有,后边应该添加 176 | "comma-style": 2, // 当换行时,逗号是在当前行还是下一行,默认是当前行 177 | "computed-property-spacing": 2, // 用[]取属性值时,是否应该有空格 178 | "consistent-this": [2, "self"], // 闭包的时候,this 用变量声明上下文应该统一,该变量就不用用在其他定义变量上 179 | "eol-last": 2, // 在行的末尾至少空上一行 180 | "func-call-spacing": 2, // 函数名与括号之间是否需要一个空格 181 | "func-name-matching": 2, // 定义函数变量时,匿名名称是否应该跟变量名称一致,默认一致 182 | "func-names": 0, // 函数表达式需要一个名称,包括匿名函数,该规则可以关闭 183 | "func-style": [0, "declaration", { // 是声明式的函数,还是定义变量式的函数,我们采用声明式,但箭头函数允许变量式 184 | "allowArrowFunctions": true 185 | }], 186 | "id-blacklist": 2, // 指定一些黑名单变量,这些变量不能出现在代码中,比如 "id-blacklist": [2, "data", "err", "e", "cb", "callback"], 187 | "id-length": 0, // 定义变量名或属性名的最小最大长度 188 | "id-match": 2, // 规范变量名或属性名的命名规范 189 | "indent": [0, 2, {"SwitchCase": 1}, 190 | { "VariableDeclarator": { "var": 2, "let": 2, "const": 3 }}, 191 | ], // 缩进,我们采用2个空格来缩进 192 | "jsx-quotes": 0, // jsx属性值应该用双引号 193 | "key-spacing": 2, // 键值之间的空格 194 | "keyword-spacing": 2, // 关键字 if, else, for, while, do, switch, try, catch, finally, and with 要求有空格 195 | "linebreak-style": 0, // 验证 unix (LF) or windows (CRLF) 196 | "lines-around-comment": 0, // 注释的规范写法,在旁边或上方 197 | "lines-around-directive": 2, // 不同的语句中间是否加一空行 198 | "max-depth": [2, 12], // 限制语句块最大嵌套深度 199 | "max-len": [ // 限定每行最大长度 200 | 2, 200, { 201 | 202 | } 203 | ], 204 | "max-lines": [2, {"max": 800, "skipBlankLines": true, "skipComments": true}], // 指定每个文件最大行 205 | "max-nested-callbacks": [1, 3], // 限定回调函数最大深度 206 | "max-params": [2, 8], // 限定函数参数最大个数 207 | "max-statements": [2, 80, {"ignoreTopLevelFunctions": true}], // 在一个函数中限定声明表达式最多个数,内部函数会或略 208 | "max-statements-per-line": [2, {"max": 2}], // 每行最大表达式 209 | "multiline-ternary": 0, // 三元表达式,是否需要多行书写 210 | "new-cap": 0, // 构造函数首字母应该大写 211 | "new-parens": 2, // 实例化构造函数时,需要加入(),即使没有参数值,所以比如 new Person 是不允许的 212 | "newline-after-var": 0, // 用var声明变量时,是否允许换行 213 | "newline-before-return": 0, 214 | "newline-per-chained-call": 0, 215 | "no-array-constructor": 0, // 不允许使用 new Array(2, 1, 2) 来创建数组,而改用 [] 216 | "no-bitwise": 0, // 禁止使用位运算符,包括以下情况 var x = y | z; var x = y & z; var x = y ^ z; var x = ~ z; var x = y << z; var x = y >> z; var x = y >>> z; x |= y; x &= y; x ^= y; x <<= y; x >>= y; x >>>= y; 217 | "no-continue": 0, // 是否允许使用 continue语句 218 | "no-inline-comments": 0,// 注释是否允许在代码的后面,开启则不允许 219 | "no-lonely-if": 0, // 应该使用 else if ,而不要使用 else { if(){} } 220 | "no-mixed-operators": 2, // 不要把多个操作符写在一起使用,最好用括号括起来 221 | "no-mixed-spaces-and-tabs": 2, // 不允许空格和制表位混合使用 222 | "no-multi-assign": 0, // 不要连续赋值,比如 var a = b = c = 5; 223 | "no-multiple-empty-lines": 2, // 代码中不要出现太多空行,默认最多为2行 224 | "no-negated-condition": 0, // 是否允许使用否定表达式 if (!a) 225 | "no-nested-ternary": 2, // 是否允许使用嵌套的三元表达式 226 | "no-new-object": 2, // 实例化对象时,不要用 new Object(); 而用 {} 227 | "no-plusplus": [0, {"allowForLoopAfterthoughts": true }], // 是否允许使用 ++ 或 -- 228 | "no-restricted-syntax": [2, "WithStatement"], // 可以指定不允许的语法 229 | "no-tabs": 2, // 是否允许使用制表符 230 | "no-ternary": 0, // 是否允许三元操作符 231 | "no-trailing-spaces": 0, // 不允许行尾有空白字符 232 | "no-underscore-dangle": 0, // 是否允许变量名前后有 _ 233 | "no-unneeded-ternary": 2, // 请不要使用不必要的三元表达式,比如 var isYes = answer === 1 ? true : false; 234 | "no-whitespace-before-property": 0, 235 | "nonblock-statement-body-position": 2, // 如果在条件或循环表达式中,只有一行的表达式,并且没有使用 {} ,最好跟条件写在一行 236 | "object-curly-newline": 0, 237 | "object-curly-spacing": 0, // 验证花括号内的空格 238 | "object-property-newline": 0, // 对象属性在新行显示 239 | "one-var": 0, // 多个变量声明是否用一个var语句 240 | "one-var-declaration-per-line": [0, "always"], // 定义多个变量时,是否需要每个变量在一行显示 241 | "operator-assignment": 2, // 对于赋值表达式,应该使用其简略式写法,比如 x = x + y 应该用 x += y 242 | "operator-linebreak": 0, // 有操作符时,是否检测打断的行 243 | "padded-blocks": 0, // 是否验证空白块 244 | "quote-props": [2, "as-needed"], // 属性加单引号或双引号,个人建议不用加的最好不加 245 | "quotes": [2, "single"], // 字符串引号,建议使用单引号 246 | "require-jsdoc": 0, // 是否需要 jsdoc 来注释代码 247 | "semi": [0, "always"], // 总是要求加上分号 248 | "semi-spacing": 2, // 分号与代码之间的间隔 249 | "sort-keys": 0, // 属性是否需要排序 250 | "sort-vars": 0, // 定义多个变量时,是否按字符顺序来排序,不建议开启该规则 251 | "space-before-blocks": 2, // 在每一块后面需要添加一空格 252 | "space-before-function-paren": 0, // 在函数名和() 之间有一空格 253 | "space-in-parens": 0, // 括号和参数之间应该没有空格 254 | "space-infix-ops": 2, // 表达式中间应该添加空白 255 | "space-unary-ops": 2, // 在一元操作符前或后不应该有空白 256 | "spaced-comment": [0, "always", { 257 | "line": { 258 | "markers": ["/"], 259 | "exceptions": ["-", "+"] 260 | }, 261 | "block": { 262 | "markers": ["!"], 263 | "exceptions": ["*"], 264 | "balanced": true 265 | } 266 | }], // 如果开启,则会检测注释符后是否有空白,always必须有,而never则没有 267 | "template-tag-spacing": 2, // 标记模板内容,中间是否需要加空格,默认不需要加 268 | "unicode-bom": 2, // 269 | "wrap-regex": 2, // 字面正则表达式需要用括号括起来 270 | 271 | // es6 272 | "arrow-body-style": [2, "always"],// 箭头函数是否需要加上{} 273 | "arrow-parens": 2,//对于箭头函数,需要添加括号,比如(a) => {}; 而不应该简写为 a => {}; 274 | "arrow-spacing": 2,//箭头函数中,箭头运算符前后需要添加空白 275 | "constructor-super": 2,//父类构造函数不应该调用 super() ,但派生类必须要调用 super() 276 | "generator-star-spacing": 2,//generator functions 中 * 前应该添加空白,后面不应该有空白 277 | "no-class-assign": 2,//不能再修改已经声明的类,即不能重现给已经声明的类赋其他值 278 | "no-confusing-arrow": 2, //箭头函数中不建议使用引起疑惑的表达式,比如 var x = a => 1 ? 2 : 3,如果使用需要用{} 括起来 279 | "no-const-assign": 2,//不能修改常量值 280 | "no-dupe-class-members": 2,//类成员不能重复定义 281 | "no-duplicate-imports": 2, 282 | "no-new-symbol": 2, //对于 Symbol,不要使用 new,例如 var foo = new Symbol("foo"); 283 | "no-restricted-imports": 2,// 禁止特定的导入 284 | "no-this-before-super": 2,//不允许在 super() 之前使用 this/super 语句 285 | "no-useless-computed-key": 2, //禁止不必要的属性计算表达式 286 | "no-useless-constructor": 2, //禁止不必要的构造方法,比如空的构造器 287 | "no-useless-rename": 2, // 禁止不必要的别名表达式,比如 export { foo as bar } from 'foo'; 288 | "no-var": 2,//在需要使用const 或 let 声明时不要使用var 289 | "object-shorthand": 2,//利用简写法来定义对象属性,如 var foo = {x, y, z}; 表示 var foo = {x:x, y:y, z:z}; 290 | "prefer-arrow-callback": 2,//建议使用箭头函数作为回调函数 291 | "prefer-const": 2,//能使用常量的地方尽量使用const 292 | "prefer-destructuring": 2, // 尽量使用解构表达式,比如 const [foo] = array; 或 const {bar: foo} = object; 293 | "prefer-numeric-literals": 2, // 不允许直接使用 parseInt 解析字面量变量,比如 parseInt("111110111", 2),而 parseInt(foo); 是允许的 294 | "prefer-rest-params": 2, // 建议使用 rest (...args) 参数来代替 arguments 295 | "prefer-spread": 2,//不要使用apply,应该使用扩展操作符来调用 Math.max(...args); 296 | "prefer-template": 2,//建议使用模板符来替代引号,比如 var str = `Hello, ${name}!`; 297 | "require-yield": 2,//generator functions 应该有 yield 298 | "rest-spread-spacing": 2,//rest 表达式中间是否加空格,默认不加 299 | "sort-imports": 0, // improt 的变量名称导入应该按顺序排位 300 | "symbol-description": 2, // 使用 Symbol 定义变量时,需要传入 Symbol description 301 | "template-curly-spacing": [2, "never"], // 模板表达式中 {} 前后是否需要空格 302 | "yield-star-spacing": [2, {"before": true, "after": false}], // yield * 号前后是否需要空格 303 | 304 | 305 | // react rules,默认设置为报错 https://github.com/yannickcr/eslint-plugin-react 306 | 307 | "react/display-name": 0, // 是否检测需要为React Component 设置一个 displayName 308 | "react/forbid-component-props": 0, // 禁止某些在组件上的属性,比如 className 等 309 | "react/forbid-elements": [2, {"forbid": [""] }], // 禁止使用某些标签 310 | "react/forbid-prop-types": 0, // 是否检测使用了React.PropTypes.any React.PropTypes.array 或 React.PropTypes.object,如果开启该规则,则不允许使用React.PropTypes 指定的类型,而用具体的类型来说明,默认该规则是关闭的 311 | "react/forbid-foreign-prop-types": 2, // 不要使用不相关的 PropTypes 312 | "react/no-array-index-key": 2, // 最好不用使用数组的 index 作为 key 313 | "react/no-children-prop": 2, // 不需要把 children 作为 prop 传递 314 | "react/no-danger": 2, // 不要使用不安全的名称来定义属性,比如 dangerouslySetInnerHTML __html,看 https://facebook.github.io/react/tips/dangerously-set-inner-html.html 315 | "react/no-danger-with-children": 2, // 对于属性dangerouslySetInnerHTML存在的话,不需要再书写 children 316 | "react/no-deprecated": 2, // 建议不要使用不赞成的方法,比如 React.render(, root); React.unmountComponentAtNode(root); 317 | "react/no-did-mount-set-state": 2, // 在componentDidMount 中不要使用 setState 方法 318 | "react/no-did-update-set-state": 2, // componentDidUpdate 中不要使用 setState 方法 319 | "react/no-direct-mutation-state": 2, // 不要直接使用 this.state 来改变值,而应该用 this.setState 320 | "react/no-find-dom-node": 2, // 不建议使用 findDOMNode,因为最终该方法会被废弃 321 | "react/no-is-mounted": 2, // 不建议使用方法 this.isMounted() 322 | "react/no-multi-comp": [2, { "ignoreStateless": true }], // 不建议在一个文件中定义多个组件,但无状态的组件被或略 323 | "react/no-render-return-value": 2, // 使用ReactDOM.render()不应该有返回值 324 | "react/no-set-state": 0, // 在 Flux 或 redux 中是使用 store 维持 state 的,在这些框架中可以不使用 state 325 | "react/no-string-refs": 0, // 不建议使用字符串的 ref 而应该使用变量 326 | "react/no-unescaped-entities": 2, // 不要出现没有转义的字符直接量 327 | "react/no-unknown-property": 2, // 不要使用扁平或不接受的属性名称,比如class,而用className,属性名应该是驼峰式命名 328 | "react/no-unused-prop-types": 2, // 声明了 props 而没有被使用 329 | "react/prefer-es6-class": 2, // 应该使用 es6 来创建 class 330 | "react/prefer-stateless-function": 2, // 对于无状态的组件尽量使用函数来声明组件,比如 const Foo = function(props) {return
{props.foo}
;}; 331 | "react/prop-types": 2, // 对于没有设置 propType 的 prop 给出警告 332 | "react/react-in-jsx-scope": 2, // 对于使用了 JSX,要使用 React 组件 333 | "react/require-default-props": 0, // 对于每个 prop ,是否需要设置一下其 defaultProps 值 334 | "react/require-optimization": 0, // 检测每个组件是否有 shouldComponentUpdate 方法 335 | "react/require-render-return": 2, // render 方法中需要 return 336 | "react/self-closing-comp": 0, // 对于没有子元素的组件应该是这样的 而不应该 337 | "react/sort-comp": 2, // 组件方法是否按一定的顺序书写,默认为: 1 static methods and properties 2 lifecycle methods: displayName, propTypes, contextTypes, childContextTypes, mixins, statics,defaultProps, constructor, getDefaultProps, getInitialState, state, getChildContext, componentWillMount, componentDidMount, componentWillReceiveProps, shouldComponentUpdate, componentWillUpdate, componentDidUpdate, componentWillUnmount (in this order). 3 custom methods 4 render method 338 | "react/sort-prop-types": 0, // propType 是否按字母顺序来排列 339 | "react/style-prop-object": 2, // style 必须是对象 340 | "react/void-dom-elements-no-children": 2, // 不要给没有子节点的 dom 标签设置 childern 内容,比如
Children

, 这些都是错误的写法 341 | 342 | // JSX-specific rules 以下为 jsx 规则 343 | "react/jsx-boolean-value": 2, // 该规则可以设置为两种情况,always 和 never ,设置为 always 如果 attribute 没有设置值,会警告;设为 never,如果 attribute 有一个 true 值,会警告 https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-boolean-value.md 344 | "react/jsx-closing-bracket-location": 0, // 检测jsx tag 闭合书写规范 345 | "react/jsx-curly-spacing": 2, // 检测赋值是否有空格,默认是不应该有空格的,但换行不检测,比如 ; 346 | "react/jsx-equals-spacing": [2, "never"], // 再给属性赋值时,是否在 = 前后加上空格 347 | "react/jsx-filename-extension": 0, // 后缀名,是否必须是 jsx 348 | "react/jsx-first-prop-new-line": 0, // 第一个属性名是否在新的一行书写 349 | "react/jsx-handler-names": 2, // 按照惯例,事件方法名前是否加上 handle 350 | "react/jsx-indent": [2, 2], // jsx 嵌套包裹缩进,默认用2个 351 | "react/jsx-indent-props": [0, 2],// jsx语法换行缩进几个空格(或制表符) 352 | "react/jsx-key": 2, // 在循环中,组件应该设置不同的 key 353 | "react/jsx-max-props-per-line": 0, // jsx 每个属性应该写在单独一行(默认),也可以设置每行的个数 354 | "react/jsx-no-bind": 2, // 不必要的地方不使用bind 355 | "react/jsx-no-comment-textnodes": 2, // 检测注释的正确性 356 | "react/jsx-no-duplicate-props": 2, // 给jsx设置同名的属性会警告 357 | "react/jsx-no-literals": 0, // 不要设置字面的值,比如 var Hello =
test
; 而用 var Hello =
{'test'}
; 358 | "react/jsx-no-target-blank": 0, 359 | "react/jsx-no-undef": 2, // 检测定义了jsx component 而没有被调用 360 | "react/jsx-pascal-case": 2, // 应该使用 pascal 来命名组件名 361 | "react/jsx-sort-props": 0, // 属性名是否按字母排序 362 | "react/jsx-space-before-closing": 0, // 在关闭标签前是否加一空格 363 | "react/jsx-tag-spacing": 0, // 检测标签空格 364 | "react/jsx-uses-react": 2,// React声明了而没有被调用 365 | "react/jsx-uses-vars": 2, // jsx组件被定义而没有被调用 366 | "react/jsx-wrap-multilines": 2 // 多行 jsx 表达式应该用 () 包裹起来 367 | }, 368 | "parser": "babel-eslint", // 指定默认解析器 369 | "env": { 370 | "es6": true, 371 | "node": true, 372 | "browser": true 373 | }, 374 | "parserOptions": { 375 | "ecmaVersion": 8, 376 | "sourceType": "module", 377 | "ecmaFeatures": { 378 | "jsx": true // enable JSX 379 | } 380 | }, 381 | "globals": { // 定义全局的变量 382 | 383 | }, 384 | "extends": [ // 推荐使用默认配置好的 385 | "eslint:recommended", "plugin:react/recommended" 386 | ], 387 | "plugins": [//定义第三方插件 388 | "react" 389 | ], 390 | "settings": {// 设置 391 | "react": { 392 | "createClass": "createReactClass", // Regex for Component Factory to use, default to "createReactClass" 393 | "pragma": "React", // Pragma to use, default to "React" 394 | "version": "16.0.0" // React version, default to the latest React stable release 395 | }, 396 | "sharedData": "sharedName" 397 | }, 398 | "root": true // 设置他后,子的js文件找到该 eslint配置文件后,则不再向上查找其他eslint配置文件 399 | } 400 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore files 2 | .idea 3 | node_modules 4 | publish 5 | !publish/package.json -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # React AlloyTouch 更新日志 2 | 3 | ## version 0.4.1 4 | 5 | * 修复了 bug #4 ref 采用建议的回调函数写法而非字符串 6 | 7 | ## version 0.4.0 8 | 9 | * 去掉了 babel-preset-es2015,改用 babel-preset-env 10 | * 升级到 react 16 11 | * 默认下拉刷新和上拉加载隐藏显示,当需要的时候再显示 12 | 13 | ## version 0.3.2 14 | 15 | * 修改了下拉刷新,有时不能正常滑到底部的 bug 16 | * 新增了两个可选项 17 | * loadedRecoilTime: PropTypes.number, // 加载完更多数据回弹时间 18 | * moveForwardOffset: PropTypes.number, // 加载完更多数据时,向前推进的距离 19 | * 修改了对应的下拉刷新,上拉加载更多例子 20 | 21 | ## version 0.2.0 22 | 23 | * 修改下拉刷新组件,当数据只有一行时的 bug 24 | 25 | ## version 0.1.8 26 | 27 | * 添加自定义轮播图内容,并添加tabs接口 28 | 29 | ## version 0.1.6 30 | 31 | * 为轮播图增加自定义事件 32 | 33 | ## version 0.1.4 34 | 35 | * 新增下拉刷新中显示轮播图例子 36 | 37 | ## version 0.1.0 开启 React AlloyTouch 之旅 38 | 39 | 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 reactjs-ui 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React AlloyTouch 2 | 3 | This is a react component for AlloyTouch. 4 | 5 | ## Install 6 | 7 | ``` 8 | npm install react-alloytouch --save 9 | ``` 10 | 11 | ## Usage 12 | 13 | ### Pull Component 14 | 15 | #### example code 16 | 17 | ```javascript 18 | import React, {Component} from 'react'; 19 | import {render} from 'react-dom'; 20 | import injectTapEventPlugin from 'react-tap-event-plugin'; 21 | import {ReactPull} from 'react-alloytouch'; 22 | import 'react-alloytouch/sass/pull.scss'; // 或者 import 'react-alloytouch/css/pull.css'; 23 | import './sass/example.scss'; // 自定义样式 24 | 25 | // 初始化 tapEvent 事件, 移动端 26 | injectTapEventPlugin(); 27 | 28 | class ReactPullExample extends Component { 29 | constructor(props) { 30 | super(props); 31 | this.state = { 32 | items: 30, 33 | disablePullUp: false 34 | }; 35 | } 36 | 37 | refreshCallback = () => { 38 | return new Promise((resolve, reject) => { 39 | setTimeout(() => { 40 | let result = false; 41 | if (Math.random() > 0.2) { 42 | result = true; 43 | } 44 | if (result) { 45 | this.setState({ 46 | items: 30, 47 | disablePullUp: false 48 | }, () => { 49 | resolve(); 50 | }); 51 | } else { 52 | reject(new Error('错误')); 53 | } 54 | }, 1000); 55 | }).then(() => { 56 | console.info('刷新成功!'); 57 | }, () => { 58 | console.info('刷新失败!'); 59 | }); 60 | }; 61 | 62 | loadMoreCallback = () => { 63 | return new Promise((resolve, reject) => { 64 | setTimeout(() => { 65 | let result = false; 66 | if (Math.random() > 0.2) { 67 | result = true; 68 | } 69 | if (result) { 70 | this.setState({ 71 | items: this.state.items + 10, 72 | disablePullUp: this.state.items >= 60 73 | }, () => { 74 | resolve(); 75 | }); 76 | } else { 77 | reject(new Error('错误')); 78 | } 79 | }, 1000); 80 | }).then(() => { 81 | console.info('加载更多成功!'); 82 | }, () => { 83 | console.info('加载更多失败!'); 84 | }); 85 | }; 86 | 87 | handleTouchTap = (e) => { 88 | console.info('测试下拉刷新插件是否与 Tap 事件冲突'); 89 | }; 90 | 91 | render() { 92 | const contents = []; 93 | const {items, disablePullUp} = this.state; 94 | 95 | for (let i = items; i > 0; i--) { 96 | if (i < 10) { 97 | contents.push(
  • 这里放置真实显示的DOM内容 {i}
  • ); 98 | } else { 99 | contents.push(
  • 这里放置真实显示的DOM内容 {i}
  • ); 100 | } 101 | } 102 | 103 | const props = { 104 | refreshCallback: this.refreshCallback, 105 | loadMoreCallback: this.loadMoreCallback, 106 | refresh: true, 107 | loadMore: true, 108 | disablePullUp, 109 | }; 110 | 111 | return ( 112 | 113 |
      114 | {contents.map((item) => { 115 | return item; 116 | })} 117 |
    118 |
    119 | ); 120 | } 121 | } 122 | 123 | render( 124 | , document.getElementById('layout') 125 | ); 126 | 127 | ``` 128 | 129 | #### Options 130 | 131 | | 选项 | 类型 | 功能 | 132 | | -------- | ----- | ---- | 133 | | children | PropTypes.node| 待渲染的内容| 134 | | className | PropTypes.string| 自定义 className| 135 | | header | PropTypes.element| 头部| 136 | | footer | PropTypes.element| 底部| 137 | | options | PropTypes.object| AlloyTouch 组件选项| 138 | | lockInTime | PropTypes.number| 延迟刷新或加载| 139 | | enableText | PropTypes.bool| 是否显示滚动条| 140 | | refresh | PropTypes.bool| 是否下拉刷新| 141 | | refreshThreshold | PropTypes.number| 设置刷新页面时,距离顶部临界值 | 142 | | refreshCallback | PropTypes.func| 刷新回调函数| 143 | | pullDownText | PropTypes.array | 下拉显示文本内容 | 144 | | loadMore | PropTypes.bool | 是否加载更多 | 145 | | loadMoreThrottle | PropTypes.number | 设置加载更多,距离最底部临界值 | 146 | | loadMoreCallback | PropTypes.func | 加载更多回调函数 | 147 | | pullUpText | PropTypes.array | 上拉显示文本内容 | 148 | | loadMoreProcessIcon | PropTypes.bool | 加载更多过程图标 | 149 | | disablePullUp | PropTypes.bool | 对于上拉加载更多时,如果没有更多记录时,禁止上滑 | 150 | | loadedRecoilTime| PropTypes.number| 加载完更多数据回弹时间| 151 | | moveForwardOffset| PropTypes.number| 加载完更多数据时,向前推进的距离| 152 | 153 | 对于 AlloyTouch 组件选项 options 设置,看[官方说明](https://github.com/AlloyTeam/AlloyTouch) 154 | 155 | ### Carousel Component 156 | 157 | #### example code 158 | 159 | ```javascript 160 | import React, {Component} from 'react'; 161 | import {render} from 'react-dom'; 162 | import {ReactCarousel} from 'react-alloytouch'; 163 | import 'react-alloytouch/sass/carousel.scss'; // 或者 import 'react-alloytouch/css/carousel.css'; 164 | import './sass/example.scss'; // 自定义样式 165 | 166 | const ReactCarouselExample = () => { 167 | 168 | const items = [{ 169 | image: 'http://alloyteam.github.io/AlloyTouch/example/asset/ci1.jpg', 170 | link: 'http://jd.com' 171 | }, { 172 | image: 'http://alloyteam.github.io/AlloyTouch/example/asset/ci2.jpg', 173 | }, { 174 | image: 'http://alloyteam.github.io/AlloyTouch/example/asset/ci3.jpg', 175 | link: 'http://jd.com' 176 | }, { 177 | image: 'http://alloyteam.github.io/AlloyTouch/example/asset/ci4.jpg' 178 | }]; 179 | const events = { 180 | onTouchTap: () => { 181 | console.info('这是个测试!'); 182 | } 183 | }; 184 | 185 | return ( 186 | 187 | ); 188 | }; 189 | 190 | render( 191 | , document.getElementById('layout') 192 | ); 193 | 194 | ``` 195 | 196 | #### Options 197 | 198 | | 选项 | 类型 | 功能 | 199 | | -------- | ----- | ---- | 200 | | className | PropTypes.string| 自定义 className| 201 | | prefix | PropTypes.string| 样式前缀| 202 | | options | PropTypes.object| AlloyTouch 组件选项| 203 | | items | PropTypes.array| 轮播图| 204 | | active | PropTypes.number| 当前活动轮播图| 205 | | autoPlay | PropTypes.oneOfType([PropTypes.bool, PropTypes.number])| 是否自动播放| 206 | | events | PropTypes.object| 自定义各种事件| 207 | 208 | ## Example 209 | 210 | ``` 211 | npm install 212 | npm start 213 | ``` 214 | 215 | http://localhost:9090 216 | 217 | 218 | ## Online Example 219 | 220 | http://reactjs-ui.github.io/react-alloytouch/ 221 | 222 | ## Build Example 223 | 第一次需要先执行前两步操作,再执行第三步。以后修改例子后,只需要执行第三步即可 224 | 225 | 1. 创建 gh-pages 分支,**在执行 git subtree add 命令之前,需确保 gh-pages 分支下至少存在一个文件** 226 | ``` 227 | git checkout -b gh-pages 228 | rm -rf * //隐藏文件需要单独删除,结合命令 ls -a 229 | vim .gitignore //输入一些内容 230 | git add . 231 | git commit -m "init branch gh-pages" 232 | git push --set-upstream origin gh-pages 233 | git checkout master 234 | ``` 235 | 236 | 2. 把分支 gh-pages 添加到本地 subtree 中,执行该命令前,请确保 examples-dist 文件夹不存在 237 | 238 | ``` 239 | git subtree add --prefix=examples-dist origin gh-pages --squash 240 | ``` 241 | 242 | 3. 生成在线 examples 243 | 244 | ``` 245 | npm run build:examples 246 | git add examples-dist 247 | git commit -m "Update online examples" 248 | git subtree pull --prefix=examples-dist origin gh-pages 249 | git subtree push --prefix=examples-dist origin gh-pages --squash 250 | git push 251 | ``` 252 | 253 | 4 使用以下命令一键发布在线例子 254 | ```bash 255 | npm run examples:publish 256 | ``` 257 | 258 | ## Build 259 | 260 | ``` 261 | npm run build 262 | ``` 263 | 264 | ## Publish 265 | 266 | ``` 267 | npm run build:publish 268 | ``` 269 | 270 | ## Issue 271 | 272 | https://github.com/reactjs-ui/react-alloytouch/issues 273 | 274 | ## Change Log 275 | 276 | Please view [here](./CHANGELOG.md) 277 | -------------------------------------------------------------------------------- /examples-dist/carousel.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 轮播 5 | 6 | 8 | 9 | 24 | 25 | 26 |
    27 | 28 | 29 | -------------------------------------------------------------------------------- /examples-dist/css/carousel.d7c89e08b5abfb774f54.css: -------------------------------------------------------------------------------- 1 | body{margin:0}a{color:#00c176}a:active,a:focus,a:hover{color:#88c100}.example{margin:50px auto;width:80%}.example-list>li{padding:10px}.footer,.header{padding:5px;background-color:#00c176;color:#fff;text-align:center}.pull-carousel .pull-refresh{top:-50px;padding-bottom:10px}.carousel-scroller .swiper-panel{text-align:center;height:200px;font-size:28px;background:#f0f0f0}.carousel-wrapper{margin:0 auto;overflow:hidden;position:relative}.carousel-scroller{position:relative;font-size:0;user-select:none;text-size-adjust:none;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none}.carousel-scroller .swiper-panel{float:left}.carousel-tabs-menu{display:flex}.carousel-tabs-menu .carousel-tabs-item{flex:1;text-align:center;line-height:2.2;bordr-bottom:2px solid transparent}.carousel-tabs-menu .active{color:#cf121b;border-bottom:2px solid #cf121b}.carousel-nav{position:absolute;bottom:6px;right:10px}.carousel-nav>a{display:inline-block;background-color:#fff;cursor:pointer;width:6px;height:6px;border-radius:5px;border:1px solid gray;transition:all .5s ease-in}.carousel-nav>a.active{background-color:#ffd800;width:10px} 2 | /*# sourceMappingURL=carousel.d7c89e08b5abfb774f54.css.map*/ -------------------------------------------------------------------------------- /examples-dist/css/carousel.d7c89e08b5abfb774f54.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":[],"names":[],"mappings":"","file":"css/carousel.d7c89e08b5abfb774f54.css","sourceRoot":""} -------------------------------------------------------------------------------- /examples-dist/css/header-footer.aa697a21f7857d4c1560.css: -------------------------------------------------------------------------------- 1 | body{margin:0}a{color:#00c176}a:active,a:focus,a:hover{color:#88c100}.example{margin:50px auto;width:80%}.example-list>li{padding:10px}.footer,.header{padding:5px;background-color:#00c176;color:#fff;text-align:center}.pull-carousel .pull-refresh{top:-50px;padding-bottom:10px}.carousel-scroller .swiper-panel{text-align:center;height:200px;font-size:28px;background:#f0f0f0}.pull-header{top:0}.pull-footer,.pull-header{position:absolute;z-index:2;left:0;right:0}.pull-footer{bottom:0}.pull-body,.pull-wrapper{position:absolute;top:0;bottom:0;left:0;right:0}.pull-wrapper{z-index:1;overflow:hidden}.pull-scroller{z-index:1;user-select:none;text-size-adjust:none;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none}.pull-refresh,.pull-scroller{position:absolute;left:0;right:0}.pull-refresh{top:-40px;display:block;overflow:hidden}.pull-refresh-icon-wrapper{position:relative;width:40px;margin:auto;text-align:center;height:25px}.pull-refresh-icon{position:absolute;top:0;left:12px;width:14px;height:25px;background-size:contain;background-position:50%;background-repeat:no-repeat;background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIj48cGF0aCBkPSJNOS44NTQgMTkuMzU0bDYtNmEuNS41IDAgMCAwLS43MDctLjcwN0wxMCAxNy43OTNWMS41YS41LjUgMCAwIDAtMSAwdjE2LjI5M2wtNS4xNDUtNS4xNDZhLjUuNSAwIDAgMC0uNzA3LjcwOGw2IDZhLjUuNSAwIDAgMCAuNzA3IDB6Ii8+PC9zdmc+)}.pull-refresh-icon.rotate{transform:translateZ(0) rotate(180deg)}.pull-refresh-icon.loading{animation:pull-loading .8s infinite linear;background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzIiIGhlaWdodD0iOTMyIiB2aWV3Qm94PSIwIDAgOTMyIDkzMiI+PHBhdGggZD0iTTQ2NiA5MzJjLTEyNC40NzMgMC0yNDEuNDk1LTQ4LjQ3My0zMjkuNTEzLTEzNi40ODdDNDguNDczIDcwNy40OTUgMCA1OTAuNDczIDAgNDY2YzAtODguMTM4IDI0Ljc0LTE3My45NjIgNzEuNTQ0LTI0OC4xOTIgNDUuNTA4LTcyLjE3MiAxMDkuODIzLTEzMC40OSAxODUuOTk2LTE2OC42NTJsMzkuMTM3IDc4LjEyQzIzNC43NTIgMTU4LjMgMTgyLjQ2IDIwNS43MiAxNDUuNDU1IDI2NC40MSAxMDcuNDYgMzI0LjY3IDg3LjM3NSAzOTQuMzc4IDg3LjM3NSA0NjZjMCAyMDguNzc0IDE2OS44NTMgMzc4LjYyNiAzNzguNjI2IDM3OC42MjZTODQ0LjYyNyA2NzQuNzc0IDg0NC42MjcgNDY2YzAtNzEuNjItMjAuMDg0LTE0MS4zMy01OC4wNzctMjAxLjU5LTM3LjAwOC01OC42OS04OS4zLTEwNi4xMS0xNTEuMjIzLTEzNy4xMzNsMzkuMTM3LTc4LjEyYzc2LjE3MyAzOC4xNiAxNDAuNDkgOTYuNDggMTg1Ljk5NiAxNjguNjVDOTA3LjI2MiAyOTIuMDQgOTMyLjAwMiAzNzcuODY0IDkzMi4wMDIgNDY2YzAgMTI0LjQ3My00OC40NzMgMjQxLjQ5NS0xMzYuNDg3IDMyOS41MTNDNzA3LjQ5NyA4ODMuNTI3IDU5MC40NzUgOTMyIDQ2Ni4wMDIgOTMyeiIvPjwvc3ZnPg==)}@keyframes pull-loading{0%{transform:translateZ(0) rotate(0deg)}to{transform:translateZ(0) rotate(1turn)}}.pull-refresh-text{color:#666;font-size:12px;text-align:center}.pull-load-more{position:absolute;bottom:5px;left:0;right:0;visibility:hidden}.pull-load-more-icon{height:20px;width:20px;margin:0 auto;color:#666;background-size:contain;background:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIj48cGF0aCBkPSJNOS44NTQgMTkuMzU0bDYtNmEuNS41IDAgMCAwLS43MDctLjcwN0wxMCAxNy43OTNWMS41YS41LjUgMCAwIDAtMSAwdjE2LjI5M2wtNS4xNDUtNS4xNDZhLjUuNSAwIDAgMC0uNzA3LjcwOGw2IDZhLjUuNSAwIDAgMCAuNzA3IDB6Ii8+PC9zdmc+) 50% no-repeat;transform:rotate(180deg)}.pull-load-more-icon.hide{display:none}.pull-load-more-icon.rotate{transform:rotate(0deg)}.pull-load-more-icon.loading{display:block;background:transparent url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 120 120' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Cdefs%3E%3Cpath id='a' stroke='%236c6c6c' stroke-width='11' stroke-linecap='round' d='M60 7v20'/%3E%3C/defs%3E%3Cuse xlink:href='%23a' opacity='.27'/%3E%3Cuse xlink:href='%23a' opacity='.27' transform='rotate(30 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.27' transform='rotate(60 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.27' transform='rotate(90 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.27' transform='rotate(120 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.27' transform='rotate(150 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.37' transform='rotate(180 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.46' transform='rotate(210 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.56' transform='rotate(240 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.66' transform='rotate(270 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.75' transform='rotate(300 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.85' transform='rotate(330 60 60)'/%3E%3C/svg%3E") 50% no-repeat;background-size:20px 20px;animation:pull-load-more 1s step-end infinite}.pull-load-more-text{font-size:12px;margin-top:5px;color:#666;text-align:center}@keyframes pull-load-more{0%{transform:rotate(0deg)}8.33333333%{transform:rotate(30deg)}16.66666667%{transform:rotate(60deg)}25%{transform:rotate(90deg)}33.33333333%{transform:rotate(120deg)}41.66666667%{transform:rotate(150deg)}50%{transform:rotate(180deg)}58.33333333%{transform:rotate(210deg)}66.66666667%{transform:rotate(240deg)}75%{transform:rotate(270deg)}83.33333333%{transform:rotate(300deg)}91.66666667%{transform:rotate(330deg)}to{transform:rotate(1turn)}} 2 | /*# sourceMappingURL=header-footer.aa697a21f7857d4c1560.css.map*/ -------------------------------------------------------------------------------- /examples-dist/css/header-footer.aa697a21f7857d4c1560.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":[],"names":[],"mappings":"","file":"css/header-footer.aa697a21f7857d4c1560.css","sourceRoot":""} -------------------------------------------------------------------------------- /examples-dist/css/index.36fbdaffa0fdd50aa664.css: -------------------------------------------------------------------------------- 1 | body{margin:0}a{color:#00c176}a:active,a:focus,a:hover{color:#88c100}.example{margin:50px auto;width:80%}.example-list>li{padding:10px}.footer,.header{padding:5px;background-color:#00c176;color:#fff;text-align:center}.pull-carousel .pull-refresh{top:-50px;padding-bottom:10px}.carousel-scroller .swiper-panel{text-align:center;height:200px;font-size:28px;background:#f0f0f0} 2 | /*# sourceMappingURL=index.36fbdaffa0fdd50aa664.css.map*/ -------------------------------------------------------------------------------- /examples-dist/css/index.36fbdaffa0fdd50aa664.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":[],"names":[],"mappings":"","file":"css/index.36fbdaffa0fdd50aa664.css","sourceRoot":""} -------------------------------------------------------------------------------- /examples-dist/css/pull-carousel.168d7ef0a8deaade6c73.css: -------------------------------------------------------------------------------- 1 | body{margin:0}a{color:#00c176}a:active,a:focus,a:hover{color:#88c100}.example{margin:50px auto;width:80%}.example-list>li{padding:10px}.footer,.header{padding:5px;background-color:#00c176;color:#fff;text-align:center}.pull-carousel .pull-refresh{top:-50px;padding-bottom:10px}.carousel-scroller .swiper-panel{text-align:center;height:200px;font-size:28px;background:#f0f0f0}.pull-header{top:0}.pull-footer,.pull-header{position:absolute;z-index:2;left:0;right:0}.pull-footer{bottom:0}.pull-body,.pull-wrapper{position:absolute;top:0;bottom:0;left:0;right:0}.pull-wrapper{z-index:1;overflow:hidden}.pull-scroller{z-index:1;user-select:none;text-size-adjust:none;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none}.pull-refresh,.pull-scroller{position:absolute;left:0;right:0}.pull-refresh{top:-40px;display:block;overflow:hidden}.pull-refresh-icon-wrapper{position:relative;width:40px;margin:auto;text-align:center;height:25px}.pull-refresh-icon{position:absolute;top:0;left:12px;width:14px;height:25px;background-size:contain;background-position:50%;background-repeat:no-repeat;background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIj48cGF0aCBkPSJNOS44NTQgMTkuMzU0bDYtNmEuNS41IDAgMCAwLS43MDctLjcwN0wxMCAxNy43OTNWMS41YS41LjUgMCAwIDAtMSAwdjE2LjI5M2wtNS4xNDUtNS4xNDZhLjUuNSAwIDAgMC0uNzA3LjcwOGw2IDZhLjUuNSAwIDAgMCAuNzA3IDB6Ii8+PC9zdmc+)}.pull-refresh-icon.rotate{transform:translateZ(0) rotate(180deg)}.pull-refresh-icon.loading{animation:pull-loading .8s infinite linear;background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzIiIGhlaWdodD0iOTMyIiB2aWV3Qm94PSIwIDAgOTMyIDkzMiI+PHBhdGggZD0iTTQ2NiA5MzJjLTEyNC40NzMgMC0yNDEuNDk1LTQ4LjQ3My0zMjkuNTEzLTEzNi40ODdDNDguNDczIDcwNy40OTUgMCA1OTAuNDczIDAgNDY2YzAtODguMTM4IDI0Ljc0LTE3My45NjIgNzEuNTQ0LTI0OC4xOTIgNDUuNTA4LTcyLjE3MiAxMDkuODIzLTEzMC40OSAxODUuOTk2LTE2OC42NTJsMzkuMTM3IDc4LjEyQzIzNC43NTIgMTU4LjMgMTgyLjQ2IDIwNS43MiAxNDUuNDU1IDI2NC40MSAxMDcuNDYgMzI0LjY3IDg3LjM3NSAzOTQuMzc4IDg3LjM3NSA0NjZjMCAyMDguNzc0IDE2OS44NTMgMzc4LjYyNiAzNzguNjI2IDM3OC42MjZTODQ0LjYyNyA2NzQuNzc0IDg0NC42MjcgNDY2YzAtNzEuNjItMjAuMDg0LTE0MS4zMy01OC4wNzctMjAxLjU5LTM3LjAwOC01OC42OS04OS4zLTEwNi4xMS0xNTEuMjIzLTEzNy4xMzNsMzkuMTM3LTc4LjEyYzc2LjE3MyAzOC4xNiAxNDAuNDkgOTYuNDggMTg1Ljk5NiAxNjguNjVDOTA3LjI2MiAyOTIuMDQgOTMyLjAwMiAzNzcuODY0IDkzMi4wMDIgNDY2YzAgMTI0LjQ3My00OC40NzMgMjQxLjQ5NS0xMzYuNDg3IDMyOS41MTNDNzA3LjQ5NyA4ODMuNTI3IDU5MC40NzUgOTMyIDQ2Ni4wMDIgOTMyeiIvPjwvc3ZnPg==)}@keyframes pull-loading{0%{transform:translateZ(0) rotate(0deg)}to{transform:translateZ(0) rotate(1turn)}}.pull-refresh-text{color:#666;font-size:12px;text-align:center}.pull-load-more{position:absolute;bottom:5px;left:0;right:0;visibility:hidden}.pull-load-more-icon{height:20px;width:20px;margin:0 auto;color:#666;background-size:contain;background:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIj48cGF0aCBkPSJNOS44NTQgMTkuMzU0bDYtNmEuNS41IDAgMCAwLS43MDctLjcwN0wxMCAxNy43OTNWMS41YS41LjUgMCAwIDAtMSAwdjE2LjI5M2wtNS4xNDUtNS4xNDZhLjUuNSAwIDAgMC0uNzA3LjcwOGw2IDZhLjUuNSAwIDAgMCAuNzA3IDB6Ii8+PC9zdmc+) 50% no-repeat;transform:rotate(180deg)}.pull-load-more-icon.hide{display:none}.pull-load-more-icon.rotate{transform:rotate(0deg)}.pull-load-more-icon.loading{display:block;background:transparent url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 120 120' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Cdefs%3E%3Cpath id='a' stroke='%236c6c6c' stroke-width='11' stroke-linecap='round' d='M60 7v20'/%3E%3C/defs%3E%3Cuse xlink:href='%23a' opacity='.27'/%3E%3Cuse xlink:href='%23a' opacity='.27' transform='rotate(30 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.27' transform='rotate(60 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.27' transform='rotate(90 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.27' transform='rotate(120 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.27' transform='rotate(150 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.37' transform='rotate(180 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.46' transform='rotate(210 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.56' transform='rotate(240 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.66' transform='rotate(270 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.75' transform='rotate(300 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.85' transform='rotate(330 60 60)'/%3E%3C/svg%3E") 50% no-repeat;background-size:20px 20px;animation:pull-load-more 1s step-end infinite}.pull-load-more-text{font-size:12px;margin-top:5px;color:#666;text-align:center}@keyframes pull-load-more{0%{transform:rotate(0deg)}8.33333333%{transform:rotate(30deg)}16.66666667%{transform:rotate(60deg)}25%{transform:rotate(90deg)}33.33333333%{transform:rotate(120deg)}41.66666667%{transform:rotate(150deg)}50%{transform:rotate(180deg)}58.33333333%{transform:rotate(210deg)}66.66666667%{transform:rotate(240deg)}75%{transform:rotate(270deg)}83.33333333%{transform:rotate(300deg)}91.66666667%{transform:rotate(330deg)}to{transform:rotate(1turn)}}.carousel-wrapper{margin:0 auto;overflow:hidden;position:relative}.carousel-scroller{position:relative;font-size:0;user-select:none;text-size-adjust:none;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none}.carousel-scroller .swiper-panel{float:left}.carousel-tabs-menu{display:flex}.carousel-tabs-menu .carousel-tabs-item{flex:1;text-align:center;line-height:2.2;bordr-bottom:2px solid transparent}.carousel-tabs-menu .active{color:#cf121b;border-bottom:2px solid #cf121b}.carousel-nav{position:absolute;bottom:6px;right:10px}.carousel-nav>a{display:inline-block;background-color:#fff;cursor:pointer;width:6px;height:6px;border-radius:5px;border:1px solid gray;transition:all .5s ease-in}.carousel-nav>a.active{background-color:#ffd800;width:10px} 2 | /*# sourceMappingURL=pull-carousel.168d7ef0a8deaade6c73.css.map*/ -------------------------------------------------------------------------------- /examples-dist/css/pull-carousel.168d7ef0a8deaade6c73.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":[],"names":[],"mappings":"","file":"css/pull-carousel.168d7ef0a8deaade6c73.css","sourceRoot":""} -------------------------------------------------------------------------------- /examples-dist/css/pull-carousel2.d50988f2dea6085f1002.css: -------------------------------------------------------------------------------- 1 | body{margin:0}a{color:#00c176}a:active,a:focus,a:hover{color:#88c100}.example{margin:50px auto;width:80%}.example-list>li{padding:10px}.footer,.header{padding:5px;background-color:#00c176;color:#fff;text-align:center}.pull-carousel .pull-refresh{top:-50px;padding-bottom:10px}.carousel-scroller .swiper-panel{text-align:center;height:200px;font-size:28px;background:#f0f0f0}.pull-header{top:0}.pull-footer,.pull-header{position:absolute;z-index:2;left:0;right:0}.pull-footer{bottom:0}.pull-body,.pull-wrapper{position:absolute;top:0;bottom:0;left:0;right:0}.pull-wrapper{z-index:1;overflow:hidden}.pull-scroller{z-index:1;user-select:none;text-size-adjust:none;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none}.pull-refresh,.pull-scroller{position:absolute;left:0;right:0}.pull-refresh{top:-40px;display:block;overflow:hidden}.pull-refresh-icon-wrapper{position:relative;width:40px;margin:auto;text-align:center;height:25px}.pull-refresh-icon{position:absolute;top:0;left:12px;width:14px;height:25px;background-size:contain;background-position:50%;background-repeat:no-repeat;background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIj48cGF0aCBkPSJNOS44NTQgMTkuMzU0bDYtNmEuNS41IDAgMCAwLS43MDctLjcwN0wxMCAxNy43OTNWMS41YS41LjUgMCAwIDAtMSAwdjE2LjI5M2wtNS4xNDUtNS4xNDZhLjUuNSAwIDAgMC0uNzA3LjcwOGw2IDZhLjUuNSAwIDAgMCAuNzA3IDB6Ii8+PC9zdmc+)}.pull-refresh-icon.rotate{transform:translateZ(0) rotate(180deg)}.pull-refresh-icon.loading{animation:pull-loading .8s infinite linear;background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzIiIGhlaWdodD0iOTMyIiB2aWV3Qm94PSIwIDAgOTMyIDkzMiI+PHBhdGggZD0iTTQ2NiA5MzJjLTEyNC40NzMgMC0yNDEuNDk1LTQ4LjQ3My0zMjkuNTEzLTEzNi40ODdDNDguNDczIDcwNy40OTUgMCA1OTAuNDczIDAgNDY2YzAtODguMTM4IDI0Ljc0LTE3My45NjIgNzEuNTQ0LTI0OC4xOTIgNDUuNTA4LTcyLjE3MiAxMDkuODIzLTEzMC40OSAxODUuOTk2LTE2OC42NTJsMzkuMTM3IDc4LjEyQzIzNC43NTIgMTU4LjMgMTgyLjQ2IDIwNS43MiAxNDUuNDU1IDI2NC40MSAxMDcuNDYgMzI0LjY3IDg3LjM3NSAzOTQuMzc4IDg3LjM3NSA0NjZjMCAyMDguNzc0IDE2OS44NTMgMzc4LjYyNiAzNzguNjI2IDM3OC42MjZTODQ0LjYyNyA2NzQuNzc0IDg0NC42MjcgNDY2YzAtNzEuNjItMjAuMDg0LTE0MS4zMy01OC4wNzctMjAxLjU5LTM3LjAwOC01OC42OS04OS4zLTEwNi4xMS0xNTEuMjIzLTEzNy4xMzNsMzkuMTM3LTc4LjEyYzc2LjE3MyAzOC4xNiAxNDAuNDkgOTYuNDggMTg1Ljk5NiAxNjguNjVDOTA3LjI2MiAyOTIuMDQgOTMyLjAwMiAzNzcuODY0IDkzMi4wMDIgNDY2YzAgMTI0LjQ3My00OC40NzMgMjQxLjQ5NS0xMzYuNDg3IDMyOS41MTNDNzA3LjQ5NyA4ODMuNTI3IDU5MC40NzUgOTMyIDQ2Ni4wMDIgOTMyeiIvPjwvc3ZnPg==)}@keyframes pull-loading{0%{transform:translateZ(0) rotate(0deg)}to{transform:translateZ(0) rotate(1turn)}}.pull-refresh-text{color:#666;font-size:12px;text-align:center}.pull-load-more{position:absolute;bottom:5px;left:0;right:0;visibility:hidden}.pull-load-more-icon{height:20px;width:20px;margin:0 auto;color:#666;background-size:contain;background:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIj48cGF0aCBkPSJNOS44NTQgMTkuMzU0bDYtNmEuNS41IDAgMCAwLS43MDctLjcwN0wxMCAxNy43OTNWMS41YS41LjUgMCAwIDAtMSAwdjE2LjI5M2wtNS4xNDUtNS4xNDZhLjUuNSAwIDAgMC0uNzA3LjcwOGw2IDZhLjUuNSAwIDAgMCAuNzA3IDB6Ii8+PC9zdmc+) 50% no-repeat;transform:rotate(180deg)}.pull-load-more-icon.hide{display:none}.pull-load-more-icon.rotate{transform:rotate(0deg)}.pull-load-more-icon.loading{display:block;background:transparent url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 120 120' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Cdefs%3E%3Cpath id='a' stroke='%236c6c6c' stroke-width='11' stroke-linecap='round' d='M60 7v20'/%3E%3C/defs%3E%3Cuse xlink:href='%23a' opacity='.27'/%3E%3Cuse xlink:href='%23a' opacity='.27' transform='rotate(30 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.27' transform='rotate(60 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.27' transform='rotate(90 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.27' transform='rotate(120 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.27' transform='rotate(150 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.37' transform='rotate(180 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.46' transform='rotate(210 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.56' transform='rotate(240 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.66' transform='rotate(270 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.75' transform='rotate(300 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.85' transform='rotate(330 60 60)'/%3E%3C/svg%3E") 50% no-repeat;background-size:20px 20px;animation:pull-load-more 1s step-end infinite}.pull-load-more-text{font-size:12px;margin-top:5px;color:#666;text-align:center}@keyframes pull-load-more{0%{transform:rotate(0deg)}8.33333333%{transform:rotate(30deg)}16.66666667%{transform:rotate(60deg)}25%{transform:rotate(90deg)}33.33333333%{transform:rotate(120deg)}41.66666667%{transform:rotate(150deg)}50%{transform:rotate(180deg)}58.33333333%{transform:rotate(210deg)}66.66666667%{transform:rotate(240deg)}75%{transform:rotate(270deg)}83.33333333%{transform:rotate(300deg)}91.66666667%{transform:rotate(330deg)}to{transform:rotate(1turn)}}.carousel-wrapper{margin:0 auto;overflow:hidden;position:relative}.carousel-scroller{position:relative;font-size:0;user-select:none;text-size-adjust:none;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none}.carousel-scroller .swiper-panel{float:left}.carousel-tabs-menu{display:flex}.carousel-tabs-menu .carousel-tabs-item{flex:1;text-align:center;line-height:2.2;bordr-bottom:2px solid transparent}.carousel-tabs-menu .active{color:#cf121b;border-bottom:2px solid #cf121b}.carousel-nav{position:absolute;bottom:6px;right:10px}.carousel-nav>a{display:inline-block;background-color:#fff;cursor:pointer;width:6px;height:6px;border-radius:5px;border:1px solid gray;transition:all .5s ease-in}.carousel-nav>a.active{background-color:#ffd800;width:10px} 2 | /*# sourceMappingURL=pull-carousel2.d50988f2dea6085f1002.css.map*/ -------------------------------------------------------------------------------- /examples-dist/css/pull-carousel2.d50988f2dea6085f1002.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":[],"names":[],"mappings":"","file":"css/pull-carousel2.d50988f2dea6085f1002.css","sourceRoot":""} -------------------------------------------------------------------------------- /examples-dist/css/pull.1cdce4fcd519ccb16612.css: -------------------------------------------------------------------------------- 1 | body{margin:0}a{color:#00c176}a:active,a:focus,a:hover{color:#88c100}.example{margin:50px auto;width:80%}.example-list>li{padding:10px}.footer,.header{padding:5px;background-color:#00c176;color:#fff;text-align:center}.pull-carousel .pull-refresh{top:-50px;padding-bottom:10px}.carousel-scroller .swiper-panel{text-align:center;height:200px;font-size:28px;background:#f0f0f0}.pull-header{top:0}.pull-footer,.pull-header{position:absolute;z-index:2;left:0;right:0}.pull-footer{bottom:0}.pull-body,.pull-wrapper{position:absolute;top:0;bottom:0;left:0;right:0}.pull-wrapper{z-index:1;overflow:hidden}.pull-scroller{z-index:1;user-select:none;text-size-adjust:none;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none}.pull-refresh,.pull-scroller{position:absolute;left:0;right:0}.pull-refresh{top:-40px;display:block;overflow:hidden}.pull-refresh-icon-wrapper{position:relative;width:40px;margin:auto;text-align:center;height:25px}.pull-refresh-icon{position:absolute;top:0;left:12px;width:14px;height:25px;background-size:contain;background-position:50%;background-repeat:no-repeat;background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIj48cGF0aCBkPSJNOS44NTQgMTkuMzU0bDYtNmEuNS41IDAgMCAwLS43MDctLjcwN0wxMCAxNy43OTNWMS41YS41LjUgMCAwIDAtMSAwdjE2LjI5M2wtNS4xNDUtNS4xNDZhLjUuNSAwIDAgMC0uNzA3LjcwOGw2IDZhLjUuNSAwIDAgMCAuNzA3IDB6Ii8+PC9zdmc+)}.pull-refresh-icon.rotate{transform:translateZ(0) rotate(180deg)}.pull-refresh-icon.loading{animation:pull-loading .8s infinite linear;background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzIiIGhlaWdodD0iOTMyIiB2aWV3Qm94PSIwIDAgOTMyIDkzMiI+PHBhdGggZD0iTTQ2NiA5MzJjLTEyNC40NzMgMC0yNDEuNDk1LTQ4LjQ3My0zMjkuNTEzLTEzNi40ODdDNDguNDczIDcwNy40OTUgMCA1OTAuNDczIDAgNDY2YzAtODguMTM4IDI0Ljc0LTE3My45NjIgNzEuNTQ0LTI0OC4xOTIgNDUuNTA4LTcyLjE3MiAxMDkuODIzLTEzMC40OSAxODUuOTk2LTE2OC42NTJsMzkuMTM3IDc4LjEyQzIzNC43NTIgMTU4LjMgMTgyLjQ2IDIwNS43MiAxNDUuNDU1IDI2NC40MSAxMDcuNDYgMzI0LjY3IDg3LjM3NSAzOTQuMzc4IDg3LjM3NSA0NjZjMCAyMDguNzc0IDE2OS44NTMgMzc4LjYyNiAzNzguNjI2IDM3OC42MjZTODQ0LjYyNyA2NzQuNzc0IDg0NC42MjcgNDY2YzAtNzEuNjItMjAuMDg0LTE0MS4zMy01OC4wNzctMjAxLjU5LTM3LjAwOC01OC42OS04OS4zLTEwNi4xMS0xNTEuMjIzLTEzNy4xMzNsMzkuMTM3LTc4LjEyYzc2LjE3MyAzOC4xNiAxNDAuNDkgOTYuNDggMTg1Ljk5NiAxNjguNjVDOTA3LjI2MiAyOTIuMDQgOTMyLjAwMiAzNzcuODY0IDkzMi4wMDIgNDY2YzAgMTI0LjQ3My00OC40NzMgMjQxLjQ5NS0xMzYuNDg3IDMyOS41MTNDNzA3LjQ5NyA4ODMuNTI3IDU5MC40NzUgOTMyIDQ2Ni4wMDIgOTMyeiIvPjwvc3ZnPg==)}@keyframes pull-loading{0%{transform:translateZ(0) rotate(0deg)}to{transform:translateZ(0) rotate(1turn)}}.pull-refresh-text{color:#666;font-size:12px;text-align:center}.pull-load-more{position:absolute;bottom:5px;left:0;right:0;visibility:hidden}.pull-load-more-icon{height:20px;width:20px;margin:0 auto;color:#666;background-size:contain;background:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIj48cGF0aCBkPSJNOS44NTQgMTkuMzU0bDYtNmEuNS41IDAgMCAwLS43MDctLjcwN0wxMCAxNy43OTNWMS41YS41LjUgMCAwIDAtMSAwdjE2LjI5M2wtNS4xNDUtNS4xNDZhLjUuNSAwIDAgMC0uNzA3LjcwOGw2IDZhLjUuNSAwIDAgMCAuNzA3IDB6Ii8+PC9zdmc+) 50% no-repeat;transform:rotate(180deg)}.pull-load-more-icon.hide{display:none}.pull-load-more-icon.rotate{transform:rotate(0deg)}.pull-load-more-icon.loading{display:block;background:transparent url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 120 120' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Cdefs%3E%3Cpath id='a' stroke='%236c6c6c' stroke-width='11' stroke-linecap='round' d='M60 7v20'/%3E%3C/defs%3E%3Cuse xlink:href='%23a' opacity='.27'/%3E%3Cuse xlink:href='%23a' opacity='.27' transform='rotate(30 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.27' transform='rotate(60 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.27' transform='rotate(90 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.27' transform='rotate(120 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.27' transform='rotate(150 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.37' transform='rotate(180 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.46' transform='rotate(210 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.56' transform='rotate(240 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.66' transform='rotate(270 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.75' transform='rotate(300 60 60)'/%3E%3Cuse xlink:href='%23a' opacity='.85' transform='rotate(330 60 60)'/%3E%3C/svg%3E") 50% no-repeat;background-size:20px 20px;animation:pull-load-more 1s step-end infinite}.pull-load-more-text{font-size:12px;margin-top:5px;color:#666;text-align:center}@keyframes pull-load-more{0%{transform:rotate(0deg)}8.33333333%{transform:rotate(30deg)}16.66666667%{transform:rotate(60deg)}25%{transform:rotate(90deg)}33.33333333%{transform:rotate(120deg)}41.66666667%{transform:rotate(150deg)}50%{transform:rotate(180deg)}58.33333333%{transform:rotate(210deg)}66.66666667%{transform:rotate(240deg)}75%{transform:rotate(270deg)}83.33333333%{transform:rotate(300deg)}91.66666667%{transform:rotate(330deg)}to{transform:rotate(1turn)}} 2 | /*# sourceMappingURL=pull.1cdce4fcd519ccb16612.css.map*/ -------------------------------------------------------------------------------- /examples-dist/css/pull.1cdce4fcd519ccb16612.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":[],"names":[],"mappings":"","file":"css/pull.1cdce4fcd519ccb16612.css","sourceRoot":""} -------------------------------------------------------------------------------- /examples-dist/css/simple.cd5bd1d575b7cc335111.css: -------------------------------------------------------------------------------- 1 | body{margin:0}a{color:#00c176}a:active,a:focus,a:hover{color:#88c100}.example{margin:50px auto;width:80%}.example-list>li{padding:10px}.footer,.header{padding:5px;background-color:#00c176;color:#fff;text-align:center}.pull-carousel .pull-refresh{top:-50px;padding-bottom:10px}.carousel-scroller .swiper-panel{text-align:center;height:200px;font-size:28px;background:#f0f0f0}.alloy-wrapper{top:0;bottom:0;overflow:hidden}.alloy-scroller,.alloy-wrapper{position:absolute;z-index:1;left:0;right:0}.alloy-scroller{user-select:none;text-size-adjust:none;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none} 2 | /*# sourceMappingURL=simple.cd5bd1d575b7cc335111.css.map*/ -------------------------------------------------------------------------------- /examples-dist/css/simple.cd5bd1d575b7cc335111.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":[],"names":[],"mappings":"","file":"css/simple.cd5bd1d575b7cc335111.css","sourceRoot":""} -------------------------------------------------------------------------------- /examples-dist/css/tabs-carousel.65b224ba332c3c8c1bb4.css: -------------------------------------------------------------------------------- 1 | body{margin:0}a{color:#00c176}a:active,a:focus,a:hover{color:#88c100}.example{margin:50px auto;width:80%}.example-list>li{padding:10px}.footer,.header{padding:5px;background-color:#00c176;color:#fff;text-align:center}.pull-carousel .pull-refresh{top:-50px;padding-bottom:10px}.carousel-scroller .swiper-panel{text-align:center;height:200px;font-size:28px;background:#f0f0f0}.carousel-wrapper{margin:0 auto;overflow:hidden;position:relative}.carousel-scroller{position:relative;font-size:0;user-select:none;text-size-adjust:none;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none}.carousel-scroller .swiper-panel{float:left}.carousel-tabs-menu{display:flex}.carousel-tabs-menu .carousel-tabs-item{flex:1;text-align:center;line-height:2.2;bordr-bottom:2px solid transparent}.carousel-tabs-menu .active{color:#cf121b;border-bottom:2px solid #cf121b}.carousel-nav{position:absolute;bottom:6px;right:10px}.carousel-nav>a{display:inline-block;background-color:#fff;cursor:pointer;width:6px;height:6px;border-radius:5px;border:1px solid gray;transition:all .5s ease-in}.carousel-nav>a.active{background-color:#ffd800;width:10px} 2 | /*# sourceMappingURL=tabs-carousel.65b224ba332c3c8c1bb4.css.map*/ -------------------------------------------------------------------------------- /examples-dist/css/tabs-carousel.65b224ba332c3c8c1bb4.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":[],"names":[],"mappings":"","file":"css/tabs-carousel.65b224ba332c3c8c1bb4.css","sourceRoot":""} -------------------------------------------------------------------------------- /examples-dist/header-footer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 带头部和底部的下拉刷新,上拉加载更多 5 | 6 | 8 | 9 | 24 | 25 | 26 |
    27 | 28 | 29 | -------------------------------------------------------------------------------- /examples-dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React AlloyTouch 例子 5 | 6 | 8 | 9 | 24 | 25 | 26 |
    27 | 28 | 29 | -------------------------------------------------------------------------------- /examples-dist/pull-carousel.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 下拉刷新中包含轮播图 5 | 6 | 8 | 9 | 24 | 25 | 26 |
    27 | 28 | 29 | -------------------------------------------------------------------------------- /examples-dist/pull-carousel2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 下拉刷新中包含轮播图2 5 | 6 | 8 | 9 | 24 | 25 | 26 |
    27 | 28 | 29 | -------------------------------------------------------------------------------- /examples-dist/pull.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 下拉刷新,上拉加载更多 5 | 6 | 8 | 9 | 24 | 25 | 26 |
    27 | 28 | 29 | -------------------------------------------------------------------------------- /examples-dist/simple.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React AlloyTouch 简单例子 5 | 6 | 8 | 9 | 24 | 25 | 26 |
    27 | 28 | 29 | -------------------------------------------------------------------------------- /examples-dist/tabs-carousel.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 自定义轮播内容+tabs 5 | 6 | 8 | 9 | 24 | 25 | 26 |
    27 | 28 | 29 | -------------------------------------------------------------------------------- /examples/carousel.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import {render} from 'react-dom'; 3 | import injectTapEventPlugin from 'react-tap-event-plugin'; 4 | import ReactCarousel from '../js/ReactCarousel'; 5 | import '../sass/carousel.scss'; 6 | import './sass/example.scss'; 7 | 8 | // 初始化 tapEvent 事件, 移动端 9 | injectTapEventPlugin(); 10 | 11 | const ReactCarouselExample = () => { 12 | 13 | const items = [{ 14 | image: 'http://alloyteam.github.io/AlloyTouch/example/asset/ci1.jpg', 15 | link: 'http://jd.com' 16 | }, { 17 | image: 'http://alloyteam.github.io/AlloyTouch/example/asset/ci2.jpg', 18 | }, { 19 | image: 'http://alloyteam.github.io/AlloyTouch/example/asset/ci3.jpg', 20 | link: 'http://jd.com' 21 | }, { 22 | image: 'http://alloyteam.github.io/AlloyTouch/example/asset/ci4.jpg' 23 | }]; 24 | 25 | const events = { 26 | onTouchTap: () => { 27 | console.info('这是个测试!'); 28 | } 29 | }; 30 | 31 | return ( 32 | 33 | ); 34 | }; 35 | 36 | render( 37 | , document.getElementById('layout') 38 | ); 39 | -------------------------------------------------------------------------------- /examples/header-footer.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import {render} from 'react-dom'; 3 | import injectTapEventPlugin from 'react-tap-event-plugin'; 4 | import ReactPull from '../js/ReactPull'; 5 | import '../sass/pull.scss'; 6 | import './sass/example.scss'; 7 | 8 | // 初始化 tapEvent 事件, 移动端 9 | injectTapEventPlugin(); 10 | 11 | class HeaderFooter extends Component { 12 | constructor(props) { 13 | super(props); 14 | this.state = { 15 | items: 2, 16 | disablePullUp: false 17 | }; 18 | } 19 | 20 | refreshCallback = () => { 21 | return new Promise((resolve, reject) => { 22 | setTimeout(() => { 23 | let result = false; 24 | if (Math.random() > 0.2) { 25 | result = true; 26 | } 27 | if (result) { 28 | this.setState({ 29 | items: 30, 30 | disablePullUp: false 31 | }, () => { 32 | resolve(); 33 | }); 34 | } else { 35 | reject(new Error('错误')); 36 | } 37 | }, 1000); 38 | }).then(() => { 39 | console.info('刷新成功!'); 40 | }, (error) => { 41 | console.info('刷新失败!'); 42 | Promise.error(error); 43 | }); 44 | }; 45 | 46 | loadMoreCallback = () => { 47 | return new Promise((resolve, reject) => { 48 | setTimeout(() => { 49 | let result = false; 50 | if (Math.random() > 0.2) { 51 | result = true; 52 | } 53 | if (result) { 54 | this.setState({ 55 | items: this.state.items + 10, 56 | disablePullUp: this.state.items >= 60 57 | }, () => { 58 | resolve(); 59 | }); 60 | } else { 61 | reject(new Error('错误')); 62 | } 63 | }, 1000); 64 | }).then(() => { 65 | console.info('加载更多成功!'); 66 | }, (error) => { 67 | console.info('加载更多失败!'); 68 | Promise.error(error); 69 | }); 70 | }; 71 | 72 | handleTouchTap = (e) => { 73 | console.info('测试下拉刷新插件是否与 Tap 事件冲突'); 74 | }; 75 | 76 | render() { 77 | const contents = []; 78 | const {items, disablePullUp} = this.state; 79 | 80 | for (let i = items; i > 0; i--) { 81 | if (i < 10) { 82 | contents.push(
  • 这里放置真实显示的DOM内容 {i}
  • ); 83 | } else { 84 | contents.push(
  • 这里放置真实显示的DOM内容 {i}
  • ); 85 | } 86 | } 87 | 88 | const props = { 89 | refreshCallback: this.refreshCallback, 90 | loadMoreCallback: this.loadMoreCallback, 91 | refresh: true, 92 | loadMore: true, 93 | disablePullUp, 94 | header: (
    头部
    ), 95 | footer: (
    底部
    ) 96 | }; 97 | 98 | return ( 99 | 100 |
      101 | {contents.map((item) => { 102 | return item; 103 | })} 104 |
    105 |
    106 | ); 107 | } 108 | } 109 | 110 | render( 111 | , document.getElementById('layout') 112 | ); 113 | -------------------------------------------------------------------------------- /examples/index.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import {render} from 'react-dom'; 3 | import './sass/example.scss'; 4 | 5 | const Index = () => { 6 | return ( 7 |
    8 |

    React AlloyTouch 例子

    9 |
      10 |
    1. 11 | 简单例子 12 |
    2. 13 |
    3. 14 | 下拉刷新,上拉加载更多 15 |
    4. 16 |
    5. 17 | 带头部和底部的下拉刷新,上拉加载更多 18 |
    6. 19 |
    7. 20 | 轮播 21 |
    8. 22 |
    9. 23 | 下拉刷新中包含轮播图 24 |
    10. 25 |
    11. 26 | 下拉刷新中包含轮播图2 27 |
    12. 28 |
    13. 29 | 自定义轮播内容+tabs 30 |
    14. 31 |
    32 |
    33 | ); 34 | }; 35 | 36 | render(, document.getElementById('layout')); 37 | -------------------------------------------------------------------------------- /examples/pull-carousel.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import {render} from 'react-dom'; 3 | import injectTapEventPlugin from 'react-tap-event-plugin'; 4 | import ReactPull from '../js/ReactPull'; 5 | import ReactCarousel from '../js/ReactCarousel'; 6 | import '../sass/pull.scss'; 7 | import '../sass/carousel.scss'; 8 | import './sass/example.scss'; 9 | 10 | // 初始化 tapEvent 事件, 移动端 11 | injectTapEventPlugin(); 12 | 13 | class ReactPullExample extends Component { 14 | constructor(props) { 15 | super(props); 16 | this.state = { 17 | items: 30, 18 | disablePullUp: false 19 | }; 20 | } 21 | 22 | refreshCallback = () => { 23 | return new Promise((resolve, reject) => { 24 | setTimeout(() => { 25 | let result = false; 26 | if (Math.random() > 0.2) { 27 | result = true; 28 | } 29 | if (result) { 30 | this.setState({ 31 | items: 30, 32 | disablePullUp: false 33 | }, () => { 34 | resolve(); 35 | }); 36 | } else { 37 | reject(new Error('错误')); 38 | } 39 | }, 1000); 40 | }).then(() => { 41 | console.info('刷新成功!'); 42 | }, () => { 43 | console.info('刷新失败!'); 44 | }); 45 | }; 46 | 47 | loadMoreCallback = () => { 48 | return new Promise((resolve, reject) => { 49 | setTimeout(() => { 50 | let result = false; 51 | if (Math.random() > 0.2) { 52 | result = true; 53 | } 54 | if (result) { 55 | this.setState({ 56 | items: this.state.items + 10, 57 | disablePullUp: this.state.items >= 60 58 | }, () => { 59 | resolve(); 60 | }); 61 | } else { 62 | reject(new Error('错误')); 63 | } 64 | }, 1000); 65 | }).then(() => { 66 | console.info('加载更多成功!'); 67 | }, () => { 68 | console.info('加载更多失败!'); 69 | }); 70 | }; 71 | 72 | handleTouchTap = (e) => { 73 | console.info('测试下拉刷新插件是否与 Tap 事件冲突'); 74 | }; 75 | 76 | render() { 77 | const contents = []; 78 | const {items, disablePullUp} = this.state; 79 | 80 | for (let i = items; i > 0; i--) { 81 | if (i < 10) { 82 | contents.push(
  • 这里放置真实显示的DOM内容 {i}
  • ); 83 | } else { 84 | contents.push(
  • 这里放置真实显示的DOM内容 {i}
  • ); 85 | } 86 | } 87 | 88 | const props = { 89 | refreshCallback: this.refreshCallback, 90 | loadMoreCallback: this.loadMoreCallback, 91 | refresh: true, 92 | loadMore: true, 93 | disablePullUp, 94 | }; 95 | 96 | const carouselItems = [{ 97 | image: 'http://alloyteam.github.io/AlloyTouch/example/asset/ci1.jpg', 98 | link: 'http://jd.com' 99 | }, { 100 | image: 'http://alloyteam.github.io/AlloyTouch/example/asset/ci2.jpg', 101 | }, { 102 | image: 'http://alloyteam.github.io/AlloyTouch/example/asset/ci3.jpg', 103 | link: 'http://jd.com' 104 | }, { 105 | image: 'http://alloyteam.github.io/AlloyTouch/example/asset/ci4.jpg' 106 | }]; 107 | 108 | const header = ( 109 |
    110 | 111 |
    112 | ); 113 | return ( 114 | 115 |
      116 | {contents.map((item) => { 117 | return item; 118 | })} 119 |
    120 |
    121 | ); 122 | } 123 | } 124 | 125 | render( 126 | , document.getElementById('layout') 127 | ); 128 | -------------------------------------------------------------------------------- /examples/pull-carousel2.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import {render} from 'react-dom'; 3 | import injectTapEventPlugin from 'react-tap-event-plugin'; 4 | import ReactPull from '../js/ReactPull'; 5 | import ReactCarousel from '../js/ReactCarousel'; 6 | import '../sass/pull.scss'; 7 | import '../sass/carousel.scss'; 8 | import './sass/example.scss'; 9 | 10 | // 初始化 tapEvent 事件, 移动端 11 | injectTapEventPlugin(); 12 | 13 | class ReactPullExample extends Component { 14 | constructor(props) { 15 | super(props); 16 | this.state = { 17 | items: 30, 18 | disablePullUp: false 19 | }; 20 | } 21 | 22 | refreshCallback = () => { 23 | return new Promise((resolve, reject) => { 24 | setTimeout(() => { 25 | let result = false; 26 | if (Math.random() > 0.2) { 27 | result = true; 28 | } 29 | if (result) { 30 | this.setState({ 31 | items: 30, 32 | disablePullUp: false 33 | }, () => { 34 | resolve(); 35 | }); 36 | } else { 37 | reject(new Error('错误')); 38 | } 39 | }, 1000); 40 | }).then(() => { 41 | console.info('刷新成功!'); 42 | }, () => { 43 | console.info('刷新失败!'); 44 | }); 45 | }; 46 | 47 | loadMoreCallback = () => { 48 | return new Promise((resolve, reject) => { 49 | setTimeout(() => { 50 | let result = false; 51 | if (Math.random() > 0.2) { 52 | result = true; 53 | } 54 | if (result) { 55 | this.setState({ 56 | items: this.state.items + 10, 57 | disablePullUp: this.state.items >= 60 58 | }, () => { 59 | resolve(); 60 | }); 61 | } else { 62 | reject(new Error('错误')); 63 | } 64 | }, 1000); 65 | }).then(() => { 66 | console.info('加载更多成功!'); 67 | }, () => { 68 | console.info('加载更多失败!'); 69 | }); 70 | }; 71 | 72 | handleTouchTap = (e) => { 73 | console.info('测试下拉刷新插件是否与 Tap 事件冲突'); 74 | }; 75 | 76 | render() { 77 | const contents = []; 78 | const {items, disablePullUp} = this.state; 79 | 80 | for (let i = items; i > 0; i--) { 81 | if (i < 10) { 82 | contents.push(
  • 这里放置真实显示的DOM内容 {i}
  • ); 83 | } else { 84 | contents.push(
  • 这里放置真实显示的DOM内容 {i}
  • ); 85 | } 86 | } 87 | 88 | const props = { 89 | refreshCallback: this.refreshCallback, 90 | loadMoreCallback: this.loadMoreCallback, 91 | refresh: true, 92 | loadMore: true, 93 | disablePullUp, 94 | }; 95 | 96 | const carouselItems = [{ 97 | image: 'http://alloyteam.github.io/AlloyTouch/example/asset/ci1.jpg', 98 | link: 'http://jd.com' 99 | }, { 100 | image: 'http://alloyteam.github.io/AlloyTouch/example/asset/ci2.jpg', 101 | }, { 102 | image: 'http://alloyteam.github.io/AlloyTouch/example/asset/ci3.jpg', 103 | link: 'http://jd.com' 104 | }, { 105 | image: 'http://alloyteam.github.io/AlloyTouch/example/asset/ci4.jpg' 106 | }]; 107 | 108 | return ( 109 | 110 |
    111 | 112 |
      113 | {contents.map((item) => { 114 | return item; 115 | })} 116 |
    117 |
    118 |
    119 | ); 120 | } 121 | } 122 | 123 | render( 124 | , document.getElementById('layout') 125 | ); 126 | -------------------------------------------------------------------------------- /examples/pull.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import {render} from 'react-dom'; 3 | import injectTapEventPlugin from 'react-tap-event-plugin'; 4 | import ReactPull from '../js/ReactPull'; 5 | import '../sass/pull.scss'; 6 | import './sass/example.scss'; 7 | 8 | // 初始化 tapEvent 事件, 移动端 9 | injectTapEventPlugin(); 10 | 11 | class ReactPullExample extends Component { 12 | constructor(props) { 13 | super(props); 14 | this.state = { 15 | items: 2, 16 | disablePullUp: false 17 | }; 18 | } 19 | 20 | refreshCallback = () => { 21 | return new Promise((resolve, reject) => { 22 | setTimeout(() => { 23 | let result = false; 24 | if (Math.random() > 0.5) { 25 | result = true; 26 | } 27 | if (result) { 28 | this.setState({ 29 | items: 30, 30 | disablePullUp: false 31 | }, () => { 32 | resolve(); 33 | }); 34 | } else { 35 | reject(new Error('错误')); 36 | } 37 | }, 1000); 38 | }).then(() => { 39 | console.info('刷新成功!'); 40 | }, (error) => { 41 | console.info('刷新失败!'); 42 | Promise.error(error); 43 | }); 44 | }; 45 | 46 | loadMoreCallback = () => { 47 | return new Promise((resolve, reject) => { 48 | setTimeout(() => { 49 | let result = false; 50 | if (Math.random() > 0.5) { 51 | result = true; 52 | } 53 | if (result) { 54 | const {items} = this.state; 55 | this.setState({ 56 | items: items >= 60 ? (items + 1) : (items + 10), 57 | disablePullUp: items >= 60 58 | }, () => { 59 | resolve(); 60 | }); 61 | } else { 62 | reject(new Error('错误')); 63 | } 64 | }, 1000); 65 | }).then(() => { 66 | console.info('加载更多成功!'); 67 | }, (error) => { 68 | console.info('加载更多失败!'); 69 | Promise.error(error); 70 | }); 71 | }; 72 | 73 | handleTouchTap = (e) => { 74 | console.info('测试下拉刷新插件是否与 Tap 事件冲突'); 75 | }; 76 | 77 | render() { 78 | const contents = []; 79 | const {items, disablePullUp} = this.state; 80 | 81 | for (let i = items; i > 0; i--) { 82 | if (i < 10) { 83 | contents.push(
  • 这里放置真实显示的DOM内容 {i}
  • ); 84 | } else { 85 | contents.push(
  • 这里放置真实显示的DOM内容 {i}
  • ); 86 | } 87 | } 88 | 89 | const props = { 90 | refreshCallback: this.refreshCallback, 91 | loadMoreCallback: this.loadMoreCallback, 92 | refresh: true, 93 | loadMore: true, 94 | disablePullUp, 95 | }; 96 | 97 | return ( 98 | 99 |
      100 | {contents.map((item) => { 101 | return item; 102 | })} 103 |
    104 |
    105 | ); 106 | } 107 | } 108 | 109 | render( 110 | , document.getElementById('layout') 111 | ); 112 | -------------------------------------------------------------------------------- /examples/sass/example.scss: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | } 4 | 5 | a { 6 | color: #00C176; 7 | &:hover, 8 | &:focus, 9 | &:active { 10 | color: #88C100; 11 | } 12 | } 13 | 14 | .example { 15 | margin: 50px auto; 16 | width: 80%; 17 | } 18 | 19 | .example-list { 20 | > li { 21 | padding: 10px; 22 | } 23 | } 24 | 25 | .header, 26 | .footer { 27 | padding: 5px; 28 | background-color: #00C176; 29 | color: #fff; 30 | text-align: center; 31 | } 32 | 33 | .pull-carousel { 34 | .pull-refresh { 35 | top: -50px; 36 | padding-bottom: 10px; 37 | } 38 | } 39 | 40 | .carousel-scroller .swiper-panel{ 41 | text-align: center; 42 | height: 200px; 43 | font-size: 28px; 44 | background: #f0f0f0; 45 | } -------------------------------------------------------------------------------- /examples/simple.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import {render} from 'react-dom'; 3 | import ReactAlloyTouch from '../js/index'; 4 | import '../sass/index.scss'; 5 | import './sass/example.scss'; 6 | 7 | const ReactAlloyTouchExample = () => { 8 | const len = 100; 9 | const content = []; 10 | for (let i = 0; i < len; i++) { 11 | content.push(i); 12 | } 13 | return ( 14 | 15 |
    16 | {content.map((it) => { 17 | return ( 18 |

    {`测试内容 ${it + 1}`}

    19 | ); 20 | })} 21 |
    22 |
    23 | ); 24 | }; 25 | 26 | render( 27 | , document.getElementById('layout') 28 | ); 29 | -------------------------------------------------------------------------------- /examples/tabs-carousel.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import {render} from 'react-dom'; 3 | import injectTapEventPlugin from 'react-tap-event-plugin'; 4 | import ReactSwiper from '../js/ReactSwiper'; 5 | import '../sass/carousel.scss'; 6 | import './sass/example.scss'; 7 | 8 | // 初始化 tapEvent 事件, 移动端 9 | injectTapEventPlugin(); 10 | 11 | class ReactSwiperExample extends Component { 12 | constructor(props) { 13 | super(props); 14 | this.state = { 15 | items: 30, 16 | disablePullUp: false 17 | }; 18 | } 19 | 20 | 21 | handleTouchTap = (e) => { 22 | console.info('测试下拉刷新插件是否与 Tap 事件冲突'); 23 | }; 24 | 25 | handleSlideChange = (currentIndex) => { 26 | console.log(`currentIndex is ${currentIndex}`) 27 | const btns = document.querySelectorAll('input') 28 | Array.prototype.forEach.call(btns, (item, index) => { 29 | if (index === currentIndex) { 30 | item.style.color = 'red' 31 | } else { 32 | item.style.color = 'black' 33 | } 34 | }) 35 | }; 36 | 37 | handleST = (index) => { 38 | 39 | return function () { 40 | const {swiper} = this.refs 41 | swiper.SlideTo(index) 42 | 43 | // slideto() 44 | 45 | console.log(swiper) 46 | }.bind(this) 47 | 48 | } 49 | 50 | render() { 51 | 52 | const swiper1 = ( 53 |
    123
    54 | ) 55 | const swiper2 = ( 56 |
    456
    57 | ) 58 | 59 | const carouselItems = [swiper1, swiper2]; 60 | 61 | return ( 62 |
    63 |
    64 | 65 | 66 |
    67 | ); 68 | } 69 | } 70 | 71 | render( 72 | , document.getElementById('layout') 73 | ); 74 | -------------------------------------------------------------------------------- /examples/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <%= htmlWebpackPlugin.options.title %> 5 | 6 | 8 | 9 | 24 | 25 | 26 |
    27 | 28 | 29 | -------------------------------------------------------------------------------- /gulp/example.babel.js: -------------------------------------------------------------------------------- 1 | import gulp from 'gulp'; 2 | import gulpLoadPlugins from 'gulp-load-plugins'; 3 | import webpack from 'webpack'; 4 | import WebpackDevServer from 'webpack-dev-server'; 5 | import opn from 'opn'; 6 | import exampleConfig from '../webpack.config.example.babel'; 7 | 8 | const $ = gulpLoadPlugins(); 9 | const {webpackConfig, ip, port} = exampleConfig; 10 | 11 | gulp.task('copy-eruda', () => { 12 | return gulp.src('node_modules/eruda/eruda.min.js') 13 | .pipe(gulp.dest('examples')); 14 | }); 15 | 16 | // 运行 example 17 | gulp.task('example', ['copy-eruda'], () => { 18 | // Start a webpack-dev-server 19 | const compiler = webpack(webpackConfig); 20 | new WebpackDevServer(compiler, webpackConfig.devServer) 21 | .listen(port, ip, (err) => { 22 | if (err) { 23 | throw new $.util.PluginError('webpack-dev-server', err); 24 | } 25 | // Server listening 26 | $.util.log('[webpack-dev-server]', `http://${ip}:${port}/`); 27 | 28 | // keep the server alive or continue? 29 | opn(port === '80' ? `http://${ip}` : `http://${ip}:${port}/`, {app: 'google chrome'}); 30 | }); 31 | }); 32 | 33 | gulp.task('copy-eruda-dist', () => { 34 | return gulp.src('node_modules/eruda/eruda.min.js') 35 | .pipe(gulp.dest('examples-dist')); 36 | }); 37 | 38 | -------------------------------------------------------------------------------- /gulp/publish.babel.js: -------------------------------------------------------------------------------- 1 | import childProcess from 'child_process'; 2 | import gulp from 'gulp'; 3 | import chalk from 'chalk'; 4 | import gulpLoadPlugins from 'gulp-load-plugins'; 5 | 6 | const $ = gulpLoadPlugins(); 7 | 8 | gulp.task('copy-publish', () => { 9 | return gulp 10 | .src(['README.md', 'sass/*', 'js/*']) 11 | .pipe($.copy('publish')) 12 | }); 13 | 14 | // 发布到 npm 中 15 | gulp.task('publish', () => { 16 | const {exec} = childProcess; 17 | exec('cd publish && npm publish && cd ..', (error, stdout, stderr) => { 18 | if (error) { 19 | console.log(chalk.magenta(error)); 20 | return; 21 | } 22 | if (stdout) { 23 | console.log(chalk.magenta(`stdout: ${stdout}`)); 24 | } 25 | if (stderr) { 26 | console.log(chalk.magenta(`stderr: ${stderr}`)); 27 | } 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /gulp/scss.babel.js: -------------------------------------------------------------------------------- 1 | import gulp from 'gulp'; 2 | import gulpLoadPlugins from 'gulp-load-plugins'; 3 | import chalk from 'chalk'; 4 | import autoprefixer from 'autoprefixer'; 5 | import flexbugs from 'postcss-flexbugs-fixes'; 6 | 7 | const $ = gulpLoadPlugins(); 8 | 9 | const scssOption = { 10 | outputStyle: 'expanded', // 不压缩,设为 compressed 表示压缩 11 | precision: 10, // 设置小数精度 12 | includePaths: ['.'] 13 | }; 14 | 15 | /** 16 | * 浏览器支持性参考 bootstrap 官方的支持,参见源码 postcss.js 的支持性说明 17 | * iOS:https://developer.apple.com/support/app-store/ 18 | * Android:https://developer.android.com/about/dashboards/index.html 19 | */ 20 | const browsers = ['Chrome >= 35', 'Firefox >= 38', 21 | 'Android >= 4.3', 'iOS >= 8', 'Safari >= 8', 'Opera >= 12']; 22 | 23 | const postcssPlugins = [ 24 | autoprefixer({ 25 | flexbox: 'no-2009', // 不生成2009定义的 Flexbox 26 | browsers 27 | }), 28 | flexbugs 29 | ]; 30 | 31 | /** 32 | * 利用sass生成styles任务 33 | * [在线补齐前缀](http://autoprefixer.github.io/) 34 | * [浏览器列表](https://github.com/ai/browserslist) 35 | * 36 | */ 37 | gulp.task('scss', () => { 38 | return gulp.src('sass/*.scss') 39 | .pipe($.sourcemaps.init()) 40 | .pipe($.sass.sync(scssOption).on('error', $.sass.logError)) 41 | .pipe($.postcss(postcssPlugins)) 42 | .pipe($.sourcemaps.write('./maps')) 43 | .pipe(gulp.dest('publish/css')); 44 | }); 45 | 46 | // 检测样式加前缀 47 | gulp.task('css-pre', () => { 48 | const info = autoprefixer({ 49 | browsers 50 | }).info(); 51 | 52 | console.log(chalk.magenta(info)); 53 | }); 54 | -------------------------------------------------------------------------------- /gulpfile.babel.js: -------------------------------------------------------------------------------- 1 | import gulp from 'gulp'; 2 | import requireDir from 'require-dir'; 3 | 4 | requireDir('./gulp'); 5 | 6 | // 默认任务 7 | gulp.task('default', () => { 8 | gulp.start('build'); 9 | }); 10 | -------------------------------------------------------------------------------- /js/AlloyTouch.js: -------------------------------------------------------------------------------- 1 | import AlloyTouch from 'alloytouch'; 2 | 3 | // 重新设置 AlloyTouch 方法 4 | AlloyTouch.prototype.setOption = function (key, value) { 5 | this[key] = value; 6 | }; 7 | 8 | export default AlloyTouch; 9 | -------------------------------------------------------------------------------- /js/ReactAlloyTouch.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import AlloyTouch from './AlloyTouch'; 4 | import Transform from 'alloytouch/transformjs/transform'; 5 | 6 | // 基于腾讯组件 https://github.com/AlloyTeam/AlloyTouch 实现 7 | class ReactAlloyTouch extends Component { 8 | //可能需要传入的参数 9 | static propTypes = { 10 | children: PropTypes.node, // 待渲染的内容 11 | className: PropTypes.string, // 自定义 className 12 | prefix: PropTypes.string, // 样式前缀 13 | options: PropTypes.object, // AlloyTouch 组件选项 14 | transform: PropTypes.bool, // 是否用 Transform 处理 15 | extensionFunc: PropTypes.func, // 扩展函数,处理额外的功能 16 | updateFunc: PropTypes.func, // 执行 componentDidUpdate 调用的回调 17 | }; 18 | 19 | static defaultProps = { 20 | className: '', 21 | prefix: 'alloy', 22 | options: {}, 23 | transform: true, 24 | }; 25 | 26 | componentDidMount() { 27 | const {wrapper, scroller} = this; 28 | const {options, transform, extensionFunc} = this.props; 29 | 30 | // 处理 options 中函数,返回 wrapper 和 scroller 31 | Object.keys(options).forEach((func) => { 32 | if (typeof func === 'function') { 33 | options[func] = function (...args) { 34 | options[func](...args, wrapper, scroller); 35 | }; 36 | } 37 | }); 38 | 39 | if (transform) { 40 | Transform(scroller, true); 41 | } 42 | 43 | let min = wrapper.clientHeight - scroller.scrollHeight; 44 | if (min >= 0) { 45 | min = 0; 46 | } 47 | 48 | const alloyOptions = { 49 | touch: wrapper, // 反馈触摸的dom 50 | target: scroller, // 运动的对象 51 | vertical: true, // 不必需,默认是true代表监听竖直方向touch 52 | property: 'translateY', // 被运动的属性 53 | sensitivity: 1, // 不必需,触摸区域的灵敏度,默认值为1,可以为负数 54 | factor: 1, // 不必需,表示触摸位移与被运动属性映射关系,默认值是1 55 | min, 56 | max: 0, // 不必需,滚动属性的最大值 57 | step: 40, // 用于校正到step的整数倍 58 | ...(options || {}) 59 | }; 60 | 61 | // 初始化 alloyTouch 实例 62 | this.alloyTouch = new AlloyTouch(alloyOptions); 63 | 64 | if (typeof extensionFunc === 'function') { 65 | extensionFunc(this.alloyTouch, wrapper, scroller); 66 | } 67 | } 68 | 69 | componentDidUpdate() { 70 | const {updateFunc} = this.props; 71 | const {wrapper, scroller} = this; 72 | if (typeof updateFunc === 'function') { 73 | updateFunc(this.alloyTouch, wrapper, scroller); 74 | } 75 | } 76 | 77 | handleWrapper = (wrapper) => { 78 | this.wrapper = wrapper; 79 | }; 80 | handleScroller = (scroller) => { 81 | this.scroller = scroller; 82 | }; 83 | 84 | render() { 85 | const { 86 | children, className, prefix, 87 | } = this.props; 88 | 89 | return ( 90 |
    91 |
    92 | {children} 93 |
    94 |
    95 | ); 96 | } 97 | } 98 | 99 | export default ReactAlloyTouch; 100 | -------------------------------------------------------------------------------- /js/ReactCarousel.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import AlloyTouch from './AlloyTouch'; 4 | import Transform from 'alloytouch/transformjs/transform'; 5 | 6 | // 基于腾讯组件 https://github.com/AlloyTeam/AlloyTouch 实现 7 | class ReactAlloyTouch extends Component { 8 | //可能需要传入的参数 9 | static propTypes = { 10 | className: PropTypes.string, // 自定义 className 11 | prefix: PropTypes.string, // 样式前缀 12 | options: PropTypes.object, // AlloyTouch 组件选项 13 | items: PropTypes.array, // 轮播图 14 | active: PropTypes.number, // 当前活动轮播图 15 | autoPlay: PropTypes.oneOfType([PropTypes.bool, PropTypes.number]), // 是否自动播放 16 | events: PropTypes.object, // 自定义各种事件 17 | }; 18 | 19 | static defaultProps = { 20 | className: '', 21 | prefix: 'carousel', 22 | active: 0, 23 | autoPlay: 4000, // 默认一4秒播放一次 24 | events: {}, 25 | }; 26 | 27 | constructor(props) { 28 | super(props); 29 | 30 | this.currentIndex = 0; 31 | } 32 | 33 | componentDidMount() { 34 | const {wrapper, scroller, nav} = this.refs; 35 | const {options, items} = this.props; 36 | 37 | this.navItems = nav.querySelectorAll('a'); 38 | Transform(scroller, true); 39 | 40 | const alloyOptions = { 41 | touch: wrapper, //反馈触摸的dom 42 | vertical: false, //不必需,默认是true代表监听竖直方向touch 43 | target: scroller, //运动的对象 44 | property: 'translateX', //被运动的属性 45 | min: wrapper.clientWidth * -(items.length - 1), //不必需,运动属性的最小值 46 | max: 0, //不必需,滚动属性的最大值 47 | step: wrapper.clientWidth, 48 | spring: true, //不必需,是否有回弹效果。默认是true 49 | inertia: false, //不必需,是否有惯性。默认是true 50 | touchStart: this.touchStart, 51 | touchEnd: this.touchEnd, 52 | animationEnd: this.animationEnd, 53 | ...(options || {}) 54 | }; 55 | 56 | // 初始化 alloyTouch 实例 57 | this.alloyTouch = new AlloyTouch(alloyOptions); 58 | this.handleAutoPlay(); 59 | } 60 | 61 | touchStart = () => { 62 | // 先删除 63 | clearInterval(this.timerId); 64 | }; 65 | 66 | touchEnd = (evt, value, index) => { 67 | const {step, min, max} = this.alloyTouch; 68 | const stepV = index * step * -1; 69 | const dx = value - stepV; 70 | 71 | if (value < min) { 72 | this.alloyTouch.to(min); 73 | } else if (value > max) { 74 | this.alloyTouch.to(max); 75 | } else if (Math.abs(dx) < 30) { 76 | this.alloyTouch.to(stepV); 77 | } else if (dx > 0) { 78 | this.alloyTouch.to(stepV + step); 79 | } else { 80 | this.alloyTouch.to(stepV - step); 81 | } 82 | this.currentIndex = index; 83 | 84 | // 开启自动播放 85 | this.handleAutoPlay(); 86 | return false; 87 | }; 88 | 89 | animationEnd = () => { 90 | const len = this.navItems.length; 91 | let i = 0; 92 | for (; i < len; i++) { 93 | if (i === this.alloyTouch.currentPage) { 94 | this.navItems[i].classList.add('active'); 95 | } else { 96 | this.navItems[i].classList.remove('active'); 97 | } 98 | } 99 | }; 100 | 101 | // 自动播放 102 | handleAutoPlay() { 103 | const {autoPlay, items} = this.props; 104 | const len = items.length; 105 | if (autoPlay) { 106 | this.timerId = setInterval(() => { 107 | const {step} = this.alloyTouch; 108 | const stepV = this.currentIndex * step * -1; 109 | this.alloyTouch.to(stepV); 110 | if (this.currentIndex >= len - 1) { 111 | this.currentIndex = 0; 112 | } else { 113 | this.currentIndex++; 114 | } 115 | }, autoPlay); 116 | } 117 | } 118 | 119 | render() { 120 | const { 121 | className, prefix, items, active, events, 122 | } = this.props; 123 | 124 | const len = items.length; 125 | return ( 126 |
    127 |
    128 | {items.map(({image, link}) => { 129 | if (link) { 130 | return ( 131 | 132 | ); 133 | } 134 | return (); 135 | })} 136 |
    137 |
    138 | {items.map((it, index) => { 139 | /*eslint-disable react/no-array-index-key*/ 140 | return (); 141 | })} 142 |
    143 |
    144 | ); 145 | } 146 | } 147 | 148 | export default ReactAlloyTouch; 149 | -------------------------------------------------------------------------------- /js/ReactPull.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import AlloyTouch from './AlloyTouch'; 4 | import Transform from 'alloytouch/transformjs/transform'; 5 | 6 | // 基于腾讯组件 7 | class ReactAlloyTouch extends Component { 8 | //可能需要传入的参数 9 | static propTypes = { 10 | children: PropTypes.node, // 待渲染的内容 11 | className: PropTypes.string, // 自定义 className 12 | header: PropTypes.element, // 头部 13 | footer: PropTypes.element, // 底部 14 | options: PropTypes.object, // AlloyTouch 组件选项 15 | lockInTime: PropTypes.number, // 延迟刷新或加载 16 | enableText: PropTypes.bool, // 是否显示文本 17 | refresh: PropTypes.bool, // 是否下拉刷新 18 | refreshThreshold: PropTypes.number, // 设置刷新页面时,距离顶部临界值, 19 | refreshCallback: PropTypes.func, // 刷新回调函数 20 | pullDownText: PropTypes.array, // 下拉显示文本内容 21 | loadMore: PropTypes.bool, // 是否加载更多 22 | loadMoreThrottle: PropTypes.number, // 设置加载更多,距离最底部临界值, 23 | loadMoreCallback: PropTypes.func, // 加载更多回调函数 24 | pullUpText: PropTypes.array, // 上拉显示文本内容 25 | loadMoreProcessIcon: PropTypes.bool, // 加载更多过程图标 26 | disablePullUp: PropTypes.bool, // 对于上拉加载更多时,如果没有更多记录时,禁止上滑, 27 | loadedRecoilTime: PropTypes.number, // 加载完更多数据回弹时间 28 | moveForwardOffset: PropTypes.number, // 加载完更多数据时,向前推进的距离 29 | }; 30 | 31 | static defaultProps = { 32 | className: '', 33 | refreshThreshold: 50, 34 | loadMoreThrottle: 30, 35 | lockInTime: 0, 36 | pullDownText: ['下拉刷新', '松开刷新数据', '加载中,请稍后...'], 37 | pullUpText: ['上滑加载更多...', '松开加载数据', '加载中,请稍后...', '没有更多数据了'], 38 | enableText: true, 39 | loadMoreProcessIcon: true, 40 | loadedRecoilTime: 300, 41 | moveForwardOffset: 50 42 | }; 43 | 44 | constructor(props) { 45 | super(props); 46 | this.state = { 47 | refreshText: props.pullDownText[0], 48 | loadMoreText: props.pullUpText[0] 49 | }; 50 | // 下拉状态: 分为没有开启,开启,加载中 null enable loading 51 | this.refreshState = null; 52 | // 上滑状态: 分为没有开启,开启,加载中 null enable loading 53 | this.loadMoreState = null; 54 | } 55 | 56 | componentDidMount() { 57 | const {wrapper, scroller} = this.refs; 58 | const {options} = this.props; 59 | 60 | Transform(scroller, true); 61 | 62 | // 设置向下滑动时,滑动的最小值,如果采用translateY,则设置 y的最小值,如果不设置 min,则可以无限制的向下滑动 63 | let min = wrapper.clientHeight - scroller.scrollHeight; 64 | if (min >= 0) { 65 | min = 0; 66 | } 67 | 68 | const alloyOptions = { 69 | touch: wrapper, // 反馈触摸的dom 70 | target: scroller, // 运动的对象 71 | vertical: true, // 不必需,默认是true代表监听竖直方向touch 72 | property: 'translateY', // 被运动的属性 73 | sensitivity: 1, // 不必需,触摸区域的灵敏度,默认值为1,可以为负数 74 | factor: 1, // 不必需,表示触摸位移与被运动属性映射关系,默认值是1 75 | min, 76 | max: 0, // 不必需,滚动属性的最大值 77 | step: 40, // 用于校正到step的整数倍 78 | maxSpeed: 2, //不必需,触摸反馈的最大速度限制 79 | touchStart: this.touchStart, 80 | touchMove: this.touchMove, 81 | touchEnd: this.touchEnd, 82 | ...(options || {}) 83 | }; 84 | 85 | // 初始化 alloyTouch 实例 86 | this.alloyTouch = new AlloyTouch(alloyOptions); 87 | 88 | this.adjustPosition(); 89 | } 90 | 91 | componentDidUpdate() { 92 | // 每次页面数据更改后,需要重新设置 this.alloyTouch 的 min 值 93 | const {wrapper, scroller} = this.refs; 94 | 95 | let min = wrapper.clientHeight - scroller.scrollHeight; 96 | if (min >= 0) { 97 | min = 0; 98 | } 99 | this.alloyTouch.setOption('min', min); 100 | 101 | this.adjustPosition(); 102 | } 103 | 104 | adjustPosition() { 105 | const {header, footer, alloyBody} = this.refs; 106 | 107 | if (header) { 108 | alloyBody.style.top = `${header.scrollHeight}px`; 109 | } 110 | 111 | if (footer) { 112 | alloyBody.style.bottom = `${footer.scrollHeight}px`; 113 | } 114 | } 115 | 116 | // touch 开始时 117 | touchStart = (e, value) => { 118 | if (this.props.loadMore) { 119 | // 记录当前滑动值 120 | const {wrapper, scroller} = this.refs; 121 | let heightOffset = wrapper.clientHeight - scroller.scrollHeight; 122 | if (heightOffset > 0) { 123 | heightOffset = 0; 124 | } 125 | 126 | this.offsetStart = heightOffset; 127 | this.moveValue = value; 128 | } 129 | }; 130 | 131 | // touch 移动时,分刷新和加载更多 132 | touchMove = (e, value) => { 133 | const { 134 | refresh, loadMore, refreshThreshold, loadMoreThrottle, 135 | pullDownText, pullUpText 136 | } = this.props; 137 | 138 | // 下拉刷新 139 | if (refresh && this.refreshState !== 'loading') { 140 | const {refreshEl, refreshIconEl} = this.refs; 141 | const {style} = refreshEl; 142 | if (value > 0) { 143 | if (value > refreshThreshold) { 144 | this.refreshState = 'enable'; 145 | refreshIconEl.classList.add('rotate'); 146 | this.setState({ 147 | refreshText: pullDownText[1] 148 | }); 149 | } else { 150 | this.refreshState = null; 151 | refreshIconEl.classList.remove('rotate'); 152 | this.setState({ 153 | refreshText: pullDownText[0] 154 | }); 155 | } 156 | } 157 | 158 | style.opacity = 1; 159 | style.webkitTransform = `translate3d(0, ${value}px, 0)`; 160 | style.transform = `translate3d(0, ${value}px, 0)`; 161 | } 162 | 163 | // 上滑加载更多 164 | if (loadMore) { 165 | const {disablePullUp} = this.props; 166 | const {loadMoreEl, loadMoreIconEl} = this.refs; 167 | const {style} = loadMoreEl; 168 | const {wrapper, scroller} = this.refs; 169 | 170 | const min = wrapper.clientHeight - scroller.scrollHeight; 171 | 172 | if (this.loadMoreState !== 'loading') { 173 | if (disablePullUp) { 174 | const min = wrapper.clientHeight - scroller.scrollHeight; 175 | if (min < 0) { 176 | loadMoreEl.style.visibility = value < min - 5 ? 'visible' : 'hidden'; 177 | } 178 | return false; 179 | } 180 | if (value < min && value < 0) { 181 | style.visibility = 'visible'; 182 | if (Math.abs(value - this.moveValue) > loadMoreThrottle) { 183 | this.loadMoreState = 'enable'; 184 | loadMoreIconEl.classList.add('rotate'); 185 | this.setState({ 186 | loadMoreText: pullUpText[1] 187 | }); 188 | } else { 189 | this.loadMoreState = null; 190 | loadMoreIconEl.classList.remove('rotate'); 191 | this.setState({ 192 | loadMoreText: pullUpText[0] 193 | }); 194 | } 195 | } else { 196 | style.visibility = 'hidden'; 197 | } 198 | } 199 | } 200 | }; 201 | 202 | // touch end 203 | touchEnd = (e, value) => { 204 | const {refresh, loadMore, disablePullUp} = this.props; 205 | // 刷新 206 | if (value > 0) { 207 | if (refresh) { 208 | if (this.refreshState === 'enable') { 209 | this.refresh(e); 210 | } else { 211 | this.resetRefreshState(); 212 | } 213 | // 阻止默认的滑动 214 | return false; 215 | } 216 | return; 217 | } 218 | 219 | // 加载更多 220 | const {wrapper, scroller} = this.refs; 221 | const min = wrapper.clientHeight - scroller.scrollHeight; 222 | if (value < min) { 223 | if (loadMore && !disablePullUp && this.loadMoreState === 'enable') { 224 | this.loadMore(e); 225 | // 阻止默认的滑动 226 | return false; 227 | } 228 | this.resetLoadMoreState({moveTo: false}); 229 | } 230 | }; 231 | 232 | // 刷新数据 233 | refresh = (e) => { 234 | if (e) { 235 | e.stopImmediatePropagation(); 236 | } 237 | 238 | if (this.refreshState === null || this.refreshState === 'loading') { 239 | return; 240 | } 241 | this.refreshState = 'loading'; 242 | const {refreshCallback, lockInTime, pullDownText} = this.props; 243 | const {refreshIconEl} = this.refs; 244 | refreshIconEl.classList.add('loading'); 245 | this.setState({ 246 | refreshText: pullDownText[2] 247 | }); 248 | 249 | if (refreshCallback && typeof refreshCallback === 'function') { 250 | if (lockInTime > 0) { 251 | clearTimeout(this.refreshTimoutId); 252 | this.refreshTimoutId = setTimeout(() => { 253 | refreshCallback().then(this.resetRefreshState, this.resetRefreshState); 254 | }, lockInTime); 255 | } else { 256 | refreshCallback().then(this.resetRefreshState, this.resetRefreshState); 257 | } 258 | } else { 259 | this.resetRefreshState(); 260 | } 261 | }; 262 | 263 | // 恢复刷新原始状态 264 | resetRefreshState = () => { 265 | const {pullDownText, refresh} = this.props; 266 | this.refreshState = null; 267 | if (refresh) { 268 | const {refreshEl, refreshIconEl} = this.refs; 269 | const {style} = refreshEl; 270 | refreshIconEl.classList.remove('rotate'); 271 | refreshIconEl.classList.remove('loading'); 272 | 273 | style.opacity = 0; 274 | style.transition = ''; 275 | style.webkitTransition = ''; 276 | style.webkitTransform = 'translate3d(0, 0, 0)'; 277 | style.transform = 'translate3d(0, 0, 0)'; 278 | 279 | this.setState({ 280 | refreshText: pullDownText[0] 281 | }); 282 | } 283 | 284 | this.alloyTouch.to(0); 285 | }; 286 | 287 | // 加载更多 288 | loadMore = (e) => { 289 | if (e) { 290 | e.stopImmediatePropagation(); 291 | } 292 | 293 | if (this.loadMoreState === null || this.loadMoreState === 'loading') { 294 | return; 295 | } 296 | this.loadMoreState = 'loading'; 297 | const {loadMoreCallback, lockInTime, pullUpText} = this.props; 298 | const {loadMoreIconEl} = this.refs; 299 | loadMoreIconEl.classList.add('loading'); 300 | this.setState({ 301 | loadMoreText: pullUpText[2] 302 | }); 303 | 304 | if (loadMoreCallback && typeof loadMoreCallback === 'function') { 305 | if (lockInTime > 0) { 306 | clearTimeout(this.loadMoreTimoutId); 307 | this.loadMoreTimoutId = setTimeout(() => { 308 | loadMoreCallback().then(() => { 309 | this.resetLoadMoreState({adjust: true}); 310 | }, () => { 311 | this.resetLoadMoreState({}); 312 | }); 313 | }, lockInTime); 314 | } else { 315 | loadMoreCallback().then(() => { 316 | this.resetLoadMoreState({adjust: true}); 317 | }, () => { 318 | this.resetLoadMoreState({}); 319 | }); 320 | } 321 | } else { 322 | this.resetLoadMoreState({}); 323 | } 324 | }; 325 | 326 | // 恢复加载更多原始状态 327 | resetLoadMoreState = ({adjust = false, moveTo = true}) => { 328 | const {pullUpText, loadedRecoilTime, moveForwardOffset, loadMore} = this.props; 329 | this.loadMoreState = null; 330 | if (loadMore) { 331 | const {loadMoreEl, loadMoreIconEl} = this.refs; 332 | loadMoreIconEl.classList.remove('rotate'); 333 | loadMoreIconEl.classList.remove('loading'); 334 | 335 | this.setState({ 336 | loadMoreText: pullUpText[0] 337 | }); 338 | loadMoreEl.style.visibility = 'hidden'; 339 | } 340 | 341 | if (this.offsetStart !== undefined) { 342 | let offset; 343 | if (adjust) { 344 | offset = this.offsetStart < -moveForwardOffset ? this.offsetStart - moveForwardOffset : this.offsetStart; 345 | } else { 346 | offset = this.offsetStart; 347 | } 348 | 349 | if (moveTo) { 350 | this.alloyTouch.to(offset, loadedRecoilTime); 351 | } 352 | } 353 | }; 354 | 355 | // 选择加载更多 356 | renderLoadMore() { 357 | const {loadMoreText} = this.state; 358 | const {enableText, loadMore, loadMoreProcessIcon, disablePullUp, pullUpText} = this.props; 359 | if (loadMore) { 360 | return ( 361 |
    362 |
    364 | {enableText ? ( 365 |
    {disablePullUp ? pullUpText[3] : loadMoreText}
    ) : null} 367 |
    368 | ); 369 | } 370 | return null; 371 | } 372 | 373 | render() { 374 | const { 375 | children, className, header, footer, refresh, enableText 376 | } = this.props; 377 | const {refreshText} = this.state; 378 | 379 | return ( 380 |
    381 | {header ? (
    {header}
    ) : null} 382 |
    383 | { 384 | refresh ? (
    385 |
    386 |
    387 |
    388 | {enableText ? (
    {refreshText}
    ) : null} 389 |
    ) : null 390 | } 391 |
    392 |
    393 | {children} 394 |
    395 |
    396 | {this.renderLoadMore()} 397 |
    398 | {footer ? (
    {footer}
    ) : null} 399 |
    400 | ); 401 | } 402 | } 403 | 404 | export default ReactAlloyTouch; 405 | -------------------------------------------------------------------------------- /js/ReactSwiper.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import AlloyTouch from './AlloyTouch'; 4 | import Transform from 'alloytouch/transformjs/transform'; 5 | 6 | // 基于腾讯组件 https://github.com/AlloyTeam/AlloyTouch 实现 7 | class ReactAlloyTouch extends Component { 8 | //可能需要传入的参数 9 | static propTypes = { 10 | className: PropTypes.string, // 自定义 className 11 | prefix: PropTypes.string, // 样式前缀 12 | options: PropTypes.object, // AlloyTouch 组件选项 13 | items: PropTypes.array, // 轮播图 14 | showDot: PropTypes.bool, //是否显示点 15 | active: PropTypes.number, // 当前活动轮播图 16 | autoPlay: PropTypes.oneOfType([PropTypes.bool, PropTypes.number]), // 是否自动播放 17 | events: PropTypes.object, // 自定义各种事件 18 | onSlideChange: PropTypes.func 19 | }; 20 | 21 | static defaultProps = { 22 | className: '', 23 | prefix: 'carousel', 24 | active: 0, 25 | autoPlay: 4000, // 默认一4秒播放一次 26 | tabsMenu: null, 27 | events: {}, 28 | }; 29 | 30 | constructor(props) { 31 | super(props); 32 | 33 | this.currentIndex = 0; 34 | } 35 | 36 | componentDidMount() { 37 | const {wrapper, scroller, nav, menu} = this.refs; 38 | const {options, items, prefix} = this.props; 39 | 40 | this.navItems = nav.querySelectorAll('a'); 41 | Transform(scroller); 42 | 43 | const alloyOptions = { 44 | touch: wrapper, //反馈触摸的dom 45 | vertical: false, //不必需,默认是true代表监听竖直方向touch 46 | target: scroller, //运动的对象 47 | property: 'translateX', //被运动的属性 48 | min: wrapper.clientWidth * -(items.length - 1), //不必需,运动属性的最小值 49 | max: 0, //不必需,滚动属性的最大值 50 | step: wrapper.clientWidth, 51 | spring: true, //不必需,是否有回弹效果。默认是true 52 | inertia: false, //不必需,是否有惯性。默认是true 53 | touchStart: this.touchStart, 54 | touchEnd: this.touchEnd, 55 | animationEnd: this.animationEnd, 56 | ...(options || {}) 57 | }; 58 | 59 | // 初始化 alloyTouch 实例 60 | this.alloyTouch = new AlloyTouch(alloyOptions); 61 | this.handleAutoPlay(); 62 | } 63 | 64 | touchStart = () => { 65 | // 先删除 66 | clearInterval(this.timerId); 67 | }; 68 | 69 | touchEnd = (evt, value, index) => { 70 | const {step, min, max} = this.alloyTouch; 71 | const stepV = index * step * -1; 72 | const dx = value - stepV; 73 | 74 | if (value < min) { 75 | this.alloyTouch.to(min); 76 | } else if (value > max) { 77 | this.alloyTouch.to(max); 78 | } else if (Math.abs(dx) < 30) { 79 | this.alloyTouch.to(stepV); 80 | } else if (dx > 0) { 81 | this.alloyTouch.to(stepV + step); 82 | } else { 83 | this.alloyTouch.to(stepV - step); 84 | } 85 | this.currentIndex = index; 86 | 87 | // 开启自动播放 88 | this.handleAutoPlay(); 89 | return false; 90 | }; 91 | 92 | animationEnd = () => { 93 | const len = this.navItems.length; 94 | let i = 0; 95 | for (; i < len; i++) { 96 | if (i === this.alloyTouch.currentPage) { 97 | this.navItems[i].classList.add('active'); 98 | } else { 99 | this.navItems[i].classList.remove('active'); 100 | } 101 | } 102 | 103 | if (typeof this.props.onSlideChange === 'function') this.props.onSlideChange(this.alloyTouch.currentPage) 104 | }; 105 | 106 | //给外部组件提供接口 107 | SlideTo = (index) => { 108 | const {step} = this.alloyTouch; 109 | const stepV = index * step * -1; 110 | this.alloyTouch.to(stepV); 111 | }; 112 | 113 | // 自动播放 114 | handleAutoPlay() { 115 | const {autoPlay, items} = this.props; 116 | const len = items.length; 117 | if (autoPlay) { 118 | this.timerId = setInterval(() => { 119 | const {step} = this.alloyTouch; 120 | const stepV = this.currentIndex * step * -1; 121 | this.alloyTouch.to(stepV); 122 | if (this.currentIndex >= len - 1) { 123 | this.currentIndex = 0; 124 | } else { 125 | this.currentIndex++; 126 | } 127 | }, autoPlay); 128 | } 129 | } 130 | 131 | render() { 132 | const { 133 | className, prefix, items, active, showDot, events, 134 | } = this.props; 135 | 136 | const len = items.length; 137 | return ( 138 |
    139 |
    140 | {items.map((item, index) => { 141 | /*eslint-disable react/no-array-index-key*/ 142 | return (
    143 | {item} 144 |
    ); 145 | })} 146 |
    147 |
    148 | {items.map((it, index) => { 149 | /*eslint-disable react/no-array-index-key*/ 150 | return (); 151 | })} 152 |
    153 |
    154 | ); 155 | } 156 | } 157 | 158 | export default ReactAlloyTouch; 159 | -------------------------------------------------------------------------------- /js/index.js: -------------------------------------------------------------------------------- 1 | import ReactAlloyTouch from './ReactAlloyTouch'; 2 | import reactPull from './ReactPull'; 3 | import reactCarousel from './ReactCarousel'; 4 | import reactSwiper from './ReactSwiper'; 5 | 6 | export const ReactPull = reactPull; 7 | export const ReactCarousel = reactCarousel; 8 | export const ReactSwiper = reactSwiper; 9 | 10 | export default ReactAlloyTouch; 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-alloytouch", 3 | "version": "0.4.1", 4 | "author": { 5 | "name": "Linder Wang", 6 | "email": "linder0209@126.com", 7 | "url": "https://github.com/hopefuture" 8 | }, 9 | "description": "This is a react component for AlloyTouch.", 10 | "keywords": [ 11 | "react", 12 | "alloyTouch" 13 | ], 14 | "main": "lib/index.js", 15 | "module": "es/index.js", 16 | "jsnext:main": "es/index.js", 17 | "scripts": { 18 | "start": "gulp example", 19 | "clean": "rimraf publish/css publish/sass publish/lib publish/js publish/dist publish/es", 20 | "clean:examples": "rimraf examples-dist", 21 | "build:commonjs": "cross-env BABEL_ENV=commonjs babel js --out-dir publish/lib", 22 | "build:es": "cross-env BABEL_ENV=es babel js --out-dir publish/es", 23 | "build:umd": "webpack --progress --colors --config webpack.config.babel.js --output-filename [name].js", 24 | "build:umd:min": "webpack --progress --colors --config webpack.config.babel.js --output-filename [name].min.js --optimize-minimize", 25 | "prebuild": "npm run clean", 26 | "build": "npm run build:commonjs && npm run build:es && npm run build:umd && npm run build:umd:min", 27 | "prebuild:examples": "npm run clean:examples", 28 | "build:examples": "webpack --progress --colors --config webpack.config.example.dist.babel.js", 29 | "postbuild:examples": "gulp copy-eruda-dist", 30 | "prebuild:publish": "npm run build && gulp scss && gulp copy-publish", 31 | "build:publish": "gulp publish", 32 | "examples:publish": "npm run build:examples && git add examples-dist && git commit -m \"Update online examples\" && git subtree push --prefix=examples-dist origin gh-pages --squash && git push" 33 | }, 34 | "dependencies": { 35 | "alloytouch": "^0.2.5", 36 | "eruda": "^1.3.1", 37 | "prop-types": "^15.6.0", 38 | "react": "^16.2.0", 39 | "react-dom": "^16.2.0", 40 | "react-tap-event-plugin": "^3.0.2" 41 | }, 42 | "devDependencies": { 43 | "autoprefixer": "^7.2.1", 44 | "babel-cli": "^6.26.0", 45 | "babel-core": "^6.26.0", 46 | "babel-eslint": "^8.0.3", 47 | "babel-loader": "^7.1.2", 48 | "babel-plugin-transform-class-properties": "^6.24.1", 49 | "babel-plugin-transform-object-rest-spread": "^6.26.0", 50 | "babel-preset-env": "^1.6.1", 51 | "babel-preset-react": "^6.24.1", 52 | "cross-env": "^5.1.1", 53 | "css-loader": "^0.28.7", 54 | "eslint": "4.12.1", 55 | "eslint-loader": "^1.9.0", 56 | "eslint-plugin-react": "^7.5.1", 57 | "extract-text-webpack-plugin": "^3.0.2", 58 | "gulp": "^3.9.1", 59 | "gulp-autoprefixer": "^4.0.0", 60 | "gulp-copy": "^1.0.1", 61 | "gulp-load-plugins": "^1.5.0", 62 | "gulp-postcss": "^7.0.0", 63 | "gulp-sass": "^3.1.0", 64 | "gulp-sourcemaps": "^2.6.1", 65 | "gulp-util": "^3.0.8", 66 | "html-webpack-plugin": "^2.30.1", 67 | "node-sass": "^4.7.2", 68 | "opn": "^5.1.0", 69 | "postcss": "^6.0.14", 70 | "postcss-flexbugs-fixes": "^3.2.0", 71 | "postcss-loader": "^2.0.9", 72 | "precss": "^2.0.0", 73 | "require-dir": "^0.3.2", 74 | "sass-loader": "^6.0.6", 75 | "style-loader": "^0.19.0", 76 | "webpack": "^3.10.0", 77 | "webpack-dev-server": "^2.9.5" 78 | }, 79 | "engines": { 80 | "node": ">=6.9.1" 81 | }, 82 | "repository": { 83 | "type": "git", 84 | "url": "git+https://github.com/joy-web/react-alloytouch.git" 85 | }, 86 | "license": "MIT", 87 | "bugs": { 88 | "url": "https://github.com/joy-web/react-alloytouch/issues" 89 | }, 90 | "homepage": "https://github.com/joy-web/react-alloytouch#readme" 91 | } 92 | -------------------------------------------------------------------------------- /publish/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-alloytouch", 3 | "version": "0.4.1", 4 | "author": { 5 | "name": "Linder Wang", 6 | "email": "linder0209@126.com", 7 | "url": "https://github.com/hopefuture" 8 | }, 9 | "description": "This is a react component for AlloyTouch.", 10 | "keywords": [ 11 | "react", 12 | "alloyTouch" 13 | ], 14 | "main": "lib/index.js", 15 | "module": "es/index.js", 16 | "jsnext:main": "es/index.js", 17 | "scripts": {}, 18 | "dependencies": { 19 | "alloytouch": "^0.2.5" 20 | }, 21 | "engines": { 22 | "node": ">=6.9.1" 23 | }, 24 | "repository": { 25 | "type": "git", 26 | "url": "git+https://github.com/joy-web/react-alloytouch.git" 27 | }, 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/joy-web/react-alloytouch/issues" 31 | }, 32 | "homepage": "https://github.com/joy-web/react-alloytouch#readme" 33 | } 34 | -------------------------------------------------------------------------------- /sass/carousel.scss: -------------------------------------------------------------------------------- 1 | .carousel-wrapper { 2 | margin: 0 auto; 3 | overflow: hidden; 4 | position: relative; 5 | } 6 | 7 | .carousel-scroller { 8 | position: relative; 9 | font-size: 0; 10 | user-select: none; 11 | text-size-adjust: none; 12 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 13 | -webkit-touch-callout: none; 14 | } 15 | .carousel-scroller .swiper-panel{ 16 | float: left; 17 | } 18 | 19 | .carousel-tabs-menu{ 20 | display: flex; 21 | .carousel-tabs-item{ 22 | flex: 1; 23 | text-align: center; 24 | line-height: 2.2; 25 | bordr-bottom: 2px solid transparent; 26 | } 27 | .active{ 28 | color: #CF121B; 29 | border-bottom: 2px solid #CF121B; 30 | } 31 | } 32 | .carousel-nav { 33 | position: absolute; 34 | bottom: 6px; 35 | right: 10px; 36 | > a { 37 | display: inline-block; 38 | background-color: white; 39 | cursor: pointer; 40 | width: 6px; 41 | height: 6px; 42 | border-radius: 5px; 43 | border: 1px solid #808080; 44 | transition: all .5s ease-in; 45 | &.active { 46 | background-color: #ffd800; 47 | width: 10px; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /sass/index.scss: -------------------------------------------------------------------------------- 1 | .alloy-wrapper { 2 | position: absolute; 3 | z-index: 1; 4 | top: 0; 5 | bottom: 0; 6 | left: 0; 7 | right: 0; 8 | overflow: hidden; 9 | } 10 | 11 | .alloy-scroller { 12 | position: absolute; 13 | left: 0; 14 | right: 0; 15 | z-index: 1; 16 | user-select: none; 17 | text-size-adjust: none; 18 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 19 | -webkit-touch-callout: none; 20 | } -------------------------------------------------------------------------------- /sass/pull.scss: -------------------------------------------------------------------------------- 1 | .pull-panel { 2 | } 3 | 4 | .pull-header { 5 | position: absolute; 6 | z-index: 2; 7 | top: 0; 8 | left: 0; 9 | right: 0; 10 | } 11 | 12 | .pull-footer { 13 | position: absolute; 14 | z-index: 2; 15 | bottom: 0; 16 | left: 0; 17 | right: 0; 18 | } 19 | 20 | .pull-body { 21 | position: absolute; 22 | top: 0; 23 | bottom: 0; 24 | left: 0; 25 | right: 0; 26 | } 27 | 28 | .pull-wrapper { 29 | position: absolute; 30 | z-index: 1; 31 | top: 0; 32 | bottom: 0; 33 | left: 0; 34 | right: 0; 35 | overflow: hidden; 36 | } 37 | 38 | .pull-scroller { 39 | position: absolute; 40 | left: 0; 41 | right: 0; 42 | z-index: 1; 43 | user-select: none; 44 | text-size-adjust: none; 45 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 46 | -webkit-touch-callout: none; 47 | } 48 | 49 | .pull-refresh { 50 | position: absolute; 51 | top: -40px; 52 | left: 0; 53 | right: 0; 54 | display: block; 55 | overflow: hidden; 56 | } 57 | 58 | .pull-refresh-icon-wrapper { 59 | position: relative; 60 | width: 40px; 61 | margin: auto; 62 | text-align: center; 63 | height: 25px; 64 | } 65 | 66 | .pull-refresh-icon { 67 | position: absolute; 68 | top: 0; 69 | left: 12px; 70 | width: 14px; 71 | height: 25px; 72 | background-size: contain; 73 | background-position: center; 74 | background-repeat: no-repeat; 75 | background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIj48cGF0aCBkPSJNOS44NTQgMTkuMzU0bDYtNmEuNS41IDAgMCAwLS43MDctLjcwN0wxMCAxNy43OTNWMS41YS41LjUgMCAwIDAtMSAwdjE2LjI5M2wtNS4xNDUtNS4xNDZhLjUuNSAwIDAgMC0uNzA3LjcwOGw2IDZhLjUuNSAwIDAgMCAuNzA3IDB6Ii8+PC9zdmc+); 76 | } 77 | 78 | .pull-refresh-icon.rotate { 79 | transform: translate3d(0, 0, 0) rotate(180deg); 80 | } 81 | 82 | .pull-refresh-icon.loading { 83 | animation: pull-loading 0.8s infinite linear; 84 | background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MzIiIGhlaWdodD0iOTMyIiB2aWV3Qm94PSIwIDAgOTMyIDkzMiI+PHBhdGggZD0iTTQ2NiA5MzJjLTEyNC40NzMgMC0yNDEuNDk1LTQ4LjQ3My0zMjkuNTEzLTEzNi40ODdDNDguNDczIDcwNy40OTUgMCA1OTAuNDczIDAgNDY2YzAtODguMTM4IDI0Ljc0LTE3My45NjIgNzEuNTQ0LTI0OC4xOTIgNDUuNTA4LTcyLjE3MiAxMDkuODIzLTEzMC40OSAxODUuOTk2LTE2OC42NTJsMzkuMTM3IDc4LjEyQzIzNC43NTIgMTU4LjMgMTgyLjQ2IDIwNS43MiAxNDUuNDU1IDI2NC40MSAxMDcuNDYgMzI0LjY3IDg3LjM3NSAzOTQuMzc4IDg3LjM3NSA0NjZjMCAyMDguNzc0IDE2OS44NTMgMzc4LjYyNiAzNzguNjI2IDM3OC42MjZTODQ0LjYyNyA2NzQuNzc0IDg0NC42MjcgNDY2YzAtNzEuNjItMjAuMDg0LTE0MS4zMy01OC4wNzctMjAxLjU5LTM3LjAwOC01OC42OS04OS4zLTEwNi4xMS0xNTEuMjIzLTEzNy4xMzNsMzkuMTM3LTc4LjEyYzc2LjE3MyAzOC4xNiAxNDAuNDkgOTYuNDggMTg1Ljk5NiAxNjguNjVDOTA3LjI2MiAyOTIuMDQgOTMyLjAwMiAzNzcuODY0IDkzMi4wMDIgNDY2YzAgMTI0LjQ3My00OC40NzMgMjQxLjQ5NS0xMzYuNDg3IDMyOS41MTNDNzA3LjQ5NyA4ODMuNTI3IDU5MC40NzUgOTMyIDQ2Ni4wMDIgOTMyeiIvPjwvc3ZnPg==); 85 | } 86 | 87 | @keyframes pull-loading { 88 | from { 89 | transform: translate3d(0, 0, 0) rotate(0deg); 90 | } 91 | to { 92 | transform: translate3d(0, 0, 0) rotate(360deg); 93 | } 94 | } 95 | 96 | .pull-refresh-text { 97 | color: #666; 98 | font-size: 12px; 99 | text-align: center; 100 | } 101 | 102 | // 加载更多 103 | .pull-load-more { 104 | position: absolute; 105 | bottom: 5px; 106 | left: 0; 107 | right: 0; 108 | visibility: hidden; 109 | } 110 | 111 | .pull-load-more-icon { 112 | height: 20px; 113 | width: 20px; 114 | margin: 0 auto; 115 | color: #666; 116 | background-size: contain; 117 | background: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIj48cGF0aCBkPSJNOS44NTQgMTkuMzU0bDYtNmEuNS41IDAgMCAwLS43MDctLjcwN0wxMCAxNy43OTNWMS41YS41LjUgMCAwIDAtMSAwdjE2LjI5M2wtNS4xNDUtNS4xNDZhLjUuNSAwIDAgMC0uNzA3LjcwOGw2IDZhLjUuNSAwIDAgMCAuNzA3IDB6Ii8+PC9zdmc+) center no-repeat; 118 | transform: rotate(180deg); 119 | } 120 | 121 | .pull-load-more-icon.hide { 122 | display: none; 123 | } 124 | 125 | .pull-load-more-icon.rotate { 126 | transform: rotate(0deg); 127 | } 128 | 129 | .pull-load-more-icon.loading { 130 | display: block; 131 | background: transparent url('data:image/svg+xml;charset=utf-8,') center no-repeat; 132 | background-size: 20px 20px; 133 | animation: pull-load-more 1s step-end infinite; 134 | } 135 | 136 | .pull-load-more-text { 137 | font-size: 12px; 138 | margin-top: 5px; 139 | color: #666; 140 | text-align: center; 141 | } 142 | 143 | @keyframes pull-load-more { 144 | 0% { 145 | transform: rotate(0deg) 146 | } 147 | 8.33333333% { 148 | transform: rotate(30deg) 149 | } 150 | 16.66666667% { 151 | transform: rotate(60deg) 152 | } 153 | 25% { 154 | transform: rotate(90deg) 155 | } 156 | 33.33333333% { 157 | transform: rotate(120deg) 158 | } 159 | 41.66666667% { 160 | transform: rotate(150deg) 161 | } 162 | 50% { 163 | transform: rotate(180deg) 164 | } 165 | 58.33333333% { 166 | transform: rotate(210deg) 167 | } 168 | 66.66666667% { 169 | transform: rotate(240deg) 170 | } 171 | 75% { 172 | transform: rotate(270deg) 173 | } 174 | 83.33333333% { 175 | transform: rotate(300deg) 176 | } 177 | 91.66666667% { 178 | transform: rotate(330deg) 179 | } 180 | 100% { 181 | transform: rotate(360deg) 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /webpack.config.babel.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import webpack from 'webpack'; 3 | import precss from 'precss'; 4 | import autoprefixer from 'autoprefixer'; 5 | 6 | const webpackConfig = { 7 | devtool: 'source-map', 8 | resolve: { 9 | //自动扩展文件后缀名 10 | extensions: ['.js', '.jsx', '.scss'] 11 | }, 12 | entry: { 13 | index: ['./js/index.js'] 14 | }, 15 | externals: { 16 | react: 'react', 17 | 'react-dom': 'react-dom', 18 | 'prop-types': 'prop-types' 19 | }, 20 | output: { 21 | path: path.join(__dirname, 'publish/dist'), //打包输出目录 22 | publicPath: './', //生成文件基于上下文路径 23 | library: ['reactAlloyTouch'], 24 | libraryTarget: 'umd' 25 | }, 26 | module: { 27 | rules: [ 28 | // https://github.com/MoOx/eslint-loader 29 | { 30 | enforce: 'pre', 31 | test: /\.js$/, 32 | exclude: /node_modules/, 33 | use: 'eslint-loader' 34 | }, 35 | { 36 | test: /\.js$/, 37 | exclude: /node_modules/, 38 | use: 'babel-loader', 39 | } 40 | ], 41 | }, 42 | 43 | plugins: [ 44 | // http://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin 45 | //用来优化生成的代码 chunk,合并相同的代码 46 | new webpack.optimize.AggressiveMergingPlugin(), 47 | //用来保证编译过程不出错 48 | new webpack.NoEmitOnErrorsPlugin(), 49 | new webpack.DefinePlugin({ 50 | 'process.env': { 51 | NODE_ENV: JSON.stringify('production') 52 | } 53 | }), 54 | new webpack.LoaderOptionsPlugin({ 55 | options: { 56 | // eslint 配置 57 | eslint: { 58 | emitError: true, // 验证失败,终止 59 | configFile: '.eslintrc' 60 | }, 61 | postcss () { 62 | return { 63 | defaults: [precss, autoprefixer], 64 | cleaner: [autoprefixer({ 65 | flexbox: 'no-2009', 66 | browsers: ['Chrome >= 35', 'Firefox >= 38', 67 | 'Android >= 4.3', 'iOS >=8', 'Safari >= 8'] 68 | })] 69 | }; 70 | }, 71 | } 72 | }) 73 | ] 74 | }; 75 | 76 | module.exports = webpackConfig; 77 | -------------------------------------------------------------------------------- /webpack.config.example.babel.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import webpack from 'webpack'; 3 | import HtmlwebpackPlugin from 'html-webpack-plugin'; 4 | import precss from 'precss'; 5 | import autoprefixer from 'autoprefixer'; 6 | 7 | const ip = '0.0.0.0'; 8 | const port = 9090; 9 | const hotDevServer = 'webpack/hot/dev-server'; 10 | // https://github.com/webpack/webpack-dev-server 11 | const webpackDevServer = `webpack-dev-server/client?http://${ip}:${port}`; 12 | 13 | const appPath = path.resolve(__dirname, 'examples'); 14 | 15 | const webpackConfig = { 16 | cache: true, 17 | devtool: 'source-map', //生成 source map文件 18 | stats: { 19 | colors: true, 20 | reasons: true 21 | }, 22 | devServer: { 23 | //指定根目录路径,比如访问 eruda.min.js 时,只需 http://localhost:9090/eruda.min.js 即可 24 | contentBase: './examples', 25 | historyApiFallback: true, 26 | hot: true, 27 | stats: { 28 | colors: true 29 | }, 30 | watchOptions: { 31 | aggregateTimeout: 300, 32 | poll: 1000 33 | }, 34 | quiet: false, // 设为true,不把任何信息输出到控制台 35 | open: true, 36 | }, 37 | resolve: { 38 | //自动扩展文件后缀名 39 | extensions: ['.js', '.jsx', '.scss'] 40 | }, 41 | 42 | // 入口文件 让webpack用哪个文件作为项目的入口 43 | entry: { 44 | index: ['./examples/index.js', webpackDevServer, hotDevServer], 45 | simple: ['./examples/simple.js', webpackDevServer, hotDevServer], 46 | pull: ['./examples/pull.js', webpackDevServer, hotDevServer], 47 | 'header-footer': ['./examples/header-footer.js', webpackDevServer, hotDevServer], 48 | carousel: ['./examples/carousel.js', webpackDevServer, hotDevServer], 49 | 'pull-carousel': ['./examples/pull-carousel.js', webpackDevServer, hotDevServer], 50 | 'pull-carousel2': ['./examples/pull-carousel2.js', webpackDevServer, hotDevServer], 51 | 'tabs-carousel': ['./examples/tabs-carousel.js', webpackDevServer, hotDevServer] 52 | }, 53 | 54 | // 出口 让webpack把处理完成的文件放在哪里 55 | output: { 56 | path: path.resolve(__dirname, 'examples/dist'), //打包输出目录 57 | filename: '[name].[hash].bundle.js', //文件名称 58 | publicPath: './' //资源路径 59 | }, 60 | 61 | module: { 62 | rules: [ 63 | // https://github.com/MoOx/eslint-loader 64 | { 65 | enforce: 'pre', 66 | test: /\.js$/, 67 | exclude: /node_modules/, 68 | use: 'eslint-loader' 69 | }, 70 | { 71 | test: /\.js$/, 72 | exclude: /node_modules/, 73 | use: 'babel-loader', 74 | }, 75 | { 76 | test: /\.scss$/, 77 | use: ['style-loader', 'css-loader', 'postcss-loader?pack=cleaner', 'sass-loader?outputStyle=expanded'], 78 | } 79 | ] 80 | }, 81 | 82 | plugins: [ 83 | new webpack.HotModuleReplacementPlugin(), // 热部署替换模块 84 | new webpack.NoEmitOnErrorsPlugin(), 85 | new webpack.LoaderOptionsPlugin({ 86 | debug: true, 87 | options: { 88 | // eslint 配置 89 | eslint: { 90 | emitError: true, // 验证失败,终止 91 | configFile: '.eslintrc' 92 | }, 93 | postcss () { 94 | return { 95 | defaults: [precss, autoprefixer], 96 | cleaner: [autoprefixer({ 97 | flexbox: 'no-2009', 98 | browsers: ['Chrome >= 35', 'Firefox >= 38', 99 | 'Android >= 4.3', 'iOS >=8', 'Safari >= 8'] 100 | })] 101 | }; 102 | }, 103 | } 104 | }) 105 | ] 106 | }; 107 | 108 | //创建 HtmlWebpackPlugin 的实例 109 | // https://www.npmjs.com/package/html-webpack-plugin 110 | const {entry} = webpackConfig; 111 | 112 | // 为 HtmlwebpackPlugin 设置配置项,与 entry 键对应,根据需要设置其参数值 113 | const htmlwebpackPluginConfig = { 114 | index: { 115 | title: 'React AlloyTouch 例子' 116 | }, 117 | simple: { 118 | title: 'React AlloyTouch 简单例子' 119 | }, 120 | pull: { 121 | title: '下拉刷新,上拉加载更多' 122 | }, 123 | 'header-footer': { 124 | title: '带头部和底部的下拉刷新,上拉加载更多' 125 | }, 126 | carousel: { 127 | title: '轮播' 128 | }, 129 | 'pull-carousel': { 130 | title: '下拉刷新中包含轮播图' 131 | }, 132 | 'pull-carousel2': { 133 | title: '下拉刷新中包含轮播图2' 134 | }, 135 | 'tabs-carousel': { 136 | title: '自定义轮播内容+tabs' 137 | } 138 | }; 139 | 140 | for (const key in entry) { 141 | if (entry.hasOwnProperty(key) && key !== 'vendors') { 142 | webpackConfig.plugins.push( 143 | new HtmlwebpackPlugin({ 144 | title: htmlwebpackPluginConfig[key].title, 145 | template: path.resolve(appPath, 'templates/layout.html'), 146 | filename: `${key}.html`, 147 | //chunks这个参数告诉插件要引用entry里面的哪几个入口 148 | chunks: [key, 'vendors'], 149 | //要把script插入到标签里 150 | inject: 'body' 151 | }) 152 | ); 153 | } 154 | } 155 | 156 | export default { 157 | webpackConfig, 158 | ip, 159 | port 160 | }; 161 | -------------------------------------------------------------------------------- /webpack.config.example.dist.babel.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import webpack from 'webpack'; 3 | import ExtractTextPlugin from 'extract-text-webpack-plugin'; 4 | import HtmlwebpackPlugin from 'html-webpack-plugin'; 5 | import precss from 'precss'; 6 | import autoprefixer from 'autoprefixer'; 7 | 8 | const appPath = path.resolve(__dirname, 'examples'); 9 | 10 | // multiple extract instances 11 | const extractSass = new ExtractTextPlugin({ 12 | filename: 'css/[name].[chunkhash].css', 13 | disable: false, 14 | allChunks: true 15 | }); 16 | 17 | const webpackConfig = { 18 | devtool: 'source-map', //生成 source map文件 19 | resolve: { 20 | //自动扩展文件后缀名 21 | extensions: ['.js', '.jsx', '.scss'] 22 | }, 23 | 24 | // 入口文件 让webpack用哪个文件作为项目的入口 25 | entry: { 26 | index: ['./examples/index.js'], 27 | simple: ['./examples/simple.js'], 28 | pull: ['./examples/pull.js'], 29 | 'header-footer': ['./examples/header-footer.js'], 30 | carousel: ['./examples/carousel.js'], 31 | 'pull-carousel': ['./examples/pull-carousel.js'], 32 | 'pull-carousel2': ['./examples/pull-carousel2.js'], 33 | 'tabs-carousel': ['./examples/tabs-carousel.js'] 34 | }, 35 | 36 | // 出口 让webpack把处理完成的文件放在哪里 37 | output: { 38 | path: path.resolve(__dirname, 'examples-dist'), //打包输出目录 39 | filename: '[name].[hash].bundle.js', //文件名称 40 | publicPath: './' //资源路径 41 | }, 42 | 43 | module: { 44 | rules: [ 45 | { 46 | test: /\.js$/, 47 | exclude: /node_modules/, 48 | use: 'babel-loader', 49 | }, 50 | { 51 | test: /\.scss$/, 52 | use: ExtractTextPlugin.extract({ 53 | fallback: 'style-loader', 54 | use: ['css-loader', 'postcss-loader?pack=cleaner', 'sass-loader?outputStyle=expanded'], 55 | publicPath: '/dist' 56 | }) 57 | } 58 | ], 59 | }, 60 | 61 | plugins: [ 62 | // http://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin 63 | //用来优化生成的代码 chunk,合并相同的代码 64 | new webpack.optimize.AggressiveMergingPlugin(), 65 | //用来保证编译过程不出错 66 | new webpack.NoEmitOnErrorsPlugin(), 67 | extractSass, 68 | //http://dev.topheman.com/make-your-react-production-minified-version-with-webpack/ 69 | new webpack.DefinePlugin({ 70 | 'process.env': { 71 | NODE_ENV: JSON.stringify('production') 72 | } 73 | }), 74 | // http://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin 75 | // 相当于命令参数 --optimize-minimize 76 | new webpack.optimize.UglifyJsPlugin({ 77 | sourceMap: true, 78 | compress: { 79 | warnings: true 80 | }, 81 | mangle: { 82 | except: [] // 设置不混淆变量名 83 | } 84 | }), 85 | new webpack.LoaderOptionsPlugin({ 86 | minimize: true, 87 | options: { 88 | postcss () { 89 | return { 90 | defaults: [precss, autoprefixer], 91 | cleaner: [autoprefixer({ 92 | flexbox: 'no-2009', 93 | browsers: ['Chrome >= 35', 'Firefox >= 38', 94 | 'Android >= 4.3', 'iOS >=8', 'Safari >= 8'] 95 | })] 96 | }; 97 | }, 98 | } 99 | }) 100 | ] 101 | }; 102 | 103 | //创建 HtmlWebpackPlugin 的实例 104 | // https://www.npmjs.com/package/html-webpack-plugin 105 | const {entry} = webpackConfig; 106 | 107 | // 为 HtmlwebpackPlugin 设置配置项,与 entry 键对应,根据需要设置其参数值 108 | const htmlwebpackPluginConfig = { 109 | index: { 110 | title: 'React AlloyTouch 例子' 111 | }, 112 | simple: { 113 | title: 'React AlloyTouch 简单例子' 114 | }, 115 | pull: { 116 | title: '下拉刷新,上拉加载更多' 117 | }, 118 | 'header-footer': { 119 | title: '带头部和底部的下拉刷新,上拉加载更多' 120 | }, 121 | carousel: { 122 | title: '轮播' 123 | }, 124 | 'pull-carousel': { 125 | title: '下拉刷新中包含轮播图' 126 | }, 127 | 'pull-carousel2': { 128 | title: '下拉刷新中包含轮播图2' 129 | }, 130 | 'tabs-carousel': { 131 | title: '自定义轮播内容+tabs' 132 | } 133 | }; 134 | 135 | for (const key in entry) { 136 | if (entry.hasOwnProperty(key) && key !== 'vendors') { 137 | webpackConfig.plugins.push( 138 | new HtmlwebpackPlugin({ 139 | title: htmlwebpackPluginConfig[key].title, 140 | template: path.resolve(appPath, 'templates/layout.html'), 141 | filename: `${key}.html`, 142 | //chunks这个参数告诉插件要引用entry里面的哪几个入口 143 | chunks: [key, 'vendors'], 144 | //要把script插入到标签里 145 | inject: 'body' 146 | }) 147 | ); 148 | } 149 | } 150 | 151 | export default webpackConfig; 152 | --------------------------------------------------------------------------------