提交 563b54c2 编写于 作者: A Amy 提交者: doly mood

Support Select (#101)

* <add>(select)

* <add>(select): test

* <add>(select): doc

* <update>(select): auto-pop, change
上级 262e1cfe
......@@ -21,6 +21,7 @@
"checkbox-group": "CheckboxGroup",
"radio": "Radio",
"input": "Input",
"select": "Select",
"switch": "Switch",
"validator": "Validator",
"loading": "Loading",
......@@ -86,6 +87,7 @@
"checkbox-group": "CheckboxGroup",
"radio": "Radio",
"input": "Input",
"select": "Select",
"switch": "Switch",
"validator": "Validator",
"loading": "Loading",
......
## Select
Select component.
### Example
- Basic usage
Basically, you need to use `options` to define each option and the selected value will bind on `v-model`.
```html
<cube-select
v-model="value"
:options="options">
</cube-select>
```
```js
export default {
data() {
return {
options: [2013, 2014, 2015, 2016, 2017, 2018],
value: 2016
}
}
}
```
- Configs and Events
Select supports the configs of picker title, placeholder, whether auto pop, disabled. And if the selected value is changed when selected, it will emit the event `change`.
```html
<cube-select
v-model="value"
:title="title"
:options="options"
:placeholder="placeholder"
:auto-pop="autoPop"
:disabled="disabled"
cancelTxt="Cancel"
confirmTxt="Confirm"
@change="change">
</cube-select>
```
```js
export default {
data() {
return {
options: [2013, 2014, 2015, 2016, 2017, 2018],
value: 2016,
title: 'Entry time',
placeholder: 'Please choose entry time',
autoPop: false,
disabled: false
}
},
methods: {
change(value, index, text) {
console.log('change', value, index, text)
}
}
}
```
There is one thing you may need notice. the `change` event won't change when you directly set the value of `v-model`, it only emit when the change is caused by select. If you want to listen the change of `v-model`, just watch it.
### Props
| Attribute | Description | Type | Accepted Values | Default |
| - | - | - | - | - |
| options | options | Array | - | [] |
| v-model | the selected value | Any | - | - |
| placeholder | placeholder | String | - | '请选择' |
| auto-pop | whether auto pop picker | Boolean | true/false | false |
| disabled | whether disabled | Boolean | true/false | false |
| title | the title of picker | String | - | '请选择' |
| cancelTxt | the cancel text of picker | String | - | '取消' |
| confirmTxt | the confirm text of picker | String | - | '确认' |
- `options ` sub configuration
| Attribute | Description | Type | Accepted Values | Example |
| - | - | - | - | - |
| value | value of the option | Any | - | - |
| text | text of the option | String | - | - |
If an option is not an object, such as 2014,we will transform it to { value: 2014, text: 2014 }.
### Events
| Event Name | Description | Parameters 1 | Parameters 2 | Parameters 3 |
| - | - | - | - | - |
| change | when the selected value changed by select | the selected value | the selected index | the selected text |
## Select
Select 组件,用于单项选择。
### 示例
- 基本用法
对于 Select 选择组件,你需要传入 options 定义各个选项,选择的结果则绑定在 v-model 上。
```html
<cube-select
v-model="value"
:options="options">
</cube-select>
```
```js
export default {
data() {
return {
options: [2013, 2014, 2015, 2016, 2017, 2018],
value: 2016
}
}
}
```
- 配置和事件
Select 支持选择器标题(title)、占位符(placeholder)、自动弹出选择器(autoPop)、禁用(disabled)的配置。并且在选择时,如果选择的值改变了,会派发 change 事件。
```html
<cube-select
v-model="value"
:title="title"
:options="options"
:placeholder="placeholder"
:auto-pop="autoPop"
:disabled="disabled"
@change="change">
</cube-select>
```
```js
export default {
data() {
return {
options: [2013, 2014, 2015, 2016, 2017, 2018],
value: 2016,
title: '入职时间',
placeholder: '请选择入职时间',
autoPop: false,
disabled: false
}
},
methods: {
change(value, index, text) {
console.log('change', value, index, text)
}
}
}
```
需要注意的一点是,change 事件在你直接赋值修改 value 的值时,不会触发,只会在选择导致的修改时触发。如果你只是想监听 value 的改变,请直接监听 value。
### Props 配置
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| - | - | - | - | - |
| options | 选项 | Array | - | [] |
| v-model | 选中的值 | Any | - | - |
| placeholder | 占位文案 | String | - | '请选择' |
| auto-pop | 是否自动弹出选择器 | Boolean | true/false | false |
| disabled | 是否禁用 | Boolean | true/false | false |
| title | 选择器的标题 | String | - | '请选择' |
| cancelTxt | 选择器的取消按钮文案 | String | - | '取消' |
| confirmTxt | 选择器的确认按钮文案 | String | - | '确认' |
- `options ` 子配置项
| 参数 | 说明 | 类型 | 可选值 | 示例 |
| - | - | - | - | - |
| value | 该选项的值 | Any | - | - |
| text | 该选项的文案 | String | - | - |
你可以将每个选项定义成一个对象,其中 text 为选项文案,value为选项的值,若没有将该选项定义为对象,比如 2014,则我们内部会把它转化成 { value: 2014, text: 2014 }
### 事件
| 事件名 | 说明 | 参数1 | 参数2 | 参数3 |
| - | - | - | - | - |
| change | 在选择时,如果选择的值改变了派发 | 选中项的值 | 选中项的索引 | 选中项的文案 |
......@@ -87,6 +87,10 @@
path: '/time-picker',
text: 'TimePicker'
},
{
path: '/select',
text: 'Select'
},
{
path: '/dialog',
text: 'Dialog'
......
<template>
<cube-page type="button-view" title="Select">
<div slot="content">
<cube-select
v-model="value"
:title="title"
:options="options"
:placeholder="placeholder"
:auto-pop="autoPop"
:disabled="disabled"
cancelTxt="Cancel"
confirmTxt="Confirm"
@change="change">
</cube-select>
<cube-button-group>
<cube-button @click="modify">modify</cube-button>
</cube-button-group>
</div>
</cube-page>
</template>
<script type="text/ecmascript-6">
import CubePage from '../components/cube-page.vue'
import CubeButtonGroup from '../components/cube-button-group.vue'
export default {
components: {
CubePage,
CubeButtonGroup
},
data() {
return {
options: [2013, 2014, 2015, 2016, 2017, 2018],
value: 2016,
title: 'Entry time',
placeholder: 'Please choose entry time',
autoPop: true,
disabled: false
}
},
methods: {
change(value, index, text) {
console.log('change', value, index, text)
},
modify() {
this.value = 2014
}
}
}
</script>
......@@ -13,6 +13,7 @@ import Rate from '../pages/rate.vue'
import Picker from '../pages/picker.vue'
import CascadePicker from '../pages/cascade-picker.vue'
import TimePicker from '../pages/time-picker.vue'
import Select from '../pages/select.vue'
import Dialog from '../pages/dialog.vue'
import ActionSheet from '../pages/action-sheet.vue'
import Scroll from '../pages/scroll.vue'
......@@ -84,6 +85,10 @@ const routes = [
path: '/time-picker',
component: TimePicker
},
{
path: '/select',
component: Select
},
{
path: '/dialog',
component: Dialog
......
......@@ -42,3 +42,5 @@
content: "\e990"
.cubeic-square-right::before
content: "\e67d"
.cubeic-select::before
content: "\e609"
......@@ -168,3 +168,14 @@ $textarea-indicator-color := $color-light-grey-s
// validator
$validator-msg-def-color := #f5222d
// select
$select-color := $color-dark-grey
$select-bgc := $color-white
$select-disabled-color := #b8b8b8
$select-disabled-bgc := $color-light-grey-opacity
$select-border-color := $color-light-grey-s
$select-border-active-color := $color-orange
$select-icon-color := $color-light-grey-s
$select-icon-active-color := $color-orange
$select-placeholder-color := $color-light-grey
<template>
<div class="cube-select" :class="{ 'cube-select_active': active, 'cube-select_disabled': disabled }" @click="showPicker">
<span v-if="selectedText" class="cube-select-text">{{ selectedText }}</span>
<span v-else class="cube-select-placeholder">{{ placeholder }}</span>
<i class="cubeic-select cube-select-icon"></i>
</div>
</template>
<script>
const COMPONENT_NAME = 'cube-select'
const EVENT_CHANGE = 'change'
const EVENT_INPUT = 'input' // only used for v-modal
export default {
name: COMPONENT_NAME,
data() {
return {
active: false
}
},
props: {
options: {
type: Array,
default() {
return []
}
},
value: null,
placeholder: {
type: String,
default: '请选择'
},
autoPop: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
title: {
type: String,
default: '请选择'
},
cancelTxt: {
type: String,
default: '取消'
},
confirmTxt: {
type: String,
default: '确定'
}
},
computed: {
adaptOptions() {
return [this.options.map(item => {
if (typeof item !== 'object') {
item = {
value: item,
text: item
}
}
return item
})]
},
findIndex() {
const findIndex = this.adaptOptions[0].findIndex((item) => {
return item.value === this.value
})
this.picker && this.picker.setData(this.adaptOptions, findIndex !== -1 ? [findIndex] : [0])
return findIndex
},
selectedText() {
return this.findIndex !== -1 ? this.adaptOptions[0][this.findIndex].text : ''
}
},
created() {
this.picker = this.$createPicker({
title: this.title,
data: this.adaptOptions,
selectedIndex: this.findIndex !== -1 ? [this.findIndex] : [0],
cancelTxt: this.cancelTxt,
confirmTxt: this.confirmTxt,
onSelect: this.hided,
onValueChange: this.changeHandle,
onCancel: this.hided
})
this.autoPop && this.showPicker()
},
methods: {
showPicker() {
if (this.disabled) {
return
}
this.picker.show()
this.active = true
},
hided() {
this.active = false
},
changeHandle(selectedVal, selectedIndex, selectedText) {
if (selectedVal[0] !== this.value) {
this.$emit(EVENT_INPUT, selectedVal[0])
this.$emit(EVENT_CHANGE, selectedVal[0], selectedIndex[0], selectedText[0])
}
}
}
}
</script>
<style lang="stylus">
@require "../../common/stylus/variable.styl"
@require "../../common/stylus/mixin.styl"
.cube-select
position: relative
box-sizing: border-box
padding: 11px 28px 11px 10px
border-radius: 2px
font-size: $fontsize-large
line-height: 1
color: $select-color
background-color: $select-bgc
border-1px($select-border-color, 2px)
> span
display: inline-block
&.cube-select_active
border-color: $select-border-active-color
.cube-select-icon
color: $select-icon-active-color
&.cube-select_disabled
background-color: $select-disabled-bgc
color: $select-disabled-color
cursor: not-allowed
.cube-select-placeholder
color: $select-placeholder-color
.cube-select-icon
position: absolute
right: 10px
top: 50%
font-size: $fontsize-large-xx
color: $select-icon-color
transform: translate(0, -50%)
</style>
......@@ -5,6 +5,7 @@ import {
Popup,
TimePicker,
CascadePicker,
Select,
Dialog,
Tip,
Toast,
......@@ -33,6 +34,7 @@ function install(Vue) {
Button,
TimePicker,
CascadePicker,
Select,
Dialog,
Tip,
Toast,
......
......@@ -9,6 +9,7 @@ import Dialog from './modules/dialog'
import Toast from './modules/toast'
import Input from './modules/input'
import Validator from './modules/validator'
import Select from './modules/select'
import Textarea from './modules/textarea'
import Rate from './modules/rate'
......@@ -39,6 +40,7 @@ export {
Picker,
TimePicker,
CascadePicker,
Select,
Dialog,
Tip,
Toast,
......
import Picker from '../../components/picker/picker.vue'
import Select from '../../components/select/select.vue'
import addPicker from '../picker/api'
Select.install = function (Vue) {
Vue.component(Picker.name, Picker)
Vue.component(Select.name, Select)
addPicker(Vue, Picker)
}
Select.Picker = Picker
export default Select
import Vue from 'vue'
import 'basic-mouse-event-polyfill-phantomjs'
import 'phantomjs-polyfill-find-index'
Vue.config.productionTip = false
......
......@@ -25,7 +25,9 @@ module.exports = function (config) {
},
frameworks: ['mocha', 'sinon-chai', 'phantomjs-shim'],
reporters: ['spec', 'coverage'],
files: ['./index.js'],
files: [
'./index.js'
],
preprocessors: {
'./index.js': ['webpack', 'sourcemap']
},
......
import Vue from 'vue2'
import Select from '@/modules/select'
import instantiateComponent from '@/common/helpers/instantiate-component'
describe('Select.vue', () => {
let vm
afterEach(() => {
if (vm) {
vm.$parent.destroy()
vm = null
}
})
it('use', () => {
Vue.use(Select)
expect(Vue.component(Select.name))
.to.be.a('function')
})
it('should render correct contents', () => {
vm = createSelect({
value: 2016,
options: [2013, 2014, 2015, 2016, 2017, 2018]
})
const el = vm.$el
expect(el.querySelector('.cube-select-text').textContent.trim())
.to.equal('2016')
})
it('should trigger events', function (done) {
this.timeout(10000)
const changeHandle = sinon.spy()
vm = createSelect({
value: 2016,
options: [2013, 2014, 2015, 2016, 2017, 2018]
}, {
change: changeHandle
})
const el = vm.$el
el.click()
setTimeout(() => {
vm.picker.scrollTo(0, 1)
setTimeout(() => {
const confirmBtn = document.querySelector('.cube-picker-choose [data-action="confirm"]')
confirmBtn.click()
expect(changeHandle)
.to.be.callCount(1)
done()
}, 1000)
}, 100)
})
})
function createSelect (props = {}, events = {}) {
return instantiateComponent(Vue, Select, {
props: props,
on: events
})
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册