├── demo ├── main.less ├── states │ ├── indicator │ │ ├── template.html │ │ └── route.js │ ├── popup │ │ ├── route.js │ │ └── template.html │ ├── app.js │ ├── index │ │ ├── route.js │ │ └── template.html │ ├── datetime-picker │ │ ├── route.js │ │ └── template.html │ ├── calendar │ │ ├── route.js │ │ └── template.html │ ├── toast │ │ ├── route.js │ │ └── template.html │ ├── pullToRefresh │ │ ├── route.js │ │ └── template.html │ ├── preloader │ │ ├── route.js │ │ └── template.html │ ├── actions │ │ ├── template.html │ │ └── route.js │ ├── picker │ │ ├── template.html │ │ └── route.js │ ├── alert │ │ ├── route.js │ │ └── template.html │ └── infiniteScroll │ │ ├── template.html │ │ └── route.js └── main.js ├── src ├── transition │ └── transition.js ├── component │ ├── indicator │ │ ├── indicator.html │ │ └── indicator.js │ ├── toast │ │ ├── toast.html │ │ └── toast.js │ ├── datetime-picker │ │ ├── datetime-picker.html │ │ └── datetime-picker.js │ ├── modal │ │ ├── modal.html │ │ └── modal.js │ ├── calendar │ │ ├── calendar-month.html │ │ ├── calendar.html │ │ ├── calendar-month.js │ │ └── calendar.js │ ├── preloader │ │ ├── preloader.html │ │ └── preloader.js │ ├── picker │ │ ├── picker-col.html │ │ ├── picker.html │ │ ├── picker.js │ │ └── picker-col.js │ ├── alert │ │ ├── alert.html │ │ └── alert.js │ └── actions │ │ ├── actions.html │ │ └── actions.js ├── index.js ├── directive │ ├── popup.js │ ├── infiniteScroll.js │ └── pullToRefresh.js └── util │ ├── device.js │ ├── zepto-adapter.js │ └── scroller.js ├── public └── demo │ ├── styles.95597131.css │ ├── layout.html │ ├── 6.48d9d228.js │ ├── 10.fc990400.js │ ├── 3.a414582e.js │ ├── 11.fd1b64bc.js │ ├── 5.3f026e59.js │ ├── 12.20624280.js │ ├── 7.f9f16e76.js │ ├── 2.ef22dae4.js │ ├── 8.b7cbe94c.js │ ├── 4.54186de6.js │ ├── 9.c5142e7c.js │ └── 1.9e649490.js ├── env.js ├── .gitignore ├── tsconfig.json ├── server ├── lib │ ├── vueServerFactory.ts │ ├── vueServerFactory.js │ └── vueServerFactory.js.map ├── webapp │ └── routes │ │ ├── index.js.map │ │ ├── picker.js.map │ │ ├── index.js │ │ ├── picker.js │ │ ├── index.ts │ │ └── picker.ts ├── typings │ ├── tsd.d.ts │ ├── cookie-parser │ │ └── cookie-parser.d.ts │ ├── method-override │ │ └── method-override.d.ts │ ├── errorhandler │ │ └── errorhandler.d.ts │ ├── request-promise │ │ └── request-promise.d.ts │ ├── serve-static │ │ └── serve-static.d.ts │ ├── body-parser │ │ └── body-parser.d.ts │ └── request │ │ └── request.d.ts └── views │ ├── dist │ └── layout.html │ └── dev │ └── layout.html ├── README.md ├── webpack.dev.config.js ├── webpack.base.config.js ├── package.json ├── tsd.json ├── webpack.prod.config.js ├── server.js ├── server.ts └── server.js.map /demo/main.less: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/transition/transition.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/demo/styles.95597131.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /env.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var env = { 3 | NODE_ENV : 'test', 4 | PORT : '5666', 5 | } 6 | 7 | exports.config = env; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | bower_components 3 | node_modules 4 | env.js 5 | .DS_Store 6 | Thumbs.db 7 | npm-debug.log 8 | logs 9 | #public/demo -------------------------------------------------------------------------------- /src/component/indicator/indicator.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
-------------------------------------------------------------------------------- /src/component/toast/toast.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/component/datetime-picker/datetime-picker.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "sourceMap": true, 5 | "target": "es5", 6 | "moduleResolution": "node" 7 | }, 8 | "files": [ 9 | "./server/typings/tsd.d.ts", 10 | "./server.ts" 11 | ] 12 | } -------------------------------------------------------------------------------- /server/lib/vueServerFactory.ts: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | import {config} from '../../env' 3 | let vueServer = require('vue-server') 4 | let Vue = new vueServer.renderer(); 5 | Vue.config.debug = !(config.NODE_ENV == 'product'); 6 | Vue.config.silent = (config.NODE_ENV == 'product'); 7 | 8 | 9 | export default Vue; -------------------------------------------------------------------------------- /src/component/modal/modal.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 9 |
-------------------------------------------------------------------------------- /server/lib/vueServerFactory.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var env_1 = require('../../env'); 3 | var vueServer = require('vue-server'); 4 | var Vue = new vueServer.renderer(); 5 | Vue.config.debug = !(env_1.config.NODE_ENV == 'product'); 6 | Vue.config.silent = (env_1.config.NODE_ENV == 'product'); 7 | Object.defineProperty(exports, "__esModule", { value: true }); 8 | exports.default = Vue; 9 | //# sourceMappingURL=vueServerFactory.js.map -------------------------------------------------------------------------------- /src/component/calendar/calendar-month.html: -------------------------------------------------------------------------------- 1 |
3 | 4 | 5 |
6 |
9 | {{day.dayNumber}} 10 |
11 |
12 |
-------------------------------------------------------------------------------- /server/lib/vueServerFactory.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"vueServerFactory.js","sourceRoot":"","sources":["vueServerFactory.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;AACZ,oBAAqB,WACrB,CAAC,CAD+B;AAChC,IAAI,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;AACrC,IAAI,GAAG,GAAG,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC;AACnC,GAAG,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,YAAM,CAAC,QAAQ,IAAI,SAAS,CAAC,CAAC;AACnD,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,YAAM,CAAC,QAAQ,IAAI,SAAS,CAAC,CAAC;AAGnD;kBAAe,GAAG,CAAC"} -------------------------------------------------------------------------------- /src/component/preloader/preloader.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/webapp/routes/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAKZ,eAAsB,GAAG,EAAE,GAAG;IAC1B,UAAU;IACV,EAAE;IACF,uBAAuB;IACvB,wBAAwB;IACxB,EAAE;IACF,iBAAiB;IACjB,sBAAsB;IACtB,qBAAqB;IACrB,qBAAqB;IACrB,qCAAqC;IACrC,0BAA0B;IAC1B,SAAS;IACT,cAAc;IACd,8BAA8B;IAC9B,mCAAmC;IACnC,oCAAoC;IACpC,QAAQ;IACR,MAAM;IACN,kDAAkD;IAClD,MAAM;IACN,MAAM;IAEN,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAEzB,CAAC;AAzBe,aAAK,QAyBpB,CAAA"} -------------------------------------------------------------------------------- /server/webapp/routes/picker.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"picker.js","sourceRoot":"","sources":["picker.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAKZ,eAAsB,GAAG,EAAE,GAAG;IAC1B,UAAU;IACV,EAAE;IACF,uBAAuB;IACvB,wBAAwB;IACxB,EAAE;IACF,iBAAiB;IACjB,sBAAsB;IACtB,qBAAqB;IACrB,qBAAqB;IACrB,qCAAqC;IACrC,0BAA0B;IAC1B,SAAS;IACT,cAAc;IACd,8BAA8B;IAC9B,mCAAmC;IACnC,oCAAoC;IACpC,QAAQ;IACR,MAAM;IACN,kDAAkD;IAClD,MAAM;IACN,MAAM;IAEN,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAEzB,CAAC;AAzBe,aAAK,QAyBpB,CAAA"} -------------------------------------------------------------------------------- /demo/states/indicator/template.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |

indicator

