├── .DS_Store ├── .gitignore ├── LICENSE ├── README-en.md ├── README.md ├── city-data.js ├── dist ├── index.js └── picker.esm.js ├── example ├── .DS_Store ├── css │ └── app.279fbbfe.css ├── favicon.ico ├── index.html └── js │ ├── app.5d01ef29.js │ └── chunk-vendors.0ee7c3c1.js ├── index.js ├── lib └── vue-picker.js ├── package.json ├── rollup.config.js ├── src ├── city-data.js ├── header.vue ├── index.js ├── index.vue ├── list.vue ├── picker.vue ├── render.js └── utils.js ├── webpack.config.js └── yarn.lock /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naihe138/vue-picker/2aed086132dc327206cd19a9f67d1de8f1532500/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [2017] [naihe138] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README-en.md: -------------------------------------------------------------------------------- 1 | English | [中文](https://github.com/naihe138/vue-picker) 2 | 3 | A picker componemt for vue2.0 4 | ------ 5 | ![vue-pick.gif][1] 6 | 7 | 8 | ## Demo 9 | 10 | [https://naihe138.github.io/vue-picker/index.html][3] 11 | 12 | 13 | ## Install 14 | 15 | `npm install vue-pickers --save` or `yarn add vue-pickers` 16 | 17 | ## Use 18 | 19 | ````javascript 20 | 31 | 32 | 67 | ```` 68 | 69 | ## Attributes 70 | 71 | Attribute | Description | require | Type | Default 72 | ---- | --- | --- | --- | --- 73 | visible | show/hide picker | yes | Boolean | false 74 | data | pickerData,colums[data1, data2] | yes | Array | [] 75 | layer | linkage column | no | Number | 0 76 | defaultIndex | default index | no | Number/Array(for more colums) | 无 77 | cancelText | cancel text | no | String | '取消' 78 | confirmText | confirm text | no | String | '确认' 79 | title | picker title | no | String | '' 80 | showToolbar | show toolbar | no | Boolean | false 81 | maskClick | click mask | no | Boolean | false 82 | itemHeight | height of each row | no | Number, String | '44px' 83 | rowNumber | how many lines to display (singular number recommended) | no | Number | 5 84 | appendToBody | Insert into body | no | Boolean | false 85 | 86 | ## Events 87 | 88 | Event Name | Description | require | Type | Default 89 | ---- | --- | --- | --- | --- 90 | change | select change | no | function(val) | - 91 | cancel | cancel button click | no | function | - 92 | confirm | confirm button click | no | function(val) | - 93 | 94 | 95 | [1]: http://ypimg.naice.me/vue-picker.gif 96 | [3]: https://naihe138.github.io/vue-picker/index.html 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 中文 | [English](https://github.com/naihe138/vue-picker/blob/master/README-en.md) 2 | 3 | 4 | `vue-picker`的组件,囊括了(`普通选择`、`联动选择`、`中国地址选择`)等等常见的picker,兼容PC、移动端,通过简单配置就可以出现一个强大的picker,感受下效果图。 5 | 6 | 7 | ![vue-pick.gif][1] 8 | 9 | 10 | ## Demo(快点去复制代码体验一波吧) 11 | 12 | [https://naihe138.github.io/vue-picker/index.html][3] 13 | 14 | 15 | ## Install 16 | 17 | `npm install vue-pickers --save` or `yarn add vue-pickers` 18 | 19 | 20 | ## 使用 21 | 22 | > 普通网页开发直接复制lib/vue-picker.js文件夹到项目即可直接使用 23 | 24 | ````javascript 25 | 36 | 37 | 72 | ```` 73 | 74 | ## 属性参数说明 75 | 76 | 参数 | 说明 | 是否必须 | 类型 |默认值 77 | ---- | --- | --- | --- | --- 78 | visible | 显示/隐藏picker | 是 | Boolean | false 79 | data | pickerData,多列[data1, data2] | 是 | Array | [] 80 | layer | 联动显示列数 | 否 | Number | 0 81 | defaultIndex | 默认显示的index | 否 | Number/Array(多列用数组) | 无 82 | cancelText | 取消按钮文字 | 否 | String | '取消' 83 | confirmText | 去确认按钮文字 | 否 | String | '确认' 84 | title | picker标题 | 否 | String | '' 85 | showToolbar | 显示头部 | 否 | Boolean | false 86 | maskClick | 遮罩层是否可以点击关闭 | 否 | Boolean | false 87 | itemHeight | 每一行的高度 | 否 | Number, String | '44px' 88 | rowNumber | 显示多少行(建议单数) | 否 | Number | 5 89 | appendToBody | 是否插入到body中 | 否 | Boolean | false 90 | 91 | ## 事件说明 92 | 93 | 参数 | 说明 | 是否必须 | 类型 |默认值 94 | ---- | --- | --- | --- | --- 95 | change | 数据变化事件 | 否 | function(val) | 无 96 | cancel | 取消选择 | 否 | function | 无 97 | confirm | 确认选择 | 否 | function(val) | 无 98 | 99 | 100 | [1]: http://ypimg.naice.me/vue-picker.gif 101 | [3]: https://naihe138.github.io/vue-picker/index.html 102 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | import Picker from './picker.esm.js' 3 | 4 | if (typeof window !== 'undefined' && window.Vue) { 5 | window.Vue.component('vue-picker', Picker) 6 | } 7 | 8 | Picker.install = function(Vue){ 9 | Vue.component(Picker.name, Picker) 10 | } 11 | 12 | export default Picker 13 | -------------------------------------------------------------------------------- /dist/picker.esm.js: -------------------------------------------------------------------------------- 1 | import { normalizeComponent, createInjector } from 'vue-runtime-helpers'; 2 | 3 | // 4 | // 5 | // 6 | // 7 | // 8 | // 9 | // 10 | // 11 | // 12 | // 13 | // 14 | // 15 | 16 | // TODO: 支持自定义的render渲染 17 | // import textRender from './render' 18 | var script = { 19 | props: { 20 | cancelText: { 21 | type: String 22 | }, 23 | confirmText: { 24 | type: String 25 | }, 26 | title: { 27 | type: String 28 | } 29 | }, 30 | methods: { 31 | cancel () { 32 | this.$emit('cancel'); 33 | }, 34 | confirm () { 35 | this.$emit('confirm'); 36 | } 37 | } 38 | }; 39 | 40 | /* script */ 41 | const __vue_script__ = script; 42 | 43 | /* template */ 44 | var __vue_render__ = function() { 45 | var _vm = this; 46 | var _h = _vm.$createElement; 47 | var _c = _vm._self._c || _h; 48 | return _c("div", { staticClass: "header" }, [ 49 | _c("div", { staticClass: "left" }, [ 50 | _c("span", { staticClass: "btn", on: { click: _vm.cancel } }, [ 51 | _vm._v(_vm._s(_vm.cancelText)) 52 | ]) 53 | ]), 54 | _vm._v(" "), 55 | _c("div", { staticClass: "title" }, [_vm._v(_vm._s(_vm.title))]), 56 | _vm._v(" "), 57 | _c("div", { staticClass: "right" }, [ 58 | _c("span", { staticClass: "btn", on: { click: _vm.confirm } }, [ 59 | _vm._v(_vm._s(_vm.confirmText)) 60 | ]) 61 | ]) 62 | ]) 63 | }; 64 | var __vue_staticRenderFns__ = []; 65 | __vue_render__._withStripped = true; 66 | 67 | /* style */ 68 | const __vue_inject_styles__ = function (inject) { 69 | if (!inject) return 70 | inject("data-v-6ffe26b0_0", { source: ".header[data-v-6ffe26b0] {\n height: 44px;\n line-height: 44px;\n display: -webkit-box;\n display: flex;\n -webkit-box-pack: justify;\n justify-content: space-between;\n position: relative;\n}\n.header[data-v-6ffe26b0]::after {\n position: absolute;\n box-sizing: border-box;\n content: \" \";\n pointer-events: none;\n top: -50%;\n right: -50%;\n bottom: -50%;\n left: -50%;\n border: 0 solid #ebedf0;\n -webkit-transform: scale(0.5);\n transform: scale(0.5);\n border-width: 1px 0;\n}\n.title[data-v-6ffe26b0] {\n max-width: 50%;\n font-weight: 500;\n font-size: 16px;\n text-align: center;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.btn[data-v-6ffe26b0] {\n padding: 0 16px;\n color: #1989fa;\n font-size: 14px;\n background-color: transparent;\n}\n\n/*# sourceMappingURL=header.vue.map */", map: {"version":3,"sources":["/Users/naice/my-project/vue-picker/src/header.vue","header.vue"],"names":[],"mappings":"AAuCA;EACA,YAAA;EACA,iBAAA;EACA,oBAAA;EAAA,aAAA;EACA,yBAAA;UAAA,8BAAA;EACA,kBAAA;ACtCA;ADuCA;EACA,kBAAA;EACA,sBAAA;EACA,YAAA;EACA,oBAAA;EACA,SAAA;EACA,WAAA;EACA,YAAA;EACA,UAAA;EACA,uBAAA;EACA,6BAAA;UAAA,qBAAA;EACA,mBAAA;ACrCA;ADwCA;EACA,cAAA;EACA,gBAAA;EACA,eAAA;EACA,kBAAA;EACA,gBAAA;EACA,uBAAA;EACA,mBAAA;ACrCA;ADuCA;EACA,eAAA;EACA,cAAA;EACA,eAAA;EACA,6BAAA;ACpCA;;AAEA,qCAAqC","file":"header.vue","sourcesContent":["\n\n\n\n\n",".header {\n height: 44px;\n line-height: 44px;\n display: flex;\n justify-content: space-between;\n position: relative;\n}\n.header::after {\n position: absolute;\n box-sizing: border-box;\n content: \" \";\n pointer-events: none;\n top: -50%;\n right: -50%;\n bottom: -50%;\n left: -50%;\n border: 0 solid #ebedf0;\n transform: scale(0.5);\n border-width: 1px 0;\n}\n\n.title {\n max-width: 50%;\n font-weight: 500;\n font-size: 16px;\n text-align: center;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.btn {\n padding: 0 16px;\n color: #1989fa;\n font-size: 14px;\n background-color: transparent;\n}\n\n/*# sourceMappingURL=header.vue.map */"]}, media: undefined }); 71 | 72 | }; 73 | /* scoped */ 74 | const __vue_scope_id__ = "data-v-6ffe26b0"; 75 | /* module identifier */ 76 | const __vue_module_identifier__ = undefined; 77 | /* functional template */ 78 | const __vue_is_functional_template__ = false; 79 | /* style inject SSR */ 80 | 81 | /* style inject shadow dom */ 82 | 83 | 84 | 85 | var Header = normalizeComponent( 86 | { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ }, 87 | __vue_inject_styles__, 88 | __vue_script__, 89 | __vue_scope_id__, 90 | __vue_is_functional_template__, 91 | __vue_module_identifier__, 92 | false, 93 | createInjector, 94 | undefined, 95 | undefined 96 | ); 97 | 98 | const DEFTAULT_ITEM_HEIGHT = 44; 99 | 100 | // 兼容pc 移动端 101 | const HAS_TOUCH = 'ontouchstart' in window; 102 | const START_EVENT = HAS_TOUCH ? 'touchstart' : 'mousedown'; 103 | const MOVE_EVENT = HAS_TOUCH ? 'touchmove' : 'mousemove'; 104 | const END_EVENT = HAS_TOUCH ? 'touchend' : 'mouseup'; 105 | 106 | const getClient = e => { 107 | let clientX = HAS_TOUCH ? e.changedTouches[0].clientX : e.clientX; 108 | let clientY = HAS_TOUCH ? e.changedTouches[0].clientY : e.clientY; 109 | return { 110 | x: clientX, 111 | y: clientY 112 | } 113 | }; 114 | const isPC = () => { 115 | const userAgentInfo = navigator.userAgent; 116 | const Agents = ['Android', 'iPhone', 'SymbianOS', 'Windows Phone', 'iPad', 'iPod']; 117 | let flag = true; 118 | for (var v = 0; v < Agents.length; v++) { 119 | if (userAgentInfo.indexOf(Agents[v]) > 0) { 120 | flag = false; 121 | break 122 | } 123 | } 124 | return flag 125 | }; 126 | 127 | // 128 | const DEFAULT_DURATION = 200; 129 | // 惯性滑动思路: 130 | // 在手指离开屏幕时,如果和上一次 move 时的间隔小于 `LIMIT_TIME` 且 move 131 | // 距离大于 `LIMIT_DISTANCE` 时,执行惯性滑动 132 | const LIMIT_TIME = 300; 133 | const LIMIT_DISTANCE = 15; 134 | const IS_PC = isPC(); 135 | var script$1 = { 136 | props: { 137 | defaultIndex: { 138 | type: Number, 139 | default: 0 140 | }, 141 | column: { 142 | type: Array, 143 | default: () => ([]) 144 | }, 145 | boxHeight: Number, 146 | itemHeight: Number, 147 | rowNumber: Number 148 | }, 149 | data() { 150 | return { 151 | ulStyle: { 152 | transform: `translate3d(0px, 0px, 0px)`, 153 | transitionDuration: `0ms`, 154 | transitionProperty: `none`, 155 | lineHeight: `${this.itemHeight}px` 156 | } 157 | } 158 | }, 159 | computed: { 160 | count() { 161 | return this.column.length 162 | }, 163 | getRoNumber() { 164 | return Math.floor(this.rowNumber / 2) 165 | } 166 | }, 167 | methods: { 168 | init () { 169 | this.setTop(this.defaultIndex); 170 | const halfBox = (this.boxHeight - this.itemHeight) / 2; 171 | this.bottom = halfBox + this.itemHeight; 172 | this.top = halfBox - this.count * this.itemHeight; 173 | }, 174 | // 根据index 设置滚动位置 175 | setTop (index = 0) { 176 | const { boxHeight, itemHeight } = this; 177 | this.startTop = ((boxHeight - itemHeight) / 2) - (index * itemHeight); 178 | this.ulStyle.transform = `translate3d(0px, ${this.startTop}px, 0px)`; 179 | this.selectIndex = index; 180 | this.change(); 181 | }, 182 | handleStart (e) { 183 | this.distStartTop = getClient(e).y; 184 | this.touchStartTime = Date.now(); 185 | // ---- 186 | this.startY = getClient(e).y; 187 | this.momentumTop = this.startTop; 188 | 189 | this.ulStyle.transitionDuration = `0ms`; 190 | this.ulStyle.transitionProperty = `none`; 191 | if (IS_PC) { 192 | document.addEventListener(MOVE_EVENT, this.handleMove, false); 193 | document.addEventListener(END_EVENT, this.handleEnd, false); 194 | } 195 | }, 196 | handleMove (e) { 197 | e.preventDefault(); 198 | e.stopPropagation(); 199 | this.disY = getClient(e).y - this.startY; 200 | this.startY = getClient(e).y; 201 | if (this.startTop >= this.bottom) { 202 | this.startTop = this.bottom; 203 | } else if (this.startTop <= this.top) { 204 | this.startTop = this.top; 205 | } else { 206 | this.startTop += this.disY; 207 | } 208 | this.ulStyle.transform = `translate3d(0px, ${this.startTop}px, 0px)`; 209 | const now = Date.now(); 210 | 211 | if (now - this.touchStartTime > LIMIT_TIME) { 212 | this.touchStartTime = now; 213 | this.momentumTop = this.startTop; 214 | } 215 | }, 216 | handleEnd () { 217 | if (IS_PC) { 218 | document.removeEventListener(MOVE_EVENT, this.handleMove, false); 219 | document.removeEventListener(END_EVENT, this.handleEnd, false); 220 | } 221 | const distance = this.startTop - this.momentumTop; 222 | const duration = Date.now() - this.touchStartTime; 223 | const allowMomentum = duration < LIMIT_TIME && Math.abs(distance) > LIMIT_DISTANCE; 224 | if (allowMomentum) { 225 | this.toMove(distance, duration); 226 | } else { 227 | this.setTranfromTop(); 228 | } 229 | }, 230 | setTranfromTop () { 231 | this.ulStyle.transitionProperty = `all`; 232 | this.ulStyle.transitionDuration = `${DEFAULT_DURATION}ms`; 233 | if (this.startTop >= this.bottom - this.itemHeight) { 234 | this.setTop(); 235 | } else if (this.startTop <= this.top + this.itemHeight) { 236 | this.setTop(this.count - 1); 237 | } else { 238 | let index = Math.round((this.startTop) / this.itemHeight); 239 | this.startTop = index * this.itemHeight; 240 | if (this.startTop > this.bottom) { 241 | this.startTop = this.bottom - this.itemHeight; 242 | index = -this.getRoNumber; 243 | } else if (this.startTop < this.top) { 244 | this.startTop = this.top + this.itemHeight; 245 | index = this.count + 1; 246 | } 247 | this.ulStyle.transform = `translate3d(0px, ${this.startTop}px, 0px)`; 248 | index = this.getRoNumber - index; 249 | if (this.selectIndex !== index) { 250 | this.selectIndex = index; 251 | this.change(); 252 | } 253 | } 254 | }, 255 | toMove (distance, duration) { 256 | const speed = Math.abs(distance / duration); 257 | distance = this.startTop + (speed / 0.002) * (distance < 0 ? -1 : 1); 258 | this.ulStyle.transitionProperty = `all`; 259 | this.ulStyle.transitionDuration = `1000ms`; 260 | this.setTop(Math.min(Math.max(Math.round(-distance / this.itemHeight), 0), this.count - 1)); 261 | }, 262 | change () { 263 | this.$emit('change', this.column[this.selectIndex]); 264 | }, 265 | mousewheel (e) { 266 | e.preventDefault(); 267 | e.stopPropagation(); 268 | this.ulStyle.transitionDuration = `0ms`; 269 | this.ulStyle.transitionProperty = `none`; 270 | const { deltaX, deltaY } = e; 271 | if (Math.abs(deltaX) < Math.abs(deltaY)) { 272 | this.startTop = this.startTop - deltaY; 273 | let b = this.bottom - this.itemHeight; 274 | let t = this.top + this.itemHeight; 275 | let shouldMove = true; 276 | if (this.startTop > b ) { 277 | this.startTop = b; 278 | shouldMove = false; 279 | } else if (this.startTop < t) { 280 | this.startTop = t; 281 | shouldMove = false; 282 | } 283 | this.ulStyle.transform = `translate3d(0px, ${this.startTop}px, 0px)`; 284 | if (shouldMove) { 285 | clearInterval(this.wheelTimer); 286 | this.wheelTimer = setTimeout(this.setTranfromTop, 100); 287 | } 288 | } 289 | } 290 | }, 291 | mounted () { 292 | this.init(); 293 | // 监听开始事件 294 | this.$el.addEventListener(START_EVENT, this.handleStart, false); 295 | if (IS_PC) { 296 | this.$el.addEventListener('wheel', this.mousewheel, false); 297 | } else { 298 | this.$el.addEventListener(MOVE_EVENT, this.handleMove, false); 299 | this.$el.addEventListener(END_EVENT, this.handleEnd, false); 300 | } 301 | }, 302 | watch: { 303 | column () { 304 | this.init(); 305 | }, 306 | defaultIndex () { 307 | this.setTop(this.defaultIndex); 308 | } 309 | }, 310 | beforeDestroy () { 311 | this.$el.removeEventListener(START_EVENT, this.handleStart, false); 312 | if (IS_PC) { 313 | this.$el.removeEventListener('wheel', this.mousewheel, false); 314 | this.$el.removeEventListener(MOVE_EVENT, this.handleMove, false); 315 | this.$el.removeEventListener(END_EVENT, this.handleEnd, false); 316 | } 317 | } 318 | }; 319 | 320 | /* script */ 321 | const __vue_script__$1 = script$1; 322 | 323 | /* template */ 324 | var __vue_render__$1 = function() { 325 | var _vm = this; 326 | var _h = _vm.$createElement; 327 | var _c = _vm._self._c || _h; 328 | return _c("div", { ref: "list", staticClass: "list" }, [ 329 | _c( 330 | "ul", 331 | { style: _vm.ulStyle }, 332 | _vm._l(_vm.column, function(item, index) { 333 | return _c("li", { key: "item" + index }, [_vm._v(_vm._s(item.label))]) 334 | }), 335 | 0 336 | ) 337 | ]) 338 | }; 339 | var __vue_staticRenderFns__$1 = []; 340 | __vue_render__$1._withStripped = true; 341 | 342 | /* style */ 343 | const __vue_inject_styles__$1 = function (inject) { 344 | if (!inject) return 345 | inject("data-v-ec129ff4_0", { source: ".list[data-v-ec129ff4] {\n margin: 0;\n padding: 0;\n -webkit-box-flex: 1;\n flex: 1;\n width: 100%;\n height: 100%;\n overflow: hidden;\n}\n.list ul[data-v-ec129ff4] {\n margin: 0;\n padding: 0;\n -webkit-transition-timing-function: cubic-bezier(0.23, 1, 0.68, 1);\n transition-timing-function: cubic-bezier(0.23, 1, 0.68, 1);\n line-height: 44px;\n}\n.list li[data-v-ec129ff4] {\n margin: 0;\n padding: 0;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n padding: 0 5px;\n color: #000;\n}\n\n/*# sourceMappingURL=list.vue.map */", map: {"version":3,"sources":["/Users/naice/my-project/vue-picker/src/list.vue","list.vue"],"names":[],"mappings":"AA4MA;EACA,SAAA;EACA,UAAA;EACA,mBAAA;UAAA,OAAA;EACA,WAAA;EACA,YAAA;EACA,gBAAA;AC3MA;AD4MA;EACA,SAAA;EACA,UAAA;EACA,kEAAA;UAAA,0DAAA;EACA,iBAAA;AC1MA;AD4MA;EACA,SAAA;EACA,UAAA;EACA,gBAAA;EACA,mBAAA;EACA,uBAAA;EACA,cAAA;EACA,WAAA;AC1MA;;AAEA,mCAAmC","file":"list.vue","sourcesContent":["\n\n\n\n\n",".list {\n margin: 0;\n padding: 0;\n flex: 1;\n width: 100%;\n height: 100%;\n overflow: hidden;\n}\n.list ul {\n margin: 0;\n padding: 0;\n transition-timing-function: cubic-bezier(0.23, 1, 0.68, 1);\n line-height: 44px;\n}\n.list li {\n margin: 0;\n padding: 0;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n padding: 0 5px;\n color: #000;\n}\n\n/*# sourceMappingURL=list.vue.map */"]}, media: undefined }); 346 | 347 | }; 348 | /* scoped */ 349 | const __vue_scope_id__$1 = "data-v-ec129ff4"; 350 | /* module identifier */ 351 | const __vue_module_identifier__$1 = undefined; 352 | /* functional template */ 353 | const __vue_is_functional_template__$1 = false; 354 | /* style inject SSR */ 355 | 356 | /* style inject shadow dom */ 357 | 358 | 359 | 360 | var List = normalizeComponent( 361 | { render: __vue_render__$1, staticRenderFns: __vue_staticRenderFns__$1 }, 362 | __vue_inject_styles__$1, 363 | __vue_script__$1, 364 | __vue_scope_id__$1, 365 | __vue_is_functional_template__$1, 366 | __vue_module_identifier__$1, 367 | false, 368 | createInjector, 369 | undefined, 370 | undefined 371 | ); 372 | 373 | // 374 | var script$2 = { 375 | name: 'VuePicker', 376 | props: { 377 | visible: { 378 | type: Boolean, 379 | default: false 380 | }, 381 | data: { 382 | type: Array, 383 | default: () => [] 384 | }, 385 | layer: { 386 | type: Number, 387 | default: 0 388 | }, 389 | itemHeight: { 390 | type: [Number, String], 391 | default: DEFTAULT_ITEM_HEIGHT 392 | }, 393 | defaultIndex: { 394 | type: [Number, Array], 395 | default: 0 396 | }, 397 | cancelText: { 398 | type: String, 399 | default: '取消' 400 | }, 401 | confirmText: { 402 | type: String, 403 | default: '确认' 404 | }, 405 | title: { 406 | type: String, 407 | default: '' 408 | }, 409 | showToolbar: { 410 | type: Boolean, 411 | default: false 412 | }, 413 | maskClick: { 414 | type: Boolean, 415 | default: false 416 | }, 417 | rowNumber: { 418 | type: Number, 419 | default: 5 420 | }, 421 | appendToBody: { 422 | type: Boolean, 423 | default: false 424 | } 425 | }, 426 | components: { 427 | Header, 428 | List 429 | }, 430 | data () { 431 | return { 432 | column1: [], 433 | column2: [], 434 | column3: [], 435 | column4: [], 436 | dIndex1: 0, 437 | dIndex2: 0, 438 | dIndex3: 0, 439 | dIndex4: 0 440 | } 441 | }, 442 | computed: { 443 | boxHeight () { 444 | let itemHeight = parseInt(this.itemHeight); 445 | itemHeight = itemHeight ? itemHeight : DEFTAULT_ITEM_HEIGHT; 446 | return itemHeight * this.getRowNumber 447 | }, 448 | getRowNumber () { 449 | if (this.rowNumber < 3) { 450 | return 3 451 | } 452 | return this.rowNumber % 2 === 0 ? this.rowNumber + 1 : this.rowNumber 453 | }, 454 | maskStyle() { 455 | let style = { backgroundSize: '100% 88px' }; 456 | if (this.getRowNumber === 3) { 457 | style = { backgroundSize: '100% 44px' }; 458 | } 459 | return style 460 | } 461 | }, 462 | methods: { 463 | clickMask () { 464 | if (this.maskClick) { 465 | this.looseBody(); 466 | this.$emit('update:visible', false); 467 | } 468 | }, 469 | formateData () { 470 | if (this.layer > 1) { 471 | this.setLinkColumn(); 472 | } else { 473 | this.column1 = this.data[0] || []; 474 | this.column2 = this.data[1] || []; 475 | this.column3 = this.data[2] || []; 476 | this.column4 = this.data[3] || []; 477 | this.setNormalIndex(); 478 | } 479 | }, 480 | setLinkColumn () { 481 | if (this.layer === 2) { 482 | this.setLinkLayer2(); 483 | } else if (this.layer === 3) { 484 | this.setLinkLayer2(); 485 | this.setLinkLayer3(); 486 | } else if (this.layer === 4) { 487 | this.setLinkLayer2(); 488 | this.setLinkLayer3(); 489 | this.setLinkLayer4(); 490 | } 491 | }, 492 | setLinkLayer2 () { 493 | const { defaultIndex } = this; 494 | this.column1 = this.data || []; 495 | if (typeof defaultIndex === 'number') { 496 | this.dIndex1 = defaultIndex; 497 | this.dIndex2 = 0; 498 | if (this.data.length > 1 && this.data[0].children) { 499 | this.column2 = this.data[0].children || []; 500 | } 501 | } else if (Array.isArray(defaultIndex) && defaultIndex.length > 0){ 502 | this.dIndex1 = defaultIndex[0] || 0; 503 | this.column2 = this.data[this.dIndex1].children || []; 504 | this.$nextTick(() => { 505 | if (this.column2.length - 1 < defaultIndex[1]) { 506 | this.dIndex2 = this.column2.length - 1; 507 | } else { 508 | this.dIndex2 = defaultIndex[1] || 0; 509 | } 510 | }); 511 | } 512 | }, 513 | setLinkLayer3 () { 514 | const { defaultIndex } = this; 515 | if (typeof defaultIndex === 'number') { 516 | this.dIndex3 = 0; 517 | if (this.column2.length > 1 && this.column2[0].children) { 518 | this.column3 = this.column2[0].children || []; 519 | } 520 | } else if (Array.isArray(defaultIndex) && defaultIndex.length > 1){ 521 | this.$nextTick(() => { 522 | this.column3 = this.column2[this.dIndex2].children || []; 523 | this.$nextTick(() => { 524 | if (this.column3.length - 1 < defaultIndex[2]) { 525 | this.dIndex3 = this.column3.length - 1; 526 | } else { 527 | this.dIndex3 = defaultIndex[2] || 0; 528 | } 529 | }); 530 | }); 531 | } 532 | }, 533 | setLinkLayer4 () { 534 | const { defaultIndex } = this; 535 | if (typeof defaultIndex === 'number') { 536 | this.dIndex4 = 0; 537 | if (this.column3.length > 1 && this.column3[0].children) { 538 | this.column4 = this.column3[0].children || []; 539 | } 540 | } else if (Array.isArray(defaultIndex) && defaultIndex.length > 2){ 541 | setTimeout(() => { 542 | this.column4 = this.column3[this.dIndex3].children || []; 543 | this.$nextTick(() => { 544 | if (this.column4.length - 1 < defaultIndex[3]) { 545 | this.dIndex4 = this.column4.length - 1; 546 | } else { 547 | this.dIndex4 = defaultIndex[3] || 0; 548 | } 549 | }); 550 | }); 551 | } 552 | }, 553 | setNormalIndex () { 554 | this.$nextTick(() => { 555 | const { defaultIndex } = this; 556 | if (Array.isArray(defaultIndex)) { 557 | this.setDefaultIndex(); 558 | } else { 559 | this.dIndex1 = Number(defaultIndex) || 0; 560 | } 561 | }); 562 | }, 563 | setDefaultIndex () { 564 | const { indexArr } = this; 565 | const self = this; 566 | function next() { 567 | let promise = Promise.resolve(); 568 | let index = 0; 569 | while (index < self.data.length) { 570 | promise = promise.then(indexArr[index]); 571 | index++; 572 | } 573 | } 574 | next(); 575 | }, 576 | change (index, res) { 577 | this.result[index] = res; 578 | this.$emit('change', this.result); 579 | }, 580 | change1 (res) { 581 | if (res) { 582 | this.change(0, res); 583 | if (this.layer > 1) { 584 | this.dIndex2 = 0; 585 | this.changeLink('column2', res); 586 | } 587 | } 588 | }, 589 | change2 (res) { 590 | if (res) { 591 | this.change(1, res); 592 | if (this.layer > 2) { 593 | this.dIndex3 = 0; 594 | this.changeLink('column3', res); 595 | } 596 | } 597 | }, 598 | change3 (res) { 599 | if (res) { 600 | this.change(2, res); 601 | if (this.layer > 3) { 602 | this.dIndex4 = 0; 603 | this.changeLink('column4', res); 604 | } 605 | } 606 | }, 607 | change4 (res) { 608 | if (res) { 609 | this.change(3, res); 610 | } 611 | }, 612 | changeLink (key, res) { 613 | if (this.layer) { 614 | // clearTimeout(this.linktimer) 615 | this.linktimer = setTimeout(() => { 616 | this[key] = res.children || []; 617 | }, 1000 / 60); 618 | } 619 | }, 620 | cancel () { 621 | this.looseBody(); 622 | this.$emit('cancel'); 623 | this.$emit('update:visible', false); 624 | }, 625 | confirm () { 626 | this.looseBody(); 627 | this.$emit('confirm', this.result); 628 | this.$emit('update:visible', false); 629 | }, 630 | stopPropagation (e) { 631 | e.stopPropagation(); 632 | }, 633 | fixedBody() { 634 | const scrollTop = document.body.scrollTop || document.documentElement.scrollTop; 635 | this.prevBodyCss = document.body.style.cssText; 636 | document.body.style.cssText += 'position:fixed;width:100%;top:-' + scrollTop + 'px;'; 637 | }, 638 | looseBody() { 639 | const body = document.body; 640 | const top = body.style.top; 641 | body.style.cssText = this.prevBodyCss; 642 | body.scrollTop = document.documentElement.scrollTop = -parseInt(top); 643 | body.style.top = ''; 644 | }, 645 | init() { 646 | this.result = []; 647 | this.indexArr = [ 648 | () => this.dIndex1 = this.defaultIndex[0] || 0, 649 | () => this.dIndex2 = this.defaultIndex[1] || 0, 650 | () => this.dIndex3 = this.defaultIndex[2] || 0, 651 | () => this.dIndex4 = this.defaultIndex[3] || 0 652 | ]; 653 | this.formateData(); 654 | } 655 | }, 656 | created () { 657 | this.init(); 658 | }, 659 | mounted () { 660 | this.$refs.picker.addEventListener('click', this.stopPropagation); 661 | if (this.appendToBody) { 662 | document.body.appendChild(this.$el); 663 | } 664 | }, 665 | watch: { 666 | visible (v) { 667 | if (v) { 668 | this.fixedBody(); 669 | } 670 | }, 671 | defaultIndex () { 672 | this.init(); 673 | }, 674 | data() { 675 | this.init(); 676 | } 677 | }, 678 | beforeDestroy () { 679 | this.$refs.picker.removeEventListener('click', this.stopPropagation); 680 | } 681 | }; 682 | 683 | /* script */ 684 | const __vue_script__$2 = script$2; 685 | 686 | /* template */ 687 | var __vue_render__$2 = function() { 688 | var _vm = this; 689 | var _h = _vm.$createElement; 690 | var _c = _vm._self._c || _h; 691 | return _c("transition", { attrs: { name: "fade" } }, [ 692 | _c( 693 | "div", 694 | { 695 | directives: [ 696 | { 697 | name: "show", 698 | rawName: "v-show", 699 | value: _vm.visible, 700 | expression: "visible" 701 | } 702 | ], 703 | staticClass: "pickerbox", 704 | on: { click: _vm.clickMask } 705 | }, 706 | [ 707 | _c("transition", { attrs: { name: "toup" } }, [ 708 | _c( 709 | "div", 710 | { 711 | directives: [ 712 | { 713 | name: "show", 714 | rawName: "v-show", 715 | value: _vm.visible, 716 | expression: "visible" 717 | } 718 | ], 719 | ref: "picker", 720 | staticClass: "vue-picker" 721 | }, 722 | [ 723 | _vm.showToolbar 724 | ? _c("Header", { 725 | attrs: { 726 | cancelText: _vm.cancelText, 727 | confirmText: _vm.confirmText, 728 | title: _vm.title 729 | }, 730 | on: { cancel: _vm.cancel, confirm: _vm.confirm } 731 | }) 732 | : _vm._e(), 733 | _vm._v(" "), 734 | _c( 735 | "div", 736 | { 737 | staticClass: "content", 738 | style: { height: _vm.boxHeight + "px" } 739 | }, 740 | [ 741 | _c( 742 | "div", 743 | { staticClass: "colums" }, 744 | [ 745 | _c("List", { 746 | attrs: { 747 | column: _vm.column1, 748 | boxHeight: _vm.boxHeight, 749 | itemHeight: _vm.itemHeight, 750 | defaultIndex: _vm.dIndex1, 751 | rowNumber: _vm.getRowNumber 752 | }, 753 | on: { change: _vm.change1 } 754 | }), 755 | _vm._v(" "), 756 | _vm.column2.length > 0 757 | ? _c("List", { 758 | attrs: { 759 | column: _vm.column2, 760 | boxHeight: _vm.boxHeight, 761 | itemHeight: _vm.itemHeight, 762 | defaultIndex: _vm.dIndex2, 763 | rowNumber: _vm.getRowNumber 764 | }, 765 | on: { change: _vm.change2 } 766 | }) 767 | : _vm._e(), 768 | _vm._v(" "), 769 | _vm.column3.length > 0 770 | ? _c("List", { 771 | attrs: { 772 | column: _vm.column3, 773 | boxHeight: _vm.boxHeight, 774 | itemHeight: _vm.itemHeight, 775 | defaultIndex: _vm.dIndex3, 776 | rowNumber: _vm.getRowNumber 777 | }, 778 | on: { change: _vm.change3 } 779 | }) 780 | : _vm._e(), 781 | _vm._v(" "), 782 | _vm.column4.length > 0 783 | ? _c("List", { 784 | attrs: { 785 | column: _vm.column4, 786 | boxHeight: _vm.boxHeight, 787 | itemHeight: _vm.itemHeight, 788 | defaultIndex: _vm.dIndex4, 789 | rowNumber: _vm.getRowNumber 790 | }, 791 | on: { change: _vm.change4 } 792 | }) 793 | : _vm._e() 794 | ], 795 | 1 796 | ), 797 | _vm._v(" "), 798 | _c("div", { staticClass: "mask", style: _vm.maskStyle }), 799 | _vm._v(" "), 800 | _c("div", { staticClass: "hairline" }) 801 | ] 802 | ) 803 | ], 804 | 1 805 | ) 806 | ]) 807 | ], 808 | 1 809 | ) 810 | ]) 811 | }; 812 | var __vue_staticRenderFns__$2 = []; 813 | __vue_render__$2._withStripped = true; 814 | 815 | /* style */ 816 | const __vue_inject_styles__$2 = function (inject) { 817 | if (!inject) return 818 | inject("data-v-176a7813_0", { source: ".pickerbox[data-v-176a7813] {\n position: fixed;\n width: 100vw;\n height: 100vh;\n left: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.7);\n z-index: 9999;\n overflow: hidden;\n}\n.fade-enter-active[data-v-176a7813], .fade-leave-active[data-v-176a7813] {\n -webkit-transition: opacity 0.2s;\n transition: opacity 0.2s;\n}\n.fade-enter[data-v-176a7813], .fade-leave-to[data-v-176a7813] {\n opacity: 0;\n}\n.toup-enter-active[data-v-176a7813], .toup-leave-active[data-v-176a7813] {\n -webkit-transition: -webkit-transform 0.3s;\n transition: -webkit-transform 0.3s;\n transition: transform 0.3s;\n transition: transform 0.3s, -webkit-transform 0.3s;\n}\n.toup-enter[data-v-176a7813], .toup-leave-to[data-v-176a7813] {\n -webkit-transform: translate3d(0, 100px, 0);\n transform: translate3d(0, 100px, 0);\n}\n.vue-picker[data-v-176a7813] {\n position: absolute;\n left: 0;\n bottom: 0;\n width: 100%;\n background-color: #fff;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n -webkit-text-size-adjust: 100%;\n -webkit-tap-highlight-color: transparent;\n display: block;\n}\n.content[data-v-176a7813] {\n overflow: hidden;\n height: 220px;\n position: relative;\n display: -webkit-box;\n display: flex;\n}\n.colums[data-v-176a7813] {\n display: -webkit-box;\n display: flex;\n overflow: hidden;\n font-size: 16px;\n text-align: center;\n -webkit-box-flex: 1;\n flex: 1;\n}\n.mask[data-v-176a7813] {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 2;\n width: 100%;\n height: 100%;\n background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(255, 255, 255, 0.9)), to(rgba(255, 255, 255, 0.4))), -webkit-gradient(linear, left bottom, left top, from(rgba(255, 255, 255, 0.9)), to(rgba(255, 255, 255, 0.4)));\n background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.4)), linear-gradient(0deg, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.4));\n background-repeat: no-repeat;\n background-position: top, bottom;\n -webkit-backface-visibility: hidden;\n backface-visibility: hidden;\n pointer-events: none;\n background-size: 100% 88px;\n}\n.hairline[data-v-176a7813] {\n position: absolute;\n top: 50%;\n left: 0;\n z-index: 3;\n width: 100%;\n -webkit-transform: translateY(-50%);\n transform: translateY(-50%);\n pointer-events: none;\n height: 44px;\n}\n.hairline[data-v-176a7813]::after {\n position: absolute;\n box-sizing: border-box;\n content: \" \";\n pointer-events: none;\n top: -50%;\n right: -50%;\n bottom: -50%;\n left: -50%;\n border: 0 solid #ebedf0;\n -webkit-transform: scale(0.5);\n transform: scale(0.5);\n border-width: 1px 0;\n}\n\n/*# sourceMappingURL=index.vue.map */", map: {"version":3,"sources":["/Users/naice/my-project/vue-picker/src/index.vue","index.vue"],"names":[],"mappings":"AA2WA;EACA,eAAA;EACA,YAAA;EACA,aAAA;EACA,OAAA;EACA,SAAA;EACA,8BAAA;EACA,aAAA;EACA,gBAAA;AC1WA;AD4WA;EACA,gCAAA;EAAA,wBAAA;ACzWA;AD2WA;EACA,UAAA;ACxWA;AD0WA;EACA,0CAAA;EAAA,kCAAA;EAAA,0BAAA;EAAA,kDAAA;ACvWA;ADyWA;EACA,2CAAA;UAAA,mCAAA;ACtWA;ADyWA;EACA,kBAAA;EACA,OAAA;EACA,SAAA;EACA,WAAA;EACA,sBAAA;EACA,yBAAA;KAAA,sBAAA;MAAA,qBAAA;UAAA,iBAAA;EACA,8BAAA;EACA,wCAAA;EACA,cAAA;ACtWA;ADwWA;EACA,gBAAA;EACA,aAAA;EACA,kBAAA;EACA,oBAAA;EAAA,aAAA;ACrWA;ADuWA;EACA,oBAAA;EAAA,aAAA;EACA,gBAAA;EACA,eAAA;EACA,kBAAA;EACA,mBAAA;UAAA,OAAA;ACpWA;ADsWA;EACA,kBAAA;EACA,MAAA;EACA,OAAA;EACA,UAAA;EACA,WAAA;EACA,YAAA;EACA,8OAAA;EAAA,wKAAA;EACA,4BAAA;EACA,gCAAA;EACA,mCAAA;UAAA,2BAAA;EACA,oBAAA;EACA,0BAAA;ACnWA;ADqWA;EACA,kBAAA;EACA,QAAA;EACA,OAAA;EACA,UAAA;EACA,WAAA;EACA,mCAAA;UAAA,2BAAA;EACA,oBAAA;EACA,YAAA;AClWA;ADmWA;EACA,kBAAA;EACA,sBAAA;EACA,YAAA;EACA,oBAAA;EACA,SAAA;EACA,WAAA;EACA,YAAA;EACA,UAAA;EACA,uBAAA;EACA,6BAAA;EACA,qBAAA;EACA,mBAAA;ACjWA;;AAEA,oCAAoC","file":"index.vue","sourcesContent":["\n\n\n",".pickerbox {\n position: fixed;\n width: 100vw;\n height: 100vh;\n left: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.7);\n z-index: 9999;\n overflow: hidden;\n}\n\n.fade-enter-active, .fade-leave-active {\n transition: opacity 0.2s;\n}\n\n.fade-enter, .fade-leave-to {\n opacity: 0;\n}\n\n.toup-enter-active, .toup-leave-active {\n transition: transform 0.3s;\n}\n\n.toup-enter, .toup-leave-to {\n transform: translate3d(0, 100px, 0);\n}\n\n.vue-picker {\n position: absolute;\n left: 0;\n bottom: 0;\n width: 100%;\n background-color: #fff;\n user-select: none;\n -webkit-text-size-adjust: 100%;\n -webkit-tap-highlight-color: transparent;\n display: block;\n}\n\n.content {\n overflow: hidden;\n height: 220px;\n position: relative;\n display: flex;\n}\n\n.colums {\n display: flex;\n overflow: hidden;\n font-size: 16px;\n text-align: center;\n flex: 1;\n}\n\n.mask {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 2;\n width: 100%;\n height: 100%;\n background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.4)), linear-gradient(0deg, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.4));\n background-repeat: no-repeat;\n background-position: top, bottom;\n backface-visibility: hidden;\n pointer-events: none;\n background-size: 100% 88px;\n}\n\n.hairline {\n position: absolute;\n top: 50%;\n left: 0;\n z-index: 3;\n width: 100%;\n transform: translateY(-50%);\n pointer-events: none;\n height: 44px;\n}\n.hairline::after {\n position: absolute;\n box-sizing: border-box;\n content: \" \";\n pointer-events: none;\n top: -50%;\n right: -50%;\n bottom: -50%;\n left: -50%;\n border: 0 solid #ebedf0;\n -webkit-transform: scale(0.5);\n transform: scale(0.5);\n border-width: 1px 0;\n}\n\n/*# sourceMappingURL=index.vue.map */"]}, media: undefined }); 819 | 820 | }; 821 | /* scoped */ 822 | const __vue_scope_id__$2 = "data-v-176a7813"; 823 | /* module identifier */ 824 | const __vue_module_identifier__$2 = undefined; 825 | /* functional template */ 826 | const __vue_is_functional_template__$2 = false; 827 | /* style inject SSR */ 828 | 829 | /* style inject shadow dom */ 830 | 831 | 832 | 833 | var index = normalizeComponent( 834 | { render: __vue_render__$2, staticRenderFns: __vue_staticRenderFns__$2 }, 835 | __vue_inject_styles__$2, 836 | __vue_script__$2, 837 | __vue_scope_id__$2, 838 | __vue_is_functional_template__$2, 839 | __vue_module_identifier__$2, 840 | false, 841 | createInjector, 842 | undefined, 843 | undefined 844 | ); 845 | 846 | export default index; 847 | -------------------------------------------------------------------------------- /example/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naihe138/vue-picker/2aed086132dc327206cd19a9f67d1de8f1532500/example/.DS_Store -------------------------------------------------------------------------------- /example/css/app.279fbbfe.css: -------------------------------------------------------------------------------- 1 | .header[data-v-70603ee2]{height:120px;background:#2fc6ff;color:#fff;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;font-size:30px;font-weight:500}.header[data-v-70603ee2],.nav[data-v-70603ee2]{display:-webkit-box;display:-ms-flexbox;display:flex}.nav[data-v-70603ee2]{-ms-flex-pack:distribute;justify-content:space-around;overflow:hidden;padding:10px;-ms-flex-wrap:wrap;flex-wrap:wrap}.nav span[data-v-70603ee2]{display:inline-block;text-decoration:none;border:1px solid #2fc6ff;padding:5px 10px;font-size:14px;margin-bottom:10px}.nav .active[data-v-70603ee2]{background:#2fc6ff;color:#fff}.tips[data-v-70603ee2]{background:rgba(0,0,0,.5);position:fixed;width:100px;height:26px;line-height:26px;text-align:center;font-size:14px;border-radius:4px;color:#fff;left:50%;top:50%;margin:-13px 0 0 -50px}.slide-fade-enter-active[data-v-70603ee2]{-webkit-transition:all .3s ease;transition:all .3s ease}.slide-fade-leave-active[data-v-70603ee2]{-webkit-transition:all .3s cubic-bezier(1,.5,.8,1);transition:all .3s cubic-bezier(1,.5,.8,1)}.slide-fade-enter[data-v-70603ee2],.slide-fade-leave-to[data-v-70603ee2]{-webkit-transform:translateY(-30px);transform:translateY(-30px);opacity:0}.btnbox{margin-top:10px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.btnbox .btn{background:#2e68fa;color:#fff;padding:5px 10px;display:inline-block;margin:0 10px;font-size:14px;border-radius:4px}.result{font-size:14px;text-align:center}.result p:nth-of-type(2){padding:0 10px;color:#004af5;line-height:2}body{margin:0;padding:0;background-color:#f8f8f8;font-family:PingFang SC,Helvetica,STHeiti STXihei,Microsoft YaHei,Tohoma,Arial,sans-serif;line-height:1;-webkit-font-smoothing:antialiased} -------------------------------------------------------------------------------- /example/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naihe138/vue-picker/2aed086132dc327206cd19a9f67d1de8f1532500/example/favicon.ico -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | vue-picker-mayun
-------------------------------------------------------------------------------- /example/js/app.5d01ef29.js: -------------------------------------------------------------------------------- 1 | (function(n){function l(l){for(var a,c,u=l[0],s=l[1],r=l[2],v=0,o=[];v\n
\n \n
\n\n\n 38 | 39 | 76 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | import Picker from './index.vue' 3 | 4 | if (typeof window !== 'undefined' && window.Vue) { 5 | window.Vue.component('vue-picker', Picker) 6 | } 7 | 8 | Picker.install = function(Vue){ 9 | Vue.component(Picker.name, Picker) 10 | } 11 | 12 | export default Picker 13 | -------------------------------------------------------------------------------- /src/index.vue: -------------------------------------------------------------------------------- 1 | 50 | 363 | 450 | -------------------------------------------------------------------------------- /src/list.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 203 | 204 | 229 | -------------------------------------------------------------------------------- /src/picker.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | 227 | 228 | 288 | -------------------------------------------------------------------------------- /src/render.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | import Vue from 'vue' 3 | 4 | const textRender = Vue.component('text-render', { 5 | functional: true, 6 | props: { 7 | crender: { 8 | type: Function, 9 | default: function () {} 10 | }, 11 | value: { 12 | type: [Object, Number, String, Boolean, Array], 13 | default: function () { 14 | return {} 15 | } 16 | }, 17 | column: { 18 | type: Object, 19 | default: function () { 20 | return {} 21 | } 22 | }, 23 | index: { 24 | type: [Number, String], 25 | default: 0 26 | }, 27 | row: { 28 | type: Object, 29 | default: function () { 30 | return {} 31 | } 32 | } 33 | }, 34 | render (h, self) { 35 | return self.props.crender(h, { index: self.props.index, value: self.props.value, column: self.props.column, row: self.props.row }) 36 | } 37 | }) 38 | 39 | export default textRender 40 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | export const DEFTAULT_ITEM_HEIGHT = 44 3 | 4 | // 兼容pc 移动端 5 | export const HAS_TOUCH = 'ontouchstart' in window 6 | export const START_EVENT = HAS_TOUCH ? 'touchstart' : 'mousedown' 7 | export const MOVE_EVENT = HAS_TOUCH ? 'touchmove' : 'mousemove' 8 | export const END_EVENT = HAS_TOUCH ? 'touchend' : 'mouseup' 9 | 10 | export const getClient = e => { 11 | let clientX = HAS_TOUCH ? e.changedTouches[0].clientX : e.clientX 12 | let clientY = HAS_TOUCH ? e.changedTouches[0].clientY : e.clientY 13 | return { 14 | x: clientX, 15 | y: clientY 16 | } 17 | } 18 | export const isPC = () => { 19 | const userAgentInfo = navigator.userAgent 20 | const Agents = ['Android', 'iPhone', 'SymbianOS', 'Windows Phone', 'iPad', 'iPod'] 21 | let flag = true 22 | for (var v = 0; v < Agents.length; v++) { 23 | if (userAgentInfo.indexOf(Agents[v]) > 0) { 24 | flag = false 25 | break 26 | } 27 | } 28 | return flag 29 | } 30 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const webpack = require('webpack') 3 | const TerserJSPlugin = require('terser-webpack-plugin') 4 | 5 | module.exports = { 6 | mode: 'production', 7 | entry: './dist/index.js', 8 | output: { 9 | path: path.resolve(__dirname, './lib'), 10 | publicPath: '/lib/', 11 | filename: 'vue-picker.js', 12 | library: 'vue-picker', 13 | libraryTarget: 'umd', 14 | umdNamedDefine: true 15 | }, 16 | devtool: 'none', 17 | module: { 18 | rules: [ 19 | { 20 | test: /\.js$/, 21 | use: { 22 | loader: 'babel-loader', 23 | options: { 24 | presets: ['@babel/preset-env'] 25 | } 26 | }, 27 | exclude: /node_modules/ 28 | }, 29 | ] 30 | }, 31 | optimization: { 32 | minimizer: [ 33 | new TerserJSPlugin({ 34 | parallel: true, 35 | sourceMap: false, 36 | terserOptions: { 37 | compress: { 38 | inline: 1, // https://github.com/mishoo/UglifyJS2/issues/2842 39 | warnings: false, 40 | drop_console: true, 41 | drop_debugger: true 42 | }, 43 | output: { 44 | comments: false 45 | } 46 | } 47 | }) 48 | ] 49 | } 50 | } 51 | --------------------------------------------------------------------------------