提交 7398ef14 编写于 作者: D doly mood 提交者: GitHub

Support Drawer

* init

* drawer item prop

* drawer logic

* lint

* scroll add destroy

* init drawer logic

* test

* clean code

* test: done drawer

* drawer check

* drawer support get value default

* update(demo): drawer log

* Clean code

* add drawer demo & doc
上级 0fcd5f23
......@@ -42,7 +42,8 @@
"cascade-picker": "CascadePicker",
"time-picker": "TimePicker",
"dialog": "Dialog",
"action-sheet": "ActionSheet"
"action-sheet": "ActionSheet",
"drawer": "Drawer"
}
},
"scroll": {
......@@ -117,7 +118,8 @@
"time-picker": "TimePicker",
"segment-picker": "SegmentPicker",
"dialog": "Dialog",
"action-sheet": "ActionSheet"
"action-sheet": "ActionSheet",
"drawer": "Drawer"
}
},
"scroll": {
......
## Drawer
Drawer, this component is used to select item in many items, it used full-page panels to interaction normally.
### Demo
- Default usage
```html
<cube-button @click="showDrawer">Show Drawer</cube-button>
<cube-drawer
ref="drawer"
title="请选择"
:data="data"
:selected-index="selectedIndex"
@change="changeHandler"
@select="selectHandler"
@cancel="cancelHandler"></cube-drawer>
```
```js
import { provinceList, cityList, areaList } from '../../data/area'
export default {
data() {
return {
selectedIndex: [],
data: [
provinceList,
[],
[]
]
}
},
methods: {
showDrawer() {
this.$refs.drawer.show()
},
changeHandler(index, item, selectedVal, selectedIndex) {
// fake request
setTimeout(() => {
let data
if (index === 0) {
// procince change, get city data
data = cityList[item.value]
} else {
// city change, get area data
data = areaList[item.value]
}
// refill panel(index + 1) data
this.$refs.drawer.refill(index + 1, data)
}, 200)
},
selectHandler(selectedVal, selectedIndex) {
console.log('select', selectedVal, selectedIndex)
},
cancelHandler() {
console.log('cancel')
}
}
}
```
`title` is the drawer's title, optional; `data` source, an array with array items; `selected-index` is the initial index of the selected value; `change``select``cancel` are events: when selected item changed (the selected item is not in the last Panel)、when selected one item (the item is in the last Panel)、cancel (when clicked the left empty area).
You can use Drawer's `fill` method to update next Panel's data.
- Custom usage
You can use slots to define your own HTML structure.
```html
<cube-drawer
ref="drawer"
:data="data"
:selected-index="selectedIndex"
@change="changeHandler"
@select="selectHandler"
@cancel="cancelHandler">
<span slot="title">{{province.text}}</span>
<cube-drawer-panel
v-for="(panel, index) in data"
:key="index"
:index="index"
:data="panel"
>
<cube-drawer-item v-for="(item, i) in panel" :item="item" :key="i" :index="i">
<i class="cubeic-round-border"></i>
<span>{{item.text}}</span>
</cube-drawer-item>
</cube-drawer-panel>
</cube-drawer>
```
```js
import { provinceList, cityList, areaList } from '../../data/area'
export default {
data() {
return {
province: {},
selectedIndex: [],
data: [
[],
[]
]
}
},
methods: {
showDrawer() {
// get radom province
const randomIndex = Math.round(Math.random() * provinceList.length)
const randomProvince = provinceList[randomIndex]
this.province = randomProvince
this.$refs.drawer.refill(0, cityList[randomProvince.value])
this.$refs.drawer.show()
},
changeHandler(index, item, selectedVal, selectedIndex) {
setTimeout(() => {
// city change, get area data
const data = areaList[item.value]
this.$refs.drawer.refill(index + 1, data)
}, 200)
},
selectHandler(selectedVal, selectedIndex) {
console.log('select', selectedVal, selectedIndex)
},
cancelHandler() {
console.log('cancel')
}
}
}
```
You can use `cube-drawer-panel` and `cube-drawer-item` in `cube-drawer`.
### Props
#### CubeDrawer
| Attribute | Description | Type | Accepted Values | Default |
| - | - | - | - | - |
| title | title | String | - | '' |
| data | data source | Array | - | [] |
| selected-index | initial selected index | Array | - | [] |
- `data` sub configuration
It is an array and it's items is Array too, eg:
```js
[
[
{
text: 'text',
value: 'value'
},
...
],
[
'text',
'text2',
...
]
]
```
#### CubeDrawerPanel
| Attribute | Description | Type | Accepted Values | Default |
| - | - | - | - | - |
| data | data source | Array | - | [] |
| index | the data source index in CubeDrawer's data | Number | - | -1 |
#### CubeDrawerItem
| Attribute | Description | Type | Accepted Values | Default |
| - | - | - | - | - |
| data | item data | String/Object | - | '' |
| index | the item index in CubeDrawerPanel's data | Number | - | -1 |
### Events
| Event Name | Description | Parameters 1 | Parameters 2 | Parameters 3 | Parameters 4 |
| - | - | - | - | - | - |
| change | when selected item changed (the selected item is not in the last Panel) | current Panel index | changed item | selectedVal: Array, selected item values of each panels | selectedIndex: Array, selected indexes of each panels |
| select | when selected one item (the item is in the last Panel) | selectedVal: Array, selected item values of each panels | selectedIndex: Array, selected indexes of each panels | - | - |
| cancel | when clicked the left empty area | - | - | - | - |
### Instance methods
| Method name | Description | Parameters 1 | Parameters 2 | Parameters 3 |
| - | - | - | - | - |
| show | show | - | - | - |
| hide | hide | - | - | - |
| refill | refill data, change one Panel's data source | the Panel index | the data source | default selected index (Optional, recommended do not specify a value) |
## Drawer
抽屉,主要用来需要大范围层级进行选择的场景,一般情况下应该是满屏状态。
### 示例
- 默认配置使用
```html
<cube-button @click="showDrawer">Show Drawer</cube-button>
<cube-drawer
ref="drawer"
title="请选择"
:data="data"
:selected-index="selectedIndex"
@change="changeHandler"
@select="selectHandler"
@cancel="cancelHandler"></cube-drawer>
```
```js
import { provinceList, cityList, areaList } from '../../data/area'
export default {
data() {
return {
selectedIndex: [],
data: [
provinceList,
[],
[]
]
}
},
methods: {
showDrawer() {
this.$refs.drawer.show()
},
changeHandler(index, item, selectedVal, selectedIndex) {
// fake request
setTimeout(() => {
let data
if (index === 0) {
// procince change, get city data
data = cityList[item.value]
} else {
// city change, get area data
data = areaList[item.value]
}
// refill panel(index + 1) data
this.$refs.drawer.refill(index + 1, data)
}, 200)
},
selectHandler(selectedVal, selectedIndex) {
console.log('select', selectedVal, selectedIndex)
},
cancelHandler() {
console.log('cancel')
}
}
}
```
`title` 就是标题,可选;`data` 数据源,二维数组,长度决定了抽屉的 Panel 数,初始长度一定要确定;`selected-index` 则是初始选择的索引值;`change``select``cancel` 则是对应的三个事件:选择发生改变(选中是非最后一个 Panel 中的项的时候触发)、选中了某个值(选择了最后一个 Panel 中的项触发)、取消(点击左侧空白蒙层触发)。
你可以在 `change` 中通过 Drawer 的 `fill` 方法更新下一个 Panel 的数据,可以是同步更新也可以是异步更新。
- 自定义使用
你可以通过插槽来自定义结构。
```html
<cube-drawer
ref="drawer"
:data="data"
:selected-index="selectedIndex"
@change="changeHandler"
@select="selectHandler"
@cancel="cancelHandler">
<span slot="title">{{province.text}}</span>
<cube-drawer-panel
v-for="(panel, index) in data"
:key="index"
:index="index"
:data="panel"
>
<cube-drawer-item v-for="(item, i) in panel" :item="item" :key="i" :index="i">
<i class="cubeic-round-border"></i>
<span>{{item.text}}</span>
</cube-drawer-item>
</cube-drawer-panel>
</cube-drawer>
```
```js
import { provinceList, cityList, areaList } from '../../data/area'
export default {
data() {
return {
province: {},
selectedIndex: [],
data: [
[],
[]
]
}
},
methods: {
showDrawer() {
// get radom province
const randomIndex = Math.round(Math.random() * provinceList.length)
const randomProvince = provinceList[randomIndex]
this.province = randomProvince
this.$refs.drawer.refill(0, cityList[randomProvince.value])
this.$refs.drawer.show()
},
changeHandler(index, item, selectedVal, selectedIndex) {
setTimeout(() => {
// city change, get area data
const data = areaList[item.value]
this.$refs.drawer.refill(index + 1, data)
}, 200)
},
selectHandler(selectedVal, selectedIndex) {
console.log('select', selectedVal, selectedIndex)
},
cancelHandler() {
console.log('cancel')
}
}
}
```
可以在 `cube-drawer` 组件中使用 `cube-drawer-panel` 以及 `cube-drawer-item` 组件来达到某些情况下的自定义目的。
### Props 配置
#### CubeDrawer
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| - | - | - | - | - |
| title | 标题 | String | - | '' |
| data | 数据源 | Array | - | [] |
| selected-index | 初始选择索引 | Array | - | [] |
- `data` 子配置项
是一个数组,数组中每一项仍然为数组,结构类似于:
```js
[
[
{
text: 'text',
value: 'value'
},
...
],
[
'text',
'text2',
...
]
]
```
里层数组的每一项可以是对象(包含 text 和 value),也可以是纯字符串。
#### CubeDrawerPanel
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| - | - | - | - | - |
| data | 数据源 | Array | - | [] |
| index | 该数据源在 CubeDrawer 的 data 中的索引值 | Number | - | -1 |
#### CubeDrawerItem
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| - | - | - | - | - |
| data | 数据项 | String/Object | - | '' |
| index | 该数据项在 CubeDrawerPanel 的 data 中的索引值 | Number | - | -1 |
### 事件
| 事件名 | 说明 | 参数1 | 参数2 | 参数3 | 参数4 |
| - | - | - | - | - | - |
| change | 选择发生改变(选中是非最后一个 Panel 中的项的时候触发) | 发生改变的 Panel 的索引 | 发生改变的数据项 | 已选中的值集合 | 已选中的索引集合 |
| select | 选择了最后一个 Panel 中的项触发 | 已选中的值集合 | 已选中的索引集合 | - | - |
| cancel | 点击左侧空白区域触发 | - | - | - | - |
### 实例方法
| 方法名 | 说明 | 参数1 | 参数2 | 参数3 |
| - | - | - | - | - |
| show | 显示 | - | - | - |
| hide | 隐藏 | - | - | - |
| refill | 填充数据,改变某个 Panel 数据 | 要改变的 Panel 的索引 | 填充数据 | 默认选中项(可选,建议不填) |
......@@ -310,7 +310,7 @@
### Props 配置
#### Form
#### CubeForm
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| - | - | - | - | - |
......@@ -386,14 +386,14 @@
| rules | 字段的校验规则,参见 <a href="#/zh-CN/docs/validator#cube-Props-anchor">Validator</a> | Object | - | - |
| messages | 字段的校验消息,参见 <a href="#/zh-CN/docs/validator#cube-Props-anchor">Validator</a> | String | - | - |
#### FormGroup
#### CubeFormGroup
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| - | - | - | - | - |
| legend | 分组名字 | String | - | '' |
| fields | 该组内所包含的字段集合 | Array | - | [] |
#### FormItem
#### CubeFormItem
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| - | - | - | - | - |
......
......@@ -131,6 +131,10 @@
{
path: '/swipe',
text: 'Swipe'
},
{
path: '/drawer',
text: 'Drawer'
}
]
}
......
<template>
<cube-page type="drawer-def" title="Drawer">
<div slot="content">
<div class="view-wrapper">
<cube-button @click="showDrawer">Show Drawer</cube-button>
<cube-drawer
ref="drawer"
:data="data"
:selected-index="selectedIndex"
@change="changeHandler"
@select="selectHandler"
@cancel="cancelHandler">
<span slot="title">{{province.text}}</span>
<cube-drawer-panel
v-for="(panel, index) in data"
:key="index"
:index="index"
:data="panel"
>
<cube-drawer-item v-for="(item, i) in panel" :item="item" :key="i" :index="i">
<i class="cubeic-round-border"></i>
<span>{{item.text}}</span>
</cube-drawer-item>
</cube-drawer-panel>
</cube-drawer>
</div>
</div>
</cube-page>
</template>
<script type="text/ecmascript-6">
import CubePage from '../../components/cube-page.vue'
import { provinceList, cityList, areaList } from '../../data/area'
export default {
data() {
return {
province: {},
selectedIndex: [],
data: [
[],
[]
]
}
},
methods: {
showDrawer() {
const randomIndex = Math.round(Math.random() * provinceList.length)
const randomProvince = provinceList[randomIndex]
this.province = randomProvince
this.$refs.drawer.refill(0, cityList[randomProvince.value])
this.$refs.drawer.show()
},
changeHandler(index, item, selectedVal, selectedIndex) {
setTimeout(() => {
// city change, get area data
const data = areaList[item.value]
this.$refs.drawer.refill(index + 1, data)
}, 200)
},
selectHandler(selectedVal, selectedIndex) {
console.log('select', selectedVal, selectedIndex)
},
cancelHandler() {
console.log('cancel')
}
},
components: {
CubePage
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
.view-wrapper
position: fixed
top: 54px
left: 0
bottom: 0
width: 100%
.cube-drawer-item_active
color: #fc9153
background-color: transparent
</style>
<template>
<cube-page type="drawer-def" title="Drawer">
<div slot="content">
<div class="view-wrapper">
<cube-button @click="showDrawer">Show Drawer</cube-button>
<cube-drawer
ref="drawer"
title="请选择"
:data="data"
:selected-index="selectedIndex"
@change="changeHandler"
@select="selectHandler"
@cancel="cancelHandler"></cube-drawer>
</div>
</div>
</cube-page>
</template>
<script type="text/ecmascript-6">
import CubePage from '../../components/cube-page.vue'
import { provinceList, cityList, areaList } from '../../data/area'
export default {
data() {
return {
selectedIndex: [],
data: [
provinceList,
[],
[]
]
}
},
methods: {
showDrawer() {
this.$refs.drawer.show()
},
changeHandler(index, item, selectedVal, selectedIndex) {
// fake request
setTimeout(() => {
let data
if (index === 0) {
// procince change, get city data
data = cityList[item.value]
} else {
// city change, get area data
data = areaList[item.value]
}
this.$refs.drawer.refill(index + 1, data)
}, 200)
},
selectHandler(selectedVal, selectedIndex) {
console.log('select', selectedVal, selectedIndex)
},
cancelHandler() {
console.log('cancel')
}
},
components: {
CubePage
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
.view-wrapper
position: fixed
top: 54px
left: 0
bottom: 0
width: 100%
</style>
<template>
<cube-page type="drawer" title="Drawer">
<div slot="content">
<cube-button-group>
<cube-button @click="goTo('default')">Default</cube-button>
<cube-button @click="goTo('custom')">Custom</cube-button>
</cube-button-group>
<cube-view></cube-view>
</div>
</cube-page>
</template>
<script type="text/ecmascript-6">
import CubePage from 'example/components/cube-page.vue'
import CubeButtonGroup from 'example/components/cube-button-group.vue'
import CubeView from 'example/components/cube-view.vue'
export default {
components: {
CubePage,
CubeButtonGroup,
CubeView
},
methods: {
goTo(subPath) {
this.$router.push('/drawer/' + subPath)
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
</style>
......@@ -30,6 +30,9 @@ import Validator from '../pages/validator.vue'
import Swipe from '../pages/swipe/index.vue'
import SwipeDefault from '../pages/swipe/default.vue'
import SwipeCustom from '../pages/swipe/custom.vue'
import Drawer from '../pages/drawer/index.vue'
import DrawerDefault from '../pages/drawer/default.vue'
import DrawerCustom from '../pages/drawer/custom.vue'
import Slide from '../pages/slide/index.vue'
import SlideVertical from '../pages/slide/vertical.vue'
import SlideHorizontal from '../pages/slide/horizontal.vue'
......@@ -169,6 +172,20 @@ const routes = [
}
]
},
{
path: '/drawer',
component: Drawer,
children: [
{
path: 'default',
component: DrawerDefault
},
{
path: 'custom',
component: DrawerCustom
}
]
},
{
path: '/slide',
component: Slide,
......
<template>
<li
class="cube-drawer-item border-bottom-1px"
:class="itemClass"
@click="clickItem(item)"
>
<slot>
{{item.text || item}}
</slot>
</li>
</template>
<script type="text/ecmascript-6">
const COMPONENT_NAME = 'cube-drawer-item'
export default {
name: COMPONENT_NAME,
props: {
item: {
type: [String, Object],
default: ''
},
index: {
type: Number,
default: -1
}
},
computed: {
itemClass() {
return this.$parent.$parent.selectedIndex === this.index ? 'cube-drawer-item_active' : ''
}
},
methods: {
clickItem(item) {
this.$parent.$parent.itemClickHandler(item, this.index)
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@require "../../common/stylus/variable.styl"
@require "../../common/stylus/mixin.styl"
.cube-drawer-item
padding: 0 20px
height: 50px
line-height: 50px
white-space: nowrap
overflow: hidden
font-size: 15px
&::after
left: 20px
&:last-child
&::after
display: none
&:first-child
&::after
display: block
.cube-drawer-item_active
background: $index-list-item-active-bgc
</style>
<template>
<transition name="cube-drawer-move">
<div class="cube-drawer-panel" v-show="isVisible">
<cube-scroll ref="scroll" :data="data">
<ul class="cube-drawer-list">
<slot>
<cube-drawer-item v-for="(item, i) in data" :item="item" :key="i" :index="i" />
</slot>
</ul>
</cube-scroll>
</div>
</transition>
</template>
<script type="text/ecmascript-6">
import apiMixin from '../../common/mixins/api'
import CubeScroll from '../scroll/scroll.vue'
import CubeDrawerItem from './drawer-item.vue'
const COMPONENT_NAME = 'cube-drawer-panel'
export default {
name: COMPONENT_NAME,
mixins: [apiMixin],
props: {
data: {
type: Array,
default() {
/* istanbul ignore next */
return []
}
},
index: {
type: Number,
default: -1
}
},
computed: {
selectedIndex() {
const selectedIndex = this.$parent.selected[this.index]
return selectedIndex === undefined ? -1 : selectedIndex
}
},
watch: {
data() {
this.scrollToTop()
},
isVisible() {
this.refresh()
}
},
mounted() {
this.$parent.addPanel(this)
},
beforeDestroy() {
this.$parent.removePanel(this)
},
methods: {
refresh() {
this.$refs.scroll.refresh()
},
scrollToTop() {
this.$refs.scroll.scroll && this.$refs.scroll.scroll.scrollTo(0, 0, 0)
},
itemClickHandler(item, index) {
if (this.selectedIndex !== index) {
this.$parent.changeHandler(this.index, item, index)
}
}
},
components: {
CubeScroll,
CubeDrawerItem
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@require "../../common/stylus/variable.styl"
@require "../../common/stylus/mixin.styl"
.cube-drawer-panel
position: relative
z-index: 1
height: 100%
flex: 1
width: 170px
background-color: $color-white
box-shadow: 0 1px 2px rgba(0, 0, 0, .2)
+ .cube-drawer-panel
margin-left: -67px
&:first-child
box-shadow: none
.cube-drawer-move-enter, .cube-drawer-move-leave-to
transform: translate(67px, 0)
.cube-drawer-move-enter-active, .cube-drawer-move-leave-active
transition: transform .3s ease-in-out
</style>
<template>
<div class="cube-drawer" @click="drawerClick" v-show="isVisible">
<div class="cube-drawer-main" :style="slideStyle" @click.stop @transitionend="transitionend">
<div class="cube-drawer-title" v-show="$slots.title || title">
<slot name="title">{{title}}</slot>
</div>
<div class="cube-drawer-panels" @transitionend.stop>
<slot>
<cube-drawer-panel
v-for="(panel, index) in data"
:key="index"
:index="index"
:data="panel" />
</slot>
</div>
</div>
</div>
</template>
<script type="text/ecmascript-6">
import { prefixStyle } from '../../common/helpers/dom'
import CubeDrawerPanel from './drawer-panel.vue'
import apiMixin from '../../common/mixins/api'
const COMPONENT_NAME = 'cube-drawer'
const EVENT_CHANGE = 'change'
const EVENT_SELECT = 'select'
const EVENT_CANCEL = 'cancel'
const transform = prefixStyle('transform')
export default {
name: COMPONENT_NAME,
mixins: [apiMixin],
props: {
title: {
type: String,
default: ''
},
data: {
type: Array,
default() {
/* istanbul ignore next */
return []
}
},
selectedIndex: {
type: Array,
default() {
/* istanbul ignore next */
return []
}
}
},
data() {
return {
index: -1,
selectedVal: [],
selected: [...this.selectedIndex],
slideStyle: {
[transform]: 'translate3d(0, 0, 0)'
}
}
},
watch: {
selectedIndex(newVal) {
this.selected = [...newVal]
},
index(newIndex, oldIndex) {
this.showPanel()
if (newIndex < oldIndex) {
this.hidePanel()
}
}
},
created() {
this.panels = []
},
methods: {
show() {
this.isVisible = true
let len = this.data.length
for (let i = 0; i < len; i++) {
this.index = i
if (this.selected[i] < 0 || this.selected[i] === undefined) {
if (i > 0) {
const lastIndex = i - 1
const index = this.selected[lastIndex]
this.changeHandler(lastIndex, this.data[lastIndex][index], index)
}
break
}
}
this.computedStyle()
},
hide() {
this.slideStyle[transform] = 'translate3d(0, 0, 0)'
this.shouldHide = true
},
addPanel(panel) {
this.panels.push(panel)
},
removePanel(panel) {
const i = this.panels.indexOf(panel)
this.panels.splice(i, 1)
},
transitionend() {
if (this.shouldHide) {
this.isVisible = false
this.shouldHide = false
}
},
refill(panelIndex, data, index) {
this.$set(this.data, panelIndex, data)
this.index = panelIndex
this.selected = this.selected.slice(0, panelIndex)
this.selectedVal = this.selectedVal.slice(0, panelIndex)
if (index >= 0) {
this.$set(this.selected, panelIndex, index)
this.changeHandler(panelIndex, this.data[panelIndex][index], index)
}
},
showPanel() {
const index = this.index
let i = 0
while (i <= index) {
this.panels[i].show()
i++
}
this.computedStyle()
},
hidePanel() {
const len = this.data.length
let i = this.index + 1
while (i < len) {
this.panels[i].hide()
i++
}
},
computedStyle() {
this.$nextTick(() => {
let allWidth = 0
let i = 0
const index = this.index
while (i <= index) {
const el = this.panels[i].$el
allWidth += el.offsetWidth
const elStyle = window.getComputedStyle(el)
allWidth += parseInt(elStyle.marginLeft)
allWidth += parseInt(elStyle.marginRight)
i++
}
this.slideStyle[transform] = `translate3d(-${allWidth}px, 0, 0)`
})
},
changeHandler(panelIndex, item, index) {
this.selectedVal[panelIndex] = typeof item === 'string' ? item : item.value
this.$set(this.selected, panelIndex, index)
if (panelIndex === (this.data.length - 1)) {
// last column
this.$emit(EVENT_SELECT, this.selectedVal, this.selected)
} else {
this.$emit(EVENT_CHANGE, panelIndex, item, this.selectedVal, this.selected)
}
},
drawerClick() {
this.hide()
this.$emit(EVENT_CANCEL)
}
},
components: {
CubeDrawerPanel
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@require "../../common/stylus/variable.styl"
@require "../../common/stylus/mixin.styl"
.cube-drawer
position: absolute
z-index: 5
top: 0
right: 0
bottom: 0
left: 0
overflow: hidden
color: $color-dark-grey
.cube-drawer-main
position: absolute
top: 0
left: 100%
bottom: 0
max-width: 90%
display: flex
flex-direction: column
overflow: hidden
box-shadow: -2px 0 2px rgba(0, 0, 0, .2)
transform: translate3d(0, 0, 0)
transition: transform .3s ease-in-out
.cube-drawer-title
position: relative
padding: 0 20px
height: 50px
line-height: 50px
border-bottom: 1px solid $color-light-grey-ss
font-size: $fontsize-large
background-color: $color-white
.cube-drawer-panels
display: flex
flex: 1
</style>
<template>
<li
class="cube-index-list-item"
:class="itemClass"
@touchstart="addActiveCls"
@touchend="removeActiveCls"
@click="selectItem()">
......@@ -32,6 +33,11 @@
}
}
},
computed: {
itemClass() {
return this.item.active ? ACTIVE_CLS : ''
}
},
methods: {
addActiveCls(e) {
addClass(e.currentTarget, ACTIVE_CLS)
......
......@@ -186,6 +186,9 @@
this.initScroll()
})
},
beforeDestroy() {
this.destroy()
},
methods: {
initScroll() {
if (!this.$refs.wrapper) {
......@@ -232,6 +235,7 @@
},
destroy() {
this.scroll && this.scroll.destroy()
this.scroll = null
},
scrollTo() {
this.scroll && this.scroll.scrollTo.apply(this.scroll, arguments)
......
......@@ -23,6 +23,7 @@ import {
IndexList,
Upload,
Swipe,
Drawer,
BScroll,
createAPI
} from './module'
......@@ -56,7 +57,8 @@ function install(Vue) {
Scroll,
Popup,
Upload,
Swipe
Swipe,
Drawer
]
components.forEach((Component) => {
Component.install(Vue)
......
......@@ -25,6 +25,7 @@ import Scroll from './modules/scroll'
import Upload from './modules/upload'
import Swipe from './modules/swipe'
import Drawer from './modules/drawer'
import BScroll from './modules/better-scroll'
import createAPI from './modules/create-api'
......@@ -38,6 +39,8 @@ const Loading = Toast.Loading
const SlideItem = Slide.Item
const Radio = RadioGroup.Radio
const SwipeItem = Swipe.Item
const DrawerPanel = Drawer.Panel
const DrawerItem = Drawer.Item
export {
Style,
......@@ -73,6 +76,9 @@ export {
Upload,
Swipe,
SwipeItem,
Drawer,
DrawerPanel,
DrawerItem,
BScroll,
createAPI
}
import Drawer from '../../components/drawer/drawer.vue'
import DrawerPanel from '../../components/drawer/drawer-panel.vue'
import DrawerItem from '../../components/drawer/drawer-item.vue'
Drawer.install = function (Vue) {
Vue.component(Drawer.name, Drawer)
Vue.component(DrawerPanel.name, DrawerPanel)
Vue.component(DrawerItem.name, DrawerItem)
}
Drawer.Panel = DrawerPanel
Drawer.Item = DrawerItem
export default Drawer
import Vue from 'vue2'
import Drawer from '@/modules/drawer'
import createVue from '../utils/create-vue'
import { dispatchTap } from '../utils/event'
describe('Drawer', () => {
let vm
afterEach(() => {
if (vm) {
vm.$parent.destroy()
vm = null
}
})
it('use', () => {
Vue.use(Drawer)
expect(Vue.component(Drawer.name))
.to.be.a('function')
})
it('should render correct contents', function (done) {
this.timeout(5000)
vm = createDrawer({
data: [['1', '2'], [], []],
selectedIndex: [0]
}, {
change(index) {
this.$refs.drawer.refill(index + 1, index === 0 ? ['11', '22'] : ['111', '222', '333'])
}
})
expect(vm.$el.querySelector('.cube-drawer-title').textContent.trim())
.to.equal('请选择')
expect(vm.$el.querySelectorAll('.cube-drawer-panel').length)
.to.equal(3)
expect(vm.$el.style.display)
.to.equal('none')
vm.show()
setTimeout(() => {
const panel = vm.$el.querySelector('.cube-drawer-panel')
expect(panel.style.display)
.not.to.equal('none')
expect(vm.$el.querySelector('.cube-drawer-panel:last-child').style.display)
.to.equal('none')
const firstItems = panel.querySelectorAll('.cube-drawer-item')
expect(firstItems.length)
.to.equal(2)
expect(firstItems[0].textContent.trim())
.to.equal('1')
expect(firstItems[1].textContent.trim())
.to.equal('2')
setTimeout(() => {
expect(panel.querySelector('.cube-drawer-item').className)
.to.include('cube-drawer-item_active')
const newPanel = vm.$el.querySelector('.cube-drawer-panel:nth-child(2)')
expect(newPanel.style.display)
.not.to.equal('none')
const items = newPanel.querySelectorAll('.cube-drawer-item')
expect(items.length)
.to.equal(2)
expect(items[1].textContent.trim())
.to.equal('22')
dispatchTap(items[0])
setTimeout(() => {
const newPanel = vm.$el.querySelector('.cube-drawer-panel:last-child')
expect(newPanel.style.display)
.not.to.equal('none')
expect(newPanel.querySelectorAll('.cube-drawer-item')[0].textContent.trim())
.to.equal('111')
// hide one
dispatchTap(firstItems[1])
setTimeout(() => {
expect(vm.$el.querySelector('.cube-drawer-panel:last-child').style.display)
.to.equal('none')
vm.hide()
vm.$el.click()
setTimeout(() => {
expect(vm.$el.style.display)
.to.equal('none')
done()
}, 400)
}, 400)
}, 400)
}, 400)
}, 400)
})
it('should trigger events', function (done) {
this.timeout(2000)
const changeHandler = sinon.spy()
const selectHandler = sinon.spy()
const cancelHandler = sinon.spy()
vm = createDrawer({}, {
change(index) {
changeHandler.apply(this, arguments)
this.$refs.drawer.refill(index + 1, ['11', '22'], 1)
},
select: selectHandler,
cancel: cancelHandler
})
vm.show()
setTimeout(() => {
const panel = vm.$el.querySelector('.cube-drawer-panel')
const items = panel.querySelectorAll('.cube-drawer-item')
dispatchTap(items[1])
expect(changeHandler)
.to.be.calledOnce
setTimeout(() => {
expect(selectHandler)
.to.be.calledOnce
const newPanel = vm.$el.querySelector('.cube-drawer-panel:last-child')
const item = newPanel.querySelector('.cube-drawer-item')
dispatchTap(item)
expect(selectHandler)
.to.be.calledTwice
// hide
vm.$el.click()
expect(cancelHandler)
.to.be.calledOnce
done()
}, 400)
}, 400)
})
function createDrawer (props = {}, events = {}) {
return createVue({
template: `
<cube-drawer
ref="drawer"
title="请选择"
:data="data"
:selected-index="selectedIndex"
@change="changeHandler"
@select="selectHandler"
@cancel="cancelHandler" />
`,
data: {
data: props.data || [['1', '2'], []],
selectedIndex: props.selectedIndex || []
},
methods: {
changeHandler(index, item, selectedVal, selectedIndex) {
if (events.change) {
events.change.call(this, index, item, selectedVal, selectedIndex)
} else {
this.$refs.drawer.refill(index + 1, ['11', '22'])
}
},
selectHandler(selectedVal, selectedIndex) {
events.select && events.select.call(this, selectedVal, selectedIndex)
},
cancelHandler() {
events.cancel && events.cancel.call(this)
}
}
})
}
})
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册