6 |
7 | 8 | 9 |
10 | 11 | 显示 12 |
13 |
14 | -------------------------------------------------------------------------------- /src/component/indicator/indicator.js: -------------------------------------------------------------------------------- 1 | import tpl from './indicator.html' 2 | export default { 3 | template : tpl, 4 | props: { 5 | option: { 6 | type: Object, 7 | default: { 8 | } 9 | } 10 | }, 11 | data(){ 12 | return { 13 | show : false 14 | } 15 | }, 16 | methods: { 17 | 18 | }, 19 | init(){ 20 | 21 | }, 22 | ready(){ 23 | this.show = true; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /server/typings/tsd.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | /// 5 | /// 6 | /// 7 | /// 8 | /// 9 | /// 10 | -------------------------------------------------------------------------------- /server/typings/cookie-parser/cookie-parser.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for cookie-parser v1.3.4 2 | // Project: https://github.com/expressjs/cookie-parser 3 | // Definitions by: Santi Albo 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /// 7 | 8 | declare module "cookie-parser" { 9 | import express = require('express'); 10 | function e(secret?: string, options?: any): express.RequestHandler; 11 | namespace e{} 12 | export = e; 13 | } -------------------------------------------------------------------------------- /src/component/picker/picker-col.html: -------------------------------------------------------------------------------- 1 |
2 | 10 | 13 |
-------------------------------------------------------------------------------- /demo/states/popup/route.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import Vue from 'vue' 3 | import Tpl from './template.html' 4 | 5 | let Index = Vue.extend({ 6 | //replace : true, //必须注释掉 不然动画失效 7 | template : Tpl, 8 | ready : function(){ 9 | 10 | }, 11 | data : ()=>{ 12 | return { 13 | 14 | } 15 | }, 16 | methods: { 17 | 18 | }, 19 | computed : { 20 | 21 | }, 22 | route : { 23 | data : function(transition){ 24 | transition.next() 25 | } 26 | } 27 | }) 28 | 29 | export default Index -------------------------------------------------------------------------------- /src/component/alert/alert.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/component/preloader/preloader.js: -------------------------------------------------------------------------------- 1 | import tpl from './preloader.html' 2 | export default { 3 | template : tpl, 4 | props: { 5 | option: { 6 | type: Object, 7 | default: { 8 | title : '加载中' 9 | } 10 | } 11 | }, 12 | data(){ 13 | return { 14 | top : 0, 15 | show : false 16 | } 17 | }, 18 | methods: { 19 | 20 | }, 21 | init(){ 22 | 23 | }, 24 | ready(){ 25 | this.top = (- Math.round($(this.$el).outerHeight() / 2) + 'px'); 26 | this.show = true; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## msui的vue版 2 | ##### 可以说是大部分抄袭了msui的代码 只是改成vue组件写法了,只是一个练习的项目,如果有问题请联系我下架. 3 | 4 | ##组件 5 | ##### 标题栏 6 | ##### 工具栏 7 | ##### 标签页 8 | ##### 对话框 9 | ##### 加载指示器 10 | ##### toast 11 | ##### popup 12 | ##### 日历 13 | ##### 操作表 14 | ##### picker 15 | ##### 日期时间 16 | ##### 下拉刷新 17 | ##### 无限滚动 18 | 19 | 20 | 21 | # demo 22 | ## 详细使用请看demo -------------------------------------------------------------------------------- /demo/states/app.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | let App = Vue.extend({ 4 | events: { 5 | //消息通知 6 | // admin_msg_notify : 'showMsgToast' 7 | }, 8 | methods : { 9 | // showMsgToast(_this){ 10 | // $('.toast.bottom').unbind(); 11 | // $.toast('有消息,点击进入聊天!','2e3','bottom') 12 | // setTimeout(()=>{ 13 | // $('.toast.bottom').on('click',()=>{ 14 | // _this.$router.go('/webapp/chat'); 15 | // //$('.toast.bottom').hide(); 16 | // }) 17 | // },100) 18 | // } 19 | } 20 | }); 21 | 22 | export default App -------------------------------------------------------------------------------- /demo/states/index/route.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import Vue from 'vue' 3 | import Tpl from './template.html' 4 | 5 | let Index = Vue.extend({ 6 | //replace : true, //必须注释掉 不然动画失效 7 | template : Tpl, 8 | ready : function(){ 9 | 10 | }, 11 | data : ()=>{ 12 | return { 13 | 14 | } 15 | }, 16 | methods: { 17 | goRoute(path){ 18 | this.$router.go(path); 19 | } 20 | }, 21 | computed : { 22 | 23 | }, 24 | route : { 25 | data : function(transition){ 26 | transition.next() 27 | } 28 | } 29 | }) 30 | 31 | export default Index -------------------------------------------------------------------------------- /demo/states/datetime-picker/route.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import Vue from 'vue' 3 | import Tpl from './template.html' 4 | 5 | let Index = Vue.extend({ 6 | //replace : true, //必须注释掉 不然动画失效 7 | template : Tpl, 8 | ready : function(){ 9 | 10 | }, 11 | data : ()=>{ 12 | return { 13 | isOpenDatetimePicker : false, 14 | datetime : '2016-04-08 09:00:00' 15 | } 16 | }, 17 | methods: { 18 | 19 | }, 20 | computed : { 21 | 22 | }, 23 | route : { 24 | data : function(transition){ 25 | transition.next() 26 | } 27 | } 28 | }) 29 | 30 | export default Index -------------------------------------------------------------------------------- /webpack.dev.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack') 2 | var config = require('./webpack.base.config') 3 | var HtmlWebpackPlugin = require('html-webpack-plugin') 4 | var ExtractTextPlugin = require("extract-text-webpack-plugin"); 5 | 6 | config.devtool = 'source-map' 7 | 8 | config.output.filename = '[name].js' 9 | config.output.chunkFilename = '[id].[hash:8].js' 10 | 11 | 12 | config.plugins = (config.plugins || []).concat([ 13 | //开发时css不打包到一个文件中,方便调试 14 | new ExtractTextPlugin("styles.css",{allChunks: true}), 15 | new webpack.optimize.UglifyJsPlugin({ 16 | compressor: { 17 | warnings: false 18 | } 19 | }) 20 | ]) 21 | 22 | module.exports = config -------------------------------------------------------------------------------- /src/component/actions/actions.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 12 |
13 |
-------------------------------------------------------------------------------- /public/demo/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | vue-msui 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /demo/states/calendar/route.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import Vue from 'vue' 3 | import Tpl from './template.html' 4 | 5 | let Index = Vue.extend({ 6 | //replace : true, //必须注释掉 不然动画失效 7 | template : Tpl, 8 | ready : function(){ 9 | 10 | }, 11 | data : ()=>{ 12 | return { 13 | isOpenCalendar : false, 14 | calendarOptions : { 15 | values : ['2016-01-01'] 16 | } 17 | } 18 | }, 19 | methods: { 20 | change(date){ 21 | console.log(date) 22 | } 23 | }, 24 | computed : { 25 | 26 | }, 27 | route : { 28 | data : function(transition){ 29 | transition.next() 30 | } 31 | } 32 | }) 33 | 34 | export default Index -------------------------------------------------------------------------------- /server/webapp/routes/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | function index(req, res) { 3 | // var vm; 4 | // 5 | // let tagClasses = [], 6 | // contentList = []; 7 | // 8 | // vm = new Vue({ 9 | // replace: false, 10 | // template: tpl, 11 | // components : { 12 | // articleItem : articleItem, 13 | // qaItem : qaItem 14 | // }, 15 | // data: { 16 | // id : req.params.id, 17 | // tagClasses : tagClasses, 18 | // contentList : contentList 19 | // } 20 | // }); 21 | // vm.$on('vueServer.htmlReady', function (html) { 22 | // 23 | // }); 24 | res.render('layout'); 25 | } 26 | exports.index = index; 27 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /server/webapp/routes/picker.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | function index(req, res) { 3 | // var vm; 4 | // 5 | // let tagClasses = [], 6 | // contentList = []; 7 | // 8 | // vm = new Vue({ 9 | // replace: false, 10 | // template: tpl, 11 | // components : { 12 | // articleItem : articleItem, 13 | // qaItem : qaItem 14 | // }, 15 | // data: { 16 | // id : req.params.id, 17 | // tagClasses : tagClasses, 18 | // contentList : contentList 19 | // } 20 | // }); 21 | // vm.$on('vueServer.htmlReady', function (html) { 22 | // 23 | // }); 24 | res.render('layout'); 25 | } 26 | exports.index = index; 27 | //# sourceMappingURL=picker.js.map -------------------------------------------------------------------------------- /src/component/picker/picker.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |

{{headerText}}

6 |
7 |
8 | 9 |
10 | 15 |
16 |
17 |
18 |
-------------------------------------------------------------------------------- /server/views/dist/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | vue-msui 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /server/webapp/routes/index.ts: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | import * as fs from 'fs' 3 | import {config} from '../../../env' 4 | import Vue from '../../lib/vueServerFactory' 5 | 6 | export function index(req, res) { 7 | // var vm; 8 | // 9 | // let tagClasses = [], 10 | // contentList = []; 11 | // 12 | // vm = new Vue({ 13 | // replace: false, 14 | // template: tpl, 15 | // components : { 16 | // articleItem : articleItem, 17 | // qaItem : qaItem 18 | // }, 19 | // data: { 20 | // id : req.params.id, 21 | // tagClasses : tagClasses, 22 | // contentList : contentList 23 | // } 24 | // }); 25 | // vm.$on('vueServer.htmlReady', function (html) { 26 | // 27 | // }); 28 | 29 | res.render('layout'); 30 | 31 | } -------------------------------------------------------------------------------- /demo/states/toast/route.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import Vue from 'vue' 3 | import Tpl from './template.html' 4 | 5 | let Index = Vue.extend({ 6 | //replace : true, //必须注释掉 不然动画失效 7 | template : Tpl, 8 | ready : function(){ 9 | 10 | }, 11 | data : ()=>{ 12 | return { 13 | text : '请输入' 14 | } 15 | }, 16 | methods: { 17 | addToast(){ 18 | let text = this.text; 19 | this.$refs.modal.add({ 20 | type : 'toast', 21 | option : { 22 | content: text, 23 | } 24 | }) 25 | } 26 | }, 27 | computed : { 28 | 29 | }, 30 | route : { 31 | data : function(transition){ 32 | transition.next() 33 | } 34 | } 35 | }) 36 | 37 | export default Index -------------------------------------------------------------------------------- /server/webapp/routes/picker.ts: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | import * as fs from 'fs' 3 | import {config} from '../../../env' 4 | import Vue from '../../lib/vueServerFactory' 5 | 6 | export function index(req, res) { 7 | // var vm; 8 | // 9 | // let tagClasses = [], 10 | // contentList = []; 11 | // 12 | // vm = new Vue({ 13 | // replace: false, 14 | // template: tpl, 15 | // components : { 16 | // articleItem : articleItem, 17 | // qaItem : qaItem 18 | // }, 19 | // data: { 20 | // id : req.params.id, 21 | // tagClasses : tagClasses, 22 | // contentList : contentList 23 | // } 24 | // }); 25 | // vm.$on('vueServer.htmlReady', function (html) { 26 | // 27 | // }); 28 | 29 | res.render('layout'); 30 | 31 | } -------------------------------------------------------------------------------- /public/demo/6.48d9d228.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([6],{44:function(t,n,e){"use strict";function a(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(n,"__esModule",{value:!0});var i=e(2),o=a(i),c=e(45),d=a(c),r=o["default"].extend({template:d["default"],ready:function(){},data:function(){return{}},methods:{indicator:function(){var t=this;this.$refs.modal.add({type:"indicator"}),setTimeout(function(){t.$refs.modal.hideIndicator()},2e3)}},computed:{},route:{data:function(t){t.next()}}});n["default"]=r},45:function(t,n){t.exports='
\n \n
\n \n

indicator

\n
\n\n \n
\n \n 显示\n
\n
\n'}}); -------------------------------------------------------------------------------- /demo/states/indicator/route.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import Vue from 'vue' 3 | import Tpl from './template.html' 4 | 5 | let Index = Vue.extend({ 6 | //replace : true, //必须注释掉 不然动画失效 7 | template : Tpl, 8 | ready : function(){ 9 | 10 | }, 11 | data : ()=>{ 12 | return { 13 | 14 | } 15 | }, 16 | methods: { 17 | indicator(){ 18 | this.$refs.modal.add({ 19 | type : 'indicator', 20 | // option : { 21 | // 22 | // }, 23 | // overlay : true //显示遮罩层 24 | }) 25 | setTimeout(()=>{ 26 | this.$refs.modal.hideIndicator() 27 | },2e3) 28 | }, 29 | }, 30 | computed : { 31 | 32 | }, 33 | route : { 34 | data : function(transition){ 35 | transition.next() 36 | } 37 | } 38 | }) 39 | 40 | export default Index -------------------------------------------------------------------------------- /src/component/actions/actions.js: -------------------------------------------------------------------------------- 1 | import tpl from './actions.html' 2 | export default { 3 | template : tpl, 4 | props: { 5 | option: { 6 | type: Array, 7 | default: [ 8 | 9 | ] 10 | } 11 | }, 12 | data(){ 13 | return { 14 | show : false 15 | } 16 | }, 17 | methods: { 18 | ok(button){ 19 | button.onClick(); 20 | this.show = false; 21 | setTimeout(()=>{ 22 | this.$dispatch('modal-remove',this.option) 23 | },300) 24 | }, 25 | cancel(){ 26 | this.show = false; 27 | setTimeout(()=>{ 28 | this.$dispatch('modal-remove',this.option) 29 | },300) 30 | } 31 | }, 32 | init(){ 33 | 34 | }, 35 | ready(){ 36 | setTimeout(()=>{ 37 | this.show = true; 38 | },100) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /demo/states/pullToRefresh/route.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import Vue from 'vue' 3 | import Tpl from './template.html' 4 | 5 | let Index = Vue.extend({ 6 | //replace : true, //必须注释掉 不然动画失效 7 | template : Tpl, 8 | ready : function(){ 9 | 10 | }, 11 | data : ()=>{ 12 | return { 13 | updateTime : new Date().getTime() 14 | } 15 | }, 16 | methods: { 17 | refresh(){ 18 | return ()=>{ 19 | return new Promise((resolve,reject)=>{ 20 | setTimeout(()=>{ 21 | this.updateTime = new Date().getTime() 22 | resolve('刷新了') 23 | },3e3) 24 | }) 25 | } 26 | } 27 | }, 28 | computed : { 29 | 30 | }, 31 | route : { 32 | data : function(transition){ 33 | transition.next() 34 | } 35 | } 36 | }) 37 | 38 | export default Index -------------------------------------------------------------------------------- /server/typings/method-override/method-override.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for method-override 2 | // Project: https://github.com/expressjs/method-override 3 | // Definitions by: Santi Albo 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /// 7 | 8 | declare module Express { 9 | export interface Request { 10 | originalMethod?: string; 11 | } 12 | } 13 | 14 | declare module "method-override" { 15 | import express = require('express'); 16 | 17 | namespace e { 18 | export interface MethodOverrideOptions { 19 | methods: string[]; 20 | } 21 | } 22 | 23 | function e(getter?: string, options?: e.MethodOverrideOptions): express.RequestHandler; 24 | function e(getter?: (req: express.Request, res: express.Response) => string, options?: e.MethodOverrideOptions): express.RequestHandler; 25 | 26 | export = e; 27 | } -------------------------------------------------------------------------------- /webpack.base.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | var ExtractTextPlugin = require("extract-text-webpack-plugin"); 4 | 5 | module.exports = { 6 | 7 | // devtool: 'source-map', 8 | 9 | entry: { 10 | demo:"./demo/main", 11 | }, 12 | 13 | output: { 14 | path: __dirname + '/public/demo', 15 | filename: '[name].[chunkhash:8].js', 16 | chunkFilename: '[id].[chunkhash:8].js', 17 | publicPath: '/demo/' 18 | }, 19 | 20 | module: { 21 | loaders: [ 22 | { test: /\.js$/, 23 | exclude: /node_modules/, 24 | loader: 'babel' , 25 | query: { 26 | cacheDirectory: true, 27 | presets: ['es2015','stage-3'] 28 | } 29 | }, 30 | { test: /\.html$/, loader: 'raw' }, 31 | // { test: /\.vue$/, loader: 'vue' }, 32 | { test: /\.less$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader!less-loader") } 33 | ] 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /server/views/dev/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | vue-msui 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /demo/states/preloader/route.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import Vue from 'vue' 3 | import Tpl from './template.html' 4 | 5 | let Index = Vue.extend({ 6 | //replace : true, //必须注释掉 不然动画失效 7 | template : Tpl, 8 | ready : function(){ 9 | 10 | }, 11 | data : ()=>{ 12 | return { 13 | title : '加载中' 14 | } 15 | }, 16 | methods: { 17 | preloader(){ 18 | this.$refs.modal.add({ 19 | type : 'preloader', 20 | option : { 21 | title : this.title, 22 | }, 23 | overlay : true //显示遮罩层 24 | }) 25 | setTimeout(()=>{ 26 | this.$refs.modal.hidePreloader() 27 | },2e3) 28 | }, 29 | }, 30 | computed : { 31 | 32 | }, 33 | route : { 34 | data : function(transition){ 35 | transition.next() 36 | } 37 | } 38 | }) 39 | 40 | export default Index -------------------------------------------------------------------------------- /demo/states/popup/template.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |

popup

6 |
7 | 8 | 9 |
10 | popup-about 11 | 12 | popup-services 13 |
14 |
15 | 16 | 23 | 24 | -------------------------------------------------------------------------------- /demo/states/preloader/template.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |

preloader

6 |
7 | 8 | 9 |
10 |
11 |
    12 |
  • 13 |
    14 |
    15 |
    16 |
    标题
    17 |
    18 | 19 |
    20 |
    21 |
    22 |
  • 23 |
24 |
25 | 显示 26 |
27 |
28 | -------------------------------------------------------------------------------- /demo/states/toast/template.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |

toast

6 |
7 | 8 | 9 |
10 |
11 |
    12 |
  • 13 |
    14 |
    15 |
    16 |
    显示文本
    17 |
    18 | 19 |
    20 |
    21 |
    22 |
  • 23 |
24 |
25 | 显示 26 |
27 |
28 | -------------------------------------------------------------------------------- /src/component/toast/toast.js: -------------------------------------------------------------------------------- 1 | import tpl from './toast.html' 2 | export default { 3 | template : tpl, 4 | props: { 5 | option: { 6 | type: Object, 7 | default: { 8 | content : '' 9 | } 10 | }, 11 | duration : { 12 | type : Number, 13 | default : 2000, 14 | }, 15 | }, 16 | data(){ 17 | return { 18 | left : 0, 19 | top : 0, 20 | show : false 21 | } 22 | }, 23 | init(){ 24 | console.log('toast init') 25 | }, 26 | ready(){ 27 | console.log('toast ready'); 28 | this.top = (- Math.round($(this.$el).outerHeight() / 2) + 'px'); 29 | this.left = (- Math.round($(this.$el).outerWidth() / 2 / 1.185) + 'px'); 30 | $(this.$el).addClass('modal-in'); 31 | setTimeout(()=>{ 32 | $(this.$el).addClass('modal-out').removeClass('modal-in'); 33 | setTimeout(()=>{ 34 | this.$dispatch('modal-remove',this.option) 35 | },300) 36 | },this.duration) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /demo/states/calendar/template.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |

picker

6 |
7 | 8 | 9 |
10 | 11 |
12 |
    13 |
  • 14 |
    15 |
    16 |
    17 |
    日期
    18 |
    19 | {{calendarOptions.values}} 20 |
    21 |
    22 |
    23 |
  • 24 |
25 |
26 |
27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import './util/device' 2 | import './util/zepto-adapter' 3 | import './util/scroller' 4 | import picker from './component/picker/picker' 5 | import modal from './component/modal/modal' 6 | import toast from './component/toast/toast' 7 | import alert from './component/alert/alert' 8 | import preloader from './component/preloader/preloader' 9 | import indicator from './component/indicator/indicator' 10 | import actions from './component/actions/actions' 11 | import calendar from './component/calendar/calendar' 12 | import datetimePicker from './component/datetime-picker/datetime-picker' 13 | 14 | import pullToRefresh from './directive/pullToRefresh' 15 | import infiniteScroll from './directive/infiniteScroll' 16 | import popup from './directive/popup' 17 | 18 | exports.picker = picker 19 | exports.modal = modal 20 | exports.toast = toast 21 | exports.alert = alert 22 | exports.preloader = preloader 23 | exports.indicator = indicator 24 | exports.actions = actions 25 | exports.calendar = calendar 26 | exports.datetimePicker = datetimePicker 27 | 28 | 29 | exports.pullToRefresh = pullToRefresh 30 | exports.infiniteScroll = infiniteScroll 31 | exports.popup = popup -------------------------------------------------------------------------------- /demo/states/actions/template.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |

actions

6 |
7 | 8 | 9 |
10 |
11 | let buttons1 = [
12 |     {
13 |         text: '请选择',
14 |         label: true
15 |     },
16 |     {
17 |         text: '卖出',
18 |         className : 'actions-modal-button-bold color-danger',
19 |         onClick: function() {
20 |             console.log('卖出')
21 |         }
22 |     },
23 |     {
24 |         text: '买入',
25 |         onClick: function() {
26 |             console.log('买入')
27 |         }
28 |     }
29 | ];
30 | let buttons2 = [
31 |     {
32 |         text: '取消',
33 |         className: 'bg-danger'
34 |     }
35 | ];
36 | 
37 | this.$refs.modal.add({
38 |     type : 'actions',
39 |     option : [ buttons1 , buttons2 ],
40 |     overlay : true //显示遮罩层
41 | })
42 | 
43 | 显示 44 |
45 |
46 | -------------------------------------------------------------------------------- /demo/states/picker/template.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |

picker

6 |
7 | 8 | 9 |
10 | 11 |
12 |
    13 |
  • 14 |
    15 |
    16 |
    17 |
    性别
    18 |
    20 | {{male[0].text}}{{male[1].text}} 21 |
    22 |
    23 |
    24 |
  • 25 |
26 |
27 |
28 |
29 | 30 | 31 | -------------------------------------------------------------------------------- /server/typings/errorhandler/errorhandler.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for errorhandler 2 | // Project: https://github.com/expressjs/errorhandler 3 | // Definitions by: Santi Albo 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /// 7 | 8 | declare module "errorhandler" { 9 | import express = require('express'); 10 | 11 | function errorHandler(options?: errorHandler.Options): express.ErrorRequestHandler; 12 | 13 | namespace errorHandler { 14 | interface LoggingCallback { 15 | (err: Error, str: string, req: express.Request, res: express.Response): void; 16 | } 17 | 18 | interface Options { 19 | /** 20 | * Defaults to true. 21 | * 22 | * Possible values: 23 | * true : Log errors using console.error(str). 24 | * false : Only send the error back in the response. 25 | * A function : pass the error to a function for handling. 26 | */ 27 | log: boolean | LoggingCallback; 28 | } 29 | } 30 | 31 | export = errorHandler; 32 | } 33 | -------------------------------------------------------------------------------- /demo/states/alert/route.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import Vue from 'vue' 3 | import Tpl from './template.html' 4 | 5 | let Index = Vue.extend({ 6 | //replace : true, //必须注释掉 不然动画失效 7 | template : Tpl, 8 | ready : function(){ 9 | 10 | }, 11 | data : ()=>{ 12 | return { 13 | title : '', 14 | content : '' 15 | } 16 | }, 17 | methods: { 18 | alert(){ 19 | this.$refs.modal.add({ 20 | type : 'alert', 21 | option : { 22 | title : this.title, 23 | content: this.content, 24 | ok : this.ok 25 | }, 26 | overlay : true //显示遮罩层 27 | }) 28 | }, 29 | ok(){ 30 | this.$refs.modal.add({ 31 | type : 'toast', 32 | option : { 33 | content: 'alert回调成功', 34 | }, 35 | duration : 3e3 36 | }) 37 | } 38 | }, 39 | computed : { 40 | 41 | }, 42 | route : { 43 | data : function(transition){ 44 | transition.next() 45 | } 46 | } 47 | }) 48 | 49 | export default Index -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-msui", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "dev": "node server --harmony", 7 | "build": "rm -rf ./public/demo && webpack --progress --hide-modules --config webpack.prod.config.js" 8 | }, 9 | "dependencies": { 10 | "babel-core": "^6.0.0", 11 | "babel-loader": "^6.0.0", 12 | "babel-preset-es2015": "^6.0.0", 13 | "babel-preset-stage-3": "^6.0.0", 14 | "babel-plugin-transform-runtime": "^6.6.0", 15 | "body-parser": "^1.14.1", 16 | "cookie-parser": "^1.4.1", 17 | "ejs": ">= 0.5.0", 18 | "errorhandler": "^1.4.2", 19 | "express": "^4.13.3", 20 | "method-override": "^2.3.5", 21 | "q": "^1.4.1", 22 | "request": "^2.69.0", 23 | "request-promise": "^2.0.1", 24 | "vue": "^1.0.15", 25 | "vue-router": "^0.7.10", 26 | "vue-server": "^0.4.2", 27 | "webpack": "^1.4.13", 28 | "webpack-dev-middleware": "^1.2.0" 29 | }, 30 | "devDependencies": { 31 | "css-loader": "^0.23.1", 32 | "extract-text-webpack-plugin": "^1.0.1", 33 | "html-webpack-plugin": "^2.8.2", 34 | "less": "^2.6.0", 35 | "less-loader": "^2.2.2", 36 | "raw-loader": "^0.5.1", 37 | "style-loader": "^0.13.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /demo/states/datetime-picker/template.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |

datetime-picker

6 |
7 | 8 | 9 |
10 | 11 |
12 |
    13 |
  • 14 |
    15 |
    16 |
    17 |
    日期时间
    18 |
    20 | {{datetime}} 21 |
    22 |
    23 |
    24 |
  • 25 |
26 |
27 |
28 |
29 | 30 | 31 | -------------------------------------------------------------------------------- /tsd.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "v4", 3 | "repo": "borisyankov/DefinitelyTyped", 4 | "ref": "master", 5 | "path": "server/typings", 6 | "bundle": "server/typings/tsd.d.ts", 7 | "installed": { 8 | "serve-static/serve-static.d.ts": { 9 | "commit": "fc341765ebbb04b7109981a25dced01f488f4d94" 10 | }, 11 | "express/express.d.ts": { 12 | "commit": "fc341765ebbb04b7109981a25dced01f488f4d94" 13 | }, 14 | "node/node.d.ts": { 15 | "commit": "fc341765ebbb04b7109981a25dced01f488f4d94" 16 | }, 17 | "method-override/method-override.d.ts": { 18 | "commit": "fc341765ebbb04b7109981a25dced01f488f4d94" 19 | }, 20 | "errorhandler/errorhandler.d.ts": { 21 | "commit": "fc341765ebbb04b7109981a25dced01f488f4d94" 22 | }, 23 | "body-parser/body-parser.d.ts": { 24 | "commit": "fc341765ebbb04b7109981a25dced01f488f4d94" 25 | }, 26 | "cookie-parser/cookie-parser.d.ts": { 27 | "commit": "fc341765ebbb04b7109981a25dced01f488f4d94" 28 | }, 29 | "request/request.d.ts": { 30 | "commit": "fc341765ebbb04b7109981a25dced01f488f4d94" 31 | }, 32 | "request-promise/request-promise.d.ts": { 33 | "commit": "fc341765ebbb04b7109981a25dced01f488f4d94" 34 | } 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/directive/popup.js: -------------------------------------------------------------------------------- 1 | export default { 2 | bind: function () { 3 | 4 | }, 5 | update: function (value) { 6 | if(this.modifiers && this.modifiers.open){ 7 | $(this.el).on('click',()=>{ 8 | $(value).removeClass('modal-out').css({ display : 'block'}); 9 | setTimeout(()=>{ 10 | if($('.popup-overlay').length == 0){ 11 | $('body').append(``) 12 | }else{ 13 | $('.popup-overlay').addClass('modal-overlay-visible') 14 | } 15 | $(value).addClass('modal-in'); 16 | }) 17 | }) 18 | }else if(this.modifiers && this.modifiers.close){ 19 | $(this.el).on('click',()=>{ 20 | $(value).removeClass('modal-in').addClass('modal-out') 21 | $('.popup-overlay').removeClass('modal-overlay-visible') 22 | setTimeout(()=>{ 23 | $(value).removeClass('modal-out').css({ display : 'none'}); 24 | },4e2) 25 | }) 26 | } 27 | }, 28 | unbind: function () { 29 | $(this.el).off('click'); 30 | }, 31 | } -------------------------------------------------------------------------------- /src/component/alert/alert.js: -------------------------------------------------------------------------------- 1 | import tpl from './alert.html' 2 | export default { 3 | template : tpl, 4 | props: { 5 | option: { 6 | type: Object, 7 | default: { 8 | title : '', 9 | content : '', 10 | okText : null, 11 | ok : null 12 | } 13 | }, 14 | duration : { 15 | type : Number, 16 | default : 2000, 17 | }, 18 | }, 19 | data(){ 20 | return { 21 | left : 0, 22 | top : 0, 23 | show : false, 24 | clicked : false 25 | } 26 | }, 27 | methods: { 28 | ok(){ 29 | if(this.clicked){ 30 | return; 31 | } 32 | if(typeof this.option.ok == 'function'){ 33 | this.clicked = true; 34 | this.option.ok(); 35 | } 36 | this.show = false; 37 | setTimeout(()=>{ 38 | this.$dispatch('modal-remove',this.option) 39 | },300) 40 | } 41 | }, 42 | init(){ 43 | 44 | }, 45 | ready(){ 46 | this.top = (- Math.round($(this.$el).outerHeight() / 2) + 'px'); 47 | this.show = true; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /public/demo/10.fc990400.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([10],{52:function(p,n,o){"use strict";function e(p){return p&&p.__esModule?p:{"default":p}}Object.defineProperty(n,"__esModule",{value:!0});var t=o(2),a=e(t),u=o(53),s=e(u),c=a["default"].extend({template:s["default"],ready:function(){},data:function(){return{}},methods:{},computed:{},route:{data:function(p){p.next()}}});n["default"]=c},53:function(p,n){p.exports='
\n \n
\n \n

popup

\n
\n\n \n \n
\n\n\n\n'}}); -------------------------------------------------------------------------------- /server/typings/request-promise/request-promise.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for request-promise v0.4.2 2 | // Project: https://www.npmjs.com/package/request-promise 3 | // Definitions by: Christopher Glantschnig , Joe Skeen 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | // Change [0]: 2015/08/20 - Aya Morisawa 7 | 8 | /// 9 | /// 10 | 11 | declare module 'request-promise' { 12 | import request = require('request'); 13 | import http = require('http'); 14 | 15 | interface RequestPromise extends request.Request { 16 | then(onFulfilled: Function, onRejected?: Function): Promise; 17 | catch(onRejected: Function): Promise; 18 | finally(onFinished: Function): Promise; 19 | promise(): Promise; 20 | } 21 | 22 | interface RequestPromiseOptions extends request.OptionalOptions { 23 | simple?: boolean; 24 | transform?: (body: any, response: http.IncomingMessage) => any; 25 | resolveWithFullResponse?: boolean; 26 | } 27 | 28 | var requestPromise: request.RequestAPI; 29 | export = requestPromise; 30 | } 31 | -------------------------------------------------------------------------------- /webpack.prod.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack') 2 | var config = require('./webpack.base.config') 3 | var HtmlWebpackPlugin = require('html-webpack-plugin') 4 | var ExtractTextPlugin = require("extract-text-webpack-plugin"); 5 | 6 | 7 | config.output.filename = '[name].[chunkhash:8].js' 8 | config.output.chunkFilename = '[id].[chunkhash:8].js' 9 | 10 | 11 | config.plugins = (config.plugins || []).concat([ 12 | //把所有独立样式的CSS打包成一个style.css 13 | new ExtractTextPlugin("styles.[hash:8].css",{allChunks: true}), 14 | // new webpack.optimize.CommonsChunkPlugin({ 15 | // name: "vendor", 16 | // 17 | // filename: "[name].[hash:8].js", 18 | // // (Give the chunk a different name) 19 | // 20 | // minChunks: Infinity, 21 | // // (with more entries, this ensures that no other module 22 | // // goes into the vendor chunk) 23 | // }), 24 | new webpack.optimize.UglifyJsPlugin({ 25 | compressor: { 26 | warnings: false 27 | } 28 | }), 29 | new HtmlWebpackPlugin({ 30 | name:'layout', 31 | template: './server/views/dist/layout.html', 32 | filename: 'layout.html', 33 | inject: 'body', 34 | chunks: ['demo'], 35 | minify:{ //压缩HTML文件 36 | removeComments:true, //移除HTML中的注释 37 | collapseWhitespace:false //删除空白符与换行符 38 | } 39 | }) 40 | ]) 41 | 42 | module.exports = config -------------------------------------------------------------------------------- /demo/states/pullToRefresh/template.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |

下拉刷新

6 |
7 | 8 | 9 |
10 | 11 |
12 |
13 |
14 |
更新时间:{{updateTime}}
15 |
16 |
17 | 
18 | <div class="content pull-to-refresh-content" v-pull-to-refresh="refresh()" data-ptr-distance="55">
19 |     <!-- 默认的下拉刷新层 -->
20 |     <div class="pull-to-refresh-layer">
21 |         <div class="preloader"></div>
22 |         <div class="pull-to-refresh-arrow"></div>
23 |     </div>
24 | </div>
25 | 
26 | 
27 | //返回的是一个生成promise的函数
28 | refresh(){
29 |     return ()=>{
30 |         return new Promise((resolve,reject)=>{
31 |             setTimeout(()=>{
32 |                 this.updateTime = new Date().getTime()
33 |                 resolve('刷新了')
34 |             },3e3)
35 |         })
36 |     }
37 | }
38 | 
39 | 
40 |
41 |
-------------------------------------------------------------------------------- /public/demo/3.a414582e.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([3],{38:function(t,n,e){"use strict";function a(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(n,"__esModule",{value:!0});var i=e(2),s=a(i),l=e(39),d=a(l),c=s["default"].extend({template:d["default"],ready:function(){},data:function(){return{text:"请输入"}},methods:{addToast:function(){var t=this.text;this.$refs.modal.add({type:"toast",option:{content:t}})}},computed:{},route:{data:function(t){t.next()}}});n["default"]=c},39:function(t,n){t.exports='
\n \n
\n \n

toast

\n
\n\n \n
\n
\n
    \n
  • \n
    \n
    \n
    \n
    显示文本
    \n
    \n \n
    \n
    \n
    \n
  • \n
\n
\n 显示\n
\n
\n'}}); -------------------------------------------------------------------------------- /public/demo/11.fd1b64bc.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([11],{54:function(n,e,a){"use strict";function i(n){return n&&n.__esModule?n:{"default":n}}Object.defineProperty(e,"__esModule",{value:!0});var t=a(2),c=i(t),l=a(55),s=i(l),d=c["default"].extend({template:s["default"],ready:function(){},data:function(){return{isOpenCalendar:!1,calendarOptions:{values:["2016-01-01"]}}},methods:{change:function(n){console.log(n)}},computed:{},route:{data:function(n){n.next()}}});e["default"]=d},55:function(n,e){n.exports='
\n \n
\n \n

picker

\n
\n\n \n
\n\n
\n
    \n
  • \n
    \n
    \n
    \n
    日期
    \n
    \n {{calendarOptions.values}}\n
    \n
    \n
    \n
  • \n
\n
\n
\n
\n\n\n'}}); -------------------------------------------------------------------------------- /public/demo/5.3f026e59.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([5],{42:function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(2),l=i(a),d=n(43),o=i(d),s=l["default"].extend({template:o["default"],ready:function(){},data:function(){return{title:"加载中"}},methods:{preloader:function(){var e=this;this.$refs.modal.add({type:"preloader",option:{title:this.title},overlay:!0}),setTimeout(function(){e.$refs.modal.hidePreloader()},2e3)}},computed:{},route:{data:function(e){e.next()}}});t["default"]=s},43:function(e,t){e.exports='
\n \n
\n \n

preloader

\n
\n\n \n
\n
\n
    \n
  • \n
    \n
    \n
    \n
    标题
    \n
    \n \n
    \n
    \n
    \n
  • \n
\n
\n 显示\n
\n
\n'}}); -------------------------------------------------------------------------------- /public/demo/12.20624280.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([12],{56:function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(2),c=i(a),d=n(57),s=i(d),l=c["default"].extend({template:s["default"],ready:function(){},data:function(){return{isOpenDatetimePicker:!1,datetime:"2016-04-08 09:00:00"}},methods:{},computed:{},route:{data:function(e){e.next()}}});t["default"]=l},57:function(e,t){e.exports='
\n \n
\n \n

datetime-picker

\n
\n\n \n
\n\n
\n
    \n
  • \n
    \n
    \n
    \n
    日期时间
    \n
    \n {{datetime}}\n
    \n
    \n
    \n
  • \n
\n
\n
\n
\n\n\n'}}); -------------------------------------------------------------------------------- /demo/states/infiniteScroll/template.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |

无限滚动

6 |
7 | 8 | 9 |
12 | 13 |
14 |
15 |
16 |
更新时间:{{updateTime}}
17 |
18 |
19 |
20 |
    21 | 22 |
  • 23 |
    24 |
    25 |
    {{item}}
    26 |
    27 |
    28 |
  • 29 |
30 |
31 |
32 | 33 | 34 |
35 |
36 |
37 |
38 |
-------------------------------------------------------------------------------- /demo/states/alert/template.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |

alert

6 |
7 | 8 | 9 |
10 |
11 |
    12 |
  • 13 |
    14 |
    15 |
    16 |
    标题
    17 |
    18 | 19 |
    20 |
    21 |
    22 |
  • 23 |
  • 24 |
    25 |
    26 |
    27 |
    内容
    28 |
    29 | 30 |
    31 |
    32 |
    33 |
  • 34 |
35 |
36 | 显示 37 |
38 |
39 | -------------------------------------------------------------------------------- /demo/states/actions/route.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import Vue from 'vue' 3 | import Tpl from './template.html' 4 | 5 | let Index = Vue.extend({ 6 | //replace : true, //必须注释掉 不然动画失效 7 | template : Tpl, 8 | ready : function(){ 9 | 10 | }, 11 | data : ()=>{ 12 | return { 13 | title : '', 14 | content : '' 15 | } 16 | }, 17 | methods: { 18 | actions(){ 19 | let buttons1 = [ 20 | { 21 | text: '请选择', 22 | label: true 23 | }, 24 | { 25 | text: '卖出', 26 | className : 'actions-modal-button-bold color-danger', 27 | onClick: function() { 28 | console.log('卖出') 29 | } 30 | }, 31 | { 32 | text: '买入', 33 | onClick: function() { 34 | console.log('买入') 35 | } 36 | } 37 | ]; 38 | let buttons2 = [ 39 | { 40 | text: '取消', 41 | className: 'bg-danger' 42 | } 43 | ]; 44 | 45 | this.$refs.modal.add({ 46 | type : 'actions', 47 | option : [ buttons1 , buttons2 ], 48 | overlay : true //显示遮罩层 49 | }) 50 | } 51 | }, 52 | computed : { 53 | 54 | }, 55 | route : { 56 | data : function(transition){ 57 | transition.next() 58 | } 59 | } 60 | }) 61 | 62 | export default Index -------------------------------------------------------------------------------- /demo/states/infiniteScroll/route.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | import Vue from 'vue' 3 | import Tpl from './template.html' 4 | 5 | let Index = Vue.extend({ 6 | //replace : true, //必须注释掉 不然动画失效 7 | template : Tpl, 8 | ready : function(){ 9 | this.loadData(); 10 | }, 11 | data : ()=>{ 12 | return { 13 | list : [], 14 | updateTime : new Date().getTime(), 15 | isShowLoad : true 16 | } 17 | }, 18 | methods: { 19 | loadMore(page){ 20 | console.log('page => ',page); 21 | 22 | //需要的是一个生成promise的函数 23 | return (page)=>{ 24 | return new Promise((resolve,reject)=>{ 25 | setTimeout(()=>{ 26 | this.loadData(); 27 | resolve('加载了') 28 | },3e3) 29 | }) 30 | } 31 | 32 | }, 33 | loadData(){ 34 | let len = this.list.length; 35 | for(let i=0;i<20;i++){ 36 | this.list.push(len+i); 37 | } 38 | }, 39 | refresh(){ 40 | return ()=>{ 41 | return new Promise((resolve,reject)=>{ 42 | setTimeout(()=>{ 43 | this.updateTime = new Date().getTime() 44 | resolve('刷新了') 45 | },3e3) 46 | }) 47 | } 48 | } 49 | }, 50 | computed : { 51 | 52 | }, 53 | route : { 54 | data : function(transition){ 55 | transition.next() 56 | } 57 | } 58 | }) 59 | 60 | export default Index -------------------------------------------------------------------------------- /public/demo/7.f9f16e76.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([7],{46:function(n,t,e){"use strict";function o(n){return n&&n.__esModule?n:{"default":n}}Object.defineProperty(t,"__esModule",{value:!0});var a=e(2),l=o(a),c=e(47),s=o(c),i=l["default"].extend({template:s["default"],ready:function(){},data:function(){return{title:"",content:""}},methods:{actions:function(){var n=[{text:"请选择",label:!0},{text:"卖出",className:"actions-modal-button-bold color-danger",onClick:function(){console.log("卖出")}},{text:"买入",onClick:function(){console.log("买入")}}],t=[{text:"取消",className:"bg-danger"}];this.$refs.modal.add({type:"actions",option:[n,t],overlay:!0})}},computed:{},route:{data:function(n){n.next()}}});t["default"]=i},47:function(n,t){n.exports='
\n \n
\n \n

actions

\n
\n\n \n
\n
\nlet buttons1 = [\n    {\n        text: \'请选择\',\n        label: true\n    },\n    {\n        text: \'卖出\',\n        className : \'actions-modal-button-bold color-danger\',\n        onClick: function() {\n            console.log(\'卖出\')\n        }\n    },\n    {\n        text: \'买入\',\n        onClick: function() {\n            console.log(\'买入\')\n        }\n    }\n];\nlet buttons2 = [\n    {\n        text: \'取消\',\n        className: \'bg-danger\'\n    }\n];\n\nthis.$refs.modal.add({\n    type : \'actions\',\n    option : [ buttons1 , buttons2 ],\n    overlay : true //显示遮罩层\n})\n
\n 显示\n
\n
\n'}}); -------------------------------------------------------------------------------- /public/demo/2.ef22dae4.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([2],{36:function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var i=n(2),l=a(i),c=n(37),s=a(c),u=l["default"].extend({template:s["default"],ready:function(){},data:function(){return{isOpenMalePicker:!1,male:[{text:"女",value:1},{text:"先生啊啊啊",value:0}],maleOptions:[{values:[{text:"男",value:0},{text:"女",value:1},{text:"中性",value:2},{text:"变性",value:3},{text:"双性",value:4},{text:"无性",value:5}]},{values:[{text:"先生啊啊啊",value:0},{text:"小姐",value:1}]}]}},methods:{},computed:{},route:{data:function(e){e.next()}}});t["default"]=u},37:function(e,t){e.exports='
\n \n
\n \n

picker

\n
\n\n \n
\n\n
\n
    \n
  • \n
    \n
    \n
    \n
    性别
    \n
    \n {{male[0].text}}{{male[1].text}}\n
    \n
    \n
    \n
  • \n
\n
\n
\n
\n\n\n'}}); -------------------------------------------------------------------------------- /public/demo/8.b7cbe94c.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([8],{48:function(e,n,t){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(n,"__esModule",{value:!0});var s=t(2),i=r(s),a=t(49),l=r(a),o=i["default"].extend({template:l["default"],ready:function(){},data:function(){return{updateTime:(new Date).getTime()}},methods:{refresh:function(){var e=this;return function(){return new Promise(function(n,t){setTimeout(function(){e.updateTime=(new Date).getTime(),n("刷新了")},3e3)})}}},computed:{},route:{data:function(e){e.next()}}});n["default"]=o},49:function(e,n){e.exports='
\n \n
\n \n

下拉刷新

\n
\n\n \n
\n \n
\n
\n
\n
更新时间:{{updateTime}}
\n
\n
\n\n<div class="content pull-to-refresh-content" v-pull-to-refresh="refresh()" data-ptr-distance="55">\n    <!-- 默认的下拉刷新层 -->\n    <div class="pull-to-refresh-layer">\n        <div class="preloader"></div>\n        <div class="pull-to-refresh-arrow"></div>\n    </div>\n</div>\n\n\n//返回的是一个生成promise的函数\nrefresh(){\n    return ()=>{\n        return new Promise((resolve,reject)=>{\n            setTimeout(()=>{\n                this.updateTime = new Date().getTime()\n                resolve(\'刷新了\')\n            },3e3)\n        })\n    }\n}\n\n
\n
\n
'}}); -------------------------------------------------------------------------------- /public/demo/4.54186de6.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([4],{40:function(t,n,i){"use strict";function e(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(n,"__esModule",{value:!0});var a=i(2),l=e(a),s=i(41),d=e(s),o=l["default"].extend({template:d["default"],ready:function(){},data:function(){return{title:"",content:""}},methods:{alert:function(){this.$refs.modal.add({type:"alert",option:{title:this.title,content:this.content,ok:this.ok},overlay:!0})},ok:function(){this.$refs.modal.add({type:"toast",option:{content:"alert回调成功"},duration:3e3})}},computed:{},route:{data:function(t){t.next()}}});n["default"]=o},41:function(t,n){t.exports='
\n \n
\n \n

alert

\n
\n\n \n
\n
\n
    \n
  • \n
    \n
    \n
    \n
    标题
    \n
    \n \n
    \n
    \n
    \n
  • \n
  • \n
    \n
    \n
    \n
    内容
    \n
    \n \n
    \n
    \n
    \n
  • \n
\n
\n 显示\n
\n
\n'}}); -------------------------------------------------------------------------------- /src/component/modal/modal.js: -------------------------------------------------------------------------------- 1 | // import tpl from './modal.html' 2 | export default { 3 | template : `
4 | 5 | 11 |
`, 12 | props: { 13 | 14 | }, 15 | data(){ 16 | return { 17 | modals : [ 18 | 19 | ] 20 | } 21 | }, 22 | components: { 23 | 24 | }, 25 | computed:{ 26 | showOverlay(){ 27 | for(let i=0;i{ 12 | return { 13 | isOpenMalePicker : false, 14 | male : [{ 15 | text : '女', 16 | value : 1 17 | },{ 18 | text : '先生啊啊啊', 19 | value : 0 20 | }], 21 | maleOptions : [ 22 | { 23 | values : [ 24 | { 25 | text : '男', 26 | value : 0 27 | }, 28 | { 29 | text : '女', 30 | value : 1 31 | }, 32 | { 33 | text : '中性', 34 | value : 2 35 | }, 36 | { 37 | text : '变性', 38 | value : 3 39 | }, 40 | { 41 | text : '双性', 42 | value : 4 43 | }, 44 | { 45 | text : '无性', 46 | value : 5 47 | } 48 | 49 | ] 50 | }, 51 | { 52 | values : [ 53 | { 54 | text : '先生啊啊啊', 55 | value : 0 56 | }, 57 | { 58 | text : '小姐', 59 | value : 1 60 | } 61 | ] 62 | } 63 | ] 64 | } 65 | }, 66 | methods: { 67 | 68 | }, 69 | computed : { 70 | 71 | }, 72 | route : { 73 | data : function(transition){ 74 | transition.next() 75 | } 76 | } 77 | }) 78 | 79 | export default Index -------------------------------------------------------------------------------- /public/demo/9.c5142e7c.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([9],{50:function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(2),l=i(a),s=n(51),o=i(s),r=l["default"].extend({template:o["default"],ready:function(){this.loadData()},data:function(){return{list:[],updateTime:(new Date).getTime(),isShowLoad:!0}},methods:{loadMore:function(e){var t=this;return console.log("page => ",e),function(e){return new Promise(function(e,n){setTimeout(function(){t.loadData(),e("加载了")},3e3)})}},loadData:function(){for(var e=this.list.length,t=0;20>t;t++)this.list.push(e+t)},refresh:function(){var e=this;return function(){return new Promise(function(t,n){setTimeout(function(){e.updateTime=(new Date).getTime(),t("刷新了")},3e3)})}}},computed:{},route:{data:function(e){e.next()}}});t["default"]=r},51:function(e,t){e.exports='
\n \n
\n \n

无限滚动

\n
\n\n \n
\n \n
\n
\n
\n
更新时间:{{updateTime}}
\n
\n
\n
\n
    \n \n
  • \n
    \n
    \n
    {{item}}
    \n
    \n
    \n
  • \n
\n
\n
\n\n \n
\n
\n
\n
\n
'}}); -------------------------------------------------------------------------------- /src/component/calendar/calendar.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | 12 | 13 | 20 |
21 |
22 |
23 |
24 |
周一
25 |
周二
26 |
周三
27 |
周四
28 |
周五
29 |
周六
30 |
周日
31 |
32 |
33 |
34 | 35 | 38 | 39 |
40 |
41 |
42 |
-------------------------------------------------------------------------------- /server.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"server.js","sourceRoot":"","sources":["server.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;AACZ,IAAY,OAAO,WAAM,SAAS,CAAC,CAAA;AACnC,IAAY,UAAU,WAAM,aAAa,CAAC,CAAA;AAC1C,IAAY,YAAY,WAAM,cAAc,CAAC,CAAA;AAC7C,IAAY,cAAc,WAAM,iBAAiB,CAAC,CAAA;AAClD,IAAY,YAAY,WAAM,eAAe,CAAC,CAAA;AAE9C,oBAAqB,OAGrB,CAAC,CAH2B;AAE5B,QAAQ;AACR,IAAY,KAAK,WAAM,8BAIvB,CAAC,CAJoD;AAIrD,IAAI,GAAG,GAAG,OAAO,EAAE,CAAC;AACpB,GAAG,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC;AACxB,gBAAgB;AAChB,IAAI,GAAG,GAAG,YAAM,CAAC,QAAQ,IAAI,aAAa,CAAC;AAC3C,EAAE,CAAC,CAAC,GAAG,KAAK,aAAa,CAAC,CAAC,CAAC;IACxB,IAAI,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IACjC,IAAI,oBAAoB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAC7D,IAAI,aAAa,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACpD,GAAG,CAAC,GAAG,CAAC,oBAAoB,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE;QACjD,UAAU,EAAE,QAAQ;QACpB,KAAK,EAAE;YACH,MAAM,EAAE,IAAI;SACf;KACJ,CAAC,CAAC,CAAC;IACJ,GAAG,CAAC,GAAG,CAAC,OAAO,EAAC,SAAS,GAAG,mBAAmB,CAAC,CAAC;AACrD,CAAC;AAAA,IAAI,CAAA,CAAC;IACF,GAAG,CAAC,GAAG,CAAC,OAAO,EAAC,SAAS,GAAG,cAAc,CAAC,CAAC;AAChD,CAAC;AAED,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;AAC/B,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAA;AAG7C,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACnD,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;AAC3B,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,CAAC;AAC1B,GAAG,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC;AACxB,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,GAAC,SAAS,CAAC,CAAC,CAAC;AAE7C,SAAS;AACT,GAAG,CAAC,GAAG,CAAC,aAAa,EAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACnC,GAAG,CAAC,GAAG,CAAC,cAAc,EAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACpC,GAAG,CAAC,GAAG,CAAC,aAAa,EAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACnC,GAAG,CAAC,GAAG,CAAC,aAAa,EAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACnC,GAAG,CAAC,GAAG,CAAC,iBAAiB,EAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACvC,GAAG,CAAC,GAAG,CAAC,iBAAiB,EAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACvC,GAAG,CAAC,GAAG,CAAC,eAAe,EAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACrC,GAAG,CAAC,GAAG,CAAC,qBAAqB,EAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAC3C,GAAG,CAAC,GAAG,CAAC,sBAAsB,EAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAC5C,GAAG,CAAC,GAAG,CAAC,aAAa,EAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACnC,GAAG,CAAC,GAAG,CAAC,gBAAgB,EAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACtC,GAAG,CAAC,GAAG,CAAC,gBAAgB,EAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAEtC,MAAM;AACN,GAAG,CAAC,GAAG,CAAC,IAAI,EAAC,UAAS,GAAG,EAAC,GAAG;IAC1B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAC;QACd,UAAU,EAAC,aAAa;KAC3B,CAAC,CAAC;IACH,GAAG,CAAC,GAAG,EAAE,CAAC;AACb,CAAC,CAAC,CAAC;AAGH,GAAG,CAAC,MAAM,CAAC,YAAM,CAAC,IAAI,EAAE;IACpB,OAAO,CAAC,GAAG,CAAC,qDAAqD,EAAE,YAAM,CAAC,IAAI,EAAE,YAAM,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;AAC3G,CAAC,CAAC,CAAC;AAEQ,WAAG,GAAG,GAAG,CAAC"} -------------------------------------------------------------------------------- /src/component/picker/picker.js: -------------------------------------------------------------------------------- 1 | import tpl from './picker.html' 2 | import pickerCol from './picker-col' 3 | export default { 4 | template : tpl, 5 | props: { 6 | open : { 7 | type : Boolean, 8 | default : false 9 | }, 10 | //文字描述 11 | headerText: { 12 | type: String, 13 | default: '请选择' 14 | }, 15 | //确定文本 16 | okText: { 17 | type: String, 18 | default: '确定' 19 | }, 20 | //选中项 21 | val: { 22 | type: Array, 23 | default: [{ 24 | text : '0', 25 | value : 0 26 | }] 27 | }, 28 | //选项列表 29 | options: { 30 | type: Array, 31 | default : [ 32 | { 33 | values : [ 34 | { 35 | text : '0', 36 | value : 0 37 | } 38 | ] 39 | } 40 | ] 41 | }, 42 | updateValuesOnMomentum:{ 43 | type: Boolean, 44 | default: false 45 | }, 46 | updateValuesOnTouchmove:{ 47 | type: Boolean, 48 | default: true 49 | }, 50 | rotateEffect: { 51 | type: Boolean, 52 | default: false 53 | }, 54 | momentumRatio: { 55 | type: Number, 56 | default: 7 57 | }, 58 | freeMode: { 59 | type: Boolean, 60 | default: false 61 | }, 62 | //选择完回调 63 | success: { 64 | type: Function, 65 | }, 66 | onChange:{ 67 | type: Function, 68 | } 69 | }, 70 | data(){ 71 | return { 72 | isMoved : false, 73 | isTouched : false 74 | } 75 | }, 76 | methods: { 77 | ok(){ 78 | this.open = false; 79 | if(this.success){ 80 | this.success(this.val); 81 | } 82 | }, 83 | initPickerCol(colElement,updateItems){ 84 | 85 | } 86 | }, 87 | components: { 88 | pickerCol : pickerCol, 89 | }, 90 | init(){ 91 | console.log('picker init') 92 | }, 93 | ready(){ 94 | let self = this; 95 | console.log('picker ready'); 96 | 97 | 98 | this.$watch('open',function (newVal) { 99 | if(newVal){ 100 | this.$broadcast('open-picker') 101 | } 102 | }) 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/directive/infiniteScroll.js: -------------------------------------------------------------------------------- 1 | let inf ; 2 | let scroller ; 3 | let scrollTop ; 4 | let scrollHeight ; 5 | let height ; 6 | let distance ; 7 | let virtualListContainer ; 8 | let virtualList; 9 | let onTop ; 10 | let pageContainer; 11 | let infiniteContent; 12 | let loading; 13 | 14 | export default { 15 | bind: function () { 16 | pageContainer = $(this.el); 17 | infiniteContent = pageContainer.hasClass('infinite-scroll')?pageContainer:pageContainer.find('.infinite-scroll'); 18 | if(infiniteContent.length == 0) return; 19 | $(infiniteContent).on('scroll',this.handleInfiniteScroll.bind(this)); 20 | //如果是顶部无限刷新,要将滚动条初始化于最下端 21 | pageContainer.forEach(function(v){ 22 | if($(v).hasClass('infinite-scroll-top')){ 23 | var height = v.scrollHeight - v.clientHeight; 24 | $(v).scrollTop(height); 25 | } 26 | }); 27 | }, 28 | update: function (promiseOrNull) { 29 | if(promiseOrNull == null){ 30 | 31 | }else if(typeof promiseOrNull == 'function'){ 32 | this.callback = promiseOrNull; 33 | }else{ 34 | console.log('无限滚动指令 必须是一个返回promise的function') 35 | } 36 | }, 37 | unbind: function () { 38 | $(infiniteContent).off('scroll',this.handleInfiniteScroll.bind(this)) 39 | }, 40 | handleInfiniteScroll: function () { 41 | inf = $(this.el); 42 | scroller = $(this.el); 43 | scrollTop = scroller.scrollTop(); 44 | scrollHeight = scroller[0].scrollHeight; 45 | height = inf[0].offsetHeight; 46 | distance = inf[0].getAttribute('data-distance'); 47 | virtualListContainer = inf.find('.virtual-list'); 48 | onTop = inf.hasClass('infinite-scroll-top'); 49 | 50 | 51 | if(!distance) distance = 50 ; 52 | if(typeof distance === 'string' && distance.indexOf('%') >= 0){ 53 | distance = parseInt(distance,10) / 100 * height; 54 | } 55 | if(distance > height) distance = height; 56 | 57 | if(onTop){ 58 | if(scrollTop < distance){ 59 | if(!loading){ 60 | this.triggerInfinite() 61 | } 62 | } 63 | }else{ 64 | if (scrollTop + height >= scrollHeight - distance) { 65 | if (virtualListContainer.length > 0) { 66 | virtualList = virtualListContainer[0].f7VirtualList; 67 | if (virtualList && !virtualList.reachEnd) return; 68 | } 69 | if(!loading){ 70 | this.triggerInfinite() 71 | } 72 | 73 | } 74 | } 75 | }, 76 | triggerInfinite(){ 77 | loading = true; 78 | //需要传入一个返回promise对象的方法来重置无限下拉 79 | this.callback().then((data)=>{ 80 | loading = false; 81 | }).catch(()=>{ 82 | loading = false; 83 | }); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /server/typings/serve-static/serve-static.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for serve-static 1.7.1 2 | // Project: https://github.com/expressjs/serve-static 3 | // Definitions by: Uros Smolnik 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /* =================== USAGE =================== 7 | 8 | import * as serveStatic from "serve-static"; 9 | app.use(serveStatic("public/ftp", {"index": ["default.html", "default.htm"]})) 10 | 11 | =============================================== */ 12 | 13 | /// 14 | /// 15 | 16 | declare module "serve-static" { 17 | import * as express from "express"; 18 | 19 | /** 20 | * Create a new middleware function to serve files from within a given root directory. 21 | * The file to serve will be determined by combining req.url with the provided root directory. 22 | * When a file is not found, instead of sending a 404 response, this module will instead call next() to move on to the next middleware, allowing for stacking and fall-backs. 23 | */ 24 | function serveStatic(root: string, options?: { 25 | /** 26 | * Set how "dotfiles" are treated when encountered. A dotfile is a file or directory that begins with a dot ("."). 27 | * Note this check is done on the path itself without checking if the path actually exists on the disk. 28 | * If root is specified, only the dotfiles above the root are checked (i.e. the root itself can be within a dotfile when when set to "deny"). 29 | * The default value is 'ignore'. 30 | * 'allow' No special treatment for dotfiles 31 | * 'deny' Send a 403 for any request for a dotfile 32 | * 'ignore' Pretend like the dotfile does not exist and call next() 33 | */ 34 | dotfiles?: string; 35 | 36 | /** 37 | * Enable or disable etag generation, defaults to true. 38 | */ 39 | etag?: boolean; 40 | 41 | /** 42 | * Set file extension fallbacks. When set, if a file is not found, the given extensions will be added to the file name and search for. 43 | * The first that exists will be served. Example: ['html', 'htm']. 44 | * The default value is false. 45 | */ 46 | extensions?: string[]; 47 | 48 | /** 49 | * By default this module will send "index.html" files in response to a request on a directory. 50 | * To disable this set false or to supply a new index pass a string or an array in preferred order. 51 | */ 52 | index?: boolean|string|string[]; 53 | 54 | /** 55 | * Enable or disable Last-Modified header, defaults to true. Uses the file system's last modified value. 56 | */ 57 | lastModified?: boolean; 58 | 59 | /** 60 | * Provide a max-age in milliseconds for http caching, defaults to 0. This can also be a string accepted by the ms module. 61 | */ 62 | maxAge?: number|string; 63 | 64 | /** 65 | * Redirect to trailing "/" when the pathname is a dir. Defaults to true. 66 | */ 67 | redirect?: boolean; 68 | 69 | /** 70 | * Function to set custom headers on response. Alterations to the headers need to occur synchronously. 71 | * The function is called as fn(res, path, stat), where the arguments are: 72 | * res the response object 73 | * path the file path that is being sent 74 | * stat the stat object of the file that is being sent 75 | */ 76 | setHeaders?: (res: express.Response, path: string, stat: any) => any; 77 | }): express.Handler; 78 | 79 | import * as m from "mime"; 80 | 81 | module serveStatic { 82 | var mime: typeof m; 83 | } 84 | 85 | export = serveStatic; 86 | } 87 | -------------------------------------------------------------------------------- /src/util/device.js: -------------------------------------------------------------------------------- 1 | /*=========================== 2 | Device/OS Detection 直接复制msui的device.js 3 | ===========================*/ 4 | ;(function ($) { 5 | "use strict"; 6 | var device = {}; 7 | var ua = navigator.userAgent; 8 | 9 | var android = ua.match(/(Android);?[\s\/]+([\d.]+)?/); 10 | var ipad = ua.match(/(iPad).*OS\s([\d_]+)/); 11 | var ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/); 12 | var iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/); 13 | 14 | device.ios = device.android = device.iphone = device.ipad = device.androidChrome = false; 15 | 16 | // Android 17 | if (android) { 18 | device.os = 'android'; 19 | device.osVersion = android[2]; 20 | device.android = true; 21 | device.androidChrome = ua.toLowerCase().indexOf('chrome') >= 0; 22 | } 23 | if (ipad || iphone || ipod) { 24 | device.os = 'ios'; 25 | device.ios = true; 26 | } 27 | // iOS 28 | if (iphone && !ipod) { 29 | device.osVersion = iphone[2].replace(/_/g, '.'); 30 | device.iphone = true; 31 | } 32 | if (ipad) { 33 | device.osVersion = ipad[2].replace(/_/g, '.'); 34 | device.ipad = true; 35 | } 36 | if (ipod) { 37 | device.osVersion = ipod[3] ? ipod[3].replace(/_/g, '.') : null; 38 | device.iphone = true; 39 | } 40 | // iOS 8+ changed UA 41 | if (device.ios && device.osVersion && ua.indexOf('Version/') >= 0) { 42 | if (device.osVersion.split('.')[0] === '10') { 43 | device.osVersion = ua.toLowerCase().split('version/')[1].split(' ')[0]; 44 | } 45 | } 46 | 47 | // Webview 48 | device.webView = (iphone || ipad || ipod) && ua.match(/.*AppleWebKit(?!.*Safari)/i); 49 | 50 | // Minimal UI 51 | if (device.os && device.os === 'ios') { 52 | var osVersionArr = device.osVersion.split('.'); 53 | device.minimalUi = !device.webView && 54 | (ipod || iphone) && 55 | (osVersionArr[0] * 1 === 7 ? osVersionArr[1] * 1 >= 1 : osVersionArr[0] * 1 > 7) && 56 | $('meta[name="viewport"]').length > 0 && $('meta[name="viewport"]').attr('content').indexOf('minimal-ui') >= 0; 57 | } 58 | 59 | // Check for status bar and fullscreen app mode 60 | var windowWidth = $(window).width(); 61 | var windowHeight = $(window).height(); 62 | device.statusBar = false; 63 | if (device.webView && (windowWidth * windowHeight === screen.width * screen.height)) { 64 | device.statusBar = true; 65 | } 66 | else { 67 | device.statusBar = false; 68 | } 69 | 70 | // Classes 71 | var classNames = []; 72 | 73 | // Pixel Ratio 74 | device.pixelRatio = window.devicePixelRatio || 1; 75 | classNames.push('pixel-ratio-' + Math.floor(device.pixelRatio)); 76 | if (device.pixelRatio >= 2) { 77 | classNames.push('retina'); 78 | } 79 | 80 | // OS classes 81 | if (device.os) { 82 | classNames.push(device.os, device.os + '-' + device.osVersion.split('.')[0], device.os + '-' + device.osVersion.replace(/\./g, '-')); 83 | if (device.os === 'ios') { 84 | var major = parseInt(device.osVersion.split('.')[0], 10); 85 | for (var i = major - 1; i >= 6; i--) { 86 | classNames.push('ios-gt-' + i); 87 | } 88 | } 89 | 90 | } 91 | // Status bar classes 92 | if (device.statusBar) { 93 | classNames.push('with-statusbar-overlay'); 94 | } 95 | else { 96 | $('html').removeClass('with-statusbar-overlay'); 97 | } 98 | 99 | // Add html classes 100 | if (classNames.length > 0) $('html').addClass(classNames.join(' ')); 101 | 102 | // keng.. 103 | device.isWeixin = /MicroMessenger/i.test(ua); 104 | 105 | $.device = device; 106 | })(Zepto); -------------------------------------------------------------------------------- /demo/states/index/template.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |

index

6 |
7 | 8 | 9 |
10 |
demo
11 |
12 |
    13 | 20 | 27 | 34 | 41 | 48 | 55 | 62 | 69 | 76 | 83 | 90 |
91 |
92 |
93 |
-------------------------------------------------------------------------------- /public/demo/1.9e649490.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([1],{34:function(i,n,e){"use strict";function t(i){return i&&i.__esModule?i:{"default":i}}Object.defineProperty(n,"__esModule",{value:!0});var s=e(2),c=t(s),l=e(35),d=t(l),a=c["default"].extend({template:d["default"],ready:function(){},data:function(){return{}},methods:{goRoute:function(i){this.$router.go(i)}},computed:{},route:{data:function(i){i.next()}}});n["default"]=a},35:function(i,n){i.exports='
\n \n
\n \n

index

\n
\n\n \n
\n
demo
\n
\n
    \n \n \n \n \n \n \n \n \n \n \n \n
\n
\n
\n
'}}); -------------------------------------------------------------------------------- /demo/main.js: -------------------------------------------------------------------------------- 1 | import './main.less' 2 | import Vue from 'vue' 3 | import VueRouter from 'vue-router' 4 | import App from './states/app' 5 | import { 6 | picker, 7 | modal, 8 | toast, 9 | alert, 10 | preloader, 11 | indicator, 12 | actions, 13 | pullToRefresh, 14 | infiniteScroll, 15 | popup, 16 | calendar, 17 | datetimePicker 18 | } from '../src/index' 19 | 20 | Vue.use(VueRouter); 21 | Vue.prototype.goBack = function(_this){ 22 | window.history.back(); 23 | }; 24 | Vue.component('picker',picker); 25 | Vue.component('modal',modal); 26 | Vue.component('toast',toast); 27 | Vue.component('alert',alert); 28 | Vue.component('preloader',preloader); 29 | Vue.component('indicator',indicator); 30 | Vue.component('actions',actions); 31 | Vue.component('calendar',calendar); 32 | Vue.component('datetime-picker',datetimePicker) 33 | 34 | Vue.directive('pull-to-refresh',pullToRefresh) 35 | Vue.directive('infinite-scroll',infiniteScroll) 36 | Vue.directive('popup',popup) 37 | 38 | var router = new VueRouter({ 39 | history: true, //html5模式 去掉锚点 40 | saveScrollPosition: true //记住页面的滚动位置 html5模式适用 41 | }) 42 | 43 | router.map({ 44 | '/demo/index': { 45 | component: function (resolve) { 46 | //webpack自带功能 实现异步加载路由 47 | require.ensure([], function () { 48 | let route = require('./states/index/route').default; 49 | resolve(route); 50 | }) 51 | } 52 | }, 53 | '/demo/picker': { 54 | component: function (resolve) { 55 | //webpack自带功能 实现异步加载路由 56 | require.ensure([], function () { 57 | let route = require('./states/picker/route').default; 58 | resolve(route); 59 | }) 60 | } 61 | }, 62 | '/demo/toast': { 63 | component: function (resolve) { 64 | //webpack自带功能 实现异步加载路由 65 | require.ensure([], function () { 66 | let route = require('./states/toast/route').default; 67 | resolve(route); 68 | }) 69 | } 70 | }, 71 | '/demo/alert': { 72 | component: function (resolve) { 73 | //webpack自带功能 实现异步加载路由 74 | require.ensure([], function () { 75 | let route = require('./states/alert/route').default; 76 | resolve(route); 77 | }) 78 | } 79 | }, 80 | '/demo/preloader': { 81 | component: function (resolve) { 82 | //webpack自带功能 实现异步加载路由 83 | require.ensure([], function () { 84 | let route = require('./states/preloader/route').default; 85 | resolve(route); 86 | }) 87 | } 88 | }, 89 | '/demo/indicator': { 90 | component: function (resolve) { 91 | //webpack自带功能 实现异步加载路由 92 | require.ensure([], function () { 93 | let route = require('./states/indicator/route').default; 94 | resolve(route); 95 | }) 96 | } 97 | }, 98 | '/demo/actions': { 99 | component: function (resolve) { 100 | //webpack自带功能 实现异步加载路由 101 | require.ensure([], function () { 102 | let route = require('./states/actions/route').default; 103 | resolve(route); 104 | }) 105 | } 106 | }, 107 | '/demo/pullToRefresh': { 108 | component: function (resolve) { 109 | //webpack自带功能 实现异步加载路由 110 | require.ensure([], function () { 111 | let route = require('./states/pullToRefresh/route').default; 112 | resolve(route); 113 | }) 114 | } 115 | }, 116 | '/demo/infiniteScroll': { 117 | component: function (resolve) { 118 | //webpack自带功能 实现异步加载路由 119 | require.ensure([], function () { 120 | let route = require('./states/infiniteScroll/route').default; 121 | resolve(route); 122 | }) 123 | } 124 | }, 125 | '/demo/popup': { 126 | component: function (resolve) { 127 | //webpack自带功能 实现异步加载路由 128 | require.ensure([], function () { 129 | let route = require('./states/popup/route').default; 130 | resolve(route); 131 | }) 132 | } 133 | }, 134 | '/demo/calendar': { 135 | component: function (resolve) { 136 | //webpack自带功能 实现异步加载路由 137 | require.ensure([], function () { 138 | let route = require('./states/calendar/route').default; 139 | resolve(route); 140 | }) 141 | } 142 | }, 143 | '/demo/datetime': { 144 | component: function (resolve) { 145 | //webpack自带功能 实现异步加载路由 146 | require.ensure([], function () { 147 | let route = require('./states/datetime-picker/route').default; 148 | resolve(route); 149 | }) 150 | } 151 | }, 152 | }) 153 | router.redirect({ 154 | '*': '/demo/index' 155 | }) 156 | 157 | router.start(App,'#demo'); -------------------------------------------------------------------------------- /server/typings/body-parser/body-parser.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for body-parser 2 | // Project: http://expressjs.com 3 | // Definitions by: Santi Albo , VILIC VANE , Jonathan Häberle 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | /// 7 | 8 | declare module "body-parser" { 9 | import * as express from "express"; 10 | 11 | /** 12 | * bodyParser: use individual json/urlencoded middlewares 13 | * @deprecated 14 | */ 15 | 16 | function bodyParser(options?: { 17 | /** 18 | * if deflated bodies will be inflated. (default: true) 19 | */ 20 | inflate?: boolean; 21 | /** 22 | * maximum request body size. (default: '100kb') 23 | */ 24 | limit?: any; 25 | /** 26 | * function to verify body content, the parsing can be aborted by throwing an error. 27 | */ 28 | verify?: (req: express.Request, res: express.Response, buf: Buffer, encoding: string) => void; 29 | /** 30 | * only parse objects and arrays. (default: true) 31 | */ 32 | strict?: boolean; 33 | /** 34 | * passed to JSON.parse(). 35 | */ 36 | receiver?: (key: string, value: any) => any; 37 | /** 38 | * parse extended syntax with the qs module. (default: true) 39 | */ 40 | extended?: boolean; 41 | }): express.RequestHandler; 42 | 43 | module bodyParser { 44 | export function json(options?: { 45 | /** 46 | * if deflated bodies will be inflated. (default: true) 47 | */ 48 | inflate?: boolean; 49 | /** 50 | * maximum request body size. (default: '100kb') 51 | */ 52 | limit?: any; 53 | /** 54 | * request content-type to parse, passed directly to the type-is library. (default: 'json') 55 | */ 56 | type?: any; 57 | /** 58 | * function to verify body content, the parsing can be aborted by throwing an error. 59 | */ 60 | verify?: (req: express.Request, res: express.Response, buf: Buffer, encoding: string) => void; 61 | /** 62 | * only parse objects and arrays. (default: true) 63 | */ 64 | strict?: boolean; 65 | /** 66 | * passed to JSON.parse(). 67 | */ 68 | receiver?: (key: string, value: any) => any; 69 | }): express.RequestHandler; 70 | 71 | export function raw(options?: { 72 | /** 73 | * if deflated bodies will be inflated. (default: true) 74 | */ 75 | inflate?: boolean; 76 | /** 77 | * maximum request body size. (default: '100kb') 78 | */ 79 | limit?: any; 80 | /** 81 | * request content-type to parse, passed directly to the type-is library. (default: 'application/octet-stream') 82 | */ 83 | type?: any; 84 | /** 85 | * function to verify body content, the parsing can be aborted by throwing an error. 86 | */ 87 | verify?: (req: express.Request, res: express.Response, buf: Buffer, encoding: string) => void; 88 | }): express.RequestHandler; 89 | 90 | export function text(options?: { 91 | /** 92 | * if deflated bodies will be inflated. (default: true) 93 | */ 94 | inflate?: boolean; 95 | /** 96 | * maximum request body size. (default: '100kb') 97 | */ 98 | limit?: any; 99 | /** 100 | * request content-type to parse, passed directly to the type-is library. (default: 'text/plain') 101 | */ 102 | type?: any; 103 | /** 104 | * function to verify body content, the parsing can be aborted by throwing an error. 105 | */ 106 | verify?: (req: express.Request, res: express.Response, buf: Buffer, encoding: string) => void; 107 | /** 108 | * the default charset to parse as, if not specified in content-type. (default: 'utf-8') 109 | */ 110 | defaultCharset?: string; 111 | }): express.RequestHandler; 112 | 113 | export function urlencoded(options?: { 114 | /** 115 | * if deflated bodies will be inflated. (default: true) 116 | */ 117 | inflate?: boolean; 118 | /** 119 | * maximum request body size. (default: '100kb') 120 | */ 121 | limit?: any; 122 | /** 123 | * request content-type to parse, passed directly to the type-is library. (default: 'urlencoded') 124 | */ 125 | type?: any; 126 | /** 127 | * function to verify body content, the parsing can be aborted by throwing an error. 128 | */ 129 | verify?: (req: express.Request, res: express.Response, buf: Buffer, encoding: string) => void; 130 | /** 131 | * parse extended syntax with the qs module. (default: true) 132 | */ 133 | extended?: boolean; 134 | }): express.RequestHandler; 135 | } 136 | 137 | export = bodyParser; 138 | } -------------------------------------------------------------------------------- /src/component/calendar/calendar-month.js: -------------------------------------------------------------------------------- 1 | import tpl from './calendar-month.html' 2 | 3 | 4 | export default { 5 | template : tpl, 6 | props: { 7 | value : { 8 | default: '' 9 | }, 10 | translate : { 11 | type : Number, 12 | default: 0 13 | } 14 | }, 15 | data(){ 16 | return { 17 | date : '', 18 | year : '', 19 | month : '', 20 | day : '', 21 | 22 | dayArray : [ 23 | [],[],[],[],[],[] 24 | ], 25 | currentValues : [], 26 | transformStyle : { 27 | transform : '' 28 | } 29 | } 30 | }, 31 | events : { 32 | 'select-day' : function(day){ 33 | this.jisuan(); 34 | } 35 | }, 36 | methods: { 37 | daysInMonth(date) { 38 | var d = new Date(date); 39 | return new Date(d.getFullYear(), d.getMonth() + 1, 0).getDate(); 40 | }, 41 | jisuan(){ 42 | let daysInPrevMonth, 43 | daysInMonth, 44 | firstDayOfMonthIndex; 45 | 46 | 47 | this.dayArray = [ 48 | [],[],[],[],[],[] 49 | ]; 50 | this.currentValues = []; 51 | //初始化年月日 52 | this.date = new Date(this.value); 53 | this.year = this.date.getFullYear(); 54 | this.month = this.date.getMonth(); 55 | this.day = this.date.getDate(); 56 | 57 | 58 | daysInPrevMonth = this.daysInMonth(new Date(this.date.getFullYear(), this.date.getMonth()).getTime() - 10 * 24 * 60 * 60 * 1000); 59 | daysInMonth = this.daysInMonth(this.date); 60 | firstDayOfMonthIndex = new Date(this.date.getFullYear(), this.date.getMonth()).getDay(); 61 | if (firstDayOfMonthIndex === 0) firstDayOfMonthIndex = 7; 62 | 63 | let dayDate, i, j, 64 | rows = 6, cols = 7, 65 | monthHTML = '', 66 | dayIndex = 0 + (this.$parent.options.firstDay - 1), 67 | today = new Date().setHours(0,0,0,0), 68 | minDate = this.$parent.options.minDate ? new Date(this.$parent.options.minDate).getTime() : null, 69 | maxDate = this.$parent.options.maxDate ? new Date(this.$parent.options.maxDate).getTime() : null; 70 | 71 | if (this.$parent.options.values && this.$parent.options.values.length) { 72 | for (i = 0; i < this.$parent.options.values.length; i++) { 73 | this.currentValues.push(new Date(this.$parent.options.values[i]).setHours(0,0,0,0)); 74 | } 75 | } 76 | for (i = 1; i <= rows; i++) { 77 | var rowHTML = ''; 78 | var row = i; 79 | for (j = 1; j <= cols; j++) { 80 | var col = j; 81 | dayIndex ++; 82 | var dayNumber = dayIndex - firstDayOfMonthIndex; 83 | var addClass = ''; 84 | if (dayNumber < 0) { 85 | dayNumber = daysInPrevMonth + dayNumber + 1; 86 | addClass += ' picker-calendar-day-prev'; 87 | dayDate = new Date(this.month - 1 < 0 ? this.year - 1 : this.year, this.month - 1 < 0 ? 11 : this.month - 1, dayNumber).getTime(); 88 | } 89 | else { 90 | dayNumber = dayNumber + 1; 91 | if (dayNumber > daysInMonth) { 92 | dayNumber = dayNumber - daysInMonth; 93 | addClass += ' picker-calendar-day-next'; 94 | dayDate = new Date(this.month + 1 > 11 ? this.year + 1 : this.year, this.month + 1 > 11 ? 0 : this.month + 1, dayNumber).getTime(); 95 | } 96 | else { 97 | dayDate = new Date(this.year, this.month, dayNumber).getTime(); 98 | } 99 | } 100 | // Today 101 | if (dayDate === today) addClass += ' picker-calendar-day-today'; 102 | // Selected 103 | if (this.currentValues.indexOf(dayDate) >= 0) addClass += ' picker-calendar-day-selected'; 104 | // Weekend 105 | if (this.$parent.options.weekendDays.indexOf(col - 1) >= 0) { 106 | addClass += ' picker-calendar-day-weekend'; 107 | } 108 | // Disabled 109 | if ((minDate && dayDate < minDate) || (maxDate && dayDate > maxDate)) { 110 | addClass += ' picker-calendar-day-disabled'; 111 | } 112 | 113 | dayDate = new Date(dayDate); 114 | var dayYear = dayDate.getFullYear(); 115 | var dayMonth = dayDate.getMonth(); 116 | 117 | // console.log(this.dayArray[row-1]) 118 | this.dayArray[row-1].push({ 119 | className : addClass, 120 | dayYear : dayYear, 121 | dayMonth : dayMonth, 122 | dayNumber : dayNumber, 123 | }); 124 | } 125 | } 126 | 127 | }, 128 | dayClick(day){ 129 | this.$dispatch('dayClick',day); 130 | } 131 | }, 132 | beforeCompile(){ 133 | this.jisuan(); 134 | }, 135 | ready(){ 136 | this.transformStyle.transform = 'translate3d('+(this.translate)+'00%, 0%, 0px)'; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/component/datetime-picker/datetime-picker.js: -------------------------------------------------------------------------------- 1 | import tpl from './datetime-picker.html' 2 | import picker from '../picker/picker' 3 | 4 | export default { 5 | template : tpl, 6 | props: { 7 | input: { 8 | type : String, 9 | default: '' 10 | }, 11 | headerText : { 12 | type : String, 13 | default: '请选择' 14 | }, 15 | datetime : { 16 | type : String, 17 | default: '' 18 | }, 19 | open: { 20 | type: Boolean, 21 | default: false 22 | }, 23 | }, 24 | components: { 25 | picker : picker, 26 | }, 27 | data : ()=>{ 28 | return { 29 | options : [ 30 | { 31 | values : [] 32 | }, 33 | { 34 | values : [] 35 | }, 36 | { 37 | values : [] 38 | }, 39 | { 40 | values : [] 41 | }, 42 | { 43 | divider: true, 44 | content: ':' 45 | }, 46 | { 47 | values : [] 48 | } 49 | ], 50 | datetimeValue : [ 51 | { 52 | text : '2016', 53 | value : 2016 54 | }, 55 | { 56 | text : '04', 57 | value : 4 58 | }, 59 | { 60 | text : '30', 61 | value : 30 62 | }, 63 | { 64 | text : '12', 65 | value : 12 66 | }, 67 | { 68 | text : '0', 69 | value : 0 70 | }, 71 | { 72 | text : '23', 73 | value : 23 74 | } 75 | 76 | ], 77 | year : '', 78 | month : '' 79 | } 80 | }, 81 | methods : { 82 | ok(value){ 83 | this.datetime =[ 84 | [value[0].text,value[1].text,value[2].text].join('-'), 85 | [value[3].text > 9 ? value[3].text : '0'+value[3].text ,value[5].text,'00'].join(':') 86 | ].join(' '); 87 | }, 88 | getDaysByMonthAndYear(value){ 89 | 90 | let year = value[0].value; 91 | let month = value[1].value; 92 | let day = value[2].value; 93 | if(this.year == year && this.month == month){ 94 | return; 95 | }else{ 96 | this.year = year; 97 | this.month = month; 98 | } 99 | 100 | let int_d = new Date(year, parseInt(month), 1); 101 | let d = new Date(int_d - 1); 102 | 103 | this.initDay(d.getDate()); 104 | 105 | //获取日期选择组件 106 | try{ 107 | 108 | let dayPickerCol = this.$children[0].$children[2]; 109 | if(day > this.options[2].values.length){ 110 | dayPickerCol.replaceValues(this.options[2],this.options[2].values[this.options[2].values.length-1]); 111 | }else{ 112 | dayPickerCol.replaceValues(this.options[2],value[2]); 113 | } 114 | }catch (e){ 115 | 116 | } 117 | 118 | }, 119 | initYear(){ 120 | for (let i = 1950; i <= 2030; i++) { 121 | this.options[0].values.push({ 122 | text : i, 123 | value : i 124 | }); 125 | } 126 | }, 127 | initMonth(){ 128 | for (let i = 1; i < 13; i++) { 129 | this.options[1].values.push({ 130 | text: i < 10 ? '0' + i : i, 131 | value: i 132 | }); 133 | } 134 | }, 135 | initDay(max){ 136 | this.options[2].values = []; 137 | for(let i=1; i<= (max||31);i++) { 138 | this.options[2].values.push({ 139 | text : i < 10 ? '0' + i : i, 140 | value : i 141 | }); 142 | } 143 | }, 144 | initHours(){ 145 | for(let i = 0; i <= 23; i++){ 146 | this.options[3].values.push({ 147 | text : i , 148 | value : i 149 | }); 150 | } 151 | }, 152 | initMinutes(){ 153 | for(let i = 0; i <= 59; i++){ 154 | this.options[5].values.push({ 155 | text : i < 10 ? '0' + i : i, 156 | value : i 157 | }); 158 | } 159 | } 160 | }, 161 | init(){ 162 | console.log('datetime-picker init') 163 | }, 164 | beforeCompile(){ 165 | this.initYear(); 166 | this.initMonth(); 167 | this.getDaysByMonthAndYear(this.datetimeValue); 168 | this.initHours(); 169 | this.initMinutes(); 170 | }, 171 | ready(){ 172 | let self = this; 173 | console.log('datetime-picker ready'); 174 | 175 | if($(this.input) && $(this.input).length > 0){ 176 | $(this.input).on('click',(e)=>{ 177 | this.open = true; 178 | }) 179 | } 180 | //点击其他地方关闭 181 | $('html').on('click', (e)=>{ 182 | if($(this.input) && $(this.input).length > 0){ 183 | if(e.target !== $(this.input)[0] && $(e.target).parents('.picker-modal').length === 0){ 184 | this.open = false; 185 | } 186 | }else{ 187 | if($(e.target).parents('.picker-modal').length === 0) { 188 | this.open = false; 189 | } 190 | } 191 | }); 192 | 193 | } 194 | } -------------------------------------------------------------------------------- /src/directive/pullToRefresh.js: -------------------------------------------------------------------------------- 1 | let isTouched, isMoved, touchesStart = {}, 2 | isScrolling, touchesDiff, touchStartTime, container, refresh = false, 3 | useTranslate = false, 4 | startTranslate = 0, 5 | translate, scrollTop, wasScrolled, triggerDistance, dynamicTriggerDistance; 6 | 7 | 8 | export default { 9 | bind: function () { 10 | container = $(this.el); 11 | container.addClass('native-scroll'); 12 | 13 | if(container.attr('data-ptr-distance')){ 14 | dynamicTriggerDistance = true; 15 | }else{ 16 | triggerDistance = 44; //默认下拉距离 17 | } 18 | 19 | this.initEvents(); 20 | }, 21 | update: function (promiseOrNull) { 22 | if(promiseOrNull == null){ 23 | 24 | }else if(typeof promiseOrNull == 'function'){ 25 | this.callback = promiseOrNull; 26 | }else{ 27 | console.log('下拉刷新指令 必须是一个返回promise的function') 28 | } 29 | }, 30 | unbind: function () { 31 | this.initEvents(true) 32 | }, 33 | initEvents(detach){ 34 | let method = detach?'off':'on'; 35 | $(this.el)[method]($.touchEvents.start,this.handleTouchStart.bind(this)); 36 | $(this.el)[method]($.touchEvents.move, this.handleTouchMove.bind(this)); 37 | $(this.el)[method]($.touchEvents.end, this.handleTouchEnd.bind(this)); 38 | }, 39 | handleTouchStart(e){ 40 | if (isTouched) { 41 | if ($.device.android) { 42 | if ('targetTouches' in e && e.targetTouches.length > 1) return; 43 | } else return; 44 | } 45 | isMoved = false; 46 | isTouched = true; 47 | isScrolling = undefined; 48 | wasScrolled = undefined; 49 | touchesStart.x = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX; 50 | touchesStart.y = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY; 51 | touchStartTime = (new Date()).getTime(); 52 | /*jshint validthis:true */ 53 | container = $(this.el); 54 | }, 55 | handleTouchMove : function(e){ 56 | if (!isTouched) return; 57 | var pageX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX; 58 | var pageY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY; 59 | if (typeof isScrolling === 'undefined') { 60 | isScrolling = !!(isScrolling || Math.abs(pageY - touchesStart.y) > Math.abs(pageX - touchesStart.x)); 61 | } 62 | if (!isScrolling) { 63 | isTouched = false; 64 | return; 65 | } 66 | 67 | scrollTop = container[0].scrollTop; 68 | if (typeof wasScrolled === 'undefined' && scrollTop !== 0) wasScrolled = true; 69 | 70 | if (!isMoved) { 71 | /*jshint validthis:true */ 72 | container.removeClass('transitioning'); 73 | if (scrollTop > container[0].offsetHeight) { 74 | isTouched = false; 75 | return; 76 | } 77 | if (dynamicTriggerDistance) { 78 | triggerDistance = container.attr('data-ptr-distance'); 79 | if (triggerDistance.indexOf('%') >= 0) triggerDistance = container[0].offsetHeight * parseInt(triggerDistance, 10) / 100; 80 | } 81 | startTranslate = container.hasClass('refreshing') ? triggerDistance : 0; 82 | if (container[0].scrollHeight === container[0].offsetHeight || !$.device.ios) { 83 | useTranslate = true; 84 | } else { 85 | useTranslate = false; 86 | } 87 | useTranslate = true; 88 | } 89 | isMoved = true; 90 | touchesDiff = pageY - touchesStart.y; 91 | 92 | if (touchesDiff > 0 && scrollTop <= 0 || scrollTop < 0) { 93 | // iOS 8 fix 94 | if ($.device.ios && parseInt($.device.osVersion.split('.')[0], 10) > 7 && scrollTop === 0 && !wasScrolled) useTranslate = true; 95 | 96 | if (useTranslate) { 97 | e.preventDefault(); 98 | translate = (Math.pow(touchesDiff, 0.85) + startTranslate); 99 | container.transform('translate3d(0,' + translate + 'px,0)'); 100 | } else {} 101 | if ((useTranslate && Math.pow(touchesDiff, 0.85) > triggerDistance) || (!useTranslate && touchesDiff >= triggerDistance * 2)) { 102 | refresh = true; 103 | container.addClass('pull-up').removeClass('pull-down'); 104 | } else { 105 | refresh = false; 106 | container.removeClass('pull-up').addClass('pull-down'); 107 | } 108 | } else { 109 | 110 | container.removeClass('pull-up pull-down'); 111 | refresh = false; 112 | return; 113 | } 114 | }, 115 | handleTouchEnd(e){ 116 | if (!isTouched || !isMoved) { 117 | isTouched = false; 118 | isMoved = false; 119 | return; 120 | } 121 | if (translate) { 122 | container.addClass('transitioning'); 123 | translate = 0; 124 | } 125 | container.transform(''); 126 | if (refresh) { 127 | //防止二次触发 128 | if(container.hasClass('refreshing')) return; 129 | container.addClass('refreshing'); 130 | container.trigger('refresh'); 131 | } else { 132 | container.removeClass('pull-down'); 133 | } 134 | isTouched = false; 135 | isMoved = false; 136 | 137 | //需要传入一个返回promise对象的方法来关闭加载提示状态 138 | this.callback().then((data)=>{ 139 | this.pullToRefreshDone(container) 140 | }).catch(()=>{ 141 | this.pullToRefreshDone(container) 142 | }); 143 | }, 144 | pullToRefreshDone(container){ 145 | $(window).scrollTop(0);//解决微信下拉刷新顶部消失的问题 146 | container = $(container); 147 | if (container.length === 0) container = $('.pull-to-refresh-content.refreshing'); 148 | container.removeClass('refreshing').addClass('transitioning'); 149 | container.transitionEnd(function() { 150 | container.removeClass('transitioning pull-up pull-down'); 151 | }); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /server/typings/request/request.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for request 2 | // Project: https://github.com/mikeal/request 3 | // Definitions by: Carlos Ballesteros Velasco , bonnici , Bart van der Schoor , Joe Skeen 4 | // Definitions: https://github.com/borisyankov/DefinitelyTyped 5 | 6 | // Imported from: https://github.com/soywiz/typescript-node-definitions/d.ts 7 | 8 | /// 9 | /// 10 | 11 | declare module 'request' { 12 | import stream = require('stream'); 13 | import http = require('http'); 14 | import FormData = require('form-data'); 15 | import url = require('url'); 16 | import fs = require('fs'); 17 | 18 | namespace request { 19 | export interface RequestAPI { 20 | defaults(options: TOptions): RequestAPI; 21 | (uri: string, options?: TOptions, callback?: RequestCallback): TRequest; 22 | (uri: string, callback?: RequestCallback): TRequest; 23 | (options?: RequiredOptions & TOptions, callback?: RequestCallback): TRequest; 24 | 25 | get(uri: string, options?: TOptions, callback?: RequestCallback): TRequest; 26 | get(uri: string, callback?: RequestCallback): TRequest; 27 | get(options: RequiredOptions & TOptions, callback?: RequestCallback): TRequest; 28 | 29 | post(uri: string, options?: TOptions, callback?: RequestCallback): TRequest; 30 | post(uri: string, callback?: RequestCallback): TRequest; 31 | post(options: RequiredOptions & TOptions, callback?: RequestCallback): TRequest; 32 | 33 | put(uri: string, options?: TOptions, callback?: RequestCallback): TRequest; 34 | put(uri: string, callback?: RequestCallback): TRequest; 35 | put(options: RequiredOptions & TOptions, callback?: RequestCallback): TRequest; 36 | 37 | head(uri: string, options?: TOptions, callback?: RequestCallback): TRequest; 38 | head(uri: string, callback?: RequestCallback): TRequest; 39 | head(options: RequiredOptions & TOptions, callback?: RequestCallback): TRequest; 40 | 41 | patch(uri: string, options?: TOptions, callback?: RequestCallback): TRequest; 42 | patch(uri: string, callback?: RequestCallback): TRequest; 43 | patch(options: RequiredOptions & TOptions, callback?: RequestCallback): TRequest; 44 | 45 | del(uri: string, options?: TOptions, callback?: RequestCallback): TRequest; 46 | del(uri: string, callback?: RequestCallback): TRequest; 47 | del(options: RequiredOptions & TOptions, callback?: RequestCallback): TRequest; 48 | 49 | forever(agentOptions: any, optionsArg: any): TRequest; 50 | jar(): CookieJar; 51 | cookie(str: string): Cookie; 52 | 53 | initParams: any; 54 | debug: boolean; 55 | } 56 | 57 | interface UriOptions { 58 | uri: string; 59 | } 60 | 61 | interface UrlOptions { 62 | url: string; 63 | } 64 | 65 | interface OptionalOptions { 66 | callback?: (error: any, response: http.IncomingMessage, body: any) => void; 67 | jar?: any; // CookieJar 68 | formData?: any; // Object 69 | form?: any; // Object or string 70 | auth?: AuthOptions; 71 | oauth?: OAuthOptions; 72 | aws?: AWSOptions; 73 | hawk?: HawkOptions; 74 | qs?: any; 75 | json?: any; 76 | multipart?: RequestPart[] | Multipart; 77 | agentOptions?: any; 78 | agentClass?: any; 79 | forever?: any; 80 | host?: string; 81 | port?: number; 82 | method?: string; 83 | headers?: Headers; 84 | body?: any; 85 | followRedirect?: boolean | ((response: http.IncomingMessage) => boolean); 86 | followAllRedirects?: boolean; 87 | maxRedirects?: number; 88 | encoding?: string; 89 | pool?: any; 90 | timeout?: number; 91 | proxy?: any; 92 | strictSSL?: boolean; 93 | gzip?: boolean; 94 | preambleCRLF?: boolean; 95 | postambleCRLF?: boolean; 96 | key?: Buffer; 97 | cert?: Buffer; 98 | passphrase?: string; 99 | ca?: Buffer; 100 | har?: HttpArchiveRequest; 101 | } 102 | 103 | export type RequiredOptions = UriOptions | UrlOptions; 104 | export type Options = RequiredOptions & OptionalOptions; 105 | 106 | export interface RequestCallback { 107 | (error: any, response: http.IncomingMessage, body: any): void; 108 | } 109 | 110 | export interface HttpArchiveRequest { 111 | url?: string; 112 | method?: string; 113 | headers?: NameValuePair[]; 114 | postData?: { 115 | mimeType?: string; 116 | params?: NameValuePair[]; 117 | } 118 | } 119 | 120 | export interface NameValuePair { 121 | name: string; 122 | value: string; 123 | } 124 | 125 | export interface Multipart { 126 | chunked?: boolean; 127 | data?: { 128 | 'content-type'?: string, 129 | body: string 130 | }[]; 131 | } 132 | 133 | export interface RequestPart { 134 | headers?: Headers; 135 | body: any; 136 | } 137 | 138 | export interface Request extends stream.Stream { 139 | readable: boolean; 140 | writable: boolean; 141 | 142 | getAgent(): http.Agent; 143 | //start(): void; 144 | //abort(): void; 145 | pipeDest(dest: any): void; 146 | setHeader(name: string, value: string, clobber?: boolean): Request; 147 | setHeaders(headers: Headers): Request; 148 | qs(q: Object, clobber?: boolean): Request; 149 | form(): FormData.FormData; 150 | form(form: any): Request; 151 | multipart(multipart: RequestPart[]): Request; 152 | json(val: any): Request; 153 | aws(opts: AWSOptions, now?: boolean): Request; 154 | auth(username: string, password: string, sendInmediately?: boolean, bearer?: string): Request; 155 | oauth(oauth: OAuthOptions): Request; 156 | jar(jar: CookieJar): Request; 157 | 158 | on(event: string, listener: Function): Request; 159 | 160 | write(buffer: Buffer, cb?: Function): boolean; 161 | write(str: string, cb?: Function): boolean; 162 | write(str: string, encoding: string, cb?: Function): boolean; 163 | write(str: string, encoding?: string, fd?: string): boolean; 164 | end(): void; 165 | end(chunk: Buffer, cb?: Function): void; 166 | end(chunk: string, cb?: Function): void; 167 | end(chunk: string, encoding: string, cb?: Function): void; 168 | pause(): void; 169 | resume(): void; 170 | abort(): void; 171 | destroy(): void; 172 | toJSON(): Object; 173 | } 174 | 175 | export interface Headers { 176 | [key: string]: any; 177 | } 178 | 179 | export interface AuthOptions { 180 | user?: string; 181 | username?: string; 182 | pass?: string; 183 | password?: string; 184 | sendImmediately?: boolean; 185 | bearer?: string; 186 | } 187 | 188 | export interface OAuthOptions { 189 | callback?: string; 190 | consumer_key?: string; 191 | consumer_secret?: string; 192 | token?: string; 193 | token_secret?: string; 194 | verifier?: string; 195 | } 196 | 197 | export interface HawkOptions { 198 | credentials: any; 199 | } 200 | 201 | export interface AWSOptions { 202 | secret: string; 203 | bucket?: string; 204 | } 205 | 206 | export interface CookieJar { 207 | setCookie(cookie: Cookie, uri: string | url.Url, options?: any): void 208 | getCookieString(uri: string | url.Url): string 209 | getCookies(uri: string | url.Url): Cookie[] 210 | } 211 | 212 | export interface CookieValue { 213 | name: string; 214 | value: any; 215 | httpOnly: boolean; 216 | } 217 | 218 | export interface Cookie extends Array { 219 | constructor(name: string, req: Request): void; 220 | str: string; 221 | expires: Date; 222 | path: string; 223 | toString(): string; 224 | } 225 | } 226 | var request: request.RequestAPI; 227 | export = request; 228 | } 229 | -------------------------------------------------------------------------------- /src/util/zepto-adapter.js: -------------------------------------------------------------------------------- 1 | /* global WebKitCSSMatrix:true */ 2 | 3 | (function($) { 4 | "use strict"; 5 | ['width', 'height'].forEach(function(dimension) { 6 | var Dimension = dimension.replace(/./, function(m) { 7 | return m[0].toUpperCase(); 8 | }); 9 | $.fn['outer' + Dimension] = function(margin) { 10 | var elem = this; 11 | if (elem) { 12 | var size = elem[dimension](); 13 | var sides = { 14 | 'width': ['left', 'right'], 15 | 'height': ['top', 'bottom'] 16 | }; 17 | sides[dimension].forEach(function(side) { 18 | if (margin) size += parseInt(elem.css('margin-' + side), 10); 19 | }); 20 | return size; 21 | } else { 22 | return null; 23 | } 24 | }; 25 | }); 26 | 27 | //support 28 | $.support = (function() { 29 | var support = { 30 | touch: !!(('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch) 31 | }; 32 | return support; 33 | })(); 34 | 35 | $.touchEvents = { 36 | start: $.support.touch ? 'touchstart' : 'mousedown', 37 | move: $.support.touch ? 'touchmove' : 'mousemove', 38 | end: $.support.touch ? 'touchend' : 'mouseup' 39 | }; 40 | 41 | $.getTranslate = function (el, axis) { 42 | var matrix, curTransform, curStyle, transformMatrix; 43 | 44 | // automatic axis detection 45 | if (typeof axis === 'undefined') { 46 | axis = 'x'; 47 | } 48 | 49 | curStyle = window.getComputedStyle(el, null); 50 | if (window.WebKitCSSMatrix) { 51 | // Some old versions of Webkit choke when 'none' is passed; pass 52 | // empty string instead in this case 53 | transformMatrix = new WebKitCSSMatrix(curStyle.webkitTransform === 'none' ? '' : curStyle.webkitTransform); 54 | } 55 | else { 56 | transformMatrix = curStyle.MozTransform || curStyle.transform || curStyle.getPropertyValue('transform').replace('translate(', 'matrix(1, 0, 0, 1,'); 57 | matrix = transformMatrix.toString().split(','); 58 | } 59 | 60 | if (axis === 'x') { 61 | //Latest Chrome and webkits Fix 62 | if (window.WebKitCSSMatrix) 63 | curTransform = transformMatrix.m41; 64 | //Crazy IE10 Matrix 65 | else if (matrix.length === 16) 66 | curTransform = parseFloat(matrix[12]); 67 | //Normal Browsers 68 | else 69 | curTransform = parseFloat(matrix[4]); 70 | } 71 | if (axis === 'y') { 72 | //Latest Chrome and webkits Fix 73 | if (window.WebKitCSSMatrix) 74 | curTransform = transformMatrix.m42; 75 | //Crazy IE10 Matrix 76 | else if (matrix.length === 16) 77 | curTransform = parseFloat(matrix[13]); 78 | //Normal Browsers 79 | else 80 | curTransform = parseFloat(matrix[5]); 81 | } 82 | 83 | return curTransform || 0; 84 | }; 85 | /* jshint ignore:start */ 86 | $.requestAnimationFrame = function (callback) { 87 | if (window.requestAnimationFrame) return window.requestAnimationFrame(callback); 88 | else if (window.webkitRequestAnimationFrame) return window.webkitRequestAnimationFrame(callback); 89 | else if (window.mozRequestAnimationFrame) return window.mozRequestAnimationFrame(callback); 90 | else { 91 | return window.setTimeout(callback, 1000 / 60); 92 | } 93 | }; 94 | $.cancelAnimationFrame = function (id) { 95 | if (window.cancelAnimationFrame) return window.cancelAnimationFrame(id); 96 | else if (window.webkitCancelAnimationFrame) return window.webkitCancelAnimationFrame(id); 97 | else if (window.mozCancelAnimationFrame) return window.mozCancelAnimationFrame(id); 98 | else { 99 | return window.clearTimeout(id); 100 | } 101 | }; 102 | /* jshint ignore:end */ 103 | 104 | $.fn.dataset = function() { 105 | var dataset = {}, 106 | ds = this[0].dataset; 107 | for (var key in ds) { // jshint ignore:line 108 | var item = (dataset[key] = ds[key]); 109 | if (item === 'false') dataset[key] = false; 110 | else if (item === 'true') dataset[key] = true; 111 | else if (parseFloat(item) === item * 1) dataset[key] = item * 1; 112 | } 113 | // mixin dataset and __eleData 114 | return $.extend({}, dataset, this[0].__eleData); 115 | }; 116 | $.fn.data = function(key, value) { 117 | var tmpData = $(this).dataset(); 118 | if (!key) { 119 | return tmpData; 120 | } 121 | // value may be 0, false, null 122 | if (typeof value === 'undefined') { 123 | // Get value 124 | var dataVal = tmpData[key], 125 | __eD = this[0].__eleData; 126 | 127 | //if (dataVal !== undefined) { 128 | if (__eD && (key in __eD)) { 129 | return __eD[key]; 130 | } else { 131 | return dataVal; 132 | } 133 | 134 | } else { 135 | // Set value,uniformly set in extra ```__eleData``` 136 | for (var i = 0; i < this.length; i++) { 137 | var el = this[i]; 138 | // delete multiple data in dataset 139 | if (key in tmpData) delete el.dataset[key]; 140 | 141 | if (!el.__eleData) el.__eleData = {}; 142 | el.__eleData[key] = value; 143 | } 144 | return this; 145 | } 146 | }; 147 | function __dealCssEvent(eventNameArr, callback) { 148 | var events = eventNameArr, 149 | i, dom = this;// jshint ignore:line 150 | 151 | function fireCallBack(e) { 152 | /*jshint validthis:true */ 153 | if (e.target !== this) return; 154 | callback.call(this, e); 155 | for (i = 0; i < events.length; i++) { 156 | dom.off(events[i], fireCallBack); 157 | } 158 | } 159 | if (callback) { 160 | for (i = 0; i < events.length; i++) { 161 | dom.on(events[i], fireCallBack); 162 | } 163 | } 164 | } 165 | $.fn.animationEnd = function(callback) { 166 | __dealCssEvent.call(this, ['webkitAnimationEnd', 'animationend'], callback); 167 | return this; 168 | }; 169 | $.fn.transitionEnd = function(callback) { 170 | __dealCssEvent.call(this, ['webkitTransitionEnd', 'transitionend'], callback); 171 | return this; 172 | }; 173 | $.fn.transition = function(duration) { 174 | if (typeof duration !== 'string') { 175 | duration = duration + 'ms'; 176 | } 177 | for (var i = 0; i < this.length; i++) { 178 | var elStyle = this[i].style; 179 | elStyle.webkitTransitionDuration = elStyle.MozTransitionDuration = elStyle.transitionDuration = duration; 180 | } 181 | return this; 182 | }; 183 | $.fn.transform = function(transform) { 184 | for (var i = 0; i < this.length; i++) { 185 | var elStyle = this[i].style; 186 | elStyle.webkitTransform = elStyle.MozTransform = elStyle.transform = transform; 187 | } 188 | return this; 189 | }; 190 | $.fn.prevAll = function (selector) { 191 | var prevEls = []; 192 | var el = this[0]; 193 | if (!el) return $([]); 194 | while (el.previousElementSibling) { 195 | var prev = el.previousElementSibling; 196 | if (selector) { 197 | if($(prev).is(selector)) prevEls.push(prev); 198 | } 199 | else prevEls.push(prev); 200 | el = prev; 201 | } 202 | return $(prevEls); 203 | }; 204 | $.fn.nextAll = function (selector) { 205 | var nextEls = []; 206 | var el = this[0]; 207 | if (!el) return $([]); 208 | while (el.nextElementSibling) { 209 | var next = el.nextElementSibling; 210 | if (selector) { 211 | if($(next).is(selector)) nextEls.push(next); 212 | } 213 | else nextEls.push(next); 214 | el = next; 215 | } 216 | return $(nextEls); 217 | }; 218 | 219 | //重置zepto的show方法,防止有些人引用的版本中 show 方法操作 opacity 属性影响动画执行 220 | $.fn.show = function(){ 221 | var elementDisplay = {}; 222 | function defaultDisplay(nodeName) { 223 | var element, display; 224 | if (!elementDisplay[nodeName]) { 225 | element = document.createElement(nodeName); 226 | document.body.appendChild(element); 227 | display = getComputedStyle(element, '').getPropertyValue("display"); 228 | element.parentNode.removeChild(element); 229 | display === "none" && (display = "block"); 230 | elementDisplay[nodeName] = display; 231 | } 232 | return elementDisplay[nodeName]; 233 | } 234 | 235 | return this.each(function(){ 236 | this.style.display === "none" && (this.style.display = ''); 237 | if (getComputedStyle(this, '').getPropertyValue("display") === "none"); 238 | this.style.display = defaultDisplay(this.nodeName); 239 | }); 240 | }; 241 | })(Zepto); -------------------------------------------------------------------------------- /src/util/scroller.js: -------------------------------------------------------------------------------- 1 | /* =============================================================================== 2 | ************ scroller ************ 3 | =============================================================================== */ 4 | + function($) { 5 | "use strict"; 6 | //重置zepto自带的滚动条 7 | var _zeptoMethodCache = { 8 | "scrollTop": $.fn.scrollTop, 9 | "scrollLeft": $.fn.scrollLeft 10 | }; 11 | //重置scrollLeft和scrollRight 12 | (function() { 13 | $.extend($.fn, { 14 | scrollTop: function(top, dur) { 15 | if (!this.length) return; 16 | var scroller = this.data('scroller'); 17 | if (scroller && scroller.scroller) { //js滚动 18 | return scroller.scrollTop(top, dur); 19 | } else { 20 | return _zeptoMethodCache.scrollTop.apply(this, arguments); 21 | } 22 | } 23 | }); 24 | $.extend($.fn, { 25 | scrollLeft: function(left, dur) { 26 | if (!this.length) return; 27 | var scroller = this.data('scroller'); 28 | if (scroller && scroller.scroller) { //js滚动 29 | return scroller.scrollLeft(left, dur); 30 | } else { 31 | return _zeptoMethodCache.scrollLeft.apply(this, arguments); 32 | } 33 | } 34 | }); 35 | })(); 36 | 37 | 38 | 39 | //自定义的滚动条 40 | var Scroller = function(pageContent, _options) { 41 | var $pageContent = this.$pageContent = $(pageContent); 42 | 43 | this.options = $.extend({}, this._defaults, _options); 44 | 45 | var type = this.options.type; 46 | //auto的type,系统版本的小于4.4.0的安卓设备和系统版本小于6.0.0的ios设备,启用js版的iscoll 47 | var useJSScroller = (type === 'js') || (type === 'auto' && ($.device.android && $.compareVersion('4.4.0', $.device.osVersion) > -1) || (type === 'auto' && ($.device.ios && $.compareVersion('6.0.0', $.device.osVersion) > -1))); 48 | 49 | if (useJSScroller) { 50 | 51 | var $pageContentInner = $pageContent.find('.content-inner'); 52 | //如果滚动内容没有被包裹,自动添加wrap 53 | if (!$pageContentInner[0]) { 54 | // $pageContent.html('
' + $pageContent.html() + '
'); 55 | var children = $pageContent.children(); 56 | if (children.length < 1) { 57 | $pageContent.children().wrapAll('
'); 58 | } else { 59 | $pageContent.html('
' + $pageContent.html() + '
'); 60 | } 61 | } 62 | 63 | if ($pageContent.hasClass('pull-to-refresh-content')) { 64 | //因为iscroll 当页面高度不足 100% 时无法滑动,所以无法触发下拉动作,这里改动一下高度 65 | //区分是否有.bar容器,如有,则content的top:0,无则content的top:-2.2rem,这里取2.2rem的最大值,近60 66 | var minHeight = $(window).height() + ($pageContent.prev().hasClass(".bar") ? 1 : 61); 67 | $pageContent.find('.content-inner').css('min-height', minHeight + 'px'); 68 | } 69 | 70 | var ptr = $(pageContent).hasClass('pull-to-refresh-content'); 71 | //js滚动模式,用transform移动内容区位置,会导致fixed失效,表现类似absolute。因此禁用transform模式 72 | var useTransform = $pageContent.find('.fixed-tab').length === 0; 73 | var options = { 74 | probeType: 1, 75 | mouseWheel: true, 76 | //解决安卓js模式下,刷新滚动条后绑定的事件不响应,对chrome内核浏览器设置click:true 77 | click: $.device.androidChrome, 78 | useTransform: useTransform, 79 | //js模式下允许滚动条横向滚动,但是需要注意,滚动容易宽度必须大于屏幕宽度滚动才生效 80 | scrollX: true 81 | }; 82 | if (ptr) { 83 | options.ptr = true; 84 | options.ptrOffset = 44; 85 | } 86 | //如果用js滚动条,用transform计算内容区位置,position:fixed将实效。若有.fixed-tab,强制使用native滚动条;备选方案,略粗暴 87 | // if($(pageContent).find('.fixed-tab').length>0){ 88 | // $pageContent.addClass('native-scroll'); 89 | // return; 90 | // } 91 | this.scroller = new IScroll(pageContent, options); // jshint ignore:line 92 | //和native滚动统一起来 93 | this._bindEventToDomWhenJs(); 94 | $.initPullToRefresh = $._pullToRefreshJSScroll.initPullToRefresh; 95 | $.pullToRefreshDone = $._pullToRefreshJSScroll.pullToRefreshDone; 96 | $.pullToRefreshTrigger = $._pullToRefreshJSScroll.pullToRefreshTrigger; 97 | $.destroyToRefresh = $._pullToRefreshJSScroll.destroyToRefresh; 98 | $pageContent.addClass('javascript-scroll'); 99 | if (!useTransform) { 100 | $pageContent.find('.content-inner').css({ 101 | width: '100%', 102 | position: 'absolute' 103 | }); 104 | } 105 | 106 | //如果页面本身已经进行了原生滚动,那么把这个滚动换成JS的滚动 107 | var nativeScrollTop = this.$pageContent[0].scrollTop; 108 | if(nativeScrollTop) { 109 | this.$pageContent[0].scrollTop = 0; 110 | this.scrollTop(nativeScrollTop); 111 | } 112 | } else { 113 | $pageContent.addClass('native-scroll'); 114 | } 115 | }; 116 | Scroller.prototype = { 117 | _defaults: { 118 | type: 'native', 119 | }, 120 | _bindEventToDomWhenJs: function() { 121 | //"scrollStart", //the scroll started. 122 | //"scroll", //the content is scrolling. Available only in scroll-probe.js edition. See onScroll event. 123 | //"scrollEnd", //content stopped scrolling. 124 | if (this.scroller) { 125 | var self = this; 126 | this.scroller.on('scrollStart', function() { 127 | self.$pageContent.trigger('scrollstart'); 128 | }); 129 | this.scroller.on('scroll', function() { 130 | self.$pageContent.trigger('scroll'); 131 | }); 132 | this.scroller.on('scrollEnd', function() { 133 | self.$pageContent.trigger('scrollend'); 134 | }); 135 | } else { 136 | //TODO: 实现native的scrollStart和scrollEnd 137 | } 138 | }, 139 | scrollTop: function(top, dur) { 140 | if (this.scroller) { 141 | if (top !== undefined) { 142 | this.scroller.scrollTo(0, -1 * top, dur); 143 | } else { 144 | return this.scroller.getComputedPosition().y * -1; 145 | } 146 | } else { 147 | return this.$pageContent.scrollTop(top, dur); 148 | } 149 | return this; 150 | }, 151 | scrollLeft: function(left, dur) { 152 | if (this.scroller) { 153 | if (left !== undefined) { 154 | this.scroller.scrollTo(-1 * left, 0); 155 | } else { 156 | return this.scroller.getComputedPosition().x * -1; 157 | } 158 | } else { 159 | return this.$pageContent.scrollTop(left, dur); 160 | } 161 | return this; 162 | }, 163 | on: function(event, callback) { 164 | if (this.scroller) { 165 | this.scroller.on(event, function() { 166 | callback.call(this.wrapper); 167 | }); 168 | } else { 169 | this.$pageContent.on(event, callback); 170 | } 171 | return this; 172 | }, 173 | off: function(event, callback) { 174 | if (this.scroller) { 175 | this.scroller.off(event, callback); 176 | } else { 177 | this.$pageContent.off(event, callback); 178 | } 179 | return this; 180 | }, 181 | refresh: function() { 182 | if (this.scroller) this.scroller.refresh(); 183 | return this; 184 | }, 185 | scrollHeight: function() { 186 | if (this.scroller) { 187 | return this.scroller.scrollerHeight; 188 | } else { 189 | return this.$pageContent[0].scrollHeight; 190 | } 191 | } 192 | 193 | }; 194 | 195 | //Scroller PLUGIN DEFINITION 196 | // ======================= 197 | 198 | function Plugin(option) { 199 | var args = Array.apply(null, arguments); 200 | args.shift(); 201 | var internal_return; 202 | 203 | this.each(function() { 204 | 205 | var $this = $(this); 206 | 207 | var options = $.extend({}, $this.dataset(), typeof option === 'object' && option); 208 | 209 | var data = $this.data('scroller'); 210 | //如果 scroller 没有被初始化,对scroller 进行初始化r 211 | if (!data) { 212 | //获取data-api的 213 | $this.data('scroller', (data = new Scroller(this, options))); 214 | 215 | } 216 | if (typeof option === 'string' && typeof data[option] === 'function') { 217 | internal_return = data[option].apply(data, args); 218 | if (internal_return !== undefined) 219 | return false; 220 | } 221 | 222 | }); 223 | 224 | if (internal_return !== undefined) 225 | return internal_return; 226 | else 227 | return this; 228 | 229 | } 230 | 231 | var old = $.fn.scroller; 232 | 233 | $.fn.scroller = Plugin; 234 | $.fn.scroller.Constructor = Scroller; 235 | 236 | 237 | // Scroll NO CONFLICT 238 | // ================= 239 | 240 | $.fn.scroller.noConflict = function() { 241 | $.fn.scroller = old; 242 | return this; 243 | }; 244 | //添加data-api 245 | $(function() { 246 | $('[data-toggle="scroller"]').scroller(); 247 | }); 248 | 249 | //统一的接口,带有 .javascript-scroll 的content 进行刷新 250 | $.refreshScroller = function(content) { 251 | if (content) { 252 | $(content).scroller('refresh'); 253 | } else { 254 | $('.javascript-scroll').each(function() { 255 | $(this).scroller('refresh'); 256 | }); 257 | } 258 | 259 | }; 260 | //全局初始化方法,会对页面上的 [data-toggle="scroller"],.content. 进行滚动条初始化 261 | $.initScroller = function(option) { 262 | this.options = $.extend({}, typeof option === 'object' && option); 263 | $('[data-toggle="scroller"],.content').scroller(option); 264 | }; 265 | //获取scroller对象 266 | $.getScroller = function(content) { 267 | //以前默认只能有一个无限滚动,因此infinitescroll都是加在content上,现在允许里面有多个,因此要判断父元素是否有content 268 | content = content.hasClass('content') ? content : content.parents('.content'); 269 | if (content) { 270 | return $(content).data('scroller'); 271 | } else { 272 | return $('.content.javascript-scroll').data('scroller'); 273 | } 274 | }; 275 | //检测滚动类型, 276 | //‘js’: javascript 滚动条 277 | //‘native’: 原生滚动条 278 | $.detectScrollerType = function(content) { 279 | if (content) { 280 | if ($(content).data('scroller') && $(content).data('scroller').scroller) { 281 | return 'js'; 282 | } else { 283 | return 'native'; 284 | } 285 | } 286 | }; 287 | 288 | }(Zepto); -------------------------------------------------------------------------------- /src/component/picker/picker-col.js: -------------------------------------------------------------------------------- 1 | import tpl from './picker-col.html' 2 | 3 | 4 | 5 | export default { 6 | template : tpl, 7 | props: { 8 | val: { 9 | type: Object, 10 | default: { 11 | text : '0', 12 | value : 0 13 | } 14 | }, 15 | //选项列表 16 | option: { 17 | type: Object, 18 | default : { 19 | values : [ 20 | 21 | ], 22 | divider : false, 23 | content : '' 24 | } 25 | }, 26 | }, 27 | data(){ 28 | return { 29 | width : 0, 30 | activeIndex : 0, //选中项的下标 31 | animationFrameId : 0, //动画ID 32 | container : null, //组件最外层 33 | wrapper : null, //组件内容层 34 | items : [], //组件选项 35 | wrapperHeight : 0, //内容层高度 36 | itemHeight : 0, //单个选项高度 37 | itemsHeight : 0, //所有选项高度 38 | minTranslate : 0, //最小滚动位置 39 | maxTranslate : 0, //最大滚动位置 40 | allowItemClick : true, //允许选项点击 41 | 42 | touchStartY : 0, //开始滚动页面坐标 43 | touchCurrentY : 0, //当前滚动页面坐标 44 | touchStartTime : 0, //滚动开始时间 45 | touchEndTime : 0, //滚动结束时间 46 | startTranslate : 0, //开始滚动位置 47 | returnTo : 0, // 48 | currentTranslate : 0, //当前滚动位置 49 | prevTranslate : 0, //上次滚动位置 50 | velocityTranslate : 0, //加速度 51 | velocityTime : 0 //加速时间 52 | } 53 | }, 54 | methods: { 55 | //更换数据对象 56 | replaceValues(option,value){ 57 | this.initEvents(true); 58 | 59 | // this.option = values; 60 | 61 | 62 | setTimeout(()=>{ 63 | this.items = $(this.wrapper).find('.picker-item'); 64 | this.calcSize(); 65 | $(this.wrapper).transform('translate3d(0,' + this.maxTranslate + 'px,0)').transition(0); 66 | if(value){ 67 | this.setValue(value, 0); 68 | } 69 | this.initEvents(); 70 | }) 71 | }, 72 | //获取具体尺寸 73 | calcSize(){ 74 | if(this.$parent.rotateEffect){ 75 | $(this.container).removeClass('picker-items-col-absolute'); 76 | if(!this.width) $(this.container).css({width:''}) 77 | } 78 | let colWidth, colHeight; 79 | colWidth = 0; 80 | colHeight = this.container[0].offsetHeight; 81 | this.wrapperHeight = this.wrapper[0].offsetHeight; 82 | this.itemHeight = this.items[0].offsetHeight; 83 | this.itemsHeight = this.itemHeight * this.items.length; 84 | this.minTranslate = colHeight / 2 - this.itemsHeight + this.itemHeight / 2; 85 | this.maxTranslate = colHeight / 2 - this.itemHeight / 2; 86 | if (this.width) { 87 | colWidth = this.width; 88 | if (parseInt(colWidth, 10) === colWidth) colWidth = colWidth + 'px'; 89 | this.container.css({width: colWidth}); 90 | } 91 | if (this.$parent.rotateEffect) { 92 | if (!this.width) { 93 | $(this.items).each(function () { 94 | var item = $(this); 95 | $(item).css({width:'auto'}); 96 | colWidth = Math.max(colWidth, $(item)[0].offsetWidth); 97 | $(item).css({width:''}); 98 | }); 99 | $(this.container).css({width: (colWidth + 2) + 'px'}); 100 | } 101 | $(this.container).addClass('picker-items-col-absolute'); 102 | } 103 | }, 104 | setValue(newValue,transition,valueCallbacks){ 105 | if (typeof transition === 'undefined') transition = ''; 106 | var newActiveIndex = this.aIndex(newValue) 107 | if(typeof newActiveIndex === 'undefined' || newActiveIndex === -1) { 108 | return; 109 | } 110 | var newTranslate = -newActiveIndex * this.itemHeight + this.maxTranslate; 111 | // Update wrapper 112 | $(this.wrapper).transition(transition); 113 | $(this.wrapper).transform('translate3d(0,' + (newTranslate) + 'px,0)'); 114 | 115 | // Watch items 116 | if (this.$parent.updateValuesOnMomentum && this.activeIndex && this.activeIndex !== newActiveIndex ) { 117 | $.cancelAnimationFrame(this.animationFrameId); 118 | $(this.wrapper).transitionEnd(function(){ 119 | $.cancelAnimationFrame(this.animationFrameId); 120 | }); 121 | this.updateDuringScroll(); 122 | } 123 | 124 | // Update items 125 | this.updateItems(newActiveIndex, newTranslate, transition, valueCallbacks); 126 | }, 127 | //更新选项 128 | updateItems(activeIndex, translate, transition, valueCallbacks){ 129 | if (typeof translate === 'undefined') { 130 | translate = $.getTranslate(this.wrapper[0], 'y'); 131 | } 132 | if(typeof activeIndex === 'undefined') activeIndex = -Math.round((translate - this.maxTranslate)/this.itemHeight); 133 | if (activeIndex < 0) activeIndex = 0; 134 | if (activeIndex >= this.items.length) activeIndex = this.items.length - 1; 135 | var previousActiveIndex = this.activeIndex; 136 | this.activeIndex = activeIndex; 137 | 138 | 139 | let oldVal = this.val.value; 140 | //设置新值 141 | this.val = this.option.values[this.activeIndex]; 142 | if(this.$parent.onChange && this.val.value !== oldVal){ 143 | this.$parent.onChange(this.$parent.val); 144 | } 145 | if (this.$parent.rotateEffect) { 146 | $(this.items).transition(transition); 147 | } 148 | $(this.items[activeIndex]).transform(''); 149 | 150 | 151 | // Set 3D rotate effect 152 | if (!this.$parent.rotateEffect) { 153 | return; 154 | } 155 | var percentage = (translate - (Math.floor((translate - this.maxTranslate)/this.itemHeight) * this.itemHeight + this.maxTranslate)) / this.itemHeight; 156 | 157 | var self = this; 158 | // 3D Transforms origin bug, only on safari 159 | var originBug = $.device.ios || (navigator.userAgent.toLowerCase().indexOf('safari') >= 0 && navigator.userAgent.toLowerCase().indexOf('chrome') < 0) && !$.device.android; 160 | 161 | $(this.items).each(function () { 162 | var item = $(this); 163 | var itemOffsetTop = item.index() * self.itemHeight; 164 | var translateOffset = self.maxTranslate - translate; 165 | var itemOffset = itemOffsetTop - translateOffset; 166 | var percentage = itemOffset / self.itemHeight; 167 | 168 | var itemsFit = Math.ceil(self.height / self.itemHeight / 2) + 1; 169 | 170 | var angle = (-18*percentage); 171 | if (angle > 180) angle = 180; 172 | if (angle < -180) angle = -180; 173 | // Far class 174 | if (Math.abs(percentage) > itemsFit){ 175 | $(item).addClass('picker-item-far'); 176 | } else { 177 | $(item).removeClass('picker-item-far'); 178 | } 179 | // Set transform 180 | $(item).transform('translate3d(0, ' + (-translate+itemOffset + self.maxTranslate) + 'px, ' + (originBug ? -110 : 0) + 'px) rotateX(' + angle + 'deg)'); 181 | }); 182 | }, 183 | updateDuringScroll(){ 184 | this.animationFrameId = $.requestAnimationFrame(()=>{ 185 | this.updateItems(undefined, undefined, 0); 186 | this.updateDuringScroll(); 187 | }); 188 | }, 189 | aIndex(newValue){ 190 | for(let i=0;i this.maxTranslate) { 242 | this.currentTranslate = this.maxTranslate + Math.pow(this.currentTranslate - this.maxTranslate, 0.8); 243 | this.returnTo = 'max'; 244 | } 245 | // Transform wrapper 246 | $(this.wrapper).transform('translate3d(0,' + this.currentTranslate + 'px,0)'); 247 | 248 | // Update items 249 | this.updateItems(undefined, this.currentTranslate, 0, this.$parent.updateValuesOnTouchmove); 250 | 251 | // Calc velocity 252 | this.velocityTranslate = this.currentTranslate - this.prevTranslate || this.currentTranslate; 253 | this.velocityTime = (new Date()).getTime(); 254 | this.prevTranslate = this.currentTranslate; 255 | }, 256 | handleTouchEnd (e) { 257 | if (!this.$parent.isTouched || !this.$parent.isMoved) { 258 | this.$parent.isTouched = this.$parent.isMoved = false; 259 | return; 260 | } 261 | this.$parent.isTouched = this.$parent.isMoved = false; 262 | $(this.wrapper).transition(''); 263 | if (this.returnTo) { 264 | if (this.returnTo === 'min') { 265 | $(this.wrapper).transform('translate3d(0,' + this.minTranslate + 'px,0)'); 266 | } 267 | else $(this.wrapper).transform('translate3d(0,' + this.maxTranslate + 'px,0)'); 268 | } 269 | this.touchEndTime = new Date().getTime(); 270 | var velocity, newTranslate; 271 | if (this.touchEndTime - this.touchStartTime > 300) { 272 | newTranslate = this.currentTranslate; 273 | } 274 | else { 275 | velocity = Math.abs(this.velocityTranslate / (this.touchEndTime - this.velocityTime)); 276 | newTranslate = this.currentTranslate + this.velocityTranslate * this.$parent.momentumRatio; 277 | } 278 | 279 | newTranslate = Math.max(Math.min(newTranslate, this.maxTranslate), this.minTranslate); 280 | 281 | // Active Index 282 | var activeIndex = -Math.floor((newTranslate - this.maxTranslate)/this.itemHeight); 283 | 284 | // Normalize translate 285 | if (!this.$parent.freeMode) newTranslate = -activeIndex * this.itemHeight + this.maxTranslate; 286 | 287 | // Transform wrapper 288 | $(this.wrapper).transform('translate3d(0,' + (parseInt(newTranslate,10)) + 'px,0)'); 289 | 290 | // Update items 291 | this.updateItems(activeIndex, newTranslate, '', true); 292 | 293 | // Watch items 294 | if (this.$parent.updateValuesOnMomentum) { 295 | this.updateDuringScroll(); 296 | $(this.wrapper).transitionEnd(function(){ 297 | $.cancelAnimationFrame(this.animationFrameId); 298 | }); 299 | } 300 | 301 | // Allow click 302 | setTimeout(function () { 303 | this.allowItemClick = true; 304 | }, 100); 305 | } 306 | }, 307 | computed : { 308 | 309 | }, 310 | components: { 311 | 312 | }, 313 | init(){ 314 | console.log('picker-col init') 315 | }, 316 | ready(){ 317 | console.log('picker-col ready'); 318 | if(this.option.divider){ 319 | return 320 | } 321 | let self = this; 322 | this.container = $(this.$el); 323 | this.wrapper = $(this.container).find('.picker-items-col-wrapper'); 324 | this.items = $(this.wrapper).find('.picker-item'); 325 | 326 | let opened = false; 327 | //监听打开状态 328 | this.$on('open-picker',()=>{ 329 | this.calcSize(); 330 | $(this.wrapper).transform('translate3d(0,' + this.maxTranslate + 'px,0)').transition(0); 331 | if(this.updateItems){ 332 | this.setValue(this.val,0) 333 | if(!opened){ 334 | this.initEvents(); 335 | opened = true; 336 | } 337 | 338 | } 339 | }) 340 | 341 | }, 342 | beforeDestroy(){ 343 | if(this.option.divider){ 344 | return 345 | } 346 | this.initEvents(true); 347 | } 348 | } 349 | -------------------------------------------------------------------------------- /src/component/calendar/calendar.js: -------------------------------------------------------------------------------- 1 | import tpl from './calendar.html' 2 | import calendarMonth from './calendar-month' 3 | 4 | let defaults = { 5 | monthNames: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月' , '九月' , '十月', '十一月', '十二月'], 6 | monthNamesShort: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月' , '九月' , '十月', '十一月', '十二月'], 7 | dayNames: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'], 8 | dayNamesShort: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'], 9 | firstDay: 1, // First day of the week, Monday 10 | weekendDays: [0, 6], // Sunday and Saturday 11 | multiple: false, 12 | dateFormat: 'yyyy-mm-dd', 13 | direction: 'horizontal', // or 'vertical' 14 | minDate: null, 15 | maxDate: null, 16 | touchMove: true, 17 | animate: true, 18 | closeOnSelect: true, 19 | monthPicker: true, 20 | yearPicker: true, 21 | weekHeader: true, 22 | // Common settings 23 | values : [], 24 | scrollToInput: true, 25 | inputReadOnly: true, 26 | toolbar: true, 27 | toolbarCloseText: 'Done', 28 | /* Callbacks 29 | onMonthAdd 30 | onChange 31 | onOpen 32 | onClose 33 | onDayClick 34 | onMonthYearChangeStart 35 | onMonthYearChangeEnd 36 | */ 37 | } 38 | 39 | let rtl = false; 40 | let col; 41 | let allowItemClick = true; 42 | let isTouched, isMoved, touchStartX, touchStartY, touchCurrentX, touchCurrentY, touchStartTime, touchEndTime, startTranslate, currentTranslate, wrapperWidth, wrapperHeight, percentage, touchesDiff, isScrolling; 43 | 44 | 45 | export default { 46 | template : tpl, 47 | props: { 48 | input : { 49 | type : String, 50 | default : '' 51 | }, 52 | open : { 53 | type : Boolean, 54 | default : false 55 | }, 56 | options: { 57 | type: Object, 58 | default: { 59 | monthNames: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月' , '九月' , '十月', '十一月', '十二月'], 60 | monthNamesShort: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月' , '九月' , '十月', '十一月', '十二月'], 61 | dayNames: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'], 62 | dayNamesShort: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'], 63 | firstDay: 1, // First day of the week, Monday 64 | weekendDays: [0, 6], // Sunday and Saturday 65 | multiple: false, 66 | dateFormat: 'yyyy-mm-dd', 67 | direction: 'horizontal', // or 'vertical' 68 | minDate: null, 69 | maxDate: null, 70 | touchMove: true, 71 | animate: true, 72 | closeOnSelect: true, 73 | monthPicker: true, 74 | yearPicker: true, 75 | weekHeader: true, 76 | // Common settings 77 | values : [], 78 | scrollToInput: true, 79 | inputReadOnly: true, 80 | toolbar: true, 81 | toolbarCloseText: 'Done', 82 | } 83 | }, 84 | change: { 85 | type : Function, 86 | default : null 87 | } 88 | }, 89 | data(){ 90 | return { 91 | monthsTranslate : 0, 92 | animating : false, 93 | chooseType : 'm', //m,y 94 | translate : 0, 95 | transition : '', //滑动时变换时间要为0ms 96 | 97 | monthList : [ 98 | 99 | ], 100 | currentMonthNumber : '', 101 | currentYearNumber : '' 102 | } 103 | }, 104 | events : { 105 | 'dayClick' : 'dayClick' 106 | }, 107 | components: { 108 | 'calendar-month' : calendarMonth, 109 | }, 110 | computed : { 111 | isH(){ 112 | return this.options.direction === 'horizontal'; 113 | }, 114 | inverter(){ 115 | return 1 116 | } 117 | }, 118 | methods: { 119 | dayClick(day){ 120 | 121 | let broadcast = false; 122 | let prevOrNext = ''; 123 | if(day.className.indexOf('picker-calendar-day-prev') >= 0){ 124 | prevOrNext = 'prev'; 125 | broadcast = true; 126 | }else if(day.className.indexOf('picker-calendar-day-next') >= 0){ 127 | prevOrNext = 'next'; 128 | broadcast = true; 129 | }else if(day.className.indexOf('picker-calendar-day-selected') >= 0){ 130 | 131 | }else { 132 | broadcast = true; 133 | } 134 | if(broadcast){ 135 | 136 | if(prevOrNext == 'prev') this.prevMonth(); 137 | else if (prevOrNext == 'next') this.nextMonth(); 138 | 139 | let monthNumber = day.dayMonth+1+'',dayNumber = day.dayNumber+''; 140 | if(monthNumber.length == 1) monthNumber = '0' + monthNumber; 141 | if(dayNumber.length == 1) dayNumber = '0' + dayNumber; 142 | this.options.values = [`${day.dayYear}-${monthNumber}-${dayNumber}`]; 143 | 144 | this.$broadcast('select-day',day); 145 | } 146 | if(this.change != null){ 147 | this.change(this.options.values[0]); 148 | } 149 | }, 150 | setCurrentNumber(){ 151 | this.currentYearNumber = this.monthList[1].year; 152 | this.currentMonthNumber = this.options.monthNames[this.monthList[1].month]; 153 | }, 154 | waitAnimate(){ 155 | $('.picker-calendar-months-wrapper').transitionEnd(()=> { 156 | this.animating = false; 157 | }); 158 | }, 159 | resetMonth(year,month,translate){ 160 | 161 | let prevCalendar,nextCalendar; 162 | if(month === 0){ 163 | prevCalendar = { 164 | year : year - 1, 165 | month: 11, 166 | date : new Date(year - 1, 11), 167 | monthsTranslate : translate - 1 168 | }; 169 | nextCalendar = { 170 | year : year, 171 | month: month + 1, 172 | date : new Date(year, month + 1), 173 | monthsTranslate : translate + 1 174 | } 175 | }else if(month === 11){ 176 | prevCalendar = { 177 | year : year, 178 | month: month - 1, 179 | date : new Date(year, month - 1), 180 | monthsTranslate : translate - 1 181 | }; 182 | nextCalendar = { 183 | year : year + 1, 184 | month: 0, 185 | date : new Date(year+1, 0), 186 | monthsTranslate : translate + 1 187 | } 188 | }else{ 189 | prevCalendar = { 190 | year : year, 191 | month: month - 1, 192 | date : new Date(year, month - 1), 193 | monthsTranslate : translate - 1 194 | }; 195 | nextCalendar = { 196 | year : year, 197 | month: month + 1, 198 | date : new Date(year, month + 1), 199 | monthsTranslate : translate + 1 200 | } 201 | } 202 | this.monthList.pop(); 203 | this.monthList.push(nextCalendar); 204 | this.monthList.shift(); 205 | this.monthList.unshift(prevCalendar); 206 | 207 | this.translate = 'translate3d(' + (this.isH ? -translate*100 : 0) + '%, ' + (this.isH ? 0 : -translate*100) + '%, 0)' 208 | this.waitAnimate() 209 | }, 210 | prevMonth(transition){ 211 | if (typeof transition === 'undefined' || typeof transition === 'object') { 212 | transition = ''; 213 | if (!this.options.animate) transition = 0; 214 | } 215 | 216 | this.monthsTranslate --; 217 | this.animating = true; 218 | 219 | let translate = (-this.monthsTranslate * 100) * this.inverter; 220 | this.transition = transition; 221 | 222 | 223 | //当前是一月的话 224 | let current = this.monthList[1]; 225 | 226 | if(this.monthList[0].month == 0 ){ 227 | this.monthList.unshift({ 228 | year : this.monthList[0].year - 1, 229 | month: 11, 230 | date : new Date(this.monthList[0].year - 1, 11), 231 | monthsTranslate : this.monthsTranslate - 1 232 | }); 233 | }else{ 234 | this.monthList.unshift({ 235 | year : this.monthList[0].year, 236 | month: this.monthList[0].month - 1, 237 | date : new Date(this.monthList[0].year, this.monthList[0].month - 1), 238 | monthsTranslate : this.monthsTranslate - 1 239 | }) 240 | } 241 | this.monthList.pop(); 242 | this.setCurrentNumber(); 243 | //计算end 244 | 245 | this.translate = 'translate3d(' + (this.isH ? translate : 0) + '%, ' + (this.isH ? 0 : translate) + '%, 0)' 246 | this.waitAnimate() 247 | }, 248 | nextMonth(transition){ 249 | if (typeof transition === 'undefined' || typeof transition === 'object') { 250 | transition = ''; 251 | if (!this.options.animate) transition = 0; 252 | } 253 | 254 | this.monthsTranslate ++; 255 | this.animating = true; 256 | 257 | let translate = (-this.monthsTranslate * 100) * this.inverter; 258 | this.transition = transition; 259 | 260 | //计算 261 | let current = this.monthList[1]; 262 | if(this.monthList[2].month == 11){ 263 | this.monthList.push({ 264 | year : this.monthList[2].year + 1, 265 | month: 0, 266 | date : new Date(this.monthList[2].year+1, 0), 267 | monthsTranslate : this.monthsTranslate + 1 268 | }) 269 | }else{ 270 | this.monthList.push({ 271 | year : this.monthList[2].year, 272 | month: this.monthList[2].month + 1, 273 | date : new Date(this.monthList[2].year,this.monthList[2].month+1), 274 | monthsTranslate : this.monthsTranslate + 1 275 | }) 276 | } 277 | this.monthList.shift(); 278 | this.setCurrentNumber(); 279 | //计算end 280 | 281 | this.translate = 'translate3d(' + (this.isH ? translate : 0) + '%, ' + (this.isH ? 0 : translate) + '%, 0)' 282 | this.waitAnimate() 283 | }, 284 | prevYear(transition){ 285 | if (typeof transition === 'undefined' || typeof transition === 'object') { 286 | transition = ''; 287 | if (!this.options.animate) transition = 0; 288 | } 289 | 290 | this.monthsTranslate --; 291 | this.animating = true; 292 | 293 | let translate = (-this.monthsTranslate * 100) * this.inverter; 294 | this.transition = transition; 295 | 296 | 297 | //计算 298 | let prev = this.monthList.shift(); 299 | let current = this.monthList[0]; 300 | this.monthList.unshift({ 301 | year : current.year -1, 302 | month: current.month, 303 | date : new Date(current.year - 1, current.month), 304 | monthsTranslate : prev.monthsTranslate 305 | }) 306 | this.monthList.unshift({ 307 | year : this.monthList[0].year - 1, 308 | month: this.monthList[0].month, 309 | date : new Date(this.monthList[0].year - 1, this.monthList[0].month), 310 | monthsTranslate : this.monthsTranslate - 1 311 | }) 312 | this.monthList.pop(); 313 | this.setCurrentNumber(); 314 | //计算end 315 | this.translate = 'translate3d(' + (this.isH ? translate : 0) + '%, ' + (this.isH ? 0 : translate) + '%, 0)' 316 | 317 | //计算之后重置为月份模式 318 | this.resetMonth(this.monthList[1].year,this.monthList[1].month,this.monthList[1].monthsTranslate); 319 | }, 320 | nextYear(transition){ 321 | if (typeof transition === 'undefined' || typeof transition === 'object') { 322 | transition = ''; 323 | if (!this.options.animate) transition = 0; 324 | } 325 | 326 | this.monthsTranslate ++; 327 | this.animating = true; 328 | 329 | let translate = (-this.monthsTranslate * 100) * this.inverter; 330 | this.transition = transition; 331 | 332 | 333 | //计算 334 | let next = this.monthList.pop(); 335 | let current = this.monthList[1]; 336 | this.monthList.push({ 337 | year : current.year + 1, 338 | month: current.month, 339 | date : new Date(current.year + 1, current.month), 340 | monthsTranslate : next.monthsTranslate 341 | }) 342 | this.monthList.push({ 343 | year : this.monthList[2].year + 1, 344 | month: this.monthList[2].month, 345 | date : new Date(this.monthList[2].year + 1,this.monthList[2].month), 346 | monthsTranslate : this.monthsTranslate + 1 347 | }); 348 | this.monthList.shift(); 349 | this.setCurrentNumber(); 350 | //计算end 351 | 352 | this.translate = 'translate3d(' + (this.isH ? translate : 0) + '%, ' + (this.isH ? 0 : translate) + '%, 0)' 353 | 354 | //计算之后重置为月份模式 355 | this.resetMonth(this.monthList[1].year,this.monthList[1].month,this.monthList[1].monthsTranslate); 356 | 357 | }, 358 | handleTouchStart(e){ 359 | if (isMoved || isTouched) return; 360 | // e.preventDefault(); 361 | isTouched = true; 362 | touchStartX = touchCurrentY = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX; 363 | touchStartY = touchCurrentY = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY; 364 | touchStartTime = (new Date()).getTime(); 365 | percentage = 0; 366 | allowItemClick = true; 367 | isScrolling = undefined; 368 | startTranslate = currentTranslate = this.monthsTranslate; 369 | }, 370 | handleTouchMove(e){ 371 | console.log(!isTouched) 372 | if (!isTouched) return; 373 | 374 | touchCurrentX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX; 375 | touchCurrentY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY; 376 | if (typeof isScrolling === 'undefined') { 377 | isScrolling = !!(isScrolling || Math.abs(touchCurrentY - touchStartY) > Math.abs(touchCurrentX - touchStartX)); 378 | } 379 | if (this.isH && isScrolling) { 380 | isTouched = false; 381 | return; 382 | } 383 | e.preventDefault(); 384 | if (this.animating) { 385 | isTouched = false; 386 | return; 387 | } 388 | allowItemClick = false; 389 | if (!isMoved) { 390 | // First move 391 | isMoved = true; 392 | wrapperWidth = $('.picker-calendar-months-wrapper')[0].offsetWidth; 393 | wrapperHeight = $('.picker-calendar-months-wrapper')[0].offsetHeight; 394 | // $('.picker-calendar-months-wrapper').transition(0); 395 | this.transition = 'transition-duration: 0ms;' 396 | } 397 | e.preventDefault(); 398 | 399 | touchesDiff = this.isH ? touchCurrentX - touchStartX : touchCurrentY - touchStartY; 400 | percentage = touchesDiff/(this.isH ? wrapperWidth : wrapperHeight); 401 | currentTranslate = (-this.monthsTranslate * this.inverter + percentage) * 100; 402 | 403 | // Transform wrapper 404 | this.translate = 'translate3d(' + (this.isH ? currentTranslate : 0) + '%, ' + (this.isH ? 0 : currentTranslate) + '%, 0)'; 405 | 406 | }, 407 | handleTouchEnd(e){ 408 | if (!isTouched || !isMoved) { 409 | isTouched = isMoved = false; 410 | return; 411 | } 412 | this.transition = ''; 413 | isTouched = isMoved = false; 414 | 415 | touchEndTime = new Date().getTime(); 416 | if (touchEndTime - touchStartTime < 300) { 417 | if (Math.abs(touchesDiff) < 10) { 418 | this.resetMonth(this.monthList[1].year,this.monthList[1].month,this.monthList[1].monthsTranslate); 419 | } 420 | else if (touchesDiff >= 10) { 421 | if (rtl) this.nextMonth(); 422 | else this.prevMonth(); 423 | } 424 | else { 425 | if (rtl) this.prevMonth(); 426 | else this.nextMonth(); 427 | } 428 | } 429 | else { 430 | if (percentage <= -0.5) { 431 | if (rtl) this.prevMonth(); 432 | else this.nextMonth(); 433 | } 434 | else if (percentage >= 0.5) { 435 | if (rtl) this.nextMonth(); 436 | else this.prevMonth(); 437 | } 438 | else { 439 | this.resetMonth(this.monthList[1].year,this.monthList[1].month,this.monthList[1].monthsTranslate); 440 | } 441 | } 442 | // Allow click 443 | setTimeout(()=>{ 444 | allowItemClick = true; 445 | }, 100); 446 | } 447 | }, 448 | beforeCompile(){ 449 | for (var def in defaults) { 450 | if (typeof this.options[def] === 'undefined') { 451 | this.options[def] = defaults[def] 452 | } 453 | } 454 | this.$set('options',this.options); 455 | }, 456 | ready(){ 457 | let initDate = this.options.values[0]; 458 | let date = new Date(initDate); 459 | let year = date.getFullYear(); 460 | let month = date.getMonth(); 461 | 462 | let prevCalendar,currentCalendar,nextCalendar; 463 | if(month === 0){ 464 | prevCalendar = { 465 | year : year - 1, 466 | month: 11, 467 | date : new Date(year - 1, 11), 468 | monthsTranslate : -1 469 | }; 470 | nextCalendar = { 471 | year : year, 472 | month: month + 1, 473 | date : new Date(year, month + 1), 474 | monthsTranslate : 1 475 | } 476 | }else if(month === 11){ 477 | prevCalendar = { 478 | year : year, 479 | month: month - 1, 480 | date : new Date(year, month - 1), 481 | monthsTranslate : -1 482 | }; 483 | nextCalendar = { 484 | year : year + 1, 485 | month: 0, 486 | date : new Date(year+1, 0), 487 | monthsTranslate : 1 488 | } 489 | }else{ 490 | prevCalendar = { 491 | year : year, 492 | month: month - 1, 493 | date : new Date(year, month - 1), 494 | monthsTranslate : translate - 1 495 | }; 496 | nextCalendar = { 497 | year : year, 498 | month: month + 1, 499 | date : new Date(year, month + 1), 500 | monthsTranslate : translate + 1 501 | } 502 | } 503 | currentCalendar = { 504 | year : year, 505 | month: month, 506 | date : new Date(year, month), 507 | monthsTranslate : 0 508 | }; 509 | this.monthList = [prevCalendar,currentCalendar,nextCalendar] 510 | this.setCurrentNumber(); 511 | 512 | //绑定触摸事件 513 | if (this.options.touchMove) { 514 | $(this.$el).find('.picker-calendar-months-wrapper').on($.touchEvents.start, this.handleTouchStart); 515 | $(this.$el).find('.picker-calendar-months-wrapper').on($.touchEvents.move, this.handleTouchMove); 516 | $(this.$el).find('.picker-calendar-months-wrapper').on($.touchEvents.end, this.handleTouchEnd); 517 | } 518 | if($(this.input) && $(this.input).length > 0){ 519 | $(this.input).on('click',(e)=>{ 520 | this.open = true; 521 | }) 522 | } 523 | //点击其他地方关闭 524 | $('html').on('click', (e)=>{ 525 | if($(this.input) && $(this.input).length > 0){ 526 | if(e.target !== $(this.input)[0] && $(e.target).parents('.picker-modal').length === 0){ 527 | this.open = false; 528 | } 529 | }else{ 530 | if($(e.target).parents('.picker-modal').length === 0) { 531 | this.open = false; 532 | } 533 | } 534 | }); 535 | } 536 | } 537 | --------------------------------------------------------------------------------