diff --git a/example/App.vue b/example/App.vue index 26788ed15..b18306415 100644 --- a/example/App.vue +++ b/example/App.vue @@ -56,6 +56,10 @@ path: '/picker', text: 'Picker' }, + { + path: '/cascade-picker', + text: 'CascadePicker' + }, { path: '/time-picker', text: 'TimePicker' diff --git a/example/components/date-picker.vue b/example/components/date-picker.vue index 1bf976230..1c452bf21 100644 --- a/example/components/date-picker.vue +++ b/example/components/date-picker.vue @@ -1,13 +1,12 @@ diff --git a/example/pages/picker.vue b/example/pages/picker.vue index 993fc229e..43dd42124 100644 --- a/example/pages/picker.vue +++ b/example/pages/picker.vue @@ -4,9 +4,7 @@ Picker Multi-column Picker - Linkage Picker Use SetData - Date Picker Normal Time Picker @@ -16,14 +14,11 @@ diff --git a/src/components/picker/picker.vue b/src/components/picker/picker.vue index 1b393e248..9ac20c6ca 100644 --- a/src/components/picker/picker.vue +++ b/src/components/picker/picker.vue @@ -158,7 +158,16 @@ setData(data, selectedIndex) { this.pickerSelectedIndex = selectedIndex ? [...selectedIndex] : [] this.pickerData = data.slice() - this.dirty = true + if (this.isVisible) { + this.$nextTick(() => { + this.wheels.forEach((wheel, i) => { + wheel.refresh() + wheel.wheelTo(this.pickerSelectedIndex[i]) + }) + }) + } else { + this.dirty = true + } }, refill(datas) { let ret = [] diff --git a/src/index.js b/src/index.js index c2c556666..0e354fada 100644 --- a/src/index.js +++ b/src/index.js @@ -4,6 +4,7 @@ import { Scroll, Popup, TimePicker, + CascadePicker, Dialog, Tip, Toast, @@ -23,6 +24,7 @@ function install(Vue) { Style, Button, TimePicker, + CascadePicker, Dialog, Tip, Toast, diff --git a/src/module.js b/src/module.js index 507158380..6df0ae4c5 100644 --- a/src/module.js +++ b/src/module.js @@ -11,6 +11,7 @@ import ActionSheet from './modules/action-sheet' import Slide from './modules/slide' import IndexList from './modules/index-list' import TimePicker from './modules/time-picker' +import CascadePicker from './modules/cascade-picker' import Scroll from './modules/scroll' import BScroll from './modules/better-scroll' @@ -28,6 +29,7 @@ export { Popup, Picker, TimePicker, + CascadePicker, Dialog, Tip, Toast, diff --git a/src/modules/cascade-picker/api.js b/src/modules/cascade-picker/api.js new file mode 100644 index 000000000..6b1f83e07 --- /dev/null +++ b/src/modules/cascade-picker/api.js @@ -0,0 +1,11 @@ +import createAPI from '../../common/helpers/create-api' +import { warn } from '../../common/helpers/debug' + +export default function addCascadePicker (Vue, CascadePicker) { + const cascadePickerAPI = createAPI(Vue, CascadePicker, ['select', 'cancel', 'change']) + cascadePickerAPI.before((data, renderFn, single) => { + if (single) { + warn('CascadePicker component can not be a singleton.') + } + }) +} diff --git a/src/modules/cascade-picker/index.js b/src/modules/cascade-picker/index.js new file mode 100644 index 000000000..73c401102 --- /dev/null +++ b/src/modules/cascade-picker/index.js @@ -0,0 +1,15 @@ +import Picker from '../../components/picker/picker.vue' +import CascadePicker from '../../components/cascade-picker/cascade-picker.vue' +import addCascadePicker from './api' +import addPicker from '../picker/api' + +CascadePicker.install = function (Vue) { + Vue.component(Picker.name, Picker) + Vue.component(CascadePicker.name, CascadePicker) + addPicker(Vue, Picker) + addCascadePicker(Vue, CascadePicker) +} + +CascadePicker.Picker = Picker + +export default CascadePicker diff --git a/test/unit/specs/cascade-picker.spec.js b/test/unit/specs/cascade-picker.spec.js new file mode 100644 index 000000000..b7221749a --- /dev/null +++ b/test/unit/specs/cascade-picker.spec.js @@ -0,0 +1,125 @@ +import Vue from 'vue2' +import CascadePicker from '@/modules/cascade-picker' +import instantiateComponent from '@/common/helpers/instantiate-component' +import { cascadeData } from 'example/data/cascade' +import { dispatchSwipe } from '../utils/event' + +describe('CascadePicker', () => { + let vm + + afterEach(() => { + if (vm) { + vm.$parent.destroy() + vm = null + } + }) + + it('use', () => { + Vue.use(CascadePicker) + expect(Vue.component(CascadePicker.name)) + .to.be.a('function') + }) + + it('should render correct contents', function () { + vm = createCascadePicker({ + data: cascadeData, + selectedIndex: [1, 1, 3] + }) + + const wheels = vm.$el.querySelectorAll('.cube-picker-wheel-wrapper > div') + expect(wheels.length) + .to.equal(3) + + const firstWheelItems = wheels[0].querySelectorAll('li') + expect(firstWheelItems.length) + .to.equal(3) + expect(firstWheelItems[1].textContent.trim()) + .to.equal('Drink') + + const secondWheelItems = wheels[1].querySelectorAll('li') + expect(secondWheelItems.length) + .to.equal(3) + expect(secondWheelItems[1].textContent.trim()) + .to.equal('Tea') + + const thirdWheelItems = wheels[2].querySelectorAll('li') + expect(thirdWheelItems.length) + .to.equal(4) + expect(thirdWheelItems[3].textContent.trim()) + .to.equal('Four') + }) + + it('should trigger events', function (done) { + this.timeout(10000) + + const selectHandle = sinon.spy() + const cancelHandle = sinon.spy() + const changeHandle = sinon.spy() + const events = { + select: selectHandle, + cancel: cancelHandle, + change: changeHandle + } + + vm = createCascadePicker({ + data: cascadeData + }, events) + + vm.show() + setTimeout(() => { + const wheels = vm.$el.querySelectorAll('.cube-picker-wheel-wrapper > div') + const firstWheelItems = wheels[0].querySelectorAll('li') + + dispatchSwipe(firstWheelItems[1], [ + { + pageX: firstWheelItems[1].offsetLeft + 10, + pageY: firstWheelItems[1].offsetTop + 10 + }, + { + pageX: 300, + pageY: 380 + } + ], 100) + + setTimeout(() => { + expect(changeHandle) + .to.be.callCount(1) + + const confirmBtn = vm.$el.querySelector('.cube-picker-choose [data-action="confirm"]') + confirmBtn.click() + expect(selectHandle) + .to.be.callCount(1) + + vm.show() + setTimeout(() => { + const cancelBtn = vm.$el.querySelector('.cube-picker-choose [data-action="cancel"]') + cancelBtn.click() + expect(cancelHandle) + .to.be.callCount(1) + done() + }, 100) + }, 1000) + }, 150) + }) + + it('setData', function () { + this.timeout(10000) + + vm = createCascadePicker() + + vm.setData(cascadeData, [1, 1, 1]) + + /* expect vm.pickerData[2] equal to cascadeData[1].children[1].children */ + expect(vm.pickerData[2].length) + .to.equal(cascadeData[1].children[1].children.length) + expect(vm.pickerData[2][0].value) + .to.equal(cascadeData[1].children[1].children[0].value) + }) + + function createCascadePicker(props = {}, events = {}) { + return instantiateComponent(Vue, CascadePicker, { + props: props, + on: events + }) + } +}) diff --git a/test/unit/specs/picker.spec.js b/test/unit/specs/picker.spec.js index f2a975917..17432c0a6 100644 --- a/test/unit/specs/picker.spec.js +++ b/test/unit/specs/picker.spec.js @@ -156,7 +156,7 @@ describe('Picker', () => { }, 150) }) - it('should add warn log when sigle is false', () => { + it('should add warn log when single is true', () => { const app = new Vue() const originWarn = console.warn const msgs = [] @@ -173,6 +173,36 @@ describe('Picker', () => { console.warn = originWarn }) + it('setData when picker is invisible', function (done) { + this.timeout(10000) + vm = createPicker() + vm.setData([data1], [1]) + vm.show() + setTimeout(() => { + vm.confirm() + expect(vm.pickerSelectedIndex[0]).to.equal(1) + expect(vm.pickerSelectedVal[0]).to.equal(data1[1].value) + done() + }, 150) + }) + + it('setData when picker is visible', function (done) { + this.timeout(10000) + vm = createPicker({ + data: [data1] + }) + vm.show() + setTimeout(() => { + vm.setData([data2], [2]) + setTimeout(() => { + vm.confirm() + expect(vm.pickerSelectedIndex[0]).to.equal(2) + expect(vm.pickerSelectedVal[0]).to.equal(data2[2].value) + done() + }, 150) + }, 150) + }) + function createPicker(props = {}, events = {}) { return instantiateComponent(Vue, Picker, { props: props,