├── .gitignore ├── .babelrc ├── lib ├── images │ └── show.png ├── js │ ├── poppicker.js │ ├── picker.js │ └── dtpicker.js └── css │ └── picker.css ├── src ├── images │ └── show.png ├── DatePicker.js ├── CityPicker.js ├── js │ ├── poppicker.js │ ├── picker.js │ ├── dtpicker.js │ └── mui.js └── css │ └── picker.css ├── example ├── server.js ├── webpack.config.example.js ├── index.html ├── src │ └── index.js └── lib │ └── city-data.js ├── index.js ├── webpack.config.js ├── package.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react", "es2015", "stage-0"] 3 | } 4 | -------------------------------------------------------------------------------- /lib/images/show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petitspois/react-picker/HEAD/lib/images/show.png -------------------------------------------------------------------------------- /src/images/show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petitspois/react-picker/HEAD/src/images/show.png -------------------------------------------------------------------------------- /example/server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var WebpackDevServer = require('webpack-dev-server'); 3 | var config = require('./webpack.config.example'); 4 | var port = 8080; 5 | var options = { 6 | publicPath: config.output.publicPath 7 | }; 8 | 9 | 10 | 11 | var server = new WebpackDevServer(webpack(config), options); 12 | server.listen(port, '0.0.0.0', function (err, result) { 13 | if (err) console.error(err); 14 | console.log('Listening at localhost:%s', port); 15 | }); 16 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.CityPicker = exports.DatePicker = undefined; 7 | 8 | var _datepicker = require('./lib/datepicker'); 9 | 10 | var _datepicker2 = _interopRequireDefault(_datepicker); 11 | 12 | var _citypicker = require('./lib/citypicker'); 13 | 14 | var _citypicker2 = _interopRequireDefault(_citypicker); 15 | 16 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 17 | 18 | exports.DatePicker = _datepicker2.default; 19 | exports.CityPicker = _citypicker2.default; 20 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var node_modules = path.resolve(__dirname, 'node_modules'); 3 | var webpack = require('webpack'); 4 | 5 | module.exports = { 6 | devtool: 'eval-source-map', 7 | entry: { 8 | datepicker: './src/DatePicker', 9 | citypicker: './src/CityPicker' 10 | }, 11 | output: { 12 | path: path.join(__dirname, '/lib'), 13 | libraryTarget: 'umd', 14 | filename: '[name].js' 15 | }, 16 | module: { 17 | loaders: [{ 18 | test: /\.js$/, 19 | exclude: /node_modules/, 20 | loaders: ['babel-loader'] 21 | }, { 22 | test: /\.css$/, 23 | exclude: path.join(__dirname, 'src'), 24 | loader: 'style!css' 25 | }] 26 | }, 27 | devServer: { 28 | contentBase: path.join(__dirname, 'example') 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /example/webpack.config.example.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var node_modules = path.resolve(__dirname, 'node_modules'); 3 | var lib = path.resolve(__dirname, 'lib'); 4 | var webpack = require('webpack'); 5 | 6 | module.exports = { 7 | entry: { 8 | app:[ 9 | 'webpack-dev-server/client?http://0.0.0.0:7000', 10 | './src/index' 11 | ] 12 | }, 13 | output: { 14 | path:path.join(__dirname, '/lib'), 15 | filename: 'app.js', 16 | publicPath: '/lib/' 17 | }, 18 | module: { 19 | loaders: [{ 20 | test: /\.js$/, 21 | exclude: [/node_modules/, /lib/], 22 | loaders: [ 'babel-loader' ] 23 | }, 24 | { 25 | test: /\.css$/, 26 | exclude: path.join(__dirname, 'src'), 27 | loader: 'style!css' 28 | } 29 | ] 30 | }, 31 | resolve: { 32 | alias: { 33 | 'react-picker': path.join(__dirname, '..', 'index.js') 34 | } 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-pickers", 3 | "version": "0.1.0", 4 | "description": "datapicker and citypicker base on MUI of picker", 5 | "main": "/index.js", 6 | "repository": "petitspois/react-picker", 7 | "homepage": "https://github.com/petitspois/react-picker#readme", 8 | "bugs": "https://github.com/petitspois/react-picker/issues", 9 | "scripts": { 10 | "start": "node server.js", 11 | "build": "./node_modules/.bin/babel src --copy-files --extensions .js --out-dir lib", 12 | "clean": "rm -rf ./lib/*", 13 | "test": "echo \"Error: no test specified\" && exit 1" 14 | }, 15 | "keywords": [ 16 | "react", 17 | "datapicker", 18 | "citypicker", 19 | "mui" 20 | ], 21 | "license": "MIT", 22 | "author": "petitspois", 23 | "dependencies": { 24 | "css-loader": "^0.23.1", 25 | "react": "^15.1.0", 26 | "react-dom": "^15.1.0", 27 | "style-loader": "^0.13.1" 28 | }, 29 | "devDependencies": { 30 | "babel-cli": "^6.11.4", 31 | "babel-core": "^6.9.1", 32 | "babel-loader": "^6.2.4", 33 | "babel-polyfill": "^6.9.1", 34 | "babel-preset-es2015": "^6.9.0", 35 | "babel-preset-react": "^6.5.0", 36 | "babel-preset-stage-0": "^6.5.0", 37 | "webpack": "^1.13.1", 38 | "webpack-dev-server": "^1.14.1" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | react-picker example 7 | 45 | 46 | 47 | 48 |
49 | 50 | 51 | -------------------------------------------------------------------------------- /src/DatePicker.js: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react' 2 | 3 | import './js/mui' 4 | import './js/picker' 5 | import DtPicker from './js/dtpicker' 6 | 7 | class DatePicker extends Component{ 8 | 9 | static defalutProps = { 10 | visible: false, 11 | options: {} 12 | }; 13 | 14 | static propTypes = { 15 | visible: PropTypes.bool, 16 | getData: PropTypes.func, 17 | confirm: PropTypes.func, 18 | cancel: PropTypes.func, 19 | options: PropTypes.object 20 | }; 21 | 22 | constructor(props){ 23 | super(props) 24 | this.userPicker = {}; 25 | } 26 | 27 | componentDidMount(){ 28 | this.userPicker = new DtPicker(this.props.options); 29 | this.userPicker.ui.cancel.addEventListener('tap', event => { 30 | this.props.cancel(); 31 | }, false); 32 | this.userPicker.ui.mask[0].addEventListener('tap', () => { 33 | this.props.cancel(); 34 | }, false); 35 | } 36 | 37 | show(){ 38 | this.userPicker.show(items => { 39 | this.props.getData(items.text); 40 | this.props.cancel && this.props.cancel(); 41 | }) 42 | } 43 | 44 | componentDidUpdate(){ 45 | if(this.props.visible){ 46 | this.show() 47 | }else{ 48 | this.userPicker.hide(); 49 | } 50 | } 51 | 52 | render(){ 53 | return( 54 |
55 | ) 56 | } 57 | } 58 | 59 | export default DatePicker 60 | -------------------------------------------------------------------------------- /src/CityPicker.js: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react' 2 | 3 | import './js/mui' 4 | import './js/picker' 5 | import PopPicker from './js/poppicker' 6 | 7 | class CityPicker extends Component{ 8 | 9 | static defalutProps = { 10 | visible: false 11 | }; 12 | 13 | static propTypes = { 14 | visible: PropTypes.bool, 15 | setData: PropTypes.array, 16 | getData: PropTypes.func, 17 | confirm: PropTypes.func, 18 | cancel: PropTypes.func 19 | }; 20 | 21 | constructor(props){ 22 | super(props) 23 | this.userPicker = {}; 24 | } 25 | 26 | componentDidMount(){ 27 | this.userPicker = new PopPicker({layer: this.props.layer || '',defaultVal:this.props.defaultVal }); 28 | this.userPicker.setData(this.props.setData); 29 | this.userPicker.cancel.addEventListener('tap', event => { 30 | this.props.cancel(); 31 | }, false); 32 | this.userPicker.mask[0].addEventListener('tap', () => { 33 | this.props.cancel(); 34 | }, false); 35 | } 36 | 37 | show(){ 38 | this.userPicker.show(items => { 39 | this.props.getData(items); 40 | this.props.cancel && this.props.cancel(); 41 | }) 42 | } 43 | 44 | componentDidUpdate(){ 45 | if(this.props.visible){ 46 | this.show() 47 | }else{ 48 | this.userPicker.hide(); 49 | } 50 | } 51 | 52 | render(){ 53 | return( 54 |
55 | ) 56 | } 57 | } 58 | 59 | export default CityPicker 60 | -------------------------------------------------------------------------------- /example/src/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { render } from 'react-dom'; 3 | 4 | import '../../lib/css/picker.css' 5 | // import { CityPicker, DatePicker } from 'react-picker' 6 | import { CityPicker, DatePicker } from '../../' 7 | 8 | 9 | import city2 from '../lib/city-data' 10 | import city3 from '../lib/city-data-3' 11 | 12 | class App extends Component{ 13 | 14 | state = { 15 | showCityPicker: false, 16 | showCity2Picker:false, 17 | showCity3Picker:false, 18 | showDatePicker:false, 19 | showDatePicker2:false, 20 | singleData : [{ 21 | value: 'ywj', 22 | text: '董事长 叶文洁' 23 | }, { 24 | value: 'aaa', 25 | text: '总经理 艾AA' 26 | }, { 27 | value: 'lj', 28 | text: '罗辑' 29 | }, { 30 | value: 'ymt', 31 | text: '云天明' 32 | }, { 33 | value: 'shq', 34 | text: '史强' 35 | }, { 36 | value: 'zhbh', 37 | text: '章北海' 38 | }, { 39 | value: 'zhy', 40 | text: '庄颜' 41 | }, { 42 | value: 'gyf', 43 | text: '关一帆' 44 | }, { 45 | value: 'zhz', 46 | text: '智子' 47 | }, { 48 | value: 'gezh', 49 | text: '歌者' 50 | }], 51 | city2: city2, 52 | city3: city3 53 | } 54 | 55 | showCityPicker(){ 56 | this.setState({showCityPicker: true }) 57 | } 58 | 59 | showCity2Picker(){ 60 | this.setState({showCity2Picker: true }) 61 | } 62 | 63 | showCity3Picker(){ 64 | this.setState({showCity3Picker: true }) 65 | } 66 | 67 | ok(){ 68 | this.setState({showCityPicker: false }) 69 | } 70 | 71 | cl(){ 72 | this.setState({showCityPicker: false }) 73 | } 74 | 75 | 76 | ok2(){ 77 | this.setState({showCity2Picker: false }) 78 | } 79 | 80 | cl2(){ 81 | this.setState({showCity2Picker: false }) 82 | } 83 | 84 | ok3(){ 85 | this.setState({showCity3Picker: false }) 86 | } 87 | 88 | cl3(){ 89 | this.setState({showCity3Picker: false }) 90 | } 91 | 92 | ok4(){ 93 | this.setState({showDatePicker: false }) 94 | } 95 | 96 | cl4(){ 97 | this.setState({showDatePicker: false }) 98 | } 99 | 100 | ok5(){ 101 | this.setState({showDatePicker2: false }) 102 | } 103 | 104 | cl5(){ 105 | this.setState({showDatePicker2: false }) 106 | } 107 | 108 | getData(ret){ 109 | console.log(ret); 110 | } 111 | 112 | getData2(ret){ 113 | console.log("你选择的城市是:" + ret[0].text + " " + ret[1].text); 114 | } 115 | 116 | getData3(ret){ 117 | console.log("你选择的城市是:" + (ret[0] || {}).text + " " + (ret[1] || {}).text + " " + (ret[2] || {}).text); 118 | } 119 | 120 | getData4(ret){ 121 | console.log('选择结果: ' + ret); 122 | } 123 | 124 | getData5(ret){ 125 | console.log('选择结果: ' + ret); 126 | } 127 | 128 | selectDate(){ 129 | this.setState({showDatePicker: true }) 130 | } 131 | 132 | selectDate2(){ 133 | this.setState({showDatePicker2: true }) 134 | } 135 | 136 | render(){ 137 | return ( 138 |
139 |
普通示例
140 | 141 | 142 |
级联示例
143 | 144 | 145 | 148 |
149 | 150 | 151 | 152 |
153 |
常规示例
154 | 155 | 156 |
设定年份区间
157 | 158 | 159 |
160 | 161 |
162 | ) 163 | } 164 | } 165 | 166 | 167 | render( 168 | , 169 | document.querySelector('#root') 170 | ) 171 | -------------------------------------------------------------------------------- /lib/js/poppicker.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _mui = require('./mui'); 8 | 9 | var _mui2 = _interopRequireDefault(_mui); 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 12 | 13 | (function ($, document) { 14 | 15 | //创建 DOM 16 | $.dom = function (str) { 17 | if (typeof str !== 'string') { 18 | if (str instanceof Array || str[0] && str.length) { 19 | return [].slice.call(str); 20 | } else { 21 | return [str]; 22 | } 23 | } 24 | if (!$.__create_dom_div__) { 25 | $.__create_dom_div__ = document.createElement('div'); 26 | } 27 | $.__create_dom_div__.innerHTML = str; 28 | return [].slice.call($.__create_dom_div__.childNodes); 29 | }; 30 | 31 | var panelBuffer = '
\ 32 |
\ 33 | \ 34 | \ 35 |
\ 36 |
\ 37 |
\ 38 |
\ 39 |
'; 40 | 41 | var pickerBuffer = '
\ 42 |
\ 43 |
\ 44 |
    \ 45 |
\ 46 |
\ 47 |
\ 48 |
'; 49 | 50 | //定义弹出选择器类 51 | var PopPicker = $.PopPicker = $.Class.extend({ 52 | //构造函数 53 | init: function init(options) { 54 | var self = this; 55 | self.options = options || {}; 56 | self.options.buttons = self.options.buttons || ['取消', '确定']; 57 | self.panel = $.dom(panelBuffer)[0]; 58 | document.body.appendChild(self.panel); 59 | self.ok = self.panel.querySelector('.mui-poppicker-btn-ok'); 60 | self.cancel = self.panel.querySelector('.mui-poppicker-btn-cancel'); 61 | self.body = self.panel.querySelector('.mui-poppicker-body'); 62 | self.mask = $.createMask(); 63 | self.cancel.innerText = self.options.buttons[0]; 64 | self.ok.innerText = self.options.buttons[1]; 65 | self.ok.addEventListener('tap', function (event) { 66 | if (self.callback) { 67 | self.callback(self.getSelectedItems()); 68 | } 69 | }, false); 70 | self._createPicker(); 71 | //防止滚动穿透 72 | self.panel.addEventListener($.EVENT_START, function (event) { 73 | event.preventDefault(); 74 | }, false); 75 | self.panel.addEventListener($.EVENT_MOVE, function (event) { 76 | event.preventDefault(); 77 | }, false); 78 | }, 79 | _createPicker: function _createPicker() { 80 | var self = this; 81 | var layer = self.options.layer || 1; 82 | var width = 100 / layer + '%'; 83 | self.pickers = []; 84 | for (var i = 1; i <= layer; i++) { 85 | var pickerElement = $.dom(pickerBuffer)[0]; 86 | pickerElement.style.width = width; 87 | self.body.appendChild(pickerElement); 88 | var picker = $(pickerElement).picker(); 89 | self.pickers.push(picker); 90 | pickerElement.addEventListener('change', function (event) { 91 | var nextPickerElement = this.nextSibling; 92 | if (nextPickerElement && nextPickerElement.picker) { 93 | var eventData = event.detail || {}; 94 | var preItem = eventData.item || {}; 95 | nextPickerElement.picker.setItems(preItem.children); 96 | } 97 | }, false); 98 | } 99 | }, 100 | //填充数据 101 | setData: function setData(data) { 102 | var self = this; 103 | data = data || []; 104 | self.pickers[0].setItems(data); 105 | }, 106 | //获取选中的项(数组) 107 | getSelectedItems: function getSelectedItems() { 108 | var self = this; 109 | var items = []; 110 | for (var i in self.pickers) { 111 | var picker = self.pickers[i]; 112 | items.push(picker.getSelectedItem() || {}); 113 | } 114 | return items; 115 | }, 116 | //显示 117 | show: function show(callback) { 118 | var self = this; 119 | self.callback = callback; 120 | self.mask.show(); 121 | document.body.classList.add($.className('poppicker-active-for-page')); 122 | self.panel.classList.add($.className('active')); 123 | //处理物理返回键 124 | self.__back = $.back; 125 | $.back = function () { 126 | self.hide(); 127 | }; 128 | }, 129 | //隐藏 130 | hide: function hide() { 131 | var self = this; 132 | if (self.disposed) return; 133 | self.panel.classList.remove($.className('active')); 134 | self.mask.close(); 135 | document.body.classList.remove($.className('poppicker-active-for-page')); 136 | //处理物理返回键 137 | $.back = self.__back; 138 | }, 139 | dispose: function dispose() { 140 | var self = this; 141 | self.hide(); 142 | setTimeout(function () { 143 | self.panel.parentNode.removeChild(self.panel); 144 | for (var name in self) { 145 | self[name] = null; 146 | delete self[name]; 147 | }; 148 | self.disposed = true; 149 | }, 300); 150 | } 151 | }); 152 | })(_mui2.default, document); /** 153 | * 弹出选择列表插件 154 | * 此组件依赖 listpcker ,请在页面中先引入 mui.picker.css + mui.picker.js 155 | * varstion 1.0.1 156 | * by Houfeng 157 | * Houfeng@DCloud.io 158 | */ 159 | 160 | exports.default = _mui2.default.PopPicker; -------------------------------------------------------------------------------- /src/js/poppicker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 弹出选择列表插件 3 | * 此组件依赖 listpcker ,请在页面中先引入 mui.picker.css + mui.picker.js 4 | * varstion 1.0.1 5 | * by Houfeng 6 | * Houfeng@DCloud.io 7 | */ 8 | 9 | import mui from './mui' 10 | 11 | (function($, document) { 12 | 13 | //创建 DOM 14 | $.dom = function(str) { 15 | if (typeof(str) !== 'string') { 16 | if ((str instanceof Array) || (str[0] && str.length)) { 17 | return [].slice.call(str); 18 | } else { 19 | return [str]; 20 | } 21 | } 22 | if (!$.__create_dom_div__) { 23 | $.__create_dom_div__ = document.createElement('div'); 24 | } 25 | $.__create_dom_div__.innerHTML = str; 26 | return [].slice.call($.__create_dom_div__.childNodes); 27 | }; 28 | 29 | var panelBuffer = '
\ 30 |
\ 31 | \ 32 | \ 33 |
\ 34 |
\ 35 |
\ 36 |
\ 37 |
'; 38 | 39 | var pickerBuffer = '
\ 40 |
\ 41 |
\ 42 |
    \ 43 |
\ 44 |
\ 45 |
\ 46 |
'; 47 | 48 | //定义弹出选择器类 49 | var PopPicker = $.PopPicker = $.Class.extend({ 50 | //构造函数 51 | init: function(options) { 52 | var self = this; 53 | self.options = options || {}; 54 | self.options.buttons = self.options.buttons || ['取消', '确定']; 55 | self.panel = $.dom(panelBuffer)[0]; 56 | document.body.appendChild(self.panel); 57 | self.ok = self.panel.querySelector('.mui-poppicker-btn-ok'); 58 | self.cancel = self.panel.querySelector('.mui-poppicker-btn-cancel'); 59 | self.body = self.panel.querySelector('.mui-poppicker-body'); 60 | self.mask = $.createMask(); 61 | self.cancel.innerText = self.options.buttons[0]; 62 | self.ok.innerText = self.options.buttons[1]; 63 | self.ok.addEventListener('tap', function(event) { 64 | if (self.callback) { 65 | self.callback(self.getSelectedItems()); 66 | } 67 | }, false); 68 | self._createPicker(); 69 | //防止滚动穿透 70 | self.panel.addEventListener($.EVENT_START, function(event) { 71 | event.preventDefault(); 72 | }, false); 73 | self.panel.addEventListener($.EVENT_MOVE, function(event) { 74 | event.preventDefault(); 75 | }, false); 76 | }, 77 | _createPicker: function() { 78 | var self = this; 79 | var layer = self.options.layer || 1; 80 | var width = (100 / layer) + '%'; 81 | self.pickers = []; 82 | for (var i = 1; i <= layer; i++) { 83 | var pickerElement = $.dom(pickerBuffer)[0]; 84 | pickerElement.style.width = width; 85 | self.body.appendChild(pickerElement); 86 | var picker = $(pickerElement).picker(); 87 | self.pickers.push(picker); 88 | pickerElement.addEventListener('change', function(event) { 89 | var nextPickerElement = this.nextSibling; 90 | if (nextPickerElement && nextPickerElement.picker) { 91 | var eventData = event.detail || {}; 92 | var preItem = eventData.item || {}; 93 | nextPickerElement.picker.setItems(preItem.children); 94 | } 95 | }, false); 96 | } 97 | 98 | //等选择数据初始化完后 再设定默认值 99 | setTimeout(function(){ 100 | //设定默认值 101 | self.setSelectedValue(self.options.defaultVal); 102 | },100) 103 | }, 104 | 105 | //设置默认选中值 106 | setSelectedValue: function(value) { 107 | 108 | if(!value)return false; 109 | 110 | var self = this; 111 | var pickers = self.panel.querySelectorAll('.pop-picker'); 112 | pickers = Array.prototype.slice.call(pickers); 113 | set(pickers,value) 114 | 115 | //设置 116 | function set(pickers,value){ 117 | if(value.length){ 118 | var val = value.shift() 119 | var pickerObj = pickers.shift() 120 | pickerObj.picker.setSelectedValue(val,0,function(pickers,value){ 121 | setTimeout(function(){ 122 | set(pickers,value); 123 | },200) 124 | }.bind(this,pickers,value)) 125 | } 126 | } 127 | }, 128 | 129 | //填充数据 130 | setData: function(data) { 131 | var self = this; 132 | data = data || []; 133 | self.pickers[0].setItems(data); 134 | }, 135 | //获取选中的项(数组) 136 | getSelectedItems: function() { 137 | var self = this; 138 | var items = []; 139 | for (var i in self.pickers) { 140 | var picker = self.pickers[i]; 141 | items.push(picker.getSelectedItem() || {}); 142 | } 143 | return items; 144 | }, 145 | //显示 146 | show: function(callback) { 147 | var self = this; 148 | self.callback = callback; 149 | self.mask.show(); 150 | document.body.classList.add($.className('poppicker-active-for-page')); 151 | self.panel.classList.add($.className('active')); 152 | //处理物理返回键 153 | self.__back = $.back; 154 | $.back = function() { 155 | self.hide(); 156 | }; 157 | }, 158 | //隐藏 159 | hide: function() { 160 | var self = this; 161 | if (self.disposed) return; 162 | self.panel.classList.remove($.className('active')); 163 | self.mask.close(); 164 | document.body.classList.remove($.className('poppicker-active-for-page')); 165 | //处理物理返回键 166 | $.back=self.__back; 167 | }, 168 | dispose: function() { 169 | var self = this; 170 | self.hide(); 171 | setTimeout(function() { 172 | self.panel.parentNode.removeChild(self.panel); 173 | for (var name in self) { 174 | self[name] = null; 175 | delete self[name]; 176 | }; 177 | self.disposed = true; 178 | }, 300); 179 | } 180 | }); 181 | 182 | })(mui, document); 183 | 184 | export default mui.PopPicker 185 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-picker 2 | datapicker and citypicker base on MUI of picker 3 | 4 | 5 | 6 | ### Installation 7 | 8 | Using [npm](https://www.npmjs.com/): 9 | 10 | $ npm install --save react-pickers 11 | 12 | 13 | Then with a module bundler like [webpack](https://webpack.github.io/) that supports either CommonJS or ES2015 modules, use as you would anything else: 14 | 15 | 16 | ```js 17 | 18 | // using an ES6 transpiler, like babel 19 | import { DatePicker, CityPicker } from 'react-pickers' 20 | 21 | // not using an ES6 transpiler 22 | var DatePicker = require('react-pickers').DatePicker 23 | var CityPicker = require('react-pickers').CityPicker 24 | 25 | 26 | ``` 27 | 28 | ### What's it look like? 29 | 30 | ```js 31 | import React, { Component } from 'react'; 32 | import { render } from 'react-dom'; 33 | 34 | import 'react-pickers/lib/css/picker.css' 35 | import { CityPicker, DatePicker } from 'react-picker' 36 | 37 | 38 | import city2 from '../lib/city-data' 39 | import city3 from '../lib/city-data-3' 40 | 41 | class App extends Component{ 42 | 43 | state = { 44 | showCityPicker: false, 45 | showCity2Picker:false, 46 | showCity3Picker:false, 47 | showDatePicker:false, 48 | showDatePicker2:false, 49 | singleData : [{ 50 | value: 'ywj', 51 | text: '董事长 叶文洁' 52 | }, { 53 | value: 'aaa', 54 | text: '总经理 艾AA' 55 | }, { 56 | value: 'lj', 57 | text: '罗辑' 58 | }, { 59 | value: 'ymt', 60 | text: '云天明' 61 | }, { 62 | value: 'shq', 63 | text: '史强' 64 | }, { 65 | value: 'zhbh', 66 | text: '章北海' 67 | }, { 68 | value: 'zhy', 69 | text: '庄颜' 70 | }, { 71 | value: 'gyf', 72 | text: '关一帆' 73 | }, { 74 | value: 'zhz', 75 | text: '智子' 76 | }, { 77 | value: 'gezh', 78 | text: '歌者' 79 | }], 80 | city2: city2, 81 | city3: city3 82 | } 83 | 84 | showCityPicker(){ 85 | this.setState({showCityPicker: true }) 86 | } 87 | 88 | showCity2Picker(){ 89 | this.setState({showCity2Picker: true }) 90 | } 91 | 92 | showCity3Picker(){ 93 | this.setState({showCity3Picker: true }) 94 | } 95 | 96 | ok(){ 97 | this.setState({showCityPicker: false }) 98 | } 99 | 100 | cl(){ 101 | this.setState({showCityPicker: false }) 102 | } 103 | 104 | 105 | ok2(){ 106 | this.setState({showCity2Picker: false }) 107 | } 108 | 109 | cl2(){ 110 | this.setState({showCity2Picker: false }) 111 | } 112 | 113 | ok3(){ 114 | this.setState({showCity3Picker: false }) 115 | } 116 | 117 | cl3(){ 118 | this.setState({showCity3Picker: false }) 119 | } 120 | 121 | ok4(){ 122 | this.setState({showDatePicker: false }) 123 | } 124 | 125 | cl4(){ 126 | this.setState({showDatePicker: false }) 127 | } 128 | 129 | ok5(){ 130 | this.setState({showDatePicker2: false }) 131 | } 132 | 133 | cl5(){ 134 | this.setState({showDatePicker2: false }) 135 | } 136 | 137 | getData(ret){ 138 | console.log(ret); 139 | } 140 | 141 | getData2(ret){ 142 | console.log("你选择的城市是:" + ret[0].text + " " + ret[1].text); 143 | } 144 | 145 | getData3(ret){ 146 | console.log("你选择的城市是:" + (ret[0] || {}).text + " " + (ret[1] || {}).text + " " + (ret[2] || {}).text); 147 | } 148 | 149 | getData4(ret){ 150 | console.log('选择结果: ' + ret); 151 | } 152 | 153 | getData5(ret){ 154 | console.log('选择结果: ' + ret); 155 | } 156 | 157 | selectDate(){ 158 | this.setState({showDatePicker: true }) 159 | } 160 | 161 | selectDate2(){ 162 | this.setState({showDatePicker2: true }) 163 | } 164 | 165 | render(){ 166 | return ( 167 |
168 |
普通示例
169 | 170 | 171 |
级联示例
172 | 173 | 174 |
175 | 176 | 177 |
178 |
常规示例
179 | 180 | 181 |
设定年份区间
182 | 183 | 184 |
185 |
186 | ) 187 | } 188 | } 189 | 190 | 191 | render( 192 | , 193 | document.querySelector('#root') 194 | ) 195 | 196 | ``` 197 | 198 | See more in the [mui-picker](http://dev.dcloud.net.cn/mui/ui/#picker) 199 | 200 | 201 | ### example 202 | 203 | ```js 204 | 205 | npm install 206 | 207 | cd example 208 | 209 | node server.js 210 | 211 | ``` 212 | -------------------------------------------------------------------------------- /lib/css/picker.css: -------------------------------------------------------------------------------- 1 | /*main*/ 2 | 3 | .mui-dtpicker h5, .mui-h5 { 4 | font-size: 14px; 5 | font-weight: normal; 6 | color: #8f8f94; 7 | } 8 | 9 | .mui-btn 10 | { 11 | font-size: 14px; 12 | font-weight: 400; 13 | line-height: 1.42; 14 | 15 | position: relative; 16 | 17 | display: inline-block; 18 | 19 | margin-bottom: 0; 20 | padding: 6px 12px; 21 | 22 | cursor: pointer; 23 | -webkit-transition: all; 24 | transition: all; 25 | -webkit-transition-timing-function: linear; 26 | transition-timing-function: linear; 27 | -webkit-transition-duration: .2s; 28 | transition-duration: .2s; 29 | text-align: center; 30 | vertical-align: top; 31 | white-space: nowrap; 32 | 33 | color: #333; 34 | border: 1px solid #ccc; 35 | border-radius: 3px; 36 | border-top-left-radius: 3px; 37 | border-top-right-radius: 3px; 38 | border-bottom-right-radius: 3px; 39 | border-bottom-left-radius: 3px; 40 | background-color: #fff; 41 | background-clip: padding-box; 42 | } 43 | 44 | .mui-btn-primary, .mui-btn-blue 45 | { 46 | color: #fff; 47 | border: 1px solid #007aff; 48 | background-color: #007aff; 49 | } 50 | 51 | .mui-backdrop { 52 | position: fixed; 53 | z-index: 998; 54 | top: 0; 55 | right: 0; 56 | bottom: 0; 57 | left: 0; 58 | background-color: rgba(0, 0, 0, .3); 59 | } 60 | 61 | /** 62 | * 选择列表插件 63 | * varstion 2.0.0 64 | * by Houfeng 65 | * Houfeng@DCloud.io 66 | */ 67 | 68 | .mui-picker { 69 | background-color: #ddd; 70 | position: relative; 71 | height: 200px; 72 | overflow: hidden; 73 | border: solid 1px rgba(0, 0, 0, 0.1); 74 | -webkit-user-select: none; 75 | user-select: none; 76 | box-sizing: border-box; 77 | } 78 | .mui-picker-inner { 79 | box-sizing: border-box; 80 | position: relative; 81 | width: 100%; 82 | height: 100%; 83 | overflow: hidden; 84 | -webkit-mask-box-image: -webkit-linear-gradient(bottom, transparent, transparent 5%, #fff 20%, #fff 80%, transparent 95%, transparent); 85 | -webkit-mask-box-image: linear-gradient(top, transparent, transparent 5%, #fff 20%, #fff 80%, transparent 95%, transparent); 86 | } 87 | .mui-pciker-list, 88 | .mui-pciker-rule { 89 | box-sizing: border-box; 90 | padding: 0px; 91 | margin: 0px; 92 | width: 100%; 93 | height: 36px; 94 | line-height: 36px; 95 | position: absolute; 96 | left: 0px; 97 | top: 50%; 98 | margin-top: -18px; 99 | } 100 | .mui-pciker-rule-bg { 101 | z-index: 0; 102 | /*background-color: #cfd5da;*/ 103 | } 104 | .mui-pciker-rule-ft { 105 | z-index: 2; 106 | border-top: solid 1px rgba(0, 0, 0, 0.1); 107 | border-bottom: solid 1px rgba(0, 0, 0, 0.1); 108 | /*-webkit-box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.1);*/ 109 | /*box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.1);*/ 110 | } 111 | .mui-pciker-list { 112 | z-index: 1; 113 | -webkit-transform-style: preserve-3d; 114 | transform-style: preserve-3d; 115 | -webkit-transform: perspective(1000px) rotateY(0deg) rotateX(0deg); 116 | transform: perspective(1000px) rotateY(0deg) rotateX(0deg); 117 | } 118 | .mui-pciker-list li { 119 | width: 100%; 120 | height: 100%; 121 | position: absolute; 122 | text-align: center; 123 | vertical-align: middle; 124 | -webkit-backface-visibility: hidden; 125 | backface-visibility: hidden; 126 | overflow: hidden; 127 | box-sizing: border-box; 128 | font-size: 16px; 129 | font-family: "Helvetica Neue", "Helvetica", "Arial", "sans-serif"; 130 | color: #888; 131 | padding: 0px 8px; 132 | white-space: nowrap; 133 | -webkit-text-overflow: ellipsis; 134 | text-overflow: ellipsis; 135 | overflow: hidden; 136 | cursor: default; 137 | visibility: hidden; 138 | } 139 | .mui-pciker-list li.highlight, 140 | .mui-pciker-list li.visible { 141 | visibility: visible; 142 | } 143 | .mui-pciker-list li.highlight { 144 | color: #222; 145 | } 146 | .mui-poppicker { 147 | position: fixed; 148 | left: 0px; 149 | width: 100%; 150 | z-index: 999; 151 | background-color: #eee; 152 | border-top: solid 1px #ccc; 153 | box-shadow: 0px -5px 7px 0px rgba(0, 0, 0, 0.1); 154 | -webkit-transition: .3s; 155 | bottom: 0px; 156 | -webkit-transform: translateY(300px); 157 | } 158 | .mui-poppicker.mui-active { 159 | -webkit-transform: translateY(0px); 160 | } 161 | .mui-android-5-1 .mui-poppicker { 162 | bottom: -300px; 163 | -webkit-transition-property: bottom; 164 | -webkit-transform: none; 165 | } 166 | .mui-android-5-1 .mui-poppicker.mui-active { 167 | bottom: 0px; 168 | -webkit-transition-property: bottom; 169 | -webkit-transform: none; 170 | } 171 | .mui-poppicker-header { 172 | padding: 6px; 173 | font-size: 14px; 174 | color: #888; 175 | } 176 | .mui-poppicker-header .mui-btn { 177 | font-size: 12px; 178 | padding: 5px 10px; 179 | } 180 | .mui-poppicker-btn-cancel { 181 | float: left; 182 | } 183 | .mui-poppicker-btn-ok { 184 | float: right; 185 | } 186 | .mui-poppicker-clear { 187 | clear: both; 188 | height: 0px; 189 | line-height: 0px; 190 | font-size: 0px; 191 | overflow: hidden; 192 | } 193 | .mui-poppicker-body { 194 | position: relative; 195 | width: 100%; 196 | height: 200px; 197 | border-top: solid 1px #ddd; 198 | /*-webkit-perspective: 1200px; 199 | perspective: 1200px; 200 | -webkit-transform-style: preserve-3d; 201 | transform-style: preserve-3d;*/ 202 | } 203 | .mui-poppicker-body .mui-picker { 204 | width: 100%; 205 | height: 100%; 206 | margin: 0px; 207 | border: none; 208 | float: left; 209 | } 210 | .mui-dtpicker { 211 | position: fixed; 212 | left: 0px; 213 | width: 100%; 214 | z-index: 999999; 215 | background-color: #eee; 216 | border-top: solid 1px #ccc; 217 | box-shadow: 0px -5px 7px 0px rgba(0, 0, 0, 0.1); 218 | -webkit-transition: .3s; 219 | bottom: 0px; 220 | -webkit-transform: translateY(300px); 221 | } 222 | .mui-dtpicker.mui-active { 223 | -webkit-transform: translateY(0px); 224 | } 225 | /*用于将 html body 禁止滚动条*/ 226 | 227 | .mui-dtpicker-active-for-page { 228 | overflow: hidden !important; 229 | } 230 | .mui-android-5-1 .mui-dtpicker { 231 | bottom: -300px; 232 | -webkit-transition-property: bottom; 233 | -webkit-transform: none; 234 | } 235 | .mui-android-5-1 .mui-dtpicker.mui-active { 236 | bottom: 0px; 237 | -webkit-transition-property: bottom; 238 | -webkit-transform: none; 239 | } 240 | .mui-dtpicker-header { 241 | padding: 6px; 242 | font-size: 14px; 243 | color: #888; 244 | } 245 | .mui-dtpicker-header button { 246 | font-size: 12px; 247 | padding: 5px 10px; 248 | } 249 | .mui-dtpicker-header button:last-child { 250 | float: right; 251 | } 252 | .mui-dtpicker-body { 253 | position: relative; 254 | width: 100%; 255 | height: 200px; 256 | /*border-top: solid 1px #eee; 257 | background-color: #fff;*/ 258 | } 259 | .mui-ios .mui-dtpicker-body { 260 | -webkit-perspective: 1200px; 261 | perspective: 1200px; 262 | -webkit-transform-style: preserve-3d; 263 | transform-style: preserve-3d; 264 | } 265 | .mui-dtpicker-title h5 { 266 | display: inline-block; 267 | width: 20%; 268 | margin: 0px; 269 | padding: 8px; 270 | text-align: center; 271 | border-top: solid 1px #ddd; 272 | background-color: #f0f0f0; 273 | border-bottom: solid 1px #ccc; 274 | } 275 | .mui-dtpicker .mui-picker { 276 | width: 20%; 277 | height: 100%; 278 | margin: 0px; 279 | float: left; 280 | border: none; 281 | } 282 | /*年月日时分*/ 283 | 284 | [data-type="datetime"] .mui-picker, 285 | [data-type="time"] .mui-dtpicker-title h5 { 286 | width: 20%; 287 | } 288 | [data-type="datetime"] [data-id="picker-h"], 289 | [data-type="datetime"] [data-id="title-h"] { 290 | border-left: dotted 1px #ccc; 291 | } 292 | /*年月日*/ 293 | 294 | [data-type="date"] .mui-picker, 295 | [data-type="date"] .mui-dtpicker-title h5 { 296 | width: 33.3%; 297 | } 298 | [data-type="date"] [data-id="picker-h"], 299 | [data-type="date"] [data-id="picker-i"], 300 | [data-type="date"] [data-id="title-h"], 301 | [data-type="date"] [data-id="title-i"] { 302 | display: none; 303 | } 304 | /*年月日时*/ 305 | 306 | [data-type="hour"] .mui-picker, 307 | [data-type="hour"] .mui-dtpicker-title h5 { 308 | width: 25%; 309 | } 310 | [data-type="hour"] [data-id="picker-i"], 311 | [data-type="hour"] [data-id="title-i"] { 312 | display: none; 313 | } 314 | [data-type="hour"] [data-id="picker-h"], 315 | [data-type="hour"] [data-id="title-h"] { 316 | border-left: dotted 1px #ccc; 317 | } 318 | /*时分*/ 319 | 320 | [data-type="time"] .mui-picker, 321 | [data-type="time"] .mui-dtpicker-title h5 { 322 | width: 50%; 323 | } 324 | [data-type="time"] [data-id="picker-y"], 325 | [data-type="time"] [data-id="picker-m"], 326 | [data-type="time"] [data-id="picker-d"], 327 | [data-type="time"] [data-id="title-y"], 328 | [data-type="time"] [data-id="title-m"], 329 | [data-type="time"] [data-id="title-d"] { 330 | display: none; 331 | } 332 | /*年月*/ 333 | 334 | [data-type="month"] .mui-picker, 335 | [data-type="month"] .mui-dtpicker-title h5 { 336 | width: 50%; 337 | } 338 | [data-type="month"] [data-id="picker-d"], 339 | [data-type="month"] [data-id="picker-h"], 340 | [data-type="month"] [data-id="picker-i"], 341 | [data-type="month"] [data-id="title-d"], 342 | [data-type="month"] [data-id="title-h"], 343 | [data-type="month"] [data-id="title-i"] { 344 | display: none; 345 | } 346 | -------------------------------------------------------------------------------- /src/css/picker.css: -------------------------------------------------------------------------------- 1 | /*main*/ 2 | 3 | .mui-dtpicker h5, .mui-h5 { 4 | font-size: 14px; 5 | font-weight: normal; 6 | color: #8f8f94; 7 | } 8 | 9 | .mui-btn 10 | { 11 | font-size: 14px; 12 | font-weight: 400; 13 | line-height: 1.42; 14 | 15 | position: relative; 16 | 17 | display: inline-block; 18 | 19 | margin-bottom: 0; 20 | padding: 6px 12px; 21 | 22 | cursor: pointer; 23 | -webkit-transition: all; 24 | transition: all; 25 | -webkit-transition-timing-function: linear; 26 | transition-timing-function: linear; 27 | -webkit-transition-duration: .2s; 28 | transition-duration: .2s; 29 | text-align: center; 30 | vertical-align: top; 31 | white-space: nowrap; 32 | 33 | color: #333; 34 | border: 1px solid #ccc; 35 | border-radius: 3px; 36 | border-top-left-radius: 3px; 37 | border-top-right-radius: 3px; 38 | border-bottom-right-radius: 3px; 39 | border-bottom-left-radius: 3px; 40 | background-color: #fff; 41 | background-clip: padding-box; 42 | } 43 | 44 | .mui-btn-primary, .mui-btn-blue 45 | { 46 | color: #fff; 47 | border: 1px solid #007aff; 48 | background-color: #007aff; 49 | } 50 | 51 | .mui-backdrop { 52 | position: fixed; 53 | z-index: 998; 54 | top: 0; 55 | right: 0; 56 | bottom: 0; 57 | left: 0; 58 | background-color: rgba(0, 0, 0, .3); 59 | } 60 | 61 | /** 62 | * 选择列表插件 63 | * varstion 2.0.0 64 | * by Houfeng 65 | * Houfeng@DCloud.io 66 | */ 67 | 68 | .mui-picker { 69 | background-color: #ddd; 70 | position: relative; 71 | height: 200px; 72 | overflow: hidden; 73 | border: solid 1px rgba(0, 0, 0, 0.1); 74 | -webkit-user-select: none; 75 | user-select: none; 76 | box-sizing: border-box; 77 | } 78 | .mui-picker-inner { 79 | box-sizing: border-box; 80 | position: relative; 81 | width: 100%; 82 | height: 100%; 83 | overflow: hidden; 84 | -webkit-mask-box-image: -webkit-linear-gradient(bottom, transparent, transparent 5%, #fff 20%, #fff 80%, transparent 95%, transparent); 85 | -webkit-mask-box-image: linear-gradient(top, transparent, transparent 5%, #fff 20%, #fff 80%, transparent 95%, transparent); 86 | } 87 | .mui-pciker-list, 88 | .mui-pciker-rule { 89 | box-sizing: border-box; 90 | padding: 0px; 91 | margin: 0px; 92 | width: 100%; 93 | height: 36px; 94 | line-height: 36px; 95 | position: absolute; 96 | left: 0px; 97 | top: 50%; 98 | margin-top: -18px; 99 | } 100 | .mui-pciker-rule-bg { 101 | z-index: 0; 102 | /*background-color: #cfd5da;*/ 103 | } 104 | .mui-pciker-rule-ft { 105 | z-index: 2; 106 | border-top: solid 1px rgba(0, 0, 0, 0.1); 107 | border-bottom: solid 1px rgba(0, 0, 0, 0.1); 108 | /*-webkit-box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.1);*/ 109 | /*box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.1);*/ 110 | } 111 | .mui-pciker-list { 112 | z-index: 1; 113 | -webkit-transform-style: preserve-3d; 114 | transform-style: preserve-3d; 115 | -webkit-transform: perspective(1000px) rotateY(0deg) rotateX(0deg); 116 | transform: perspective(1000px) rotateY(0deg) rotateX(0deg); 117 | } 118 | .mui-pciker-list li { 119 | width: 100%; 120 | height: 100%; 121 | position: absolute; 122 | text-align: center; 123 | vertical-align: middle; 124 | -webkit-backface-visibility: hidden; 125 | backface-visibility: hidden; 126 | overflow: hidden; 127 | box-sizing: border-box; 128 | font-size: 16px; 129 | font-family: "Helvetica Neue", "Helvetica", "Arial", "sans-serif"; 130 | color: #888; 131 | padding: 0px 8px; 132 | white-space: nowrap; 133 | -webkit-text-overflow: ellipsis; 134 | text-overflow: ellipsis; 135 | overflow: hidden; 136 | cursor: default; 137 | visibility: hidden; 138 | } 139 | .mui-pciker-list li.highlight, 140 | .mui-pciker-list li.visible { 141 | visibility: visible; 142 | } 143 | .mui-pciker-list li.highlight { 144 | color: #222; 145 | } 146 | .mui-poppicker { 147 | position: fixed; 148 | left: 0px; 149 | width: 100%; 150 | z-index: 999; 151 | background-color: #eee; 152 | border-top: solid 1px #ccc; 153 | box-shadow: 0px -5px 7px 0px rgba(0, 0, 0, 0.1); 154 | -webkit-transition: .3s; 155 | bottom: 0px; 156 | -webkit-transform: translateY(300px); 157 | } 158 | .mui-poppicker.mui-active { 159 | -webkit-transform: translateY(0px); 160 | } 161 | .mui-android-5-1 .mui-poppicker { 162 | bottom: -300px; 163 | -webkit-transition-property: bottom; 164 | -webkit-transform: none; 165 | } 166 | .mui-android-5-1 .mui-poppicker.mui-active { 167 | bottom: 0px; 168 | -webkit-transition-property: bottom; 169 | -webkit-transform: none; 170 | } 171 | .mui-poppicker-header { 172 | padding: 6px; 173 | font-size: 14px; 174 | color: #888; 175 | } 176 | .mui-poppicker-header .mui-btn { 177 | font-size: 12px; 178 | padding: 5px 10px; 179 | } 180 | .mui-poppicker-btn-cancel { 181 | float: left; 182 | } 183 | .mui-poppicker-btn-ok { 184 | float: right; 185 | } 186 | .mui-poppicker-clear { 187 | clear: both; 188 | height: 0px; 189 | line-height: 0px; 190 | font-size: 0px; 191 | overflow: hidden; 192 | } 193 | .mui-poppicker-body { 194 | position: relative; 195 | width: 100%; 196 | height: 200px; 197 | border-top: solid 1px #ddd; 198 | /*-webkit-perspective: 1200px; 199 | perspective: 1200px; 200 | -webkit-transform-style: preserve-3d; 201 | transform-style: preserve-3d;*/ 202 | } 203 | .mui-poppicker-body .mui-picker { 204 | width: 100%; 205 | height: 100%; 206 | margin: 0px; 207 | border: none; 208 | float: left; 209 | } 210 | .mui-dtpicker { 211 | position: fixed; 212 | left: 0px; 213 | width: 100%; 214 | z-index: 999999; 215 | background-color: #eee; 216 | border-top: solid 1px #ccc; 217 | box-shadow: 0px -5px 7px 0px rgba(0, 0, 0, 0.1); 218 | -webkit-transition: .3s; 219 | bottom: 0px; 220 | -webkit-transform: translateY(300px); 221 | } 222 | .mui-dtpicker.mui-active { 223 | -webkit-transform: translateY(0px); 224 | } 225 | /*用于将 html body 禁止滚动条*/ 226 | 227 | .mui-dtpicker-active-for-page { 228 | overflow: hidden !important; 229 | } 230 | .mui-android-5-1 .mui-dtpicker { 231 | bottom: -300px; 232 | -webkit-transition-property: bottom; 233 | -webkit-transform: none; 234 | } 235 | .mui-android-5-1 .mui-dtpicker.mui-active { 236 | bottom: 0px; 237 | -webkit-transition-property: bottom; 238 | -webkit-transform: none; 239 | } 240 | .mui-dtpicker-header { 241 | padding: 6px; 242 | font-size: 14px; 243 | color: #888; 244 | } 245 | .mui-dtpicker-header button { 246 | font-size: 12px; 247 | padding: 5px 10px; 248 | } 249 | .mui-dtpicker-header button:last-child { 250 | float: right; 251 | } 252 | .mui-dtpicker-body { 253 | position: relative; 254 | width: 100%; 255 | height: 200px; 256 | /*border-top: solid 1px #eee; 257 | background-color: #fff;*/ 258 | } 259 | .mui-ios .mui-dtpicker-body { 260 | -webkit-perspective: 1200px; 261 | perspective: 1200px; 262 | -webkit-transform-style: preserve-3d; 263 | transform-style: preserve-3d; 264 | } 265 | .mui-dtpicker-title h5 { 266 | display: inline-block; 267 | width: 20%; 268 | margin: 0px; 269 | padding: 8px; 270 | text-align: center; 271 | border-top: solid 1px #ddd; 272 | background-color: #f0f0f0; 273 | border-bottom: solid 1px #ccc; 274 | } 275 | .mui-dtpicker .mui-picker { 276 | width: 20%; 277 | height: 100%; 278 | margin: 0px; 279 | float: left; 280 | border: none; 281 | } 282 | /*年月日时分*/ 283 | 284 | [data-type="datetime"] .mui-picker, 285 | [data-type="time"] .mui-dtpicker-title h5 { 286 | width: 20%; 287 | } 288 | [data-type="datetime"] [data-id="picker-h"], 289 | [data-type="datetime"] [data-id="title-h"] { 290 | border-left: dotted 1px #ccc; 291 | } 292 | /*年月日*/ 293 | 294 | [data-type="date"] .mui-picker, 295 | [data-type="date"] .mui-dtpicker-title h5 { 296 | width: 33.3%; 297 | } 298 | [data-type="date"] [data-id="picker-h"], 299 | [data-type="date"] [data-id="picker-i"], 300 | [data-type="date"] [data-id="title-h"], 301 | [data-type="date"] [data-id="title-i"] { 302 | display: none; 303 | } 304 | /*年月日时*/ 305 | 306 | [data-type="hour"] .mui-picker, 307 | [data-type="hour"] .mui-dtpicker-title h5 { 308 | width: 25%; 309 | } 310 | [data-type="hour"] [data-id="picker-i"], 311 | [data-type="hour"] [data-id="title-i"] { 312 | display: none; 313 | } 314 | [data-type="hour"] [data-id="picker-h"], 315 | [data-type="hour"] [data-id="title-h"] { 316 | border-left: dotted 1px #ccc; 317 | } 318 | /*时分*/ 319 | 320 | [data-type="time"] .mui-picker, 321 | [data-type="time"] .mui-dtpicker-title h5 { 322 | width: 50%; 323 | } 324 | [data-type="time"] [data-id="picker-y"], 325 | [data-type="time"] [data-id="picker-m"], 326 | [data-type="time"] [data-id="picker-d"], 327 | [data-type="time"] [data-id="title-y"], 328 | [data-type="time"] [data-id="title-m"], 329 | [data-type="time"] [data-id="title-d"] { 330 | display: none; 331 | } 332 | /*年月*/ 333 | 334 | [data-type="month"] .mui-picker, 335 | [data-type="month"] .mui-dtpicker-title h5 { 336 | width: 50%; 337 | } 338 | [data-type="month"] [data-id="picker-d"], 339 | [data-type="month"] [data-id="picker-h"], 340 | [data-type="month"] [data-id="picker-i"], 341 | [data-type="month"] [data-id="title-d"], 342 | [data-type="month"] [data-id="title-h"], 343 | [data-type="month"] [data-id="title-i"] { 344 | display: none; 345 | } 346 | -------------------------------------------------------------------------------- /src/js/picker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 选择列表插件 3 | * varstion 2.0.0 4 | * by Houfeng 5 | * Houfeng@DCloud.io 6 | */ 7 | 8 | import mui from './mui' 9 | 10 | (function($, window, document, undefined) { 11 | 12 | var MAX_EXCEED = 30; 13 | var VISIBLE_RANGE = 90; 14 | var DEFAULT_ITEM_HEIGHT = 40; 15 | var BLUR_WIDTH = 10; 16 | 17 | var rad2deg = $.rad2deg = function(rad) { 18 | return rad / (Math.PI / 180); 19 | }; 20 | 21 | var deg2rad = $.deg2rad = function(deg) { 22 | return deg * (Math.PI / 180); 23 | }; 24 | 25 | var platform = navigator.platform.toLowerCase(); 26 | var userAgent = navigator.userAgent.toLowerCase(); 27 | var isIos = (userAgent.indexOf('iphone') > -1 || 28 | userAgent.indexOf('ipad') > -1 || 29 | userAgent.indexOf('ipod') > -1) && 30 | (platform.indexOf('iphone') > -1 || 31 | platform.indexOf('ipad') > -1 || 32 | platform.indexOf('ipod') > -1); 33 | //alert(isIos); 34 | 35 | var Picker = $.Picker = function(holder, options) { 36 | var self = this; 37 | self.holder = holder; 38 | self.options = options || {}; 39 | self.init(); 40 | self.initInertiaParams(); 41 | self.calcElementItemPostion(true); 42 | self.bindEvent(); 43 | }; 44 | 45 | Picker.prototype.findElementItems = function() { 46 | var self = this; 47 | self.elementItems = [].slice.call(self.holder.querySelectorAll('li')); 48 | return self.elementItems; 49 | }; 50 | 51 | Picker.prototype.init = function() { 52 | var self = this; 53 | self.list = self.holder.querySelector('ul'); 54 | self.findElementItems(); 55 | self.standardHeight = document.querySelector('.mui-pciker-rule').getBoundingClientRect() 56 | self.height = self.holder.offsetHeight; 57 | self.r = self.height / 2 - BLUR_WIDTH; 58 | self.d = self.r * 2; 59 | self.itemHeight = typeof self.standardHeight == 'object' ? self.standardHeight.height : DEFAULT_ITEM_HEIGHT; 60 | self.itemAngle = parseInt(self.calcAngle(self.itemHeight * 0.8)); 61 | self.hightlightRange = self.itemAngle / 2; 62 | self.visibleRange = VISIBLE_RANGE; 63 | self.beginAngle = 0; 64 | self.beginExceed = self.beginAngle - MAX_EXCEED; 65 | self.list.angle = self.beginAngle; 66 | if (isIos) { 67 | self.list.style.webkitTransformOrigin = "center center " + self.r + "px"; 68 | } 69 | }; 70 | 71 | Picker.prototype.calcElementItemPostion = function(andGenerateItms) { 72 | var self = this; 73 | if (andGenerateItms) { 74 | self.items = []; 75 | } 76 | self.elementItems.forEach(function(item) { 77 | var index = self.elementItems.indexOf(item); 78 | self.endAngle = self.itemAngle * index; 79 | item.angle = self.endAngle; 80 | item.style.webkitTransformOrigin = "center center -" + self.r + "px"; 81 | item.style.webkitTransform = "translateZ(" + self.r + "px) rotateX(" + (-self.endAngle) + "deg)"; 82 | if (andGenerateItms) { 83 | var dataItem = {}; 84 | dataItem.text = item.innerHTML || ''; 85 | dataItem.value = item.getAttribute('data-value') || dataItem.text; 86 | self.items.push(dataItem); 87 | } 88 | }); 89 | self.endExceed = self.endAngle + MAX_EXCEED; 90 | self.calcElementItemVisibility(self.beginAngle); 91 | }; 92 | 93 | Picker.prototype.calcAngle = function(c) { 94 | var self = this; 95 | var a = parseFloat(self.r); 96 | var b = parseFloat(self.r); 97 | //直径的整倍数部分直接乘以 180 98 | c = Math.abs(c); //只算角度不关心正否值 99 | var intDeg = parseInt(c / self.d) * 180; 100 | c = c % self.d; 101 | //余弦 102 | var cosC = (a * a + b * b - c * c) / (2 * a * b); 103 | var angleC = intDeg + rad2deg(Math.acos(cosC)); 104 | return angleC; 105 | }; 106 | 107 | Picker.prototype.calcElementItemVisibility = function(angle) { 108 | var self = this; 109 | self.elementItems.forEach(function(item) { 110 | var difference = Math.abs(item.angle - angle); 111 | if (difference < self.hightlightRange) { 112 | item.classList.add('highlight'); 113 | } else if (difference < self.visibleRange) { 114 | item.classList.add('visible'); 115 | item.classList.remove('highlight'); 116 | } else { 117 | item.classList.remove('highlight'); 118 | item.classList.remove('visible'); 119 | } 120 | }); 121 | }; 122 | 123 | Picker.prototype.setAngle = function(angle) { 124 | var self = this; 125 | self.list.angle = angle; 126 | self.list.style.webkitTransform = "perspective(1000px) rotateY(0deg) rotateX(" + angle + "deg)"; 127 | self.calcElementItemVisibility(angle); 128 | }; 129 | 130 | Picker.prototype.bindEvent = function() { 131 | var self = this; 132 | var lastAngle = 0; 133 | var startY = null; 134 | var isPicking = false; 135 | self.holder.addEventListener($.EVENT_START, function(event) { 136 | isPicking = true; 137 | event.preventDefault(); 138 | self.list.style.webkitTransition = ''; 139 | startY = (event.changedTouches ? event.changedTouches[0] : event).pageY; 140 | lastAngle = self.list.angle; 141 | self.updateInertiaParams(event, true); 142 | }, false); 143 | self.holder.addEventListener($.EVENT_END, function(event) { 144 | isPicking = false; 145 | event.preventDefault(); 146 | self.startInertiaScroll(event); 147 | }, false); 148 | self.holder.addEventListener($.EVENT_CANCEL, function(event) { 149 | isPicking = false; 150 | event.preventDefault(); 151 | self.startInertiaScroll(event); 152 | }, false); 153 | self.holder.addEventListener($.EVENT_MOVE, function(event) { 154 | if (!isPicking) { 155 | return; 156 | } 157 | event.preventDefault(); 158 | var endY = (event.changedTouches ? event.changedTouches[0] : event).pageY; 159 | var dragRange = endY - startY; 160 | var dragAngle = self.calcAngle(dragRange); 161 | var newAngle = dragRange > 0 ? lastAngle - dragAngle : lastAngle + dragAngle; 162 | if (newAngle > self.endExceed) { 163 | newAngle = self.endExceed 164 | } 165 | if (newAngle < self.beginExceed) { 166 | newAngle = self.beginExceed 167 | } 168 | self.setAngle(newAngle); 169 | self.updateInertiaParams(event); 170 | }, false); 171 | //-- 172 | self.list.addEventListener('tap', function(event) { 173 | elementItem = event.target; 174 | if (elementItem.tagName == 'LI') { 175 | self.setSelectedIndex(self.elementItems.indexOf(elementItem), 200); 176 | } 177 | }, false); 178 | }; 179 | 180 | Picker.prototype.initInertiaParams = function() { 181 | var self = this; 182 | self.lastMoveTime = 0; 183 | self.lastMoveStart = 0; 184 | self.stopInertiaMove = false; 185 | }; 186 | 187 | Picker.prototype.updateInertiaParams = function(event, isStart) { 188 | var self = this; 189 | var point = event.changedTouches ? event.changedTouches[0] : event; 190 | if (isStart) { 191 | self.lastMoveStart = point.pageY; 192 | self.lastMoveTime = event.timeStamp || Date.now(); 193 | self.startAngle = self.list.angle; 194 | } else { 195 | var nowTime = event.timeStamp || Date.now(); 196 | if (nowTime - self.lastMoveTime > 300) { 197 | self.lastMoveTime = nowTime; 198 | self.lastMoveStart = point.pageY; 199 | } 200 | } 201 | self.stopInertiaMove = true; 202 | }; 203 | 204 | Picker.prototype.startInertiaScroll = function(event) { 205 | var self = this; 206 | var point = event.changedTouches ? event.changedTouches[0] : event; 207 | /** 208 | * 缓动代码 209 | */ 210 | var nowTime = event.timeStamp || Date.now(); 211 | var v = (point.pageY - self.lastMoveStart) / (nowTime - self.lastMoveTime); //最后一段时间手指划动速度 212 | var dir = v > 0 ? -1 : 1; //加速度方向 213 | var deceleration = dir * 0.0006 * -1; 214 | var duration = Math.abs(v / deceleration); // 速度消减至0所需时间 215 | var dist = v * duration / 2; //最终移动多少 216 | var startAngle = self.list.angle; 217 | var distAngle = self.calcAngle(dist) * dir; 218 | //---- 219 | var srcDistAngle = distAngle; 220 | if (startAngle + distAngle < self.beginExceed) { 221 | distAngle = self.beginExceed - startAngle; 222 | duration = duration * (distAngle / srcDistAngle) * 0.6; 223 | } 224 | if (startAngle + distAngle > self.endExceed) { 225 | distAngle = self.endExceed - startAngle; 226 | duration = duration * (distAngle / srcDistAngle) * 0.6; 227 | } 228 | //---- 229 | if (distAngle == 0) { 230 | self.endScroll(); 231 | return; 232 | } 233 | self.scrollDistAngle(nowTime, startAngle, distAngle, duration); 234 | }; 235 | 236 | Picker.prototype.scrollDistAngle = function(nowTime, startAngle, distAngle, duration) { 237 | var self = this; 238 | self.stopInertiaMove = false; 239 | (function(nowTime, startAngle, distAngle, duration) { 240 | var frameInterval = 13; 241 | var stepCount = duration / frameInterval; 242 | var stepIndex = 0; 243 | (function inertiaMove() { 244 | if (self.stopInertiaMove) return; 245 | var newAngle = self.quartEaseOut(stepIndex, startAngle, distAngle, stepCount); 246 | self.setAngle(newAngle); 247 | stepIndex++; 248 | if (stepIndex > stepCount - 1 || newAngle < self.beginExceed || newAngle > self.endExceed) { 249 | self.endScroll(); 250 | return; 251 | } 252 | setTimeout(inertiaMove, frameInterval); 253 | })(); 254 | })(nowTime, startAngle, distAngle, duration); 255 | }; 256 | 257 | Picker.prototype.quartEaseOut = function(t, b, c, d) { 258 | return -c * ((t = t / d - 1) * t * t * t - 1) + b; 259 | }; 260 | 261 | Picker.prototype.endScroll = function() { 262 | var self = this; 263 | if (self.list.angle < self.beginAngle) { 264 | self.list.style.webkitTransition = "150ms ease-out"; 265 | self.setAngle(self.beginAngle); 266 | } else if (self.list.angle > self.endAngle) { 267 | self.list.style.webkitTransition = "150ms ease-out"; 268 | self.setAngle(self.endAngle); 269 | } else { 270 | var index = parseInt((self.list.angle / self.itemAngle).toFixed(0)); 271 | self.list.style.webkitTransition = "100ms ease-out"; 272 | self.setAngle(self.itemAngle * index); 273 | } 274 | self.triggerChange(); 275 | }; 276 | 277 | Picker.prototype.triggerChange = function(force) { 278 | var self = this; 279 | setTimeout(function() { 280 | var index = self.getSelectedIndex(); 281 | var item = self.items[index]; 282 | if ($.trigger && (index != self.lastIndex || force === true)) { 283 | $.trigger(self.holder, 'change', { 284 | "index": index, 285 | "item": item 286 | }); 287 | //console.log('change:' + index); 288 | } 289 | self.lastIndex = index; 290 | typeof force === 'function' && force(); 291 | }, 0); 292 | }; 293 | 294 | Picker.prototype.correctAngle = function(angle) { 295 | var self = this; 296 | if (angle < self.beginAngle) { 297 | return self.beginAngle; 298 | } else if (angle > self.endAngle) { 299 | return self.endAngle; 300 | } else { 301 | return angle; 302 | } 303 | }; 304 | 305 | Picker.prototype.setItems = function(items) { 306 | var self = this; 307 | self.items = items || []; 308 | var buffer = []; 309 | self.items.forEach(function(item) { 310 | if (item !== null && item !== undefined) { 311 | buffer.push('
  • ' + (item.text || item) + '
  • '); 312 | } 313 | }); 314 | self.list.innerHTML = buffer.join(''); 315 | self.findElementItems(); 316 | self.calcElementItemPostion(); 317 | self.setAngle(self.correctAngle(self.list.angle)); 318 | self.triggerChange(true); 319 | }; 320 | 321 | Picker.prototype.getItems = function() { 322 | var self = this; 323 | return self.items; 324 | }; 325 | 326 | Picker.prototype.getSelectedIndex = function() { 327 | var self = this; 328 | return parseInt((self.list.angle / self.itemAngle).toFixed(0)); 329 | }; 330 | 331 | Picker.prototype.setSelectedIndex = function(index, duration, callback) { 332 | var self = this; 333 | self.list.style.webkitTransition = ''; 334 | var angle = self.correctAngle(self.itemAngle * index); 335 | if (duration && duration > 0) { 336 | var distAngle = angle - self.list.angle; 337 | self.scrollDistAngle(Date.now(), self.list.angle, distAngle, duration); 338 | } else { 339 | self.setAngle(angle); 340 | } 341 | self.triggerChange(callback); 342 | }; 343 | 344 | Picker.prototype.getSelectedItem = function() { 345 | var self = this; 346 | return self.items[self.getSelectedIndex()]; 347 | }; 348 | 349 | Picker.prototype.getSelectedValue = function() { 350 | var self = this; 351 | return (self.items[self.getSelectedIndex()] || {}).value; 352 | }; 353 | 354 | Picker.prototype.getSelectedText = function() { 355 | var self = this; 356 | return (self.items[self.getSelectedIndex()] || {}).text; 357 | }; 358 | 359 | Picker.prototype.setSelectedValue = function(value, duration, callback) { 360 | var self = this; 361 | for (var index in self.items) { 362 | var item = self.items[index]; 363 | if (item.value == value) { 364 | self.setSelectedIndex(index, duration, callback); 365 | return; 366 | } 367 | } 368 | }; 369 | 370 | if ($.fn) { 371 | $.fn.picker = function(options) { 372 | //遍历选择的元素 373 | this.each(function(i, element) { 374 | if (element.picker) return; 375 | if (options) { 376 | element.picker = new Picker(element, options); 377 | } else { 378 | var optionsText = element.getAttribute('data-picker-options'); 379 | var _options = optionsText ? JSON.parse(optionsText) : {}; 380 | element.picker = new Picker(element, _options); 381 | } 382 | }); 383 | return this[0] ? this[0].picker : null; 384 | }; 385 | 386 | //自动初始化 387 | $.ready(function() { 388 | $('.mui-picker').picker(); 389 | }); 390 | } 391 | 392 | })(mui || window, window, document, undefined); 393 | -------------------------------------------------------------------------------- /lib/js/picker.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; /** 4 | * 选择列表插件 5 | * varstion 2.0.0 6 | * by Houfeng 7 | * Houfeng@DCloud.io 8 | */ 9 | 10 | var _mui = require('./mui'); 11 | 12 | var _mui2 = _interopRequireDefault(_mui); 13 | 14 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 15 | 16 | (function ($, window, document, undefined) { 17 | 18 | var MAX_EXCEED = 30; 19 | var VISIBLE_RANGE = 90; 20 | var DEFAULT_ITEM_HEIGHT = 40; 21 | var BLUR_WIDTH = 10; 22 | 23 | var rad2deg = $.rad2deg = function (rad) { 24 | return rad / (Math.PI / 180); 25 | }; 26 | 27 | var deg2rad = $.deg2rad = function (deg) { 28 | return deg * (Math.PI / 180); 29 | }; 30 | 31 | var platform = navigator.platform.toLowerCase(); 32 | var userAgent = navigator.userAgent.toLowerCase(); 33 | var isIos = (userAgent.indexOf('iphone') > -1 || userAgent.indexOf('ipad') > -1 || userAgent.indexOf('ipod') > -1) && (platform.indexOf('iphone') > -1 || platform.indexOf('ipad') > -1 || platform.indexOf('ipod') > -1); 34 | //alert(isIos); 35 | 36 | var Picker = $.Picker = function (holder, options) { 37 | var self = this; 38 | self.holder = holder; 39 | self.options = options || {}; 40 | self.init(); 41 | self.initInertiaParams(); 42 | self.calcElementItemPostion(true); 43 | self.bindEvent(); 44 | }; 45 | 46 | Picker.prototype.findElementItems = function () { 47 | var self = this; 48 | self.elementItems = [].slice.call(self.holder.querySelectorAll('li')); 49 | return self.elementItems; 50 | }; 51 | 52 | Picker.prototype.init = function () { 53 | var self = this; 54 | self.list = self.holder.querySelector('ul'); 55 | self.findElementItems(); 56 | self.standardHeight = document.querySelector('.mui-pciker-rule').getBoundingClientRect(); 57 | self.height = self.holder.offsetHeight; 58 | self.r = self.height / 2 - BLUR_WIDTH; 59 | self.d = self.r * 2; 60 | self.itemHeight = _typeof(self.standardHeight) == 'object' ? self.standardHeight.height : DEFAULT_ITEM_HEIGHT; 61 | self.itemAngle = parseInt(self.calcAngle(self.itemHeight * 0.8)); 62 | self.hightlightRange = self.itemAngle / 2; 63 | self.visibleRange = VISIBLE_RANGE; 64 | self.beginAngle = 0; 65 | self.beginExceed = self.beginAngle - MAX_EXCEED; 66 | self.list.angle = self.beginAngle; 67 | if (isIos) { 68 | self.list.style.webkitTransformOrigin = "center center " + self.r + "px"; 69 | } 70 | }; 71 | 72 | Picker.prototype.calcElementItemPostion = function (andGenerateItms) { 73 | var self = this; 74 | if (andGenerateItms) { 75 | self.items = []; 76 | } 77 | self.elementItems.forEach(function (item) { 78 | var index = self.elementItems.indexOf(item); 79 | self.endAngle = self.itemAngle * index; 80 | item.angle = self.endAngle; 81 | item.style.webkitTransformOrigin = "center center -" + self.r + "px"; 82 | item.style.webkitTransform = "translateZ(" + self.r + "px) rotateX(" + -self.endAngle + "deg)"; 83 | if (andGenerateItms) { 84 | var dataItem = {}; 85 | dataItem.text = item.innerHTML || ''; 86 | dataItem.value = item.getAttribute('data-value') || dataItem.text; 87 | self.items.push(dataItem); 88 | } 89 | }); 90 | self.endExceed = self.endAngle + MAX_EXCEED; 91 | self.calcElementItemVisibility(self.beginAngle); 92 | }; 93 | 94 | Picker.prototype.calcAngle = function (c) { 95 | var self = this; 96 | var a = parseFloat(self.r); 97 | var b = parseFloat(self.r); 98 | //直径的整倍数部分直接乘以 180 99 | c = Math.abs(c); //只算角度不关心正否值 100 | var intDeg = parseInt(c / self.d) * 180; 101 | c = c % self.d; 102 | //余弦 103 | var cosC = (a * a + b * b - c * c) / (2 * a * b); 104 | var angleC = intDeg + rad2deg(Math.acos(cosC)); 105 | return angleC; 106 | }; 107 | 108 | Picker.prototype.calcElementItemVisibility = function (angle) { 109 | var self = this; 110 | self.elementItems.forEach(function (item) { 111 | var difference = Math.abs(item.angle - angle); 112 | if (difference < self.hightlightRange) { 113 | item.classList.add('highlight'); 114 | } else if (difference < self.visibleRange) { 115 | item.classList.add('visible'); 116 | item.classList.remove('highlight'); 117 | } else { 118 | item.classList.remove('highlight'); 119 | item.classList.remove('visible'); 120 | } 121 | }); 122 | }; 123 | 124 | Picker.prototype.setAngle = function (angle) { 125 | var self = this; 126 | self.list.angle = angle; 127 | self.list.style.webkitTransform = "perspective(1000px) rotateY(0deg) rotateX(" + angle + "deg)"; 128 | self.calcElementItemVisibility(angle); 129 | }; 130 | 131 | Picker.prototype.bindEvent = function () { 132 | var self = this; 133 | var lastAngle = 0; 134 | var startY = null; 135 | var isPicking = false; 136 | self.holder.addEventListener($.EVENT_START, function (event) { 137 | isPicking = true; 138 | event.preventDefault(); 139 | self.list.style.webkitTransition = ''; 140 | startY = (event.changedTouches ? event.changedTouches[0] : event).pageY; 141 | lastAngle = self.list.angle; 142 | self.updateInertiaParams(event, true); 143 | }, false); 144 | self.holder.addEventListener($.EVENT_END, function (event) { 145 | isPicking = false; 146 | event.preventDefault(); 147 | self.startInertiaScroll(event); 148 | }, false); 149 | self.holder.addEventListener($.EVENT_CANCEL, function (event) { 150 | isPicking = false; 151 | event.preventDefault(); 152 | self.startInertiaScroll(event); 153 | }, false); 154 | self.holder.addEventListener($.EVENT_MOVE, function (event) { 155 | if (!isPicking) { 156 | return; 157 | } 158 | event.preventDefault(); 159 | var endY = (event.changedTouches ? event.changedTouches[0] : event).pageY; 160 | var dragRange = endY - startY; 161 | var dragAngle = self.calcAngle(dragRange); 162 | var newAngle = dragRange > 0 ? lastAngle - dragAngle : lastAngle + dragAngle; 163 | if (newAngle > self.endExceed) { 164 | newAngle = self.endExceed; 165 | } 166 | if (newAngle < self.beginExceed) { 167 | newAngle = self.beginExceed; 168 | } 169 | self.setAngle(newAngle); 170 | self.updateInertiaParams(event); 171 | }, false); 172 | //-- 173 | self.list.addEventListener('tap', function (event) { 174 | elementItem = event.target; 175 | if (elementItem.tagName == 'LI') { 176 | self.setSelectedIndex(self.elementItems.indexOf(elementItem), 200); 177 | } 178 | }, false); 179 | }; 180 | 181 | Picker.prototype.initInertiaParams = function () { 182 | var self = this; 183 | self.lastMoveTime = 0; 184 | self.lastMoveStart = 0; 185 | self.stopInertiaMove = false; 186 | }; 187 | 188 | Picker.prototype.updateInertiaParams = function (event, isStart) { 189 | var self = this; 190 | var point = event.changedTouches ? event.changedTouches[0] : event; 191 | if (isStart) { 192 | self.lastMoveStart = point.pageY; 193 | self.lastMoveTime = event.timeStamp || Date.now(); 194 | self.startAngle = self.list.angle; 195 | } else { 196 | var nowTime = event.timeStamp || Date.now(); 197 | if (nowTime - self.lastMoveTime > 300) { 198 | self.lastMoveTime = nowTime; 199 | self.lastMoveStart = point.pageY; 200 | } 201 | } 202 | self.stopInertiaMove = true; 203 | }; 204 | 205 | Picker.prototype.startInertiaScroll = function (event) { 206 | var self = this; 207 | var point = event.changedTouches ? event.changedTouches[0] : event; 208 | /** 209 | * 缓动代码 210 | */ 211 | var nowTime = event.timeStamp || Date.now(); 212 | var v = (point.pageY - self.lastMoveStart) / (nowTime - self.lastMoveTime); //最后一段时间手指划动速度 213 | var dir = v > 0 ? -1 : 1; //加速度方向 214 | var deceleration = dir * 0.0006 * -1; 215 | var duration = Math.abs(v / deceleration); // 速度消减至0所需时间 216 | var dist = v * duration / 2; //最终移动多少 217 | var startAngle = self.list.angle; 218 | var distAngle = self.calcAngle(dist) * dir; 219 | //---- 220 | var srcDistAngle = distAngle; 221 | if (startAngle + distAngle < self.beginExceed) { 222 | distAngle = self.beginExceed - startAngle; 223 | duration = duration * (distAngle / srcDistAngle) * 0.6; 224 | } 225 | if (startAngle + distAngle > self.endExceed) { 226 | distAngle = self.endExceed - startAngle; 227 | duration = duration * (distAngle / srcDistAngle) * 0.6; 228 | } 229 | //---- 230 | if (distAngle == 0) { 231 | self.endScroll(); 232 | return; 233 | } 234 | self.scrollDistAngle(nowTime, startAngle, distAngle, duration); 235 | }; 236 | 237 | Picker.prototype.scrollDistAngle = function (nowTime, startAngle, distAngle, duration) { 238 | var self = this; 239 | self.stopInertiaMove = false; 240 | (function (nowTime, startAngle, distAngle, duration) { 241 | var frameInterval = 13; 242 | var stepCount = duration / frameInterval; 243 | var stepIndex = 0; 244 | (function inertiaMove() { 245 | if (self.stopInertiaMove) return; 246 | var newAngle = self.quartEaseOut(stepIndex, startAngle, distAngle, stepCount); 247 | self.setAngle(newAngle); 248 | stepIndex++; 249 | if (stepIndex > stepCount - 1 || newAngle < self.beginExceed || newAngle > self.endExceed) { 250 | self.endScroll(); 251 | return; 252 | } 253 | setTimeout(inertiaMove, frameInterval); 254 | })(); 255 | })(nowTime, startAngle, distAngle, duration); 256 | }; 257 | 258 | Picker.prototype.quartEaseOut = function (t, b, c, d) { 259 | return -c * ((t = t / d - 1) * t * t * t - 1) + b; 260 | }; 261 | 262 | Picker.prototype.endScroll = function () { 263 | var self = this; 264 | if (self.list.angle < self.beginAngle) { 265 | self.list.style.webkitTransition = "150ms ease-out"; 266 | self.setAngle(self.beginAngle); 267 | } else if (self.list.angle > self.endAngle) { 268 | self.list.style.webkitTransition = "150ms ease-out"; 269 | self.setAngle(self.endAngle); 270 | } else { 271 | var index = parseInt((self.list.angle / self.itemAngle).toFixed(0)); 272 | self.list.style.webkitTransition = "100ms ease-out"; 273 | self.setAngle(self.itemAngle * index); 274 | } 275 | self.triggerChange(); 276 | }; 277 | 278 | Picker.prototype.triggerChange = function (force) { 279 | var self = this; 280 | setTimeout(function () { 281 | var index = self.getSelectedIndex(); 282 | var item = self.items[index]; 283 | if ($.trigger && (index != self.lastIndex || force === true)) { 284 | $.trigger(self.holder, 'change', { 285 | "index": index, 286 | "item": item 287 | }); 288 | //console.log('change:' + index); 289 | } 290 | self.lastIndex = index; 291 | typeof force === 'function' && force(); 292 | }, 0); 293 | }; 294 | 295 | Picker.prototype.correctAngle = function (angle) { 296 | var self = this; 297 | if (angle < self.beginAngle) { 298 | return self.beginAngle; 299 | } else if (angle > self.endAngle) { 300 | return self.endAngle; 301 | } else { 302 | return angle; 303 | } 304 | }; 305 | 306 | Picker.prototype.setItems = function (items) { 307 | var self = this; 308 | self.items = items || []; 309 | var buffer = []; 310 | self.items.forEach(function (item) { 311 | if (item !== null && item !== undefined) { 312 | buffer.push('
  • ' + (item.text || item) + '
  • '); 313 | } 314 | }); 315 | self.list.innerHTML = buffer.join(''); 316 | self.findElementItems(); 317 | self.calcElementItemPostion(); 318 | self.setAngle(self.correctAngle(self.list.angle)); 319 | self.triggerChange(true); 320 | }; 321 | 322 | Picker.prototype.getItems = function () { 323 | var self = this; 324 | return self.items; 325 | }; 326 | 327 | Picker.prototype.getSelectedIndex = function () { 328 | var self = this; 329 | return parseInt((self.list.angle / self.itemAngle).toFixed(0)); 330 | }; 331 | 332 | Picker.prototype.setSelectedIndex = function (index, duration, callback) { 333 | var self = this; 334 | self.list.style.webkitTransition = ''; 335 | var angle = self.correctAngle(self.itemAngle * index); 336 | if (duration && duration > 0) { 337 | var distAngle = angle - self.list.angle; 338 | self.scrollDistAngle(Date.now(), self.list.angle, distAngle, duration); 339 | } else { 340 | self.setAngle(angle); 341 | } 342 | self.triggerChange(callback); 343 | }; 344 | 345 | Picker.prototype.getSelectedItem = function () { 346 | var self = this; 347 | return self.items[self.getSelectedIndex()]; 348 | }; 349 | 350 | Picker.prototype.getSelectedValue = function () { 351 | var self = this; 352 | return (self.items[self.getSelectedIndex()] || {}).value; 353 | }; 354 | 355 | Picker.prototype.getSelectedText = function () { 356 | var self = this; 357 | return (self.items[self.getSelectedIndex()] || {}).text; 358 | }; 359 | 360 | Picker.prototype.setSelectedValue = function (value, duration, callback) { 361 | var self = this; 362 | for (var index in self.items) { 363 | var item = self.items[index]; 364 | if (item.value == value) { 365 | self.setSelectedIndex(index, duration, callback); 366 | return; 367 | } 368 | } 369 | }; 370 | 371 | if ($.fn) { 372 | $.fn.picker = function (options) { 373 | //遍历选择的元素 374 | this.each(function (i, element) { 375 | if (element.picker) return; 376 | if (options) { 377 | element.picker = new Picker(element, options); 378 | } else { 379 | var optionsText = element.getAttribute('data-picker-options'); 380 | var _options = optionsText ? JSON.parse(optionsText) : {}; 381 | element.picker = new Picker(element, _options); 382 | } 383 | }); 384 | return this[0] ? this[0].picker : null; 385 | }; 386 | 387 | //自动初始化 388 | $.ready(function () { 389 | $('.mui-picker').picker(); 390 | }); 391 | } 392 | })(_mui2.default || window, window, document, undefined); -------------------------------------------------------------------------------- /src/js/dtpicker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 日期时间插件 3 | * varstion 1.0.5 4 | * by Houfeng 5 | * Houfeng@DCloud.io 6 | */ 7 | 8 | import mui from './mui' 9 | 10 | (function($, document) { 11 | 12 | //创建 DOM 13 | $.dom = function(str) { 14 | if (typeof(str) !== 'string') { 15 | if ((str instanceof Array) || (str[0] && str.length)) { 16 | return [].slice.call(str); 17 | } else { 18 | return [str]; 19 | } 20 | } 21 | if (!$.__create_dom_div__) { 22 | $.__create_dom_div__ = document.createElement('div'); 23 | } 24 | $.__create_dom_div__.innerHTML = str; 25 | return [].slice.call($.__create_dom_div__.childNodes); 26 | }; 27 | 28 | var domBuffer = '
    \ 29 |
    \ 30 | \ 31 | \ 32 |
    \ 33 |
    \ 34 |
    \ 35 |
    \ 36 |
    \ 37 |
    \ 38 |
      \ 39 |
    \ 40 |
    \ 41 |
    \ 42 |
    \ 43 |
    \ 44 |
    \ 45 |
    \ 46 |
      \ 47 |
    \ 48 |
    \ 49 |
    \ 50 |
    \ 51 |
    \ 52 |
    \ 53 |
    \ 54 |
      \ 55 |
    \ 56 |
    \ 57 |
    \ 58 |
    \ 59 |
    \ 60 |
    \ 61 |
    \ 62 |
      \ 63 |
    \ 64 |
    \ 65 |
    \ 66 |
    \ 67 |
    \ 68 |
    \ 69 |
    \ 70 |
      \ 71 |
    \ 72 |
    \ 73 |
    \ 74 |
    \ 75 |
    \ 76 |
    '; 77 | 78 | //plugin 79 | var DtPicker = $.DtPicker = $.Class.extend({ 80 | init: function(options) { 81 | var self = this; 82 | var _picker = $.dom(domBuffer)[0]; 83 | document.body.appendChild(_picker); 84 | $('[data-id*="picker"]', _picker).picker(); 85 | var ui = self.ui = { 86 | picker: _picker, 87 | mask: $.createMask(), 88 | ok: $('[data-id="btn-ok"]', _picker)[0], 89 | cancel: $('[data-id="btn-cancel"]', _picker)[0], 90 | y: $('[data-id="picker-y"]', _picker)[0], 91 | m: $('[data-id="picker-m"]', _picker)[0], 92 | d: $('[data-id="picker-d"]', _picker)[0], 93 | h: $('[data-id="picker-h"]', _picker)[0], 94 | i: $('[data-id="picker-i"]', _picker)[0], 95 | labels: $('[data-id*="title-"]', _picker), 96 | }; 97 | ui.cancel.addEventListener('tap', function() { 98 | self.hide(); 99 | }, false); 100 | ui.ok.addEventListener('tap', function() { 101 | self.callback(self.getSelected()); 102 | }, false); 103 | ui.y.addEventListener('change', function(e) { //目前的change事件容易导致级联触发 104 | if (self.options.beginMonth || self.options.endMonth) { 105 | self._createMonth(); 106 | } else { 107 | self._createDay(); 108 | } 109 | }, false); 110 | ui.m.addEventListener('change', function(e) { 111 | self._createDay(); 112 | }, false); 113 | ui.d.addEventListener('change', function(e) { 114 | if (self.options.beginMonth || self.options.endMonth) { //仅提供了beginDate时,触发day,hours,minutes的change 115 | self._createHours(); 116 | } 117 | }, false); 118 | ui.h.addEventListener('change', function(e) { 119 | if (self.options.beginMonth || self.options.endMonth) { 120 | self._createMinutes(); 121 | } 122 | }, false); 123 | 124 | self._create(options); 125 | //防止滚动穿透 126 | self.ui.picker.addEventListener($.EVENT_START, function(event) { 127 | event.preventDefault(); 128 | }, false); 129 | self.ui.picker.addEventListener($.EVENT_MOVE, function(event) { 130 | event.preventDefault(); 131 | }, false); 132 | }, 133 | getSelected: function() { 134 | var self = this; 135 | var ui = self.ui; 136 | var type = self.options.type; 137 | var selected = { 138 | type: type, 139 | y: ui.y.picker.getSelectedItem(), 140 | m: ui.m.picker.getSelectedItem(), 141 | d: ui.d.picker.getSelectedItem(), 142 | h: ui.h.picker.getSelectedItem(), 143 | i: ui.i.picker.getSelectedItem(), 144 | toString: function() { 145 | return this.value; 146 | } 147 | }; 148 | switch (type) { 149 | case 'datetime': 150 | selected.value = selected.y.value + '-' + selected.m.value + '-' + selected.d.value + ' ' + selected.h.value + ':' + selected.i.value; 151 | selected.text = selected.y.text + '-' + selected.m.text + '-' + selected.d.text + ' ' + selected.h.text + ':' + selected.i.text; 152 | break; 153 | case 'date': 154 | selected.value = selected.y.value + '-' + selected.m.value + '-' + selected.d.value; 155 | selected.text = selected.y.text + '-' + selected.m.text + '-' + selected.d.text; 156 | break; 157 | case 'time': 158 | selected.value = selected.h.value + ':' + selected.i.value; 159 | selected.text = selected.h.text + ':' + selected.i.text; 160 | break; 161 | case 'month': 162 | selected.value = selected.y.value + '-' + selected.m.value; 163 | selected.text = selected.y.text + '-' + selected.m.text; 164 | break; 165 | case 'hour': 166 | selected.value = selected.y.value + '-' + selected.m.value + '-' + selected.d.value + ' ' + selected.h.value; 167 | selected.text = selected.y.text + '-' + selected.m.text + '-' + selected.d.text + ' ' + selected.h.text; 168 | break; 169 | } 170 | return selected; 171 | }, 172 | setSelectedValue: function(value) { 173 | var self = this; 174 | var ui = self.ui; 175 | var parsedValue = self._parseValue(value); 176 | //TODO 嵌套过多,因为picker的change时间是异步(考虑到性能)的,所以为了保证change之后再setSelected,目前使用回调处理 177 | ui.y.picker.setSelectedValue(parsedValue.y, 0, function() { 178 | ui.m.picker.setSelectedValue(parsedValue.m, 0, function() { 179 | ui.d.picker.setSelectedValue(parsedValue.d, 0, function() { 180 | ui.h.picker.setSelectedValue(parsedValue.h, 0, function() { 181 | ui.i.picker.setSelectedValue(parsedValue.i, 0); 182 | }); 183 | }); 184 | }); 185 | }); 186 | }, 187 | isLeapYear: function(year) { 188 | return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); 189 | }, 190 | _inArray: function(array, item) { 191 | for (var index in array) { 192 | var _item = array[index]; 193 | if (_item === item) return true; 194 | } 195 | return false; 196 | }, 197 | getDayNum: function(year, month) { 198 | var self = this; 199 | if (self._inArray([1, 3, 5, 7, 8, 10, 12], month)) { 200 | return 31; 201 | } else if (self._inArray([4, 6, 9, 11], month)) { 202 | return 30; 203 | } else if (self.isLeapYear(year)) { 204 | return 29; 205 | } else { 206 | return 28; 207 | } 208 | }, 209 | _fill: function(num) { 210 | num = num.toString(); 211 | if (num.length < 2) { 212 | num = 0 + num; 213 | } 214 | return num; 215 | }, 216 | _isBeginYear: function() { 217 | return this.options.beginYear === parseInt(this.ui.y.picker.getSelectedValue()); 218 | }, 219 | _isBeginMonth: function() { 220 | return this.options.beginMonth && this._isBeginYear() && this.options.beginMonth === parseInt(this.ui.m.picker.getSelectedValue()); 221 | }, 222 | _isBeginDay: function() { 223 | return this._isBeginMonth() && this.options.beginDay === parseInt(this.ui.d.picker.getSelectedValue()); 224 | }, 225 | _isBeginHours: function() { 226 | return this._isBeginDay() && this.options.beginHours === parseInt(this.ui.h.picker.getSelectedValue()); 227 | }, 228 | _isEndYear: function() { 229 | return this.options.endYear === parseInt(this.ui.y.picker.getSelectedValue()); 230 | }, 231 | _isEndMonth: function() { 232 | return this.options.endMonth && this._isEndYear() && this.options.endMonth === parseInt(this.ui.m.picker.getSelectedValue()); 233 | }, 234 | _isEndDay: function() { 235 | return this._isEndMonth() && this.options.endDay === parseInt(this.ui.d.picker.getSelectedValue()); 236 | }, 237 | _isEndHours: function() { 238 | return this._isEndDay() && this.options.endHours === parseInt(this.ui.h.picker.getSelectedValue()); 239 | }, 240 | _createYear: function(current) { 241 | var self = this; 242 | var options = self.options; 243 | var ui = self.ui; 244 | //生成年列表 245 | var yArray = []; 246 | if (options.customData.y) { 247 | yArray = options.customData.y; 248 | } else { 249 | var yBegin = options.beginYear; 250 | var yEnd = options.endYear; 251 | for (var y = yBegin; y <= yEnd; y++) { 252 | yArray.push({ 253 | text: y + '', 254 | value: y 255 | }); 256 | } 257 | } 258 | ui.y.picker.setItems(yArray); 259 | //ui.y.picker.setSelectedValue(current); 260 | }, 261 | _createMonth: function(current) { 262 | var self = this; 263 | var options = self.options; 264 | var ui = self.ui; 265 | 266 | //生成月列表 267 | var mArray = []; 268 | if (options.customData.m) { 269 | mArray = options.customData.m; 270 | } else { 271 | var m = options.beginMonth && self._isBeginYear() ? options.beginMonth : 1; 272 | var maxMonth = options.endMonth && self._isEndYear() ? options.endMonth : 12; 273 | for (; m <= maxMonth; m++) { 274 | var val = self._fill(m); 275 | mArray.push({ 276 | text: val, 277 | value: val 278 | }); 279 | } 280 | } 281 | ui.m.picker.setItems(mArray); 282 | //ui.m.picker.setSelectedValue(current); 283 | }, 284 | _createDay: function(current) { 285 | var self = this; 286 | var options = self.options; 287 | var ui = self.ui; 288 | 289 | //生成日列表 290 | var dArray = []; 291 | if (options.customData.d) { 292 | dArray = options.customData.d; 293 | } else { 294 | var d = self._isBeginMonth() ? options.beginDay : 1; 295 | var maxDay = self._isEndMonth() ? options.endDay : self.getDayNum(parseInt(this.ui.y.picker.getSelectedValue()), parseInt(this.ui.m.picker.getSelectedValue())); 296 | for (; d <= maxDay; d++) { 297 | var val = self._fill(d); 298 | dArray.push({ 299 | text: val, 300 | value: val 301 | }); 302 | } 303 | } 304 | ui.d.picker.setItems(dArray); 305 | current = current || ui.d.picker.getSelectedValue(); 306 | //ui.d.picker.setSelectedValue(current); 307 | }, 308 | _createHours: function(current) { 309 | var self = this; 310 | var options = self.options; 311 | var ui = self.ui; 312 | //生成时列表 313 | var hArray = []; 314 | if (options.customData.h) { 315 | hArray = options.customData.h; 316 | } else { 317 | var h = self._isBeginDay() ? options.beginHours : 0; 318 | var maxHours = self._isEndDay() ? options.endHours : 23; 319 | for (; h <= maxHours; h++) { 320 | var val = self._fill(h); 321 | hArray.push({ 322 | text: val, 323 | value: val 324 | }); 325 | } 326 | } 327 | ui.h.picker.setItems(hArray); 328 | //ui.h.picker.setSelectedValue(current); 329 | }, 330 | _createMinutes: function(current) { 331 | var self = this; 332 | var options = self.options; 333 | var ui = self.ui; 334 | 335 | //生成分列表 336 | var iArray = []; 337 | if (options.customData.i) { 338 | iArray = options.customData.i; 339 | } else { 340 | var i = self._isBeginHours() ? options.beginMinutes : 0; 341 | var maxMinutes = self._isEndHours() ? options.endMinutes : 59; 342 | for (; i <= maxMinutes; i++) { 343 | var val = self._fill(i); 344 | iArray.push({ 345 | text: val, 346 | value: val 347 | }); 348 | } 349 | } 350 | ui.i.picker.setItems(iArray); 351 | //ui.i.picker.setSelectedValue(current); 352 | }, 353 | _setLabels: function() { 354 | var self = this; 355 | var options = self.options; 356 | var ui = self.ui; 357 | ui.labels.each(function(i, label) { 358 | label.innerText = options.labels[i]; 359 | }); 360 | }, 361 | _setButtons: function() { 362 | var self = this; 363 | var options = self.options; 364 | var ui = self.ui; 365 | ui.cancel.innerText = options.buttons[0]; 366 | ui.ok.innerText = options.buttons[1]; 367 | }, 368 | _parseValue: function(value) { 369 | var self = this; 370 | var rs = {}; 371 | if (value) { 372 | var parts = value.replace(":", "-").replace(" ", "-").split("-"); 373 | rs.y = parts[0]; 374 | rs.m = parts[1]; 375 | rs.d = parts[2]; 376 | rs.h = parts[3]; 377 | rs.i = parts[4]; 378 | } else { 379 | var now = new Date(); 380 | rs.y = now.getFullYear(); 381 | rs.m = now.getMonth() + 1; 382 | rs.d = now.getDate(); 383 | rs.h = now.getHours(); 384 | rs.i = now.getMinutes(); 385 | } 386 | return rs; 387 | }, 388 | _create: function(options) { 389 | var self = this; 390 | options = options || {}; 391 | options.labels = options.labels || ['年', '月', '日', '时', '分']; 392 | options.buttons = options.buttons || ['取消', '确定']; 393 | options.type = options.type || 'datetime'; 394 | options.customData = options.customData || {}; 395 | self.options = options; 396 | var now = new Date(); 397 | var beginDate = options.beginDate; 398 | if (beginDate instanceof Date && !isNaN(beginDate.valueOf())) { //设定了开始日期 399 | options.beginYear = beginDate.getFullYear(); 400 | options.beginMonth = beginDate.getMonth() + 1; 401 | options.beginDay = beginDate.getDate(); 402 | options.beginHours = beginDate.getHours(); 403 | options.beginMinutes = beginDate.getMinutes(); 404 | } 405 | var endDate = options.endDate; 406 | if (endDate instanceof Date && !isNaN(endDate.valueOf())) { //设定了结束日期 407 | options.endYear = endDate.getFullYear(); 408 | options.endMonth = endDate.getMonth() + 1; 409 | options.endDay = endDate.getDate(); 410 | options.endHours = endDate.getHours(); 411 | options.endMinutes = endDate.getMinutes(); 412 | } 413 | options.beginYear = options.beginYear || (now.getFullYear() - 5); 414 | options.endYear = options.endYear || (now.getFullYear() + 5); 415 | var ui = self.ui; 416 | //设定label 417 | self._setLabels(); 418 | self._setButtons(); 419 | //设定类型 420 | ui.picker.setAttribute('data-type', options.type); 421 | //生成 422 | self._createYear(); 423 | self._createMonth(); 424 | self._createDay(); 425 | self._createHours(); 426 | self._createMinutes(); 427 | //设定默认值 428 | self.setSelectedValue(options.value); 429 | }, 430 | //显示 431 | show: function(callback) { 432 | var self = this; 433 | var ui = self.ui; 434 | self.callback = callback || $.noop; 435 | ui.mask.show(); 436 | document.body.classList.add($.className('dtpicker-active-for-page')); 437 | ui.picker.classList.add($.className('active')); 438 | //处理物理返回键 439 | self.__back = $.back; 440 | $.back = function() { 441 | self.hide(); 442 | }; 443 | }, 444 | hide: function() { 445 | var self = this; 446 | if (self.disposed) return; 447 | var ui = self.ui; 448 | ui.picker.classList.remove($.className('active')); 449 | ui.mask.close(); 450 | document.body.classList.remove($.className('dtpicker-active-for-page')); 451 | //处理物理返回键 452 | $.back = self.__back; 453 | }, 454 | dispose: function() { 455 | var self = this; 456 | self.hide(); 457 | setTimeout(function() { 458 | self.ui.picker.parentNode.removeChild(self.ui.picker); 459 | for (var name in self) { 460 | self[name] = null; 461 | delete self[name]; 462 | }; 463 | self.disposed = true; 464 | }, 300); 465 | } 466 | }); 467 | 468 | })(mui, document); 469 | 470 | 471 | export default mui.DtPicker 472 | -------------------------------------------------------------------------------- /lib/js/dtpicker.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _mui = require('./mui'); 8 | 9 | var _mui2 = _interopRequireDefault(_mui); 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 12 | 13 | (function ($, document) { 14 | 15 | //创建 DOM 16 | $.dom = function (str) { 17 | if (typeof str !== 'string') { 18 | if (str instanceof Array || str[0] && str.length) { 19 | return [].slice.call(str); 20 | } else { 21 | return [str]; 22 | } 23 | } 24 | if (!$.__create_dom_div__) { 25 | $.__create_dom_div__ = document.createElement('div'); 26 | } 27 | $.__create_dom_div__.innerHTML = str; 28 | return [].slice.call($.__create_dom_div__.childNodes); 29 | }; 30 | 31 | var domBuffer = '
    \ 32 |
    \ 33 | \ 34 | \ 35 |
    \ 36 |
    \ 37 |
    \ 38 |
    \ 39 |
    \ 40 |
    \ 41 |
      \ 42 |
    \ 43 |
    \ 44 |
    \ 45 |
    \ 46 |
    \ 47 |
    \ 48 |
    \ 49 |
      \ 50 |
    \ 51 |
    \ 52 |
    \ 53 |
    \ 54 |
    \ 55 |
    \ 56 |
    \ 57 |
      \ 58 |
    \ 59 |
    \ 60 |
    \ 61 |
    \ 62 |
    \ 63 |
    \ 64 |
    \ 65 |
      \ 66 |
    \ 67 |
    \ 68 |
    \ 69 |
    \ 70 |
    \ 71 |
    \ 72 |
    \ 73 |
      \ 74 |
    \ 75 |
    \ 76 |
    \ 77 |
    \ 78 |
    \ 79 |
    '; 80 | 81 | //plugin 82 | var DtPicker = $.DtPicker = $.Class.extend({ 83 | init: function init(options) { 84 | var self = this; 85 | var _picker = $.dom(domBuffer)[0]; 86 | document.body.appendChild(_picker); 87 | $('[data-id*="picker"]', _picker).picker(); 88 | var ui = self.ui = { 89 | picker: _picker, 90 | mask: $.createMask(), 91 | ok: $('[data-id="btn-ok"]', _picker)[0], 92 | cancel: $('[data-id="btn-cancel"]', _picker)[0], 93 | y: $('[data-id="picker-y"]', _picker)[0], 94 | m: $('[data-id="picker-m"]', _picker)[0], 95 | d: $('[data-id="picker-d"]', _picker)[0], 96 | h: $('[data-id="picker-h"]', _picker)[0], 97 | i: $('[data-id="picker-i"]', _picker)[0], 98 | labels: $('[data-id*="title-"]', _picker) 99 | }; 100 | ui.cancel.addEventListener('tap', function () { 101 | self.hide(); 102 | }, false); 103 | ui.ok.addEventListener('tap', function () { 104 | self.callback(self.getSelected()); 105 | }, false); 106 | ui.y.addEventListener('change', function (e) { 107 | //目前的change事件容易导致级联触发 108 | if (self.options.beginMonth || self.options.endMonth) { 109 | self._createMonth(); 110 | } else { 111 | self._createDay(); 112 | } 113 | }, false); 114 | ui.m.addEventListener('change', function (e) { 115 | self._createDay(); 116 | }, false); 117 | ui.d.addEventListener('change', function (e) { 118 | if (self.options.beginMonth || self.options.endMonth) { 119 | //仅提供了beginDate时,触发day,hours,minutes的change 120 | self._createHours(); 121 | } 122 | }, false); 123 | ui.h.addEventListener('change', function (e) { 124 | if (self.options.beginMonth || self.options.endMonth) { 125 | self._createMinutes(); 126 | } 127 | }, false); 128 | 129 | self._create(options); 130 | //防止滚动穿透 131 | self.ui.picker.addEventListener($.EVENT_START, function (event) { 132 | event.preventDefault(); 133 | }, false); 134 | self.ui.picker.addEventListener($.EVENT_MOVE, function (event) { 135 | event.preventDefault(); 136 | }, false); 137 | }, 138 | getSelected: function getSelected() { 139 | var self = this; 140 | var ui = self.ui; 141 | var type = self.options.type; 142 | var selected = { 143 | type: type, 144 | y: ui.y.picker.getSelectedItem(), 145 | m: ui.m.picker.getSelectedItem(), 146 | d: ui.d.picker.getSelectedItem(), 147 | h: ui.h.picker.getSelectedItem(), 148 | i: ui.i.picker.getSelectedItem(), 149 | toString: function toString() { 150 | return this.value; 151 | } 152 | }; 153 | switch (type) { 154 | case 'datetime': 155 | selected.value = selected.y.value + '-' + selected.m.value + '-' + selected.d.value + ' ' + selected.h.value + ':' + selected.i.value; 156 | selected.text = selected.y.text + '-' + selected.m.text + '-' + selected.d.text + ' ' + selected.h.text + ':' + selected.i.text; 157 | break; 158 | case 'date': 159 | selected.value = selected.y.value + '-' + selected.m.value + '-' + selected.d.value; 160 | selected.text = selected.y.text + '-' + selected.m.text + '-' + selected.d.text; 161 | break; 162 | case 'time': 163 | selected.value = selected.h.value + ':' + selected.i.value; 164 | selected.text = selected.h.text + ':' + selected.i.text; 165 | break; 166 | case 'month': 167 | selected.value = selected.y.value + '-' + selected.m.value; 168 | selected.text = selected.y.text + '-' + selected.m.text; 169 | break; 170 | case 'hour': 171 | selected.value = selected.y.value + '-' + selected.m.value + '-' + selected.d.value + ' ' + selected.h.value; 172 | selected.text = selected.y.text + '-' + selected.m.text + '-' + selected.d.text + ' ' + selected.h.text; 173 | break; 174 | } 175 | return selected; 176 | }, 177 | setSelectedValue: function setSelectedValue(value) { 178 | var self = this; 179 | var ui = self.ui; 180 | var parsedValue = self._parseValue(value); 181 | //TODO 嵌套过多,因为picker的change时间是异步(考虑到性能)的,所以为了保证change之后再setSelected,目前使用回调处理 182 | ui.y.picker.setSelectedValue(parsedValue.y, 0, function () { 183 | ui.m.picker.setSelectedValue(parsedValue.m, 0, function () { 184 | ui.d.picker.setSelectedValue(parsedValue.d, 0, function () { 185 | ui.h.picker.setSelectedValue(parsedValue.h, 0, function () { 186 | ui.i.picker.setSelectedValue(parsedValue.i, 0); 187 | }); 188 | }); 189 | }); 190 | }); 191 | }, 192 | isLeapYear: function isLeapYear(year) { 193 | return year % 4 == 0 && year % 100 != 0 || year % 400 == 0; 194 | }, 195 | _inArray: function _inArray(array, item) { 196 | for (var index in array) { 197 | var _item = array[index]; 198 | if (_item === item) return true; 199 | } 200 | return false; 201 | }, 202 | getDayNum: function getDayNum(year, month) { 203 | var self = this; 204 | if (self._inArray([1, 3, 5, 7, 8, 10, 12], month)) { 205 | return 31; 206 | } else if (self._inArray([4, 6, 9, 11], month)) { 207 | return 30; 208 | } else if (self.isLeapYear(year)) { 209 | return 29; 210 | } else { 211 | return 28; 212 | } 213 | }, 214 | _fill: function _fill(num) { 215 | num = num.toString(); 216 | if (num.length < 2) { 217 | num = 0 + num; 218 | } 219 | return num; 220 | }, 221 | _isBeginYear: function _isBeginYear() { 222 | return this.options.beginYear === parseInt(this.ui.y.picker.getSelectedValue()); 223 | }, 224 | _isBeginMonth: function _isBeginMonth() { 225 | return this.options.beginMonth && this._isBeginYear() && this.options.beginMonth === parseInt(this.ui.m.picker.getSelectedValue()); 226 | }, 227 | _isBeginDay: function _isBeginDay() { 228 | return this._isBeginMonth() && this.options.beginDay === parseInt(this.ui.d.picker.getSelectedValue()); 229 | }, 230 | _isBeginHours: function _isBeginHours() { 231 | return this._isBeginDay() && this.options.beginHours === parseInt(this.ui.h.picker.getSelectedValue()); 232 | }, 233 | _isEndYear: function _isEndYear() { 234 | return this.options.endYear === parseInt(this.ui.y.picker.getSelectedValue()); 235 | }, 236 | _isEndMonth: function _isEndMonth() { 237 | return this.options.endMonth && this._isEndYear() && this.options.endMonth === parseInt(this.ui.m.picker.getSelectedValue()); 238 | }, 239 | _isEndDay: function _isEndDay() { 240 | return this._isEndMonth() && this.options.endDay === parseInt(this.ui.d.picker.getSelectedValue()); 241 | }, 242 | _isEndHours: function _isEndHours() { 243 | return this._isEndDay() && this.options.endHours === parseInt(this.ui.h.picker.getSelectedValue()); 244 | }, 245 | _createYear: function _createYear(current) { 246 | var self = this; 247 | var options = self.options; 248 | var ui = self.ui; 249 | //生成年列表 250 | var yArray = []; 251 | if (options.customData.y) { 252 | yArray = options.customData.y; 253 | } else { 254 | var yBegin = options.beginYear; 255 | var yEnd = options.endYear; 256 | for (var y = yBegin; y <= yEnd; y++) { 257 | yArray.push({ 258 | text: y + '', 259 | value: y 260 | }); 261 | } 262 | } 263 | ui.y.picker.setItems(yArray); 264 | //ui.y.picker.setSelectedValue(current); 265 | }, 266 | _createMonth: function _createMonth(current) { 267 | var self = this; 268 | var options = self.options; 269 | var ui = self.ui; 270 | 271 | //生成月列表 272 | var mArray = []; 273 | if (options.customData.m) { 274 | mArray = options.customData.m; 275 | } else { 276 | var m = options.beginMonth && self._isBeginYear() ? options.beginMonth : 1; 277 | var maxMonth = options.endMonth && self._isEndYear() ? options.endMonth : 12; 278 | for (; m <= maxMonth; m++) { 279 | var val = self._fill(m); 280 | mArray.push({ 281 | text: val, 282 | value: val 283 | }); 284 | } 285 | } 286 | ui.m.picker.setItems(mArray); 287 | //ui.m.picker.setSelectedValue(current); 288 | }, 289 | _createDay: function _createDay(current) { 290 | var self = this; 291 | var options = self.options; 292 | var ui = self.ui; 293 | 294 | //生成日列表 295 | var dArray = []; 296 | if (options.customData.d) { 297 | dArray = options.customData.d; 298 | } else { 299 | var d = self._isBeginMonth() ? options.beginDay : 1; 300 | var maxDay = self._isEndMonth() ? options.endDay : self.getDayNum(parseInt(this.ui.y.picker.getSelectedValue()), parseInt(this.ui.m.picker.getSelectedValue())); 301 | for (; d <= maxDay; d++) { 302 | var val = self._fill(d); 303 | dArray.push({ 304 | text: val, 305 | value: val 306 | }); 307 | } 308 | } 309 | ui.d.picker.setItems(dArray); 310 | current = current || ui.d.picker.getSelectedValue(); 311 | //ui.d.picker.setSelectedValue(current); 312 | }, 313 | _createHours: function _createHours(current) { 314 | var self = this; 315 | var options = self.options; 316 | var ui = self.ui; 317 | //生成时列表 318 | var hArray = []; 319 | if (options.customData.h) { 320 | hArray = options.customData.h; 321 | } else { 322 | var h = self._isBeginDay() ? options.beginHours : 0; 323 | var maxHours = self._isEndDay() ? options.endHours : 23; 324 | for (; h <= maxHours; h++) { 325 | var val = self._fill(h); 326 | hArray.push({ 327 | text: val, 328 | value: val 329 | }); 330 | } 331 | } 332 | ui.h.picker.setItems(hArray); 333 | //ui.h.picker.setSelectedValue(current); 334 | }, 335 | _createMinutes: function _createMinutes(current) { 336 | var self = this; 337 | var options = self.options; 338 | var ui = self.ui; 339 | 340 | //生成分列表 341 | var iArray = []; 342 | if (options.customData.i) { 343 | iArray = options.customData.i; 344 | } else { 345 | var i = self._isBeginHours() ? options.beginMinutes : 0; 346 | var maxMinutes = self._isEndHours() ? options.endMinutes : 59; 347 | for (; i <= maxMinutes; i++) { 348 | var val = self._fill(i); 349 | iArray.push({ 350 | text: val, 351 | value: val 352 | }); 353 | } 354 | } 355 | ui.i.picker.setItems(iArray); 356 | //ui.i.picker.setSelectedValue(current); 357 | }, 358 | _setLabels: function _setLabels() { 359 | var self = this; 360 | var options = self.options; 361 | var ui = self.ui; 362 | ui.labels.each(function (i, label) { 363 | label.innerText = options.labels[i]; 364 | }); 365 | }, 366 | _setButtons: function _setButtons() { 367 | var self = this; 368 | var options = self.options; 369 | var ui = self.ui; 370 | ui.cancel.innerText = options.buttons[0]; 371 | ui.ok.innerText = options.buttons[1]; 372 | }, 373 | _parseValue: function _parseValue(value) { 374 | var self = this; 375 | var rs = {}; 376 | if (value) { 377 | var parts = value.replace(":", "-").replace(" ", "-").split("-"); 378 | rs.y = parts[0]; 379 | rs.m = parts[1]; 380 | rs.d = parts[2]; 381 | rs.h = parts[3]; 382 | rs.i = parts[4]; 383 | } else { 384 | var now = new Date(); 385 | rs.y = now.getFullYear(); 386 | rs.m = now.getMonth() + 1; 387 | rs.d = now.getDate(); 388 | rs.h = now.getHours(); 389 | rs.i = now.getMinutes(); 390 | } 391 | return rs; 392 | }, 393 | _create: function _create(options) { 394 | var self = this; 395 | options = options || {}; 396 | options.labels = options.labels || ['年', '月', '日', '时', '分']; 397 | options.buttons = options.buttons || ['取消', '确定']; 398 | options.type = options.type || 'datetime'; 399 | options.customData = options.customData || {}; 400 | self.options = options; 401 | var now = new Date(); 402 | var beginDate = options.beginDate; 403 | if (beginDate instanceof Date && !isNaN(beginDate.valueOf())) { 404 | //设定了开始日期 405 | options.beginYear = beginDate.getFullYear(); 406 | options.beginMonth = beginDate.getMonth() + 1; 407 | options.beginDay = beginDate.getDate(); 408 | options.beginHours = beginDate.getHours(); 409 | options.beginMinutes = beginDate.getMinutes(); 410 | } 411 | var endDate = options.endDate; 412 | if (endDate instanceof Date && !isNaN(endDate.valueOf())) { 413 | //设定了结束日期 414 | options.endYear = endDate.getFullYear(); 415 | options.endMonth = endDate.getMonth() + 1; 416 | options.endDay = endDate.getDate(); 417 | options.endHours = endDate.getHours(); 418 | options.endMinutes = endDate.getMinutes(); 419 | } 420 | options.beginYear = options.beginYear || now.getFullYear() - 5; 421 | options.endYear = options.endYear || now.getFullYear() + 5; 422 | var ui = self.ui; 423 | //设定label 424 | self._setLabels(); 425 | self._setButtons(); 426 | //设定类型 427 | ui.picker.setAttribute('data-type', options.type); 428 | //生成 429 | self._createYear(); 430 | self._createMonth(); 431 | self._createDay(); 432 | self._createHours(); 433 | self._createMinutes(); 434 | //设定默认值 435 | self.setSelectedValue(options.value); 436 | }, 437 | //显示 438 | show: function show(callback) { 439 | var self = this; 440 | var ui = self.ui; 441 | self.callback = callback || $.noop; 442 | ui.mask.show(); 443 | document.body.classList.add($.className('dtpicker-active-for-page')); 444 | ui.picker.classList.add($.className('active')); 445 | //处理物理返回键 446 | self.__back = $.back; 447 | $.back = function () { 448 | self.hide(); 449 | }; 450 | }, 451 | hide: function hide() { 452 | var self = this; 453 | if (self.disposed) return; 454 | var ui = self.ui; 455 | ui.picker.classList.remove($.className('active')); 456 | ui.mask.close(); 457 | document.body.classList.remove($.className('dtpicker-active-for-page')); 458 | //处理物理返回键 459 | $.back = self.__back; 460 | }, 461 | dispose: function dispose() { 462 | var self = this; 463 | self.hide(); 464 | setTimeout(function () { 465 | self.ui.picker.parentNode.removeChild(self.ui.picker); 466 | for (var name in self) { 467 | self[name] = null; 468 | delete self[name]; 469 | }; 470 | self.disposed = true; 471 | }, 300); 472 | } 473 | }); 474 | })(_mui2.default, document); /** 475 | * 日期时间插件 476 | * varstion 1.0.5 477 | * by Houfeng 478 | * Houfeng@DCloud.io 479 | */ 480 | 481 | exports.default = _mui2.default.DtPicker; -------------------------------------------------------------------------------- /example/lib/city-data.js: -------------------------------------------------------------------------------- 1 | module.exports = [{ 2 | value: '110000', 3 | text: '北京市', 4 | children: [{ 5 | value: "110101", 6 | text: "东城区" 7 | }, { 8 | value: "110102", 9 | text: "西城区" 10 | }, { 11 | value: "110103", 12 | text: "崇文区" 13 | }, { 14 | value: "110104", 15 | text: "宣武区" 16 | }, { 17 | value: "110105", 18 | text: "朝阳区" 19 | }, { 20 | value: "110106", 21 | text: "丰台区" 22 | }, { 23 | value: "110107", 24 | text: "石景山区" 25 | }, { 26 | value: "110108", 27 | text: "海淀区" 28 | }, { 29 | value: "110109", 30 | text: "门头沟区" 31 | }, { 32 | value: "110111", 33 | text: "房山区" 34 | }, { 35 | value: "110112", 36 | text: "通州区" 37 | }, { 38 | value: "110113", 39 | text: "顺义区" 40 | }, { 41 | value: "110114", 42 | text: "昌平区" 43 | }, { 44 | value: "110115", 45 | text: "大兴区" 46 | }, { 47 | value: "110116", 48 | text: "怀柔区" 49 | }, { 50 | value: "110117", 51 | text: "平谷区" 52 | }, { 53 | value: "110228", 54 | text: "密云县" 55 | }, { 56 | value: "110229", 57 | text: "延庆县" 58 | }, { 59 | value: "110230", 60 | text: "其它区" 61 | }] 62 | }, { 63 | value: '120000', 64 | text: '天津市', 65 | children: [{ 66 | value: "120101", 67 | text: "和平区" 68 | }, { 69 | value: "120102", 70 | text: "河东区" 71 | }, { 72 | value: "120103", 73 | text: "河西区" 74 | }, { 75 | value: "120104", 76 | text: "南开区" 77 | }, { 78 | value: "120105", 79 | text: "河北区" 80 | }, { 81 | value: "120106", 82 | text: "红桥区" 83 | }, { 84 | value: "120107", 85 | text: "塘沽区" 86 | }, { 87 | value: "120108", 88 | text: "汉沽区" 89 | }, { 90 | value: "120109", 91 | text: "大港区" 92 | }, { 93 | value: "120110", 94 | text: "东丽区" 95 | }, { 96 | value: "120111", 97 | text: "西青区" 98 | }, { 99 | value: "120112", 100 | text: "津南区" 101 | }, { 102 | value: "120113", 103 | text: "北辰区" 104 | }, { 105 | value: "120114", 106 | text: "武清区" 107 | }, { 108 | value: "120115", 109 | text: "宝坻区" 110 | }, { 111 | value: "120116", 112 | text: "滨海新区" 113 | }, { 114 | value: "120221", 115 | text: "宁河县" 116 | }, { 117 | value: "120223", 118 | text: "静海县" 119 | }, { 120 | value: "120225", 121 | text: "蓟县" 122 | }, { 123 | value: "120226", 124 | text: "其它区" 125 | }] 126 | }, { 127 | value: '130000', 128 | text: '河北省', 129 | children: [{ 130 | value: "130100", 131 | text: "石家庄市" 132 | }, { 133 | value: "130200", 134 | text: "唐山市" 135 | }, { 136 | value: "130300", 137 | text: "秦皇岛市" 138 | }, { 139 | value: "130400", 140 | text: "邯郸市" 141 | }, { 142 | value: "130500", 143 | text: "邢台市" 144 | }, { 145 | value: "130600", 146 | text: "保定市" 147 | }, { 148 | value: "130700", 149 | text: "张家口市" 150 | }, { 151 | value: "130800", 152 | text: "承德市" 153 | }, { 154 | value: "130900", 155 | text: "沧州市" 156 | }, { 157 | value: "131000", 158 | text: "廊坊市" 159 | }, { 160 | value: "131100", 161 | text: "衡水市" 162 | }] 163 | }, { 164 | value: '140000', 165 | text: '山西省', 166 | children: [{ 167 | value: "140100", 168 | text: "太原市" 169 | }, { 170 | value: "140200", 171 | text: "大同市" 172 | }, { 173 | value: "140300", 174 | text: "阳泉市" 175 | }, { 176 | value: "140400", 177 | text: "长治市" 178 | }, { 179 | value: "140500", 180 | text: "晋城市" 181 | }, { 182 | value: "140600", 183 | text: "朔州市" 184 | }, { 185 | value: "140700", 186 | text: "晋中市" 187 | }, { 188 | value: "140800", 189 | text: "运城市" 190 | }, { 191 | value: "140900", 192 | text: "忻州市" 193 | }, { 194 | value: "141000", 195 | text: "临汾市" 196 | }, { 197 | value: "141100", 198 | text: "吕梁市" 199 | }] 200 | }, { 201 | value: '150000', 202 | text: '内蒙古', 203 | children: [{ 204 | value: "150100", 205 | text: "呼和浩特市" 206 | }, { 207 | value: "150200", 208 | text: "包头市" 209 | }, { 210 | value: "150300", 211 | text: "乌海市" 212 | }, { 213 | value: "150400", 214 | text: "赤峰市" 215 | }, { 216 | value: "150500", 217 | text: "通辽市" 218 | }, { 219 | value: "150600", 220 | text: "鄂尔多斯市" 221 | }, { 222 | value: "150700", 223 | text: "呼伦贝尔市" 224 | }, { 225 | value: "150800", 226 | text: "巴彦淖尔市" 227 | }, { 228 | value: "150900", 229 | text: "乌兰察布市" 230 | }, { 231 | value: "152200", 232 | text: "兴安盟" 233 | }, { 234 | value: "152500", 235 | text: "锡林郭勒盟" 236 | }, { 237 | value: "152900", 238 | text: "阿拉善盟" 239 | }] 240 | }, { 241 | value: '210000', 242 | text: '辽宁省', 243 | children: [{ 244 | value: "210100", 245 | text: "沈阳市" 246 | }, { 247 | value: "210200", 248 | text: "大连市" 249 | }, { 250 | value: "210300", 251 | text: "鞍山市" 252 | }, { 253 | value: "210400", 254 | text: "抚顺市" 255 | }, { 256 | value: "210500", 257 | text: "本溪市" 258 | }, { 259 | value: "210600", 260 | text: "丹东市" 261 | }, { 262 | value: "210700", 263 | text: "锦州市" 264 | }, { 265 | value: "210800", 266 | text: "营口市" 267 | }, { 268 | value: "210900", 269 | text: "阜新市" 270 | }, { 271 | value: "211000", 272 | text: "辽阳市" 273 | }, { 274 | value: "211100", 275 | text: "盘锦市" 276 | }, { 277 | value: "211200", 278 | text: "铁岭市" 279 | }, { 280 | value: "211300", 281 | text: "朝阳市" 282 | }, { 283 | value: "211400", 284 | text: "葫芦岛市" 285 | }] 286 | }, { 287 | value: '220000', 288 | text: '吉林省', 289 | children: [{ 290 | value: "220100", 291 | text: "长春市" 292 | }, { 293 | value: "220200", 294 | text: "吉林市" 295 | }, { 296 | value: "220300", 297 | text: "四平市" 298 | }, { 299 | value: "220400", 300 | text: "辽源市" 301 | }, { 302 | value: "220500", 303 | text: "通化市" 304 | }, { 305 | value: "220600", 306 | text: "白山市" 307 | }, { 308 | value: "220700", 309 | text: "松原市" 310 | }, { 311 | value: "220800", 312 | text: "白城市" 313 | }, { 314 | value: "222400", 315 | text: "延边朝鲜族自治州" 316 | }] 317 | }, { 318 | value: '230000', 319 | text: '黑龙江省', 320 | children: [{ 321 | value: "230100", 322 | text: "哈尔滨市" 323 | }, { 324 | value: "230200", 325 | text: "齐齐哈尔市" 326 | }, { 327 | value: "230300", 328 | text: "鸡西市" 329 | }, { 330 | value: "230400", 331 | text: "鹤岗市" 332 | }, { 333 | value: "230500", 334 | text: "双鸭山市" 335 | }, { 336 | value: "230600", 337 | text: "大庆市" 338 | }, { 339 | value: "230700", 340 | text: "伊春市" 341 | }, { 342 | value: "230800", 343 | text: "佳木斯市" 344 | }, { 345 | value: "230900", 346 | text: "七台河市" 347 | }, { 348 | value: "231000", 349 | text: "牡丹江市" 350 | }, { 351 | value: "231100", 352 | text: "黑河市" 353 | }, { 354 | value: "231200", 355 | text: "绥化市" 356 | }, { 357 | value: "232700", 358 | text: "大兴安岭地区" 359 | }] 360 | }, { 361 | value: '310000', 362 | text: '上海市', 363 | children: [{ 364 | value: "310101", 365 | text: "黄浦区" 366 | }, { 367 | value: "310103", 368 | text: "卢湾区" 369 | }, { 370 | value: "310104", 371 | text: "徐汇区" 372 | }, { 373 | value: "310105", 374 | text: "长宁区" 375 | }, { 376 | value: "310106", 377 | text: "静安区" 378 | }, { 379 | value: "310107", 380 | text: "普陀区" 381 | }, { 382 | value: "310108", 383 | text: "闸北区" 384 | }, { 385 | value: "310109", 386 | text: "虹口区" 387 | }, { 388 | value: "310110", 389 | text: "杨浦区" 390 | }, { 391 | value: "310112", 392 | text: "闵行区" 393 | }, { 394 | value: "310113", 395 | text: "宝山区" 396 | }, { 397 | value: "310114", 398 | text: "嘉定区" 399 | }, { 400 | value: "310115", 401 | text: "浦东新区" 402 | }, { 403 | value: "310116", 404 | text: "金山区" 405 | }, { 406 | value: "310117", 407 | text: "松江区" 408 | }, { 409 | value: "310118", 410 | text: "青浦区" 411 | }, { 412 | value: "310119", 413 | text: "南汇区" 414 | }, { 415 | value: "310120", 416 | text: "奉贤区" 417 | }, { 418 | value: "310152", 419 | text: "川沙区" 420 | }, { 421 | value: "310230", 422 | text: "崇明县" 423 | }, { 424 | value: "310231", 425 | text: "其它区" 426 | }] 427 | }, { 428 | value: '320000', 429 | text: '江苏省', 430 | children: [{ 431 | value: "320100", 432 | text: "南京市" 433 | }, { 434 | value: "320200", 435 | text: "无锡市" 436 | }, { 437 | value: "320300", 438 | text: "徐州市" 439 | }, { 440 | value: "320400", 441 | text: "常州市" 442 | }, { 443 | value: "320500", 444 | text: "苏州市" 445 | }, { 446 | value: "320600", 447 | text: "南通市" 448 | }, { 449 | value: "320700", 450 | text: "连云港市" 451 | }, { 452 | value: "320800", 453 | text: "淮安市" 454 | }, { 455 | value: "320900", 456 | text: "盐城市" 457 | }, { 458 | value: "321000", 459 | text: "扬州市" 460 | }, { 461 | value: "321100", 462 | text: "镇江市" 463 | }, { 464 | value: "321200", 465 | text: "泰州市" 466 | }, { 467 | value: "321300", 468 | text: "宿迁市" 469 | }] 470 | }, { 471 | value: '330000', 472 | text: '浙江省', 473 | children: [{ 474 | value: "330100", 475 | text: "杭州市" 476 | }, { 477 | value: "330200", 478 | text: "宁波市" 479 | }, { 480 | value: "330300", 481 | text: "温州市" 482 | }, { 483 | value: "330400", 484 | text: "嘉兴市" 485 | }, { 486 | value: "330500", 487 | text: "湖州市" 488 | }, { 489 | value: "330600", 490 | text: "绍兴市" 491 | }, { 492 | value: "330700", 493 | text: "金华市" 494 | }, { 495 | value: "330800", 496 | text: "衢州市" 497 | }, { 498 | value: "330900", 499 | text: "舟山市" 500 | }, { 501 | value: "331000", 502 | text: "台州市" 503 | }, { 504 | value: "331100", 505 | text: "丽水市" 506 | }] 507 | }, { 508 | value: '340000', 509 | text: '安徽省', 510 | children: [{ 511 | value: "340100", 512 | text: "合肥市" 513 | }, { 514 | value: "340200", 515 | text: "芜湖市" 516 | }, { 517 | value: "340300", 518 | text: "蚌埠市" 519 | }, { 520 | value: "340400", 521 | text: "淮南市" 522 | }, { 523 | value: "340500", 524 | text: "马鞍山市" 525 | }, { 526 | value: "340600", 527 | text: "淮北市" 528 | }, { 529 | value: "340700", 530 | text: "铜陵市" 531 | }, { 532 | value: "340800", 533 | text: "安庆市" 534 | }, { 535 | value: "341000", 536 | text: "黄山市" 537 | }, { 538 | value: "341100", 539 | text: "滁州市" 540 | }, { 541 | value: "341200", 542 | text: "阜阳市" 543 | }, { 544 | value: "341300", 545 | text: "宿州市" 546 | }, { 547 | value: "341500", 548 | text: "六安市" 549 | }, { 550 | value: "341600", 551 | text: "亳州市" 552 | }, { 553 | value: "341700", 554 | text: "池州市" 555 | }, { 556 | value: "341800", 557 | text: "宣城市" 558 | }] 559 | }, { 560 | value: '350000', 561 | text: '福建省', 562 | children: [{ 563 | value: "350100", 564 | text: "福州市" 565 | }, { 566 | value: "350200", 567 | text: "厦门市" 568 | }, { 569 | value: "350300", 570 | text: "莆田市" 571 | }, { 572 | value: "350400", 573 | text: "三明市" 574 | }, { 575 | value: "350500", 576 | text: "泉州市" 577 | }, { 578 | value: "350600", 579 | text: "漳州市" 580 | }, { 581 | value: "350700", 582 | text: "南平市" 583 | }, { 584 | value: "350800", 585 | text: "龙岩市" 586 | }, { 587 | value: "350900", 588 | text: "宁德市" 589 | }] 590 | }, { 591 | value: '360000', 592 | text: '江西省', 593 | children: [{ 594 | value: "360100", 595 | text: "南昌市" 596 | }, { 597 | value: "360200", 598 | text: "景德镇市" 599 | }, { 600 | value: "360300", 601 | text: "萍乡市" 602 | }, { 603 | value: "360400", 604 | text: "九江市" 605 | }, { 606 | value: "360500", 607 | text: "新余市" 608 | }, { 609 | value: "360600", 610 | text: "鹰潭市" 611 | }, { 612 | value: "360700", 613 | text: "赣州市" 614 | }, { 615 | value: "360800", 616 | text: "吉安市" 617 | }, { 618 | value: "360900", 619 | text: "宜春市" 620 | }, { 621 | value: "361000", 622 | text: "抚州市" 623 | }, { 624 | value: "361100", 625 | text: "上饶市" 626 | }] 627 | }, { 628 | value: '370000', 629 | text: '山东省', 630 | children: [{ 631 | value: "370100", 632 | text: "济南市" 633 | }, { 634 | value: "370200", 635 | text: "青岛市" 636 | }, { 637 | value: "370300", 638 | text: "淄博市" 639 | }, { 640 | value: "370400", 641 | text: "枣庄市" 642 | }, { 643 | value: "370500", 644 | text: "东营市" 645 | }, { 646 | value: "370600", 647 | text: "烟台市" 648 | }, { 649 | value: "370700", 650 | text: "潍坊市" 651 | }, { 652 | value: "370800", 653 | text: "济宁市" 654 | }, { 655 | value: "370900", 656 | text: "泰安市" 657 | }, { 658 | value: "371000", 659 | text: "威海市" 660 | }, { 661 | value: "371100", 662 | text: "日照市" 663 | }, { 664 | value: "371200", 665 | text: "莱芜市" 666 | }, { 667 | value: "371300", 668 | text: "临沂市" 669 | }, { 670 | value: "371400", 671 | text: "德州市" 672 | }, { 673 | value: "371500", 674 | text: "聊城市" 675 | }, { 676 | value: "371600", 677 | text: "滨州市" 678 | }, { 679 | value: "371700", 680 | text: "菏泽市" 681 | }] 682 | }, { 683 | value: '410000', 684 | text: '河南省', 685 | children: [{ 686 | value: "410100", 687 | text: "郑州市" 688 | }, { 689 | value: "410200", 690 | text: "开封市" 691 | }, { 692 | value: "410300", 693 | text: "洛阳市" 694 | }, { 695 | value: "410400", 696 | text: "平顶山市" 697 | }, { 698 | value: "410500", 699 | text: "安阳市" 700 | }, { 701 | value: "410600", 702 | text: "鹤壁市" 703 | }, { 704 | value: "410700", 705 | text: "新乡市" 706 | }, { 707 | value: "410800", 708 | text: "焦作市" 709 | }, { 710 | value: "410881", 711 | text: "济源市" 712 | }, { 713 | value: "410900", 714 | text: "濮阳市" 715 | }, { 716 | value: "411000", 717 | text: "许昌市" 718 | }, { 719 | value: "411100", 720 | text: "漯河市" 721 | }, { 722 | value: "411200", 723 | text: "三门峡市" 724 | }, { 725 | value: "411300", 726 | text: "南阳市" 727 | }, { 728 | value: "411400", 729 | text: "商丘市" 730 | }, { 731 | value: "411500", 732 | text: "信阳市" 733 | }, { 734 | value: "411600", 735 | text: "周口市" 736 | }, { 737 | value: "411700", 738 | text: "驻马店市" 739 | }] 740 | }, { 741 | value: '420000', 742 | text: '湖北省', 743 | children: [{ 744 | value: "420100", 745 | text: "武汉市" 746 | }, { 747 | value: "420200", 748 | text: "黄石市" 749 | }, { 750 | value: "420300", 751 | text: "十堰市" 752 | }, { 753 | value: "420500", 754 | text: "宜昌市" 755 | }, { 756 | value: "420600", 757 | text: "襄阳市" 758 | }, { 759 | value: "420700", 760 | text: "鄂州市" 761 | }, { 762 | value: "420800", 763 | text: "荆门市" 764 | }, { 765 | value: "420900", 766 | text: "孝感市" 767 | }, { 768 | value: "421000", 769 | text: "荆州市" 770 | }, { 771 | value: "421100", 772 | text: "黄冈市" 773 | }, { 774 | value: "421200", 775 | text: "咸宁市" 776 | }, { 777 | value: "421300", 778 | text: "随州市" 779 | }, { 780 | value: "422800", 781 | text: "恩施土家族苗族自治州" 782 | }, { 783 | value: "429004", 784 | text: "仙桃市" 785 | }, { 786 | value: "429005", 787 | text: "潜江市" 788 | }, { 789 | value: "429006", 790 | text: "天门市" 791 | }, { 792 | value: "429021", 793 | text: "神农架林区" 794 | }] 795 | }, { 796 | value: '430000', 797 | text: '湖南省', 798 | children: [{ 799 | value: "430100", 800 | text: "长沙市" 801 | }, { 802 | value: "430200", 803 | text: "株洲市" 804 | }, { 805 | value: "430300", 806 | text: "湘潭市" 807 | }, { 808 | value: "430400", 809 | text: "衡阳市" 810 | }, { 811 | value: "430500", 812 | text: "邵阳市" 813 | }, { 814 | value: "430600", 815 | text: "岳阳市" 816 | }, { 817 | value: "430700", 818 | text: "常德市" 819 | }, { 820 | value: "430800", 821 | text: "张家界市" 822 | }, { 823 | value: "430900", 824 | text: "益阳市" 825 | }, { 826 | value: "431000", 827 | text: "郴州市" 828 | }, { 829 | value: "431100", 830 | text: "永州市" 831 | }, { 832 | value: "431200", 833 | text: "怀化市" 834 | }, { 835 | value: "431300", 836 | text: "娄底市" 837 | }, { 838 | value: "433100", 839 | text: "湘西土家族苗族自治州" 840 | }] 841 | }, { 842 | value: '440000', 843 | text: '广东省', 844 | children: [{ 845 | value: "440100", 846 | text: "广州市" 847 | }, { 848 | value: "440200", 849 | text: "韶关市" 850 | }, { 851 | value: "440300", 852 | text: "深圳市" 853 | }, { 854 | value: "440400", 855 | text: "珠海市" 856 | }, { 857 | value: "440500", 858 | text: "汕头市" 859 | }, { 860 | value: "440600", 861 | text: "佛山市" 862 | }, { 863 | value: "440700", 864 | text: "江门市" 865 | }, { 866 | value: "440800", 867 | text: "湛江市" 868 | }, { 869 | value: "440900", 870 | text: "茂名市" 871 | }, { 872 | value: "441200", 873 | text: "肇庆市" 874 | }, { 875 | value: "441300", 876 | text: "惠州市" 877 | }, { 878 | value: "441400", 879 | text: "梅州市" 880 | }, { 881 | value: "441500", 882 | text: "汕尾市" 883 | }, { 884 | value: "441600", 885 | text: "河源市" 886 | }, { 887 | value: "441700", 888 | text: "阳江市" 889 | }, { 890 | value: "441800", 891 | text: "清远市" 892 | }, { 893 | value: "441900", 894 | text: "东莞市" 895 | }, { 896 | value: "442000", 897 | text: "中山市" 898 | }, { 899 | value: "445100", 900 | text: "潮州市" 901 | }, { 902 | value: "445200", 903 | text: "揭阳市" 904 | }, { 905 | value: "445300", 906 | text: "云浮市" 907 | }] 908 | }, { 909 | value: '450000', 910 | text: '广西壮族', 911 | children: [{ 912 | value: "450100", 913 | text: "南宁市" 914 | }, { 915 | value: "450200", 916 | text: "柳州市" 917 | }, { 918 | value: "450300", 919 | text: "桂林市" 920 | }, { 921 | value: "450400", 922 | text: "梧州市" 923 | }, { 924 | value: "450500", 925 | text: "北海市" 926 | }, { 927 | value: "450600", 928 | text: "防城港市" 929 | }, { 930 | value: "450700", 931 | text: "钦州市" 932 | }, { 933 | value: "450800", 934 | text: "贵港市" 935 | }, { 936 | value: "450900", 937 | text: "玉林市" 938 | }, { 939 | value: "451000", 940 | text: "百色市" 941 | }, { 942 | value: "451100", 943 | text: "贺州市" 944 | }, { 945 | value: "451200", 946 | text: "河池市" 947 | }, { 948 | value: "451300", 949 | text: "来宾市" 950 | }, { 951 | value: "451400", 952 | text: "崇左市" 953 | }] 954 | }, { 955 | value: '460000', 956 | text: '海南省', 957 | children: [{ 958 | value: "460100", 959 | text: "海口市" 960 | }, { 961 | value: "460200", 962 | text: "三亚市" 963 | }, { 964 | value: "469001", 965 | text: "五指山市" 966 | }, { 967 | value: "469002", 968 | text: "琼海市" 969 | }, { 970 | value: "469003", 971 | text: "儋州市" 972 | }, { 973 | value: "469005", 974 | text: "文昌市" 975 | }, { 976 | value: "469006", 977 | text: "万宁市" 978 | }, { 979 | value: "469007", 980 | text: "东方市" 981 | }, { 982 | value: "469025", 983 | text: "定安县" 984 | }, { 985 | value: "469026", 986 | text: "屯昌县" 987 | }, { 988 | value: "469027", 989 | text: "澄迈县" 990 | }, { 991 | value: "469028", 992 | text: "临高县" 993 | }, { 994 | value: "469030", 995 | text: "白沙黎族自治县" 996 | }, { 997 | value: "469031", 998 | text: "昌江黎族自治县" 999 | }, { 1000 | value: "469033", 1001 | text: "乐东黎族自治县" 1002 | }, { 1003 | value: "469034", 1004 | text: "陵水黎族自治县" 1005 | }, { 1006 | value: "469035", 1007 | text: "保亭黎族苗族自治县" 1008 | }, { 1009 | value: "469036", 1010 | text: "琼中黎族苗族自治县" 1011 | }, { 1012 | value: "469037", 1013 | text: "西沙群岛" 1014 | }, { 1015 | value: "469038", 1016 | text: "南沙群岛" 1017 | }, { 1018 | value: "469039", 1019 | text: "中沙群岛的岛礁及其海域" 1020 | }] 1021 | }, { 1022 | value: '500000', 1023 | text: '重庆', 1024 | children: [{ 1025 | value: "500101", 1026 | text: "万州区" 1027 | }, { 1028 | value: "500102", 1029 | text: "涪陵区" 1030 | }, { 1031 | value: "500103", 1032 | text: "渝中区" 1033 | }, { 1034 | value: "500104", 1035 | text: "大渡口区" 1036 | }, { 1037 | value: "500105", 1038 | text: "江北区" 1039 | }, { 1040 | value: "500106", 1041 | text: "沙坪坝区" 1042 | }, { 1043 | value: "500107", 1044 | text: "九龙坡区" 1045 | }, { 1046 | value: "500108", 1047 | text: "南岸区" 1048 | }, { 1049 | value: "500109", 1050 | text: "北碚区" 1051 | }, { 1052 | value: "500110", 1053 | text: "万盛区" 1054 | }, { 1055 | value: "500111", 1056 | text: "双桥区" 1057 | }, { 1058 | value: "500112", 1059 | text: "渝北区" 1060 | }, { 1061 | value: "500113", 1062 | text: "巴南区" 1063 | }, { 1064 | value: "500114", 1065 | text: "黔江区" 1066 | }, { 1067 | value: "500115", 1068 | text: "长寿区" 1069 | }, { 1070 | value: "500222", 1071 | text: "綦江县" 1072 | }, { 1073 | value: "500223", 1074 | text: "潼南县" 1075 | }, { 1076 | value: "500224", 1077 | text: "铜梁县" 1078 | }, { 1079 | value: "500225", 1080 | text: "大足县" 1081 | }, { 1082 | value: "500226", 1083 | text: "荣昌县" 1084 | }, { 1085 | value: "500227", 1086 | text: "璧山县" 1087 | }, { 1088 | value: "500228", 1089 | text: "梁平县" 1090 | }, { 1091 | value: "500229", 1092 | text: "城口县" 1093 | }, { 1094 | value: "500230", 1095 | text: "丰都县" 1096 | }, { 1097 | value: "500231", 1098 | text: "垫江县" 1099 | }, { 1100 | value: "500232", 1101 | text: "武隆县" 1102 | }, { 1103 | value: "500233", 1104 | text: "忠县" 1105 | }, { 1106 | value: "500234", 1107 | text: "开县" 1108 | }, { 1109 | value: "500235", 1110 | text: "云阳县" 1111 | }, { 1112 | value: "500236", 1113 | text: "奉节县" 1114 | }, { 1115 | value: "500237", 1116 | text: "巫山县" 1117 | }, { 1118 | value: "500238", 1119 | text: "巫溪县" 1120 | }, { 1121 | value: "500240", 1122 | text: "石柱土家族自治县" 1123 | }, { 1124 | value: "500241", 1125 | text: "秀山土家族苗族自治县" 1126 | }, { 1127 | value: "500242", 1128 | text: "酉阳土家族苗族自治县" 1129 | }, { 1130 | value: "500243", 1131 | text: "彭水苗族土家族自治县" 1132 | }, { 1133 | value: "500381", 1134 | text: "江津区" 1135 | }, { 1136 | value: "500382", 1137 | text: "合川区" 1138 | }, { 1139 | value: "500383", 1140 | text: "永川区" 1141 | }, { 1142 | value: "500384", 1143 | text: "南川区" 1144 | }, { 1145 | value: "500385", 1146 | text: "其它区" 1147 | }] 1148 | }, { 1149 | value: '510000', 1150 | text: '四川省', 1151 | children: [{ 1152 | value: "510100", 1153 | text: "成都市" 1154 | }, { 1155 | value: "510300", 1156 | text: "自贡市" 1157 | }, { 1158 | value: "510400", 1159 | text: "攀枝花市" 1160 | }, { 1161 | value: "510500", 1162 | text: "泸州市" 1163 | }, { 1164 | value: "510600", 1165 | text: "德阳市" 1166 | }, { 1167 | value: "510700", 1168 | text: "绵阳市" 1169 | }, { 1170 | value: "510800", 1171 | text: "广元市" 1172 | }, { 1173 | value: "510900", 1174 | text: "遂宁市" 1175 | }, { 1176 | value: "511000", 1177 | text: "内江市" 1178 | }, { 1179 | value: "511100", 1180 | text: "乐山市" 1181 | }, { 1182 | value: "511300", 1183 | text: "南充市" 1184 | }, { 1185 | value: "511400", 1186 | text: "眉山市" 1187 | }, { 1188 | value: "511500", 1189 | text: "宜宾市" 1190 | }, { 1191 | value: "511600", 1192 | text: "广安市" 1193 | }, { 1194 | value: "511700", 1195 | text: "达州市" 1196 | }, { 1197 | value: "511800", 1198 | text: "雅安市" 1199 | }, { 1200 | value: "511900", 1201 | text: "巴中市" 1202 | }, { 1203 | value: "512000", 1204 | text: "资阳市" 1205 | }, { 1206 | value: "513200", 1207 | text: "阿坝藏族羌族自治州" 1208 | }, { 1209 | value: "513300", 1210 | text: "甘孜藏族自治州" 1211 | }, { 1212 | value: "513400", 1213 | text: "凉山彝族自治州" 1214 | }] 1215 | }, { 1216 | value: '520000', 1217 | text: '贵州省', 1218 | children: [{ 1219 | value: "520100", 1220 | text: "贵阳市" 1221 | }, { 1222 | value: "520200", 1223 | text: "六盘水市" 1224 | }, { 1225 | value: "520300", 1226 | text: "遵义市" 1227 | }, { 1228 | value: "520400", 1229 | text: "安顺市" 1230 | }, { 1231 | value: "522200", 1232 | text: "铜仁地区" 1233 | }, { 1234 | value: "522300", 1235 | text: "黔西南布依族苗族自治州" 1236 | }, { 1237 | value: "522400", 1238 | text: "毕节地区" 1239 | }, { 1240 | value: "522600", 1241 | text: "黔东南苗族侗族自治州" 1242 | }, { 1243 | value: "522700", 1244 | text: "黔南布依族苗族自治州" 1245 | }] 1246 | }, { 1247 | value: '530000', 1248 | text: '云南省', 1249 | children: [{ 1250 | value: "530100", 1251 | text: "昆明市" 1252 | }, { 1253 | value: "530300", 1254 | text: "曲靖市" 1255 | }, { 1256 | value: "530400", 1257 | text: "玉溪市" 1258 | }, { 1259 | value: "530500", 1260 | text: "保山市" 1261 | }, { 1262 | value: "530600", 1263 | text: "昭通市" 1264 | }, { 1265 | value: "530700", 1266 | text: "丽江市" 1267 | }, { 1268 | value: "530800", 1269 | text: "普洱市" 1270 | }, { 1271 | value: "530900", 1272 | text: "临沧市" 1273 | }, { 1274 | value: "532300", 1275 | text: "楚雄彝族自治州" 1276 | }, { 1277 | value: "532500", 1278 | text: "红河哈尼族彝族自治州" 1279 | }, { 1280 | value: "532600", 1281 | text: "文山壮族苗族自治州" 1282 | }, { 1283 | value: "532800", 1284 | text: "西双版纳傣族自治州" 1285 | }, { 1286 | value: "532900", 1287 | text: "大理白族自治州" 1288 | }, { 1289 | value: "533100", 1290 | text: "德宏傣族景颇族自治州" 1291 | }, { 1292 | value: "533300", 1293 | text: "怒江傈僳族自治州" 1294 | }, { 1295 | value: "533400", 1296 | text: "迪庆藏族自治州" 1297 | }] 1298 | }, { 1299 | value: '540000', 1300 | text: '西藏', 1301 | children: [{ 1302 | value: "540100", 1303 | text: "拉萨市" 1304 | }, { 1305 | value: "542100", 1306 | text: "昌都地区" 1307 | }, { 1308 | value: "542200", 1309 | text: "山南地区" 1310 | }, { 1311 | value: "542300", 1312 | text: "日喀则地区" 1313 | }, { 1314 | value: "542400", 1315 | text: "那曲地区" 1316 | }, { 1317 | value: "542500", 1318 | text: "阿里地区" 1319 | }, { 1320 | value: "542600", 1321 | text: "林芝地区" 1322 | }] 1323 | }, { 1324 | value: '610000', 1325 | text: '陕西省', 1326 | children: [{ 1327 | value: "610100", 1328 | text: "西安市" 1329 | }, { 1330 | value: "610200", 1331 | text: "铜川市" 1332 | }, { 1333 | value: "610300", 1334 | text: "宝鸡市" 1335 | }, { 1336 | value: "610400", 1337 | text: "咸阳市" 1338 | }, { 1339 | value: "610500", 1340 | text: "渭南市" 1341 | }, { 1342 | value: "610600", 1343 | text: "延安市" 1344 | }, { 1345 | value: "610700", 1346 | text: "汉中市" 1347 | }, { 1348 | value: "610800", 1349 | text: "榆林市" 1350 | }, { 1351 | value: "610900", 1352 | text: "安康市" 1353 | }, { 1354 | value: "611000", 1355 | text: "商洛市" 1356 | }] 1357 | }, { 1358 | value: '620000', 1359 | text: '甘肃省', 1360 | children: [{ 1361 | value: "620100", 1362 | text: "兰州市" 1363 | }, { 1364 | value: "620200", 1365 | text: "嘉峪关市" 1366 | }, { 1367 | value: "620300", 1368 | text: "金昌市" 1369 | }, { 1370 | value: "620400", 1371 | text: "白银市" 1372 | }, { 1373 | value: "620500", 1374 | text: "天水市" 1375 | }, { 1376 | value: "620600", 1377 | text: "武威市" 1378 | }, { 1379 | value: "620700", 1380 | text: "张掖市" 1381 | }, { 1382 | value: "620800", 1383 | text: "平凉市" 1384 | }, { 1385 | value: "620900", 1386 | text: "酒泉市" 1387 | }, { 1388 | value: "621000", 1389 | text: "庆阳市" 1390 | }, { 1391 | value: "621100", 1392 | text: "定西市" 1393 | }, { 1394 | value: "621200", 1395 | text: "陇南市" 1396 | }, { 1397 | value: "622900", 1398 | text: "临夏回族自治州" 1399 | }, { 1400 | value: "623000", 1401 | text: "甘南藏族自治州" 1402 | }] 1403 | }, { 1404 | value: '630000', 1405 | text: '青海省', 1406 | children: [{ 1407 | value: "630100", 1408 | text: "西宁市" 1409 | }, { 1410 | value: "632100", 1411 | text: "海东地区" 1412 | }, { 1413 | value: "632200", 1414 | text: "海北藏族自治州" 1415 | }, { 1416 | value: "632300", 1417 | text: "黄南藏族自治州" 1418 | }, { 1419 | value: "632500", 1420 | text: "海南藏族自治州" 1421 | }, { 1422 | value: "632600", 1423 | text: "果洛藏族自治州" 1424 | }, { 1425 | value: "632700", 1426 | text: "玉树藏族自治州" 1427 | }, { 1428 | value: "632800", 1429 | text: "海西蒙古族藏族自治州" 1430 | }] 1431 | }, { 1432 | value: '640000', 1433 | text: '宁夏', 1434 | children: [{ 1435 | value: "640100", 1436 | text: "银川市" 1437 | }, { 1438 | value: "640200", 1439 | text: "石嘴山市" 1440 | }, { 1441 | value: "640300", 1442 | text: "吴忠市" 1443 | }, { 1444 | value: "640400", 1445 | text: "固原市" 1446 | }, { 1447 | value: "640500", 1448 | text: "中卫市" 1449 | }] 1450 | }, { 1451 | value: '650000', 1452 | text: '新疆', 1453 | children: [{ 1454 | value: "650100", 1455 | text: "乌鲁木齐市" 1456 | }, { 1457 | value: "650200", 1458 | text: "克拉玛依市" 1459 | }, { 1460 | value: "652100", 1461 | text: "吐鲁番地区" 1462 | }, { 1463 | value: "652200", 1464 | text: "哈密地区" 1465 | }, { 1466 | value: "652300", 1467 | text: "昌吉回族自治州" 1468 | }, { 1469 | value: "652700", 1470 | text: "博尔塔拉蒙古自治州" 1471 | }, { 1472 | value: "652800", 1473 | text: "巴音郭楞蒙古自治州" 1474 | }, { 1475 | value: "652900", 1476 | text: "阿克苏地区" 1477 | }, { 1478 | value: "653000", 1479 | text: "克孜勒苏柯尔克孜自治州" 1480 | }, { 1481 | value: "653100", 1482 | text: "喀什地区" 1483 | }, { 1484 | value: "653200", 1485 | text: "和田地区" 1486 | }, { 1487 | value: "654000", 1488 | text: "伊犁哈萨克自治州" 1489 | }, { 1490 | value: "654200", 1491 | text: "塔城地区" 1492 | }, { 1493 | value: "654300", 1494 | text: "阿勒泰地区" 1495 | }, { 1496 | value: "659001", 1497 | text: "石河子市" 1498 | }, { 1499 | value: "659002", 1500 | text: "阿拉尔市" 1501 | }, { 1502 | value: "659003", 1503 | text: "图木舒克市" 1504 | }, { 1505 | value: "659004", 1506 | text: "五家渠市" 1507 | }] 1508 | }, { 1509 | value: '710000', 1510 | text: '台湾省', 1511 | children: [{ 1512 | value: "710100", 1513 | text: "台北市" 1514 | }, { 1515 | value: "710200", 1516 | text: "高雄市" 1517 | }, { 1518 | value: "710300", 1519 | text: "台南市" 1520 | }, { 1521 | value: "710400", 1522 | text: "台中市" 1523 | }, { 1524 | value: "710500", 1525 | text: "金门县" 1526 | }, { 1527 | value: "710600", 1528 | text: "南投县" 1529 | }, { 1530 | value: "710700", 1531 | text: "基隆市" 1532 | }, { 1533 | value: "710800", 1534 | text: "新竹市" 1535 | }, { 1536 | value: "710900", 1537 | text: "嘉义市" 1538 | }, { 1539 | value: "711100", 1540 | text: "新北市" 1541 | }, { 1542 | value: "711200", 1543 | text: "宜兰县" 1544 | }, { 1545 | value: "711300", 1546 | text: "新竹县" 1547 | }, { 1548 | value: "711400", 1549 | text: "桃园县" 1550 | }, { 1551 | value: "711500", 1552 | text: "苗栗县" 1553 | }, { 1554 | value: "711700", 1555 | text: "彰化县" 1556 | }, { 1557 | value: "711900", 1558 | text: "嘉义县" 1559 | }, { 1560 | value: "712100", 1561 | text: "云林县" 1562 | }, { 1563 | value: "712400", 1564 | text: "屏东县" 1565 | }, { 1566 | value: "712500", 1567 | text: "台东县" 1568 | }, { 1569 | value: "712600", 1570 | text: "花莲县" 1571 | }, { 1572 | value: "712700", 1573 | text: "澎湖县" 1574 | }] 1575 | }, { 1576 | value: '810000', 1577 | text: '香港', 1578 | children: [{ 1579 | value: "810100", 1580 | text: "香港岛" 1581 | }, { 1582 | value: "810200", 1583 | text: "九龙" 1584 | }, { 1585 | value: "810300", 1586 | text: "新界" 1587 | }] 1588 | }, { 1589 | value: '820000', 1590 | text: '澳门', 1591 | children: [{ 1592 | value: "820100", 1593 | text: "澳门半岛" 1594 | }, { 1595 | value: "820200", 1596 | text: "离岛" 1597 | }] 1598 | }, { 1599 | value: '990000', 1600 | text: '海外', 1601 | children: [{ 1602 | value: "990100", 1603 | text: "海外" 1604 | }] 1605 | }] 1606 | -------------------------------------------------------------------------------- /src/js/mui.js: -------------------------------------------------------------------------------- 1 | var mui = (function(document, undefined) { 2 | var readyRE = /complete|loaded|interactive/; 3 | var idSelectorRE = /^#([\w-]+)$/; 4 | var classSelectorRE = /^\.([\w-]+)$/; 5 | var tagSelectorRE = /^[\w-]+$/; 6 | var translateRE = /translate(?:3d)?\((.+?)\)/; 7 | var translateMatrixRE = /matrix(3d)?\((.+?)\)/; 8 | 9 | var $ = function(selector, context) { 10 | context = context || document; 11 | if (!selector) 12 | return wrap(); 13 | if (typeof selector === 'object') 14 | if ($.isArrayLike(selector)) { 15 | return wrap($.slice.call(selector), null); 16 | } else { 17 | return wrap([selector], null); 18 | } 19 | if (typeof selector === 'function') 20 | return $.ready(selector); 21 | if (typeof selector === 'string') { 22 | try { 23 | selector = selector.trim(); 24 | if (idSelectorRE.test(selector)) { 25 | var found = document.getElementById(RegExp.$1); 26 | return wrap(found ? [found] : []); 27 | } 28 | return wrap($.qsa(selector, context), selector); 29 | } catch (e) {} 30 | } 31 | return wrap(); 32 | }; 33 | 34 | var wrap = function(dom, selector) { 35 | dom = dom || []; 36 | dom.__proto__ = $.fn; 37 | dom.selector = selector || ''; 38 | return dom; 39 | }; 40 | 41 | $.uuid = 0; 42 | 43 | $.data = {}; 44 | /** 45 | * extend(simple) 46 | * @param {type} target 47 | * @param {type} source 48 | * @param {type} deep 49 | * @returns {unresolved} 50 | */ 51 | $.extend = function() { //from jquery2 52 | var options, name, src, copy, copyIsArray, clone, 53 | target = arguments[0] || {}, 54 | i = 1, 55 | length = arguments.length, 56 | deep = false; 57 | 58 | if (typeof target === "boolean") { 59 | deep = target; 60 | 61 | target = arguments[i] || {}; 62 | i++; 63 | } 64 | 65 | if (typeof target !== "object" && !$.isFunction(target)) { 66 | target = {}; 67 | } 68 | 69 | if (i === length) { 70 | target = this; 71 | i--; 72 | } 73 | 74 | for (; i < length; i++) { 75 | if ((options = arguments[i]) != null) { 76 | for (name in options) { 77 | src = target[name]; 78 | copy = options[name]; 79 | 80 | if (target === copy) { 81 | continue; 82 | } 83 | 84 | if (deep && copy && ($.isPlainObject(copy) || (copyIsArray = $.isArray(copy)))) { 85 | if (copyIsArray) { 86 | copyIsArray = false; 87 | clone = src && $.isArray(src) ? src : []; 88 | 89 | } else { 90 | clone = src && $.isPlainObject(src) ? src : {}; 91 | } 92 | 93 | target[name] = $.extend(deep, clone, copy); 94 | 95 | } else if (copy !== undefined) { 96 | target[name] = copy; 97 | } 98 | } 99 | } 100 | } 101 | 102 | return target; 103 | }; 104 | /** 105 | * mui noop(function) 106 | */ 107 | $.noop = function() {}; 108 | /** 109 | * mui slice(array) 110 | */ 111 | $.slice = [].slice; 112 | /** 113 | * mui filter(array) 114 | */ 115 | $.filter = [].filter; 116 | 117 | $.type = function(obj) { 118 | return obj == null ? String(obj) : class2type[{}.toString.call(obj)] || "object"; 119 | }; 120 | /** 121 | * mui isArray 122 | */ 123 | $.isArray = Array.isArray || 124 | function(object) { 125 | return object instanceof Array; 126 | }; 127 | /** 128 | * mui isArrayLike 129 | * @param {Object} obj 130 | */ 131 | $.isArrayLike = function(obj) { 132 | var length = !!obj && "length" in obj && obj.length; 133 | var type = $.type(obj); 134 | if (type === "function" || $.isWindow(obj)) { 135 | return false; 136 | } 137 | return type === "array" || length === 0 || 138 | typeof length === "number" && length > 0 && (length - 1) in obj; 139 | }; 140 | /** 141 | * mui isWindow(需考虑obj为undefined的情况) 142 | */ 143 | $.isWindow = function(obj) { 144 | return obj != null && obj === obj.window; 145 | }; 146 | /** 147 | * mui isObject 148 | */ 149 | $.isObject = function(obj) { 150 | return $.type(obj) === "object"; 151 | }; 152 | /** 153 | * mui isPlainObject 154 | */ 155 | $.isPlainObject = function(obj) { 156 | return $.isObject(obj) && !$.isWindow(obj) && Object.getPrototypeOf(obj) === Object.prototype; 157 | }; 158 | /** 159 | * mui isEmptyObject 160 | * @param {Object} o 161 | */ 162 | $.isEmptyObject = function(o) { 163 | for (var p in o) { 164 | if (p !== undefined) { 165 | return false; 166 | } 167 | } 168 | return true; 169 | }; 170 | /** 171 | * mui isFunction 172 | */ 173 | $.isFunction = function(value) { 174 | return $.type(value) === "function"; 175 | }; 176 | /** 177 | * mui querySelectorAll 178 | * @param {type} selector 179 | * @param {type} context 180 | * @returns {Array} 181 | */ 182 | $.qsa = function(selector, context) { 183 | context = context || document; 184 | return $.slice.call(classSelectorRE.test(selector) ? context.getElementsByClassName(RegExp.$1) : tagSelectorRE.test(selector) ? context.getElementsByTagName(selector) : context.querySelectorAll(selector)); 185 | }; 186 | /** 187 | * ready(DOMContentLoaded) 188 | * @param {type} callback 189 | * @returns {_L6.$} 190 | */ 191 | $.ready = function(callback) { 192 | if (readyRE.test(document.readyState)) { 193 | callback($); 194 | } else { 195 | document.addEventListener('DOMContentLoaded', function() { 196 | callback($); 197 | }, false); 198 | } 199 | return this; 200 | }; 201 | /** 202 | * 将 fn 缓存一段时间后, 再被调用执行 203 | * 此方法为了避免在 ms 段时间内, 执行 fn 多次. 常用于 resize , scroll , mousemove 等连续性事件中; 204 | * 当 ms 设置为 -1, 表示立即执行 fn, 即和直接调用 fn 一样; 205 | * 调用返回函数的 stop 停止最后一次的 buffer 效果 206 | * @param {Object} fn 207 | * @param {Object} ms 208 | * @param {Object} context 209 | */ 210 | $.buffer = function(fn, ms, context) { 211 | var timer; 212 | var lastStart = 0; 213 | var lastEnd = 0; 214 | var ms = ms || 150; 215 | 216 | function run() { 217 | if (timer) { 218 | timer.cancel(); 219 | timer = 0; 220 | } 221 | lastStart = $.now(); 222 | fn.apply(context || this, arguments); 223 | lastEnd = $.now(); 224 | } 225 | 226 | return $.extend(function() { 227 | if ( 228 | (!lastStart) || // 从未运行过 229 | (lastEnd >= lastStart && $.now() - lastEnd > ms) || // 上次运行成功后已经超过ms毫秒 230 | (lastEnd < lastStart && $.now() - lastStart > ms * 8) // 上次运行或未完成,后8*ms毫秒 231 | ) { 232 | run(); 233 | } else { 234 | if (timer) { 235 | timer.cancel(); 236 | } 237 | timer = $.later(run, ms, null, arguments); 238 | } 239 | }, { 240 | stop: function() { 241 | if (timer) { 242 | timer.cancel(); 243 | timer = 0; 244 | } 245 | } 246 | }); 247 | }; 248 | /** 249 | * each 250 | * @param {type} elements 251 | * @param {type} callback 252 | * @returns {_L8.$} 253 | */ 254 | $.each = function(elements, callback, hasOwnProperty) { 255 | if (!elements) { 256 | return this; 257 | } 258 | if (typeof elements.length === 'number') { 259 | [].every.call(elements, function(el, idx) { 260 | return callback.call(el, idx, el) !== false; 261 | }); 262 | } else { 263 | for (var key in elements) { 264 | if (hasOwnProperty) { 265 | if (elements.hasOwnProperty(key)) { 266 | if (callback.call(elements[key], key, elements[key]) === false) return elements; 267 | } 268 | } else { 269 | if (callback.call(elements[key], key, elements[key]) === false) return elements; 270 | } 271 | } 272 | } 273 | return this; 274 | }; 275 | $.focus = function(element) { 276 | if ($.os.ios) { 277 | setTimeout(function() { 278 | element.focus(); 279 | }, 10); 280 | } else { 281 | element.focus(); 282 | } 283 | }; 284 | /** 285 | * trigger event 286 | * @param {type} element 287 | * @param {type} eventType 288 | * @param {type} eventData 289 | * @returns {_L8.$} 290 | */ 291 | $.trigger = function(element, eventType, eventData) { 292 | element.dispatchEvent(new CustomEvent(eventType, { 293 | detail: eventData, 294 | bubbles: true, 295 | cancelable: true 296 | })); 297 | return this; 298 | }; 299 | /** 300 | * getStyles 301 | * @param {type} element 302 | * @param {type} property 303 | * @returns {styles} 304 | */ 305 | $.getStyles = function(element, property) { 306 | var styles = element.ownerDocument.defaultView.getComputedStyle(element, null); 307 | if (property) { 308 | return styles.getPropertyValue(property) || styles[property]; 309 | } 310 | return styles; 311 | }; 312 | /** 313 | * parseTranslate 314 | * @param {type} translateString 315 | * @param {type} position 316 | * @returns {Object} 317 | */ 318 | $.parseTranslate = function(translateString, position) { 319 | var result = translateString.match(translateRE || ''); 320 | if (!result || !result[1]) { 321 | result = ['', '0,0,0']; 322 | } 323 | result = result[1].split(","); 324 | result = { 325 | x: parseFloat(result[0]), 326 | y: parseFloat(result[1]), 327 | z: parseFloat(result[2]) 328 | }; 329 | if (position && result.hasOwnProperty(position)) { 330 | return result[position]; 331 | } 332 | return result; 333 | }; 334 | /** 335 | * parseTranslateMatrix 336 | * @param {type} translateString 337 | * @param {type} position 338 | * @returns {Object} 339 | */ 340 | $.parseTranslateMatrix = function(translateString, position) { 341 | var matrix = translateString.match(translateMatrixRE); 342 | var is3D = matrix && matrix[1]; 343 | if (matrix) { 344 | matrix = matrix[2].split(","); 345 | if (is3D === "3d") 346 | matrix = matrix.slice(12, 15); 347 | else { 348 | matrix.push(0); 349 | matrix = matrix.slice(4, 7); 350 | } 351 | } else { 352 | matrix = [0, 0, 0]; 353 | } 354 | var result = { 355 | x: parseFloat(matrix[0]), 356 | y: parseFloat(matrix[1]), 357 | z: parseFloat(matrix[2]) 358 | }; 359 | if (position && result.hasOwnProperty(position)) { 360 | return result[position]; 361 | } 362 | return result; 363 | }; 364 | $.hooks = {}; 365 | $.addAction = function(type, hook) { 366 | var hooks = $.hooks[type]; 367 | if (!hooks) { 368 | hooks = []; 369 | } 370 | hook.index = hook.index || 1000; 371 | hooks.push(hook); 372 | hooks.sort(function(a, b) { 373 | return a.index - b.index; 374 | }); 375 | $.hooks[type] = hooks; 376 | return $.hooks[type]; 377 | }; 378 | $.doAction = function(type, callback) { 379 | if ($.isFunction(callback)) { //指定了callback 380 | $.each($.hooks[type], callback); 381 | } else { //未指定callback,直接执行 382 | $.each($.hooks[type], function(index, hook) { 383 | return !hook.handle(); 384 | }); 385 | } 386 | }; 387 | /** 388 | * setTimeout封装 389 | * @param {Object} fn 390 | * @param {Object} when 391 | * @param {Object} context 392 | * @param {Object} data 393 | */ 394 | $.later = function(fn, when, context, data) { 395 | when = when || 0; 396 | var m = fn; 397 | var d = data; 398 | var f; 399 | var r; 400 | 401 | if (typeof fn === 'string') { 402 | m = context[fn]; 403 | } 404 | 405 | f = function() { 406 | m.apply(context, $.isArray(d) ? d : [d]); 407 | }; 408 | 409 | r = setTimeout(f, when); 410 | 411 | return { 412 | id: r, 413 | cancel: function() { 414 | clearTimeout(r); 415 | } 416 | }; 417 | }; 418 | $.now = Date.now || function() { 419 | return +new Date(); 420 | }; 421 | var class2type = {}; 422 | $.each(['Boolean', 'Number', 'String', 'Function', 'Array', 'Date', 'RegExp', 'Object', 'Error'], function(i, name) { 423 | class2type["[object " + name + "]"] = name.toLowerCase(); 424 | }); 425 | if (window.JSON) { 426 | $.parseJSON = JSON.parse; 427 | } 428 | /** 429 | * $.fn 430 | */ 431 | $.fn = { 432 | each: function(callback) { 433 | [].every.call(this, function(el, idx) { 434 | return callback.call(el, idx, el) !== false; 435 | }); 436 | return this; 437 | } 438 | }; 439 | 440 | return $; 441 | })(document); 442 | 443 | 444 | 445 | (function($, window) { 446 | function detect(ua) { 447 | this.os = {}; 448 | var funcs = [ 449 | 450 | function() { //wechat 451 | var wechat = ua.match(/(MicroMessenger)\/([\d\.]+)/i); 452 | if (wechat) { //wechat 453 | this.os.wechat = { 454 | version: wechat[2].replace(/_/g, '.') 455 | }; 456 | } 457 | return false; 458 | }, 459 | function() { //android 460 | var android = ua.match(/(Android);?[\s\/]+([\d.]+)?/); 461 | if (android) { 462 | this.os.android = true; 463 | this.os.version = android[2]; 464 | 465 | this.os.isBadAndroid = !(/Chrome\/\d/.test(window.navigator.appVersion)); 466 | } 467 | return this.os.android === true; 468 | }, 469 | function() { //ios 470 | var iphone = ua.match(/(iPhone\sOS)\s([\d_]+)/); 471 | if (iphone) { //iphone 472 | this.os.ios = this.os.iphone = true; 473 | this.os.version = iphone[2].replace(/_/g, '.'); 474 | } else { 475 | var ipad = ua.match(/(iPad).*OS\s([\d_]+)/); 476 | if (ipad) { //ipad 477 | this.os.ios = this.os.ipad = true; 478 | this.os.version = ipad[2].replace(/_/g, '.'); 479 | } 480 | } 481 | return this.os.ios === true; 482 | } 483 | ]; 484 | [].every.call(funcs, function(func) { 485 | return !func.call($); 486 | }); 487 | } 488 | detect.call($, navigator.userAgent); 489 | })(mui, window); 490 | /** 491 | * $.os.plus 492 | * @param {type} $ 493 | * @returns {undefined} 494 | */ 495 | (function($, document) { 496 | function detect(ua) { 497 | this.os = this.os || {}; 498 | var plus = ua.match(/Html5Plus/i); //TODO 5\+Browser? 499 | if (plus) { 500 | this.os.plus = true; 501 | $(function() { 502 | document.body.classList.add('mui-plus'); 503 | }); 504 | if (ua.match(/StreamApp/i)) { //TODO 最好有流应用自己的标识 505 | this.os.stream = true; 506 | $(function() { 507 | document.body.classList.add('mui-plus-stream'); 508 | }); 509 | } 510 | } 511 | } 512 | detect.call($, navigator.userAgent); 513 | })(mui, document); 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | (function($) { 526 | var initializing = false, 527 | fnTest = /xyz/.test(function() { 528 | xyz; 529 | }) ? /\b_super\b/ : /.*/; 530 | 531 | var Class = function() {}; 532 | Class.extend = function(prop) { 533 | var _super = this.prototype; 534 | initializing = true; 535 | var prototype = new this(); 536 | initializing = false; 537 | for (var name in prop) { 538 | prototype[name] = typeof prop[name] == "function" && 539 | typeof _super[name] == "function" && fnTest.test(prop[name]) ? 540 | (function(name, fn) { 541 | return function() { 542 | var tmp = this._super; 543 | 544 | this._super = _super[name]; 545 | 546 | var ret = fn.apply(this, arguments); 547 | this._super = tmp; 548 | 549 | return ret; 550 | }; 551 | })(name, prop[name]) : 552 | prop[name]; 553 | } 554 | function Class() { 555 | if (!initializing && this.init) 556 | this.init.apply(this, arguments); 557 | } 558 | Class.prototype = prototype; 559 | Class.prototype.constructor = Class; 560 | Class.extend = this; 561 | return Class; 562 | }; 563 | $.Class = Class; 564 | })(mui); 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | /** 579 | * mui.init 580 | * @param {type} $ 581 | * @returns {undefined} 582 | */ 583 | (function($) { 584 | $.global = $.options = { 585 | gestureConfig: { 586 | tap: true, 587 | doubletap: false, 588 | longtap: false, 589 | hold: false, 590 | flick: true, 591 | swipe: true, 592 | drag: true, 593 | pinch: false 594 | } 595 | }; 596 | /** 597 | * 598 | * @param {type} options 599 | * @returns {undefined} 600 | */ 601 | $.initGlobal = function(options) { 602 | $.options = $.extend(true, $.global, options); 603 | return this; 604 | }; 605 | var inits = {}; 606 | 607 | var isInitialized = false; 608 | //TODO 自动调用init?因为用户自己调用init的时机可能不确定,如果晚于自动init,则会有潜在问题 609 | // $.ready(function() { 610 | // setTimeout(function() { 611 | // if (!isInitialized) { 612 | // $.init(); 613 | // } 614 | // }, 300); 615 | // }); 616 | /** 617 | * 单页配置 初始化 618 | * @param {object} options 619 | */ 620 | $.init = function(options) { 621 | isInitialized = true; 622 | $.options = $.extend(true, $.global, options || {}); 623 | $.ready(function() { 624 | $.doAction('inits', function(index, init) { 625 | var isInit = !!(!inits[init.name] || init.repeat); 626 | if (isInit) { 627 | init.handle.call($); 628 | inits[init.name] = true; 629 | } 630 | }); 631 | }); 632 | return this; 633 | }; 634 | 635 | /** 636 | * 增加初始化执行流程 637 | * @param {function} init 638 | */ 639 | $.addInit = function(init) { 640 | return $.addAction('inits', init); 641 | }; 642 | 643 | 644 | })(mui); 645 | 646 | 647 | 648 | 649 | 650 | /** 651 | * mui target(action>popover>modal>tab>toggle) 652 | */ 653 | (function($, window, document) { 654 | /** 655 | * targets 656 | */ 657 | $.targets = {}; 658 | /** 659 | * target handles 660 | */ 661 | $.targetHandles = []; 662 | /** 663 | * register target 664 | * @param {type} target 665 | * @returns {$.targets} 666 | */ 667 | $.registerTarget = function(target) { 668 | 669 | target.index = target.index || 1000; 670 | 671 | $.targetHandles.push(target); 672 | 673 | $.targetHandles.sort(function(a, b) { 674 | return a.index - b.index; 675 | }); 676 | 677 | return $.targetHandles; 678 | }; 679 | window.addEventListener($.EVENT_START, function(event) { 680 | var target = event.target; 681 | var founds = {}; 682 | for (; target && target !== document; target = target.parentNode) { 683 | var isFound = false; 684 | $.each($.targetHandles, function(index, targetHandle) { 685 | var name = targetHandle.name; 686 | if (!isFound && !founds[name] && targetHandle.hasOwnProperty('handle')) { 687 | $.targets[name] = targetHandle.handle(event, target); 688 | if ($.targets[name]) { 689 | founds[name] = true; 690 | if (targetHandle.isContinue !== true) { 691 | isFound = true; 692 | } 693 | } 694 | } else { 695 | if (!founds[name]) { 696 | if (targetHandle.isReset !== false) 697 | $.targets[name] = false; 698 | } 699 | } 700 | }); 701 | if (isFound) { 702 | break; 703 | } 704 | } 705 | }); 706 | window.addEventListener('click', function(event) { //解决touch与click的target不一致的问题(比如链接边缘点击时,touch的target为html,而click的target为A) 707 | var target = event.target; 708 | var isFound = false; 709 | for (; target && target !== document; target = target.parentNode) { 710 | if (target.tagName === 'A') { 711 | $.each($.targetHandles, function(index, targetHandle) { 712 | var name = targetHandle.name; 713 | if (targetHandle.hasOwnProperty('handle')) { 714 | if (targetHandle.handle(event, target)) { 715 | isFound = true; 716 | event.preventDefault(); 717 | return false; 718 | } 719 | } 720 | }); 721 | if (isFound) { 722 | break; 723 | } 724 | } 725 | } 726 | }); 727 | })(mui, window, document); 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | /** 736 | * Popovers 737 | * @param {type} $ 738 | * @param {type} window 739 | * @param {type} document 740 | * @param {type} name 741 | * @param {type} undefined 742 | * @returns {undefined} 743 | */ 744 | (function($, window, document, name) { 745 | 746 | var CLASS_POPOVER = 'mui-popover'; 747 | var CLASS_POPOVER_ARROW = 'mui-popover-arrow'; 748 | var CLASS_ACTION_POPOVER = 'mui-popover-action'; 749 | var CLASS_BACKDROP = 'mui-backdrop'; 750 | var CLASS_BAR_POPOVER = 'mui-bar-popover'; 751 | var CLASS_BAR_BACKDROP = 'mui-bar-backdrop'; 752 | var CLASS_ACTION_BACKDROP = 'mui-backdrop-action'; 753 | var CLASS_ACTIVE = 'mui-active'; 754 | var CLASS_BOTTOM = 'mui-bottom'; 755 | 756 | 757 | 758 | var handle = function(event, target) { 759 | if (target.tagName === 'A' && target.hash) { 760 | $.targets._popover = document.getElementById(target.hash.replace('#', '')); 761 | if ($.targets._popover && $.targets._popover.classList.contains(CLASS_POPOVER)) { 762 | return target; 763 | } else { 764 | $.targets._popover = null; 765 | } 766 | } 767 | return false; 768 | }; 769 | 770 | $.registerTarget({ 771 | name: name, 772 | index: 60, 773 | handle: handle, 774 | target: false, 775 | isReset: false, 776 | isContinue: true 777 | }); 778 | 779 | var fixedPopoverScroll = function(isPopoverScroll) { 780 | // if (isPopoverScroll) { 781 | // document.body.setAttribute('style', 'overflow:hidden;'); 782 | // } else { 783 | // document.body.setAttribute('style', ''); 784 | // } 785 | }; 786 | var onPopoverShown = function(e) { 787 | this.removeEventListener('webkitTransitionEnd', onPopoverShown); 788 | this.addEventListener($.EVENT_MOVE, $.preventDefault); 789 | $.trigger(this, 'shown', this); 790 | } 791 | var onPopoverHidden = function(e) { 792 | setStyle(this, 'none'); 793 | this.removeEventListener('webkitTransitionEnd', onPopoverHidden); 794 | this.removeEventListener($.EVENT_MOVE, $.preventDefault); 795 | fixedPopoverScroll(false); 796 | $.trigger(this, 'hidden', this); 797 | }; 798 | 799 | var backdrop = (function() { 800 | var element = document.createElement('div'); 801 | element.classList.add(CLASS_BACKDROP); 802 | element.addEventListener($.EVENT_MOVE, $.preventDefault); 803 | element.addEventListener('tap', function(e) { 804 | var popover = $.targets._popover; 805 | if (popover) { 806 | popover.addEventListener('webkitTransitionEnd', onPopoverHidden); 807 | popover.classList.remove(CLASS_ACTIVE); 808 | removeBackdrop(popover); 809 | document.body.setAttribute('style', ''); //webkitTransitionEnd有时候不触发? 810 | } 811 | }); 812 | 813 | return element; 814 | }()); 815 | var removeBackdropTimer; 816 | var removeBackdrop = function(popover) { 817 | backdrop.setAttribute('style', 'opacity:0'); 818 | $.targets.popover = $.targets._popover = null; //reset 819 | removeBackdropTimer = $.later(function() { 820 | if (!popover.classList.contains(CLASS_ACTIVE) && backdrop.parentNode && backdrop.parentNode === document.body) { 821 | document.body.removeChild(backdrop); 822 | } 823 | }, 350); 824 | }; 825 | window.addEventListener('tap', function(e) { 826 | if (!$.targets.popover) { 827 | return; 828 | } 829 | var toggle = false; 830 | var target = e.target; 831 | for (; target && target !== document; target = target.parentNode) { 832 | if (target === $.targets.popover) { 833 | toggle = true; 834 | } 835 | } 836 | if (toggle) { 837 | e.detail.gesture.preventDefault(); //fixed hashchange 838 | togglePopover($.targets._popover, $.targets.popover); 839 | } 840 | 841 | }); 842 | 843 | var togglePopover = function(popover, anchor, state) { 844 | if ((state === 'show' && popover.classList.contains(CLASS_ACTIVE)) || (state === 'hide' && !popover.classList.contains(CLASS_ACTIVE))) { 845 | return; 846 | } 847 | removeBackdropTimer && removeBackdropTimer.cancel(); //取消remove的timer 848 | //remove一遍,以免来回快速切换,导致webkitTransitionEnd不触发,无法remove 849 | popover.removeEventListener('webkitTransitionEnd', onPopoverShown); 850 | popover.removeEventListener('webkitTransitionEnd', onPopoverHidden); 851 | backdrop.classList.remove(CLASS_BAR_BACKDROP); 852 | backdrop.classList.remove(CLASS_ACTION_BACKDROP); 853 | var _popover = document.querySelector('.mui-popover.mui-active'); 854 | if (_popover) { 855 | // _popover.setAttribute('style', ''); 856 | _popover.addEventListener('webkitTransitionEnd', onPopoverHidden); 857 | _popover.classList.remove(CLASS_ACTIVE); 858 | // _popover.removeEventListener('webkitTransitionEnd', onPopoverHidden); 859 | // fixedPopoverScroll(false); 860 | //同一个弹出则直接返回,解决同一个popover的toggle 861 | if (popover === _popover) { 862 | removeBackdrop(_popover); 863 | return; 864 | } 865 | } 866 | var isActionSheet = false; 867 | if (popover.classList.contains(CLASS_BAR_POPOVER) || popover.classList.contains(CLASS_ACTION_POPOVER)) { //navBar 868 | if (popover.classList.contains(CLASS_ACTION_POPOVER)) { //action sheet popover 869 | isActionSheet = true; 870 | backdrop.classList.add(CLASS_ACTION_BACKDROP); 871 | } else { //bar popover 872 | backdrop.classList.add(CLASS_BAR_BACKDROP); 873 | // if (anchor) { 874 | // if (anchor.parentNode) { 875 | // var offsetWidth = anchor.offsetWidth; 876 | // var offsetLeft = anchor.offsetLeft; 877 | // var innerWidth = window.innerWidth; 878 | // popover.style.left = (Math.min(Math.max(offsetLeft, defaultPadding), innerWidth - offsetWidth - defaultPadding)) + "px"; 879 | // } else { 880 | // //TODO anchor is position:{left,top,bottom,right} 881 | // } 882 | // } 883 | } 884 | } 885 | setStyle(popover, 'block'); //actionsheet transform 886 | popover.offsetHeight; 887 | popover.classList.add(CLASS_ACTIVE); 888 | backdrop.setAttribute('style', ''); 889 | document.body.appendChild(backdrop); 890 | fixedPopoverScroll(true); 891 | calPosition(popover, anchor, isActionSheet); //position 892 | backdrop.classList.add(CLASS_ACTIVE); 893 | popover.addEventListener('webkitTransitionEnd', onPopoverShown); 894 | }; 895 | var setStyle = function(popover, display, top, left) { 896 | var style = popover.style; 897 | if (typeof display !== 'undefined') 898 | style.display = display; 899 | if (typeof top !== 'undefined') 900 | style.top = top + 'px'; 901 | if (typeof left !== 'undefined') 902 | style.left = left + 'px'; 903 | }; 904 | var calPosition = function(popover, anchor, isActionSheet) { 905 | if (!popover || !anchor) { 906 | return; 907 | } 908 | 909 | if (isActionSheet) { //actionsheet 910 | setStyle(popover, 'block') 911 | return; 912 | } 913 | 914 | var wWidth = window.innerWidth; 915 | var wHeight = window.innerHeight; 916 | 917 | var pWidth = popover.offsetWidth; 918 | var pHeight = popover.offsetHeight; 919 | 920 | var aWidth = anchor.offsetWidth; 921 | var aHeight = anchor.offsetHeight; 922 | var offset = $.offset(anchor); 923 | 924 | var arrow = popover.querySelector('.' + CLASS_POPOVER_ARROW); 925 | if (!arrow) { 926 | arrow = document.createElement('div'); 927 | arrow.className = CLASS_POPOVER_ARROW; 928 | popover.appendChild(arrow); 929 | } 930 | var arrowSize = arrow && arrow.offsetWidth / 2 || 0; 931 | 932 | 933 | 934 | var pTop = 0; 935 | var pLeft = 0; 936 | var diff = 0; 937 | var arrowLeft = 0; 938 | var defaultPadding = popover.classList.contains(CLASS_ACTION_POPOVER) ? 0 : 5; 939 | 940 | var position = 'top'; 941 | if ((pHeight + arrowSize) < (offset.top - window.pageYOffset)) { //top 942 | pTop = offset.top - pHeight - arrowSize; 943 | } else if ((pHeight + arrowSize) < (wHeight - (offset.top - window.pageYOffset) - aHeight)) { //bottom 944 | position = 'bottom'; 945 | pTop = offset.top + aHeight + arrowSize; 946 | } else { //middle 947 | position = 'middle'; 948 | pTop = Math.max((wHeight - pHeight) / 2 + window.pageYOffset, 0); 949 | pLeft = Math.max((wWidth - pWidth) / 2 + window.pageXOffset, 0); 950 | } 951 | if (position === 'top' || position === 'bottom') { 952 | pLeft = aWidth / 2 + offset.left - pWidth / 2; 953 | diff = pLeft; 954 | if (pLeft < defaultPadding) pLeft = defaultPadding; 955 | if (pLeft + pWidth > wWidth) pLeft = wWidth - pWidth - defaultPadding; 956 | 957 | if (arrow) { 958 | if (position === 'top') { 959 | arrow.classList.add(CLASS_BOTTOM); 960 | } else { 961 | arrow.classList.remove(CLASS_BOTTOM); 962 | } 963 | diff = diff - pLeft; 964 | arrowLeft = (pWidth / 2 - arrowSize / 2 + diff); 965 | arrowLeft = Math.max(Math.min(arrowLeft, pWidth - arrowSize * 2 - 6), 6); 966 | arrow.setAttribute('style', 'left:' + arrowLeft + 'px'); 967 | } 968 | } else if (position === 'middle') { 969 | arrow.setAttribute('style', 'display:none'); 970 | } 971 | setStyle(popover, 'block', pTop, pLeft); 972 | }; 973 | 974 | $.createMask = function(callback) { 975 | var element = document.createElement('div'); 976 | element.classList.add(CLASS_BACKDROP); 977 | element.addEventListener($.EVENT_MOVE, $.preventDefault); 978 | element.addEventListener('tap', function() { 979 | mask.close(); 980 | }); 981 | var mask = [element]; 982 | mask._show = false; 983 | mask.show = function() { 984 | mask._show = true; 985 | element.setAttribute('style', 'opacity:1'); 986 | document.body.appendChild(element); 987 | return mask; 988 | }; 989 | mask._remove = function() { 990 | if (mask._show) { 991 | mask._show = false; 992 | element.setAttribute('style', 'opacity:0'); 993 | $.later(function() { 994 | var body = document.body; 995 | element.parentNode === body && body.removeChild(element); 996 | }, 350); 997 | } 998 | return mask; 999 | }; 1000 | mask.close = function() { 1001 | if (callback) { 1002 | if (callback() !== false) { 1003 | mask._remove(); 1004 | } 1005 | } else { 1006 | mask._remove(); 1007 | } 1008 | }; 1009 | return mask; 1010 | }; 1011 | $.fn.popover = function() { 1012 | var args = arguments; 1013 | this.each(function() { 1014 | $.targets._popover = this; 1015 | if (args[0] === 'show' || args[0] === 'hide' || args[0] === 'toggle') { 1016 | togglePopover(this, args[1], args[0]); 1017 | } 1018 | }); 1019 | }; 1020 | 1021 | })(mui, window, document, 'popover'); 1022 | 1023 | 1024 | 1025 | /** 1026 | * mui namespace(optimization) 1027 | * @param {type} $ 1028 | * @returns {undefined} 1029 | */ 1030 | (function($) { 1031 | $.namespace = 'mui'; 1032 | $.classNamePrefix = $.namespace + '-'; 1033 | $.classSelectorPrefix = '.' + $.classNamePrefix; 1034 | /** 1035 | * 返回正确的className 1036 | * @param {type} className 1037 | * @returns {String} 1038 | */ 1039 | $.className = function(className) { 1040 | return $.classNamePrefix + className; 1041 | }; 1042 | /** 1043 | * 返回正确的classSelector 1044 | * @param {type} classSelector 1045 | * @returns {String} 1046 | */ 1047 | $.classSelector = function(classSelector) { 1048 | return classSelector.replace(/\./g, $.classSelectorPrefix); 1049 | }; 1050 | /** 1051 | * 返回正确的eventName 1052 | * @param {type} event 1053 | * @param {type} module 1054 | * @returns {String} 1055 | */ 1056 | $.eventName = function(event, module) { 1057 | return event + ($.namespace ? ('.' + $.namespace) : '') + ( module ? ('.' + module) : ''); 1058 | }; 1059 | })(mui); 1060 | 1061 | 1062 | 1063 | 1064 | 1065 | 1066 | 1067 | 1068 | 1069 | 1070 | 1071 | 1072 | 1073 | 1074 | 1075 | /** 1076 | * 仅提供简单的on,off(仅支持事件委托,不支持当前元素绑定,当前元素绑定请直接使用addEventListener,removeEventListener) 1077 | * @param {Object} $ 1078 | */ 1079 | (function($) { 1080 | if ('ontouchstart' in window) { 1081 | $.isTouchable = true; 1082 | $.EVENT_START = 'touchstart'; 1083 | $.EVENT_MOVE = 'touchmove'; 1084 | $.EVENT_END = 'touchend'; 1085 | } else { 1086 | $.isTouchable = false; 1087 | $.EVENT_START = 'mousedown'; 1088 | $.EVENT_MOVE = 'mousemove'; 1089 | $.EVENT_END = 'mouseup'; 1090 | } 1091 | $.EVENT_CANCEL = 'touchcancel'; 1092 | $.EVENT_CLICK = 'click'; 1093 | 1094 | var _mid = 1; 1095 | var delegates = {}; 1096 | //需要wrap的函数 1097 | var eventMethods = { 1098 | preventDefault: 'isDefaultPrevented', 1099 | stopImmediatePropagation: 'isImmediatePropagationStopped', 1100 | stopPropagation: 'isPropagationStopped' 1101 | }; 1102 | //默认true返回函数 1103 | var returnTrue = function() { 1104 | return true 1105 | }; 1106 | //默认false返回函数 1107 | var returnFalse = function() { 1108 | return false 1109 | }; 1110 | //wrap浏览器事件 1111 | var compatible = function(event, target) { 1112 | if (!event.detail) { 1113 | event.detail = { 1114 | currentTarget: target 1115 | }; 1116 | } else { 1117 | event.detail.currentTarget = target; 1118 | } 1119 | $.each(eventMethods, function(name, predicate) { 1120 | var sourceMethod = event[name]; 1121 | event[name] = function() { 1122 | this[predicate] = returnTrue; 1123 | return sourceMethod && sourceMethod.apply(event, arguments) 1124 | } 1125 | event[predicate] = returnFalse; 1126 | }, true); 1127 | return event; 1128 | }; 1129 | //简单的wrap对象_mid 1130 | var mid = function(obj) { 1131 | return obj && (obj._mid || (obj._mid = _mid++)); 1132 | }; 1133 | //事件委托对象绑定的事件回调列表 1134 | var delegateFns = {}; 1135 | //返回事件委托的wrap事件回调 1136 | var delegateFn = function(element, event, selector, callback) { 1137 | return function(e) { 1138 | //same event 1139 | var callbackObjs = delegates[element._mid][event]; 1140 | var handlerQueue = []; 1141 | var target = e.target; 1142 | var selectorAlls = {}; 1143 | for (; target && target !== document; target = target.parentNode) { 1144 | if (target === element) { 1145 | break; 1146 | } 1147 | if (~['click', 'tap', 'doubletap', 'longtap', 'hold'].indexOf(event) && (target.disabled || target.classList.contains($.className('disabled')))) { 1148 | break; 1149 | } 1150 | var matches = {}; 1151 | $.each(callbackObjs, function(selector, callbacks) { //same selector 1152 | selectorAlls[selector] || (selectorAlls[selector] = $.qsa(selector, element)); 1153 | if (selectorAlls[selector] && ~(selectorAlls[selector]).indexOf(target)) { 1154 | if (!matches[selector]) { 1155 | matches[selector] = callbacks; 1156 | } 1157 | } 1158 | }, true); 1159 | if (!$.isEmptyObject(matches)) { 1160 | handlerQueue.push({ 1161 | element: target, 1162 | handlers: matches 1163 | }); 1164 | } 1165 | } 1166 | selectorAlls = null; 1167 | e = compatible(e); //compatible event 1168 | $.each(handlerQueue, function(index, handler) { 1169 | target = handler.element; 1170 | var tagName = target.tagName; 1171 | if (event === 'tap' && (tagName !== 'INPUT' && tagName !== 'TEXTAREA' && tagName !== 'SELECT')) { 1172 | e.preventDefault(); 1173 | e.detail && e.detail.gesture && e.detail.gesture.preventDefault(); 1174 | } 1175 | $.each(handler.handlers, function(index, handler) { 1176 | $.each(handler, function(index, callback) { 1177 | if (callback.call(target, e) === false) { 1178 | e.preventDefault(); 1179 | e.stopPropagation(); 1180 | } 1181 | }, true); 1182 | }, true) 1183 | if (e.isPropagationStopped()) { 1184 | return false; 1185 | } 1186 | }, true); 1187 | }; 1188 | }; 1189 | var findDelegateFn = function(element, event) { 1190 | var delegateCallbacks = delegateFns[mid(element)]; 1191 | var result = []; 1192 | if (delegateCallbacks) { 1193 | result = []; 1194 | if (event) { 1195 | var filterFn = function(fn) { 1196 | return fn.type === event; 1197 | } 1198 | return delegateCallbacks.filter(filterFn); 1199 | } else { 1200 | result = delegateCallbacks; 1201 | } 1202 | } 1203 | return result; 1204 | }; 1205 | var preventDefaultException = /^(INPUT|TEXTAREA|BUTTON|SELECT)$/; 1206 | /** 1207 | * mui delegate events 1208 | * @param {type} event 1209 | * @param {type} selector 1210 | * @param {type} callback 1211 | * @returns {undefined} 1212 | */ 1213 | $.fn.on = function(event, selector, callback) { //仅支持简单的事件委托,主要是tap事件使用,类似mouse,focus之类暂不封装支持 1214 | return this.each(function() { 1215 | var element = this; 1216 | mid(element); 1217 | mid(callback); 1218 | var isAddEventListener = false; 1219 | var delegateEvents = delegates[element._mid] || (delegates[element._mid] = {}); 1220 | var delegateCallbackObjs = delegateEvents[event] || ((delegateEvents[event] = {})); 1221 | if ($.isEmptyObject(delegateCallbackObjs)) { 1222 | isAddEventListener = true; 1223 | } 1224 | var delegateCallbacks = delegateCallbackObjs[selector] || (delegateCallbackObjs[selector] = []); 1225 | delegateCallbacks.push(callback); 1226 | if (isAddEventListener) { 1227 | var delegateFnArray = delegateFns[mid(element)]; 1228 | if (!delegateFnArray) { 1229 | delegateFnArray = []; 1230 | } 1231 | var delegateCallback = delegateFn(element, event, selector, callback); 1232 | delegateFnArray.push(delegateCallback); 1233 | delegateCallback.i = delegateFnArray.length - 1; 1234 | delegateCallback.type = event; 1235 | delegateFns[mid(element)] = delegateFnArray; 1236 | element.addEventListener(event, delegateCallback); 1237 | if (event === 'tap') { //TODO 需要找个更好的解决方案 1238 | element.addEventListener('click', function(e) { 1239 | if (e.target) { 1240 | var tagName = e.target.tagName; 1241 | if (!preventDefaultException.test(tagName)) { 1242 | if (tagName === 'A') { 1243 | var href = e.target.href; 1244 | if (!(href && ~href.indexOf('tel:'))) { 1245 | e.preventDefault(); 1246 | } 1247 | } else { 1248 | e.preventDefault(); 1249 | } 1250 | } 1251 | } 1252 | }); 1253 | } 1254 | } 1255 | }); 1256 | }; 1257 | $.fn.off = function(event, selector, callback) { 1258 | return this.each(function() { 1259 | var _mid = mid(this); 1260 | if (!event) { //mui(selector).off(); 1261 | delegates[_mid] && delete delegates[_mid]; 1262 | } else if (!selector) { //mui(selector).off(event); 1263 | delegates[_mid] && delete delegates[_mid][event]; 1264 | } else if (!callback) { //mui(selector).off(event,selector); 1265 | delegates[_mid] && delegates[_mid][event] && delete delegates[_mid][event][selector]; 1266 | } else { //mui(selector).off(event,selector,callback); 1267 | var delegateCallbacks = delegates[_mid] && delegates[_mid][event] && delegates[_mid][event][selector]; 1268 | $.each(delegateCallbacks, function(index, delegateCallback) { 1269 | if (mid(delegateCallback) === mid(callback)) { 1270 | delegateCallbacks.splice(index, 1); 1271 | return false; 1272 | } 1273 | }, true); 1274 | } 1275 | if (delegates[_mid]) { 1276 | //如果off掉了所有当前element的指定的event事件,则remove掉当前element的delegate回调 1277 | if ((!delegates[_mid][event] || $.isEmptyObject(delegates[_mid][event]))) { 1278 | findDelegateFn(this, event).forEach(function(fn) { 1279 | this.removeEventListener(fn.type, fn); 1280 | delete delegateFns[_mid][fn.i]; 1281 | }.bind(this)); 1282 | } 1283 | } else { 1284 | //如果delegates[_mid]已不存在,删除所有 1285 | findDelegateFn(this).forEach(function(fn) { 1286 | this.removeEventListener(fn.type, fn); 1287 | delete delegateFns[_mid][fn.i]; 1288 | }.bind(this)); 1289 | } 1290 | }); 1291 | 1292 | }; 1293 | })(mui); 1294 | 1295 | 1296 | 1297 | 1298 | /** 1299 | * mui gestures 1300 | * @param {type} $ 1301 | * @param {type} window 1302 | * @returns {undefined} 1303 | */ 1304 | (function($, window) { 1305 | $.gestures = { 1306 | session: {} 1307 | }; 1308 | /** 1309 | * Gesture preventDefault 1310 | * @param {type} e 1311 | * @returns {undefined} 1312 | */ 1313 | $.preventDefault = function(e) { 1314 | e.preventDefault(); 1315 | }; 1316 | /** 1317 | * Gesture stopPropagation 1318 | * @param {type} e 1319 | * @returns {undefined} 1320 | */ 1321 | $.stopPropagation = function(e) { 1322 | e.stopPropagation(); 1323 | }; 1324 | 1325 | /** 1326 | * register gesture 1327 | * @param {type} gesture 1328 | * @returns {$.gestures} 1329 | */ 1330 | $.addGesture = function(gesture) { 1331 | return $.addAction('gestures', gesture); 1332 | 1333 | }; 1334 | 1335 | var round = Math.round; 1336 | var abs = Math.abs; 1337 | var sqrt = Math.sqrt; 1338 | var atan = Math.atan; 1339 | var atan2 = Math.atan2; 1340 | /** 1341 | * distance 1342 | * @param {type} p1 1343 | * @param {type} p2 1344 | * @returns {Number} 1345 | */ 1346 | var getDistance = function(p1, p2, props) { 1347 | if (!props) { 1348 | props = ['x', 'y']; 1349 | } 1350 | var x = p2[props[0]] - p1[props[0]]; 1351 | var y = p2[props[1]] - p1[props[1]]; 1352 | return sqrt((x * x) + (y * y)); 1353 | }; 1354 | /** 1355 | * scale 1356 | * @param {Object} starts 1357 | * @param {Object} moves 1358 | */ 1359 | var getScale = function(starts, moves) { 1360 | if (starts.length >= 2 && moves.length >= 2) { 1361 | var props = ['pageX', 'pageY']; 1362 | return getDistance(moves[1], moves[0], props) / getDistance(starts[1], starts[0], props); 1363 | } 1364 | return 1; 1365 | }; 1366 | /** 1367 | * angle 1368 | * @param {type} p1 1369 | * @param {type} p2 1370 | * @returns {Number} 1371 | */ 1372 | var getAngle = function(p1, p2, props) { 1373 | if (!props) { 1374 | props = ['x', 'y']; 1375 | } 1376 | var x = p2[props[0]] - p1[props[0]]; 1377 | var y = p2[props[1]] - p1[props[1]]; 1378 | return atan2(y, x) * 180 / Math.PI; 1379 | }; 1380 | /** 1381 | * direction 1382 | * @param {Object} x 1383 | * @param {Object} y 1384 | */ 1385 | var getDirection = function(x, y) { 1386 | if (x === y) { 1387 | return ''; 1388 | } 1389 | if (abs(x) >= abs(y)) { 1390 | return x > 0 ? 'left' : 'right'; 1391 | } 1392 | return y > 0 ? 'up' : 'down'; 1393 | }; 1394 | /** 1395 | * rotation 1396 | * @param {Object} start 1397 | * @param {Object} end 1398 | */ 1399 | var getRotation = function(start, end) { 1400 | var props = ['pageX', 'pageY']; 1401 | return getAngle(end[1], end[0], props) - getAngle(start[1], start[0], props); 1402 | }; 1403 | /** 1404 | * px per ms 1405 | * @param {Object} deltaTime 1406 | * @param {Object} x 1407 | * @param {Object} y 1408 | */ 1409 | var getVelocity = function(deltaTime, x, y) { 1410 | return { 1411 | x: x / deltaTime || 0, 1412 | y: y / deltaTime || 0 1413 | }; 1414 | }; 1415 | /** 1416 | * detect gestures 1417 | * @param {type} event 1418 | * @param {type} touch 1419 | * @returns {undefined} 1420 | */ 1421 | var detect = function(event, touch) { 1422 | if ($.gestures.stoped) { 1423 | return; 1424 | } 1425 | $.doAction('gestures', function(index, gesture) { 1426 | if (!$.gestures.stoped) { 1427 | if ($.options.gestureConfig[gesture.name] !== false) { 1428 | gesture.handle(event, touch); 1429 | } 1430 | } 1431 | }); 1432 | }; 1433 | /** 1434 | * 暂时无用 1435 | * @param {Object} node 1436 | * @param {Object} parent 1437 | */ 1438 | var hasParent = function(node, parent) { 1439 | while (node) { 1440 | if (node == parent) { 1441 | return true; 1442 | } 1443 | node = node.parentNode; 1444 | } 1445 | return false; 1446 | }; 1447 | 1448 | var uniqueArray = function(src, key, sort) { 1449 | var results = []; 1450 | var values = []; 1451 | var i = 0; 1452 | 1453 | while (i < src.length) { 1454 | var val = key ? src[i][key] : src[i]; 1455 | if (values.indexOf(val) < 0) { 1456 | results.push(src[i]); 1457 | } 1458 | values[i] = val; 1459 | i++; 1460 | } 1461 | 1462 | if (sort) { 1463 | if (!key) { 1464 | results = results.sort(); 1465 | } else { 1466 | results = results.sort(function sortUniqueArray(a, b) { 1467 | return a[key] > b[key]; 1468 | }); 1469 | } 1470 | } 1471 | 1472 | return results; 1473 | }; 1474 | var getMultiCenter = function(touches) { 1475 | var touchesLength = touches.length; 1476 | if (touchesLength === 1) { 1477 | return { 1478 | x: round(touches[0].pageX), 1479 | y: round(touches[0].pageY) 1480 | }; 1481 | } 1482 | 1483 | var x = 0; 1484 | var y = 0; 1485 | var i = 0; 1486 | while (i < touchesLength) { 1487 | x += touches[i].pageX; 1488 | y += touches[i].pageY; 1489 | i++; 1490 | } 1491 | 1492 | return { 1493 | x: round(x / touchesLength), 1494 | y: round(y / touchesLength) 1495 | }; 1496 | }; 1497 | var multiTouch = function() { 1498 | return $.options.gestureConfig.pinch; 1499 | }; 1500 | var copySimpleTouchData = function(touch) { 1501 | var touches = []; 1502 | var i = 0; 1503 | while (i < touch.touches.length) { 1504 | touches[i] = { 1505 | pageX: round(touch.touches[i].pageX), 1506 | pageY: round(touch.touches[i].pageY) 1507 | }; 1508 | i++; 1509 | } 1510 | return { 1511 | timestamp: $.now(), 1512 | gesture: touch.gesture, 1513 | touches: touches, 1514 | center: getMultiCenter(touch.touches), 1515 | deltaX: touch.deltaX, 1516 | deltaY: touch.deltaY 1517 | }; 1518 | }; 1519 | 1520 | var calDelta = function(touch) { 1521 | var session = $.gestures.session; 1522 | var center = touch.center; 1523 | var offset = session.offsetDelta || {}; 1524 | var prevDelta = session.prevDelta || {}; 1525 | var prevTouch = session.prevTouch || {}; 1526 | 1527 | if (touch.gesture.type === $.EVENT_START || touch.gesture.type === $.EVENT_END) { 1528 | prevDelta = session.prevDelta = { 1529 | x: prevTouch.deltaX || 0, 1530 | y: prevTouch.deltaY || 0 1531 | }; 1532 | 1533 | offset = session.offsetDelta = { 1534 | x: center.x, 1535 | y: center.y 1536 | }; 1537 | } 1538 | touch.deltaX = prevDelta.x + (center.x - offset.x); 1539 | touch.deltaY = prevDelta.y + (center.y - offset.y); 1540 | }; 1541 | var calTouchData = function(touch) { 1542 | var session = $.gestures.session; 1543 | var touches = touch.touches; 1544 | var touchesLength = touches.length; 1545 | 1546 | if (!session.firstTouch) { 1547 | session.firstTouch = copySimpleTouchData(touch); 1548 | } 1549 | 1550 | if (multiTouch() && touchesLength > 1 && !session.firstMultiTouch) { 1551 | session.firstMultiTouch = copySimpleTouchData(touch); 1552 | } else if (touchesLength === 1) { 1553 | session.firstMultiTouch = false; 1554 | } 1555 | 1556 | var firstTouch = session.firstTouch; 1557 | var firstMultiTouch = session.firstMultiTouch; 1558 | var offsetCenter = firstMultiTouch ? firstMultiTouch.center : firstTouch.center; 1559 | 1560 | var center = touch.center = getMultiCenter(touches); 1561 | touch.timestamp = $.now(); 1562 | touch.deltaTime = touch.timestamp - firstTouch.timestamp; 1563 | 1564 | touch.angle = getAngle(offsetCenter, center); 1565 | touch.distance = getDistance(offsetCenter, center); 1566 | 1567 | calDelta(touch); 1568 | 1569 | touch.offsetDirection = getDirection(touch.deltaX, touch.deltaY); 1570 | 1571 | touch.scale = firstMultiTouch ? getScale(firstMultiTouch.touches, touches) : 1; 1572 | touch.rotation = firstMultiTouch ? getRotation(firstMultiTouch.touches, touches) : 0; 1573 | 1574 | calIntervalTouchData(touch); 1575 | 1576 | }; 1577 | var CAL_INTERVAL = 25; 1578 | var calIntervalTouchData = function(touch) { 1579 | var session = $.gestures.session; 1580 | var last = session.lastInterval || touch; 1581 | var deltaTime = touch.timestamp - last.timestamp; 1582 | var velocity; 1583 | var velocityX; 1584 | var velocityY; 1585 | var direction; 1586 | 1587 | if (touch.gesture.type != $.EVENT_CANCEL && (deltaTime > CAL_INTERVAL || last.velocity === undefined)) { 1588 | var deltaX = last.deltaX - touch.deltaX; 1589 | var deltaY = last.deltaY - touch.deltaY; 1590 | 1591 | var v = getVelocity(deltaTime, deltaX, deltaY); 1592 | velocityX = v.x; 1593 | velocityY = v.y; 1594 | velocity = (abs(v.x) > abs(v.y)) ? v.x : v.y; 1595 | direction = getDirection(deltaX, deltaY) || last.direction; 1596 | 1597 | session.lastInterval = touch; 1598 | } else { 1599 | velocity = last.velocity; 1600 | velocityX = last.velocityX; 1601 | velocityY = last.velocityY; 1602 | direction = last.direction; 1603 | } 1604 | 1605 | touch.velocity = velocity; 1606 | touch.velocityX = velocityX; 1607 | touch.velocityY = velocityY; 1608 | touch.direction = direction; 1609 | }; 1610 | var targetIds = {}; 1611 | var convertTouches = function(touches) { 1612 | for (var i = 0; i < touches.length; i++) { 1613 | !touches['identifier'] && (touches['identifier'] = 0); 1614 | } 1615 | return touches; 1616 | }; 1617 | var getTouches = function(event, touch) { 1618 | var allTouches = convertTouches($.slice.call(event.touches || [event])); 1619 | 1620 | var type = event.type; 1621 | 1622 | var targetTouches = []; 1623 | var changedTargetTouches = []; 1624 | 1625 | //当touchstart或touchmove且touches长度为1,直接获得all和changed 1626 | if ((type === $.EVENT_START || type === $.EVENT_MOVE) && allTouches.length === 1) { 1627 | targetIds[allTouches[0].identifier] = true; 1628 | targetTouches = allTouches; 1629 | changedTargetTouches = allTouches; 1630 | touch.target = event.target; 1631 | } else { 1632 | var i = 0; 1633 | var targetTouches = []; 1634 | var changedTargetTouches = []; 1635 | var changedTouches = convertTouches($.slice.call(event.changedTouches || [event])); 1636 | 1637 | touch.target = event.target; 1638 | var sessionTarget = $.gestures.session.target || event.target; 1639 | targetTouches = allTouches.filter(function(touch) { 1640 | return hasParent(touch.target, sessionTarget); 1641 | }); 1642 | 1643 | if (type === $.EVENT_START) { 1644 | i = 0; 1645 | while (i < targetTouches.length) { 1646 | targetIds[targetTouches[i].identifier] = true; 1647 | i++; 1648 | } 1649 | } 1650 | 1651 | i = 0; 1652 | while (i < changedTouches.length) { 1653 | if (targetIds[changedTouches[i].identifier]) { 1654 | changedTargetTouches.push(changedTouches[i]); 1655 | } 1656 | if (type === $.EVENT_END || type === $.EVENT_CANCEL) { 1657 | delete targetIds[changedTouches[i].identifier]; 1658 | } 1659 | i++; 1660 | } 1661 | 1662 | if (!changedTargetTouches.length) { 1663 | return false; 1664 | } 1665 | } 1666 | targetTouches = uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true); 1667 | var touchesLength = targetTouches.length; 1668 | var changedTouchesLength = changedTargetTouches.length; 1669 | if (type === $.EVENT_START && touchesLength - changedTouchesLength === 0) { //first 1670 | touch.isFirst = true; 1671 | $.gestures.touch = $.gestures.session = { 1672 | target: event.target 1673 | }; 1674 | } 1675 | touch.isFinal = ((type === $.EVENT_END || type === $.EVENT_CANCEL) && (touchesLength - changedTouchesLength === 0)); 1676 | 1677 | touch.touches = targetTouches; 1678 | touch.changedTouches = changedTargetTouches; 1679 | return true; 1680 | 1681 | }; 1682 | var handleTouchEvent = function(event) { 1683 | var touch = { 1684 | gesture: event 1685 | }; 1686 | var touches = getTouches(event, touch); 1687 | if (!touches) { 1688 | return; 1689 | } 1690 | calTouchData(touch); 1691 | detect(event, touch); 1692 | $.gestures.session.prevTouch = touch; 1693 | if (event.type === $.EVENT_END && !$.isTouchable) { 1694 | $.gestures.touch = $.gestures.session = {}; 1695 | } 1696 | }; 1697 | window.addEventListener($.EVENT_START, handleTouchEvent); 1698 | window.addEventListener($.EVENT_MOVE, handleTouchEvent); 1699 | window.addEventListener($.EVENT_END, handleTouchEvent); 1700 | window.addEventListener($.EVENT_CANCEL, handleTouchEvent); 1701 | //fixed hashchange(android) 1702 | window.addEventListener($.EVENT_CLICK, function(e) { 1703 | //TODO 应该判断当前target是不是在targets.popover内部,而不是非要相等 1704 | if (($.os.android || $.os.ios) && (($.targets.popover && e.target === $.targets.popover) || ($.targets.tab) || $.targets.offcanvas || $.targets.modal)) { 1705 | e.preventDefault(); 1706 | } 1707 | }, true); 1708 | 1709 | 1710 | //增加原生滚动识别 1711 | $.isScrolling = false; 1712 | var scrollingTimeout = null; 1713 | window.addEventListener('scroll', function() { 1714 | $.isScrolling = true; 1715 | scrollingTimeout && clearTimeout(scrollingTimeout); 1716 | scrollingTimeout = setTimeout(function() { 1717 | $.isScrolling = false; 1718 | }, 250); 1719 | }); 1720 | })(mui, window); 1721 | 1722 | 1723 | /** 1724 | * mui gesture tap and doubleTap 1725 | * @param {type} $ 1726 | * @param {type} name 1727 | * @returns {undefined} 1728 | */ 1729 | (function($, name) { 1730 | var lastTarget; 1731 | var lastTapTime; 1732 | var handle = function(event, touch) { 1733 | var session = $.gestures.session; 1734 | var options = this.options; 1735 | switch (event.type) { 1736 | case $.EVENT_END: 1737 | if (!touch.isFinal) { 1738 | return; 1739 | } 1740 | var target = session.target; 1741 | if (!target || (target.disabled || (target.classList && target.classList.contains($.className('disabled'))))) { 1742 | return; 1743 | } 1744 | if (touch.distance < options.tapMaxDistance && touch.deltaTime < options.tapMaxTime) { 1745 | if ($.options.gestureConfig.doubletap && lastTarget && (lastTarget === target)) { //same target 1746 | if (lastTapTime && (touch.timestamp - lastTapTime) < options.tapMaxInterval) { 1747 | $.trigger(target, 'doubletap', touch); 1748 | lastTapTime = $.now(); 1749 | lastTarget = target; 1750 | return; 1751 | } 1752 | } 1753 | $.trigger(target, name, touch); 1754 | lastTapTime = $.now(); 1755 | lastTarget = target; 1756 | } 1757 | break; 1758 | } 1759 | }; 1760 | /** 1761 | * mui gesture tap 1762 | */ 1763 | $.addGesture({ 1764 | name: name, 1765 | index: 30, 1766 | handle: handle, 1767 | options: { 1768 | fingers: 1, 1769 | tapMaxInterval: 300, 1770 | tapMaxDistance: 5, 1771 | tapMaxTime: 250 1772 | } 1773 | }); 1774 | })(mui, 'tap'); 1775 | 1776 | 1777 | export default mui; 1778 | --------------------------------------------------------------------------------