提交 51491c05 编写于 作者: C christlala 提交者: doly mood

Feat Checker (#326)

* feat(checker): new component checker

* test(checker): init checker test

* refactor(demo): add checker

* docs(checker): init checker docs

* refactor(checker): remove console

* test(checker): fix radio test

* fix(checker): radio & checkbox type active condition

* fix(checker): radio condition error

* refactor(example): checker router component path err

* test(checker): fix test
上级 1ca38eb1
......@@ -31,6 +31,7 @@
"checkbox": "Checkbox",
"checkbox-group": "CheckboxGroup",
"radio": "Radio",
"checker": "Checker",
"input": "Input",
"textarea": "Textarea",
"select": "Select",
......@@ -113,6 +114,7 @@
"checkbox": "Checkbox",
"checkbox-group": "CheckboxGroup",
"radio": "Radio",
"checker": "Checker",
"input": "Input",
"textarea": "Textarea",
"select": "Select",
......
## Checker
Checker is more flexible selection component, you can alse customize the layout.
### Example
- Basic usage
```html
<cube-checker
v-model="checkerValue"
:options="options" />
```
```js
export default {
data() {
return {
checkerValue: [],
options: [
{
value: 1,
text: 'red'
},
{
value: 2,
text: 'yellow'
},
{
value: 3,
text: 'blue'
},
{
value: 4,
text: 'green'
}
]
}
}
}
```
The value of `options` is an array. The default `checkerValue` value is `''`,
If you clicked one option, the `checkerValue` will be set as the value of this option.
- radio
```html
<cube-checker
v-model="checkerValue"
:options="options"
type="radio" />
```
```js
export default {
data() {
return {
checkerValue: '',
options: [
{
value: 0,
text: 'AAAAA'
},
{
value: 1,
text: 'BBBBB'
}
]
}
}
}
```
If the `type` is set to `'radio'`, the checker will be a radio type.
The default type is a `'checkbox'`.
- Use slot
You can use slot to implement custom layout.
```html
<cube-checker
v-model="checkerList"
:options="options"
type="radio">
<cube-checker-item
v-for="item in options"
:key="item.value"
:option="item">
<span class="orange"><i class="cubeic-alert"></i>{{item.text}}</span>
</cube-checker-item>
</cube-checker>
```
```js
export default {
data() {
return {
checkerList: [],
options: [
{
value: 0,
text: 'AAAAA'
},
{
value: 1,
text: 'BBBBB'
}
]
}
}
}
```
- Use min & max prop
You can use `min` and `max` prop but the `type` must set to `'checkbox'`.
`max` set the max number of checked items, `min` set the min number of checked items.
```html
<cube-checker
v-model="checkerList"
:options="options"
:min="1"
:max="2"/>
```
```js
export default {
data() {
return {
checkerList: [3],
option: [
{
value: 1,
text: 'red'
},
{
value: 2,
text: 'yellow'
},
{
value: 3,
text: 'blue'
},
{
value: 4,
text: 'green'
}
]
}
}
}
```
### Props configuration
| Attribute | Description | Type | Accepted Values | Default |
| - | - | - | - | - |
| options | a collection of configuration items | Array | - | - |
| type | the type of checker | String | checkbox/radio | checkbox |
| min | the min number | Number | - | 0 |
| max | the max number | Number | - | options length |
* options sub configuration
| Attribute | Description | Type |
| - | - | - |
| value | the value of checker item | String/Number |
| text | the text of checker item | String |
### CubeCheckerItem Props configuration
| Attribute | Description | Type | Accepted Values | Default |
| - | - | - | - | - |
| option | item configuration object | Object | - | - |
* option sub configuration
| Attribute | Description | Type |
| - | - | - |
| value | the value of checker item | String/Number |
| text | the text of checker item | String |
## Checker
Checker 是更加灵活的选择组件,可以自定义需要的布局样式。
### 示例
- 默认
```html
<cube-checker
v-model="checkerValue"
:options="options" />
```
```js
export default {
data() {
return {
checkerValue: [],
options: [
{
value: 1,
text: 'red'
},
{
value: 2,
text: 'yellow'
},
{
value: 3,
text: 'blue'
},
{
value: 4,
text: 'green'
}
]
}
}
}
```
如果选中了,则 `checkerValue` 的值就为 `value`
设置 `option`,当选中某一项的时候,`checkerValue` 的值就是 `'optionValue'`,当未选中的时候,`checkerValue` 的值就是 `''`
- 单选
```html
<cube-checker
v-model="checkerValue"
:options="options"
type="radio" />
```
```js
export default {
data() {
return {
checkerValue: '',
options: [
{
value: 0,
text: 'AAAAA'
},
{
value: 1,
text: 'BBBBB'
}
]
}
}
}
```
可通过设置 `type` ,若为 `'radio'` 则是单选,若为 `'checkbox'` 则是多选。
- 自定义结构
可通过默认插槽插入 CubeCheckerItem 实现自定义每项的结构。
```html
<cube-checker
v-model="checkerList"
:options="options"
type="radio">
<cube-checker-item
v-for="item in options"
:key="item.value"
:option="item">
<span class="orange"><i class="cubeic-alert"></i>{{item.text}}</span>
</cube-checker-item>
</cube-checker>
```
```js
export default {
data() {
return {
checkerList: [],
options: [
{
value: 0,
text: 'AAAAA'
},
{
value: 1,
text: 'BBBBB'
}
]
}
}
}
```
- 个数限制
`max` 设置最多可选个数,多选时可用。
`min` 设置最少可选个数,多选时可用。
```html
<cube-checker
v-model="checkerList"
:options="options"
:min="1"
:max="2"/>
```
```js
export default {
data() {
return {
checkerList: [3],
option: [
{
value: 1,
text: 'red'
},
{
value: 2,
text: 'yellow'
},
{
value: 3,
text: 'blue'
},
{
value: 4,
text: 'green'
}
]
}
}
}
```
### Props 配置
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| - | - | - | - | - |
| options | 配置项集合 | Array | - | - |
| type | 选项类型 | String | checkbox/radio | checkbox |
| min | 最少可选个数 | Number | - | 0 |
| max | 最多可选个数 | Number | - | options 的长度 |
* options 子配置项
| 参数 | 说明 | 类型 |
| - | - | - |
| value | 选项的值 | String/Number |
| text | 选项的文本 | String |
### CubeCheckerItem Props 配置
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| - | - | - | - | - |
| option | 单个配置项 | Object | - | - |
* option 子配置项
| 参数 | 说明 | 类型 |
| - | - | - |
| value | 选项的值 | String/Number |
| text | 选项的文本 | String |
......@@ -66,6 +66,10 @@
path: '/checkbox-group',
text: 'CheckboxGroup'
},
{
path: '/checker',
text: 'Checker'
},
{
path: '/radio',
text: 'Radio'
......
<template>
<cube-page type="checker-view" title="Checker">
<template slot="content">
<p>default usage</p>
<br>
<cube-checker
v-model="checkboxCheckerList"
:options="checkboxOptions" />
<br>
<p>checker value : {{checkboxCheckerList}}</p>
<br><br>
<p>type: radio</p>
<br>
<cube-checker
v-model="checkerValue"
:options="radioOptions"
type="radio" />
<br>
<p>checker value : {{checkerValue}}</p>
<br><br>
<p>use slot</p>
<br>
<cube-checker
v-model="checkerValue"
:options="radioOptions"
type="radio">
<cube-checker-item
v-for="item in radioOptions"
:key="item.value"
:option="item">
<span class="orange"><i class="cubeic-alert"></i>{{item.text}}</span>
</cube-checker-item>
</cube-checker>
<br>
<p>checker value : {{checkerValue}}</p>
<br><br>
<p>set min and max</p>
<br>
<cube-checker
v-model="defaultCheckerList"
:options="checkboxOptions"
:min="1"
:max="2"/>
<br>
<p>checker value : {{defaultCheckerList}} (min: 1 max: 2)</p>
<br><br>
</template>
</cube-page>
</template>
<script type="text/ecmascript-6">
import CubePage from '../components/cube-page.vue'
export default {
data() {
return {
checkerValue: '',
radioOptions: [
{
value: 0,
text: 'AAAAA'
},
{
value: 1,
text: 'BBBBB'
}
],
checkboxCheckerList: [],
checkboxOptions: [
{
value: 1,
text: 'red'
},
{
value: 2,
text: 'yellow'
},
{
value: 3,
text: 'blue'
},
{
value: 4,
text: 'green'
}
],
defaultCheckerList: [3]
}
},
components: {
CubePage
},
methods: {
radioClick(value) {
console.log(value)
this.radioCheckerList = [value]
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
.checker-group-view
.content
>
*
margin: 10px 0
.checker-item
display: inline-block
vertical-align: top
text-align: center
padding: 8px 10px
margin-right: 10px
color: #fff
border-radius: 4px
position: relative
background: #fc9153
&:active
background: #e8864c
.orange
font-weight: 700
color: #ff8000
</style>
......@@ -68,6 +68,7 @@ import Tab from '../pages/tab-bar/tab-entry.vue'
import TabBasic from '../pages/tab-bar/tab-basic.vue'
import TabComposite from '../pages/tab-bar/tab-composite.vue'
import ScrollTab from '../pages/tab-bar/scroll-tab.vue'
import Checker from '../pages/checker.vue'
const routes = [
{
......@@ -82,6 +83,10 @@ const routes = [
path: '/checkbox-group',
component: CheckboxGroup
},
{
path: '/checker',
component: Checker
},
{
path: '/radio',
component: Radio
......
......@@ -76,6 +76,14 @@ $radio-disabled-icon-bgc := $color-light-grey-ss
$radio-hollow-selected-icon-color := $color-orange
$radio-hollow-disabled-icon-color := $color-light-grey-ss
//checker
$checker-item-color := $color-grey
$checker-item-bdc := $color-light-grey-sss
$checker-item-bgc := $color-white
$checker-item-active-color := $color-orange
$checker-item-active-bdc := $color-orange
$checker-item-active-bgc := $color-light-orange-opacity
// dialog
$dialog-color := $color-grey
$dialog-bgc := $color-white
......
<template>
<li
class="cube-checker-item"
:class="{'cube-checker-item_active': isActive}"
@click="clickHandler"
>
<slot>
<span v-html="option.text"></span>
</slot>
</li>
</template>
<script type="text/ecmascript-6">
const COMPONENT_NAME = 'cube-checker-item'
export default {
name: COMPONENT_NAME,
props: {
option: {
type: Object,
default() {
/* istanbul ignore next */
return {}
}
}
},
computed: {
isActive() {
const isRadio = this.$parent.isRadio
const currentValue = this.$parent.currentValue
const value = this.option.value
return isRadio ? currentValue === value : currentValue.indexOf(value) >= 0
}
},
methods: {
clickHandler() {
this.$parent.check(this.option)
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@require "../../common/stylus/variable.styl"
@require "../../common/stylus/mixin.styl"
.cube-checker-item
display: inline-block
vertical-align: top
text-align: center
padding: 8px 10px
margin-right: 10px
color: $checker-item-color
background: $checker-item-bgc
border-radius: 4px
border-1px($checker-item-bdc, 4px)
.cube-checker-item_active
color: $checker-item-active-color
background: $checker-item-active-bgc
border-1px($checker-item-active-bdc, 4px)
</style>
<template>
<ul class="cube-checker">
<slot>
<cube-checker-item
v-for="(option, index) in options"
:option="option"
:key="index" />
</slot>
</ul>
</template>
<script type="text/ecmascript-6">
import CubeCheckerItem from './checker-item.vue'
const COMPONENT_NAME = 'cube-checker'
const EVENT_INPUT = 'input'
export default {
name: COMPONENT_NAME,
props: {
value: [String, Number, Array],
options: {
type: Array,
default() {
/* istanbul ignore next */
return []
}
},
type: {
type: String,
default: 'checkbox'
},
min: {
type: Number,
default: 0
},
max: {
type: Number,
default() {
return this.options.length
}
}
},
data () {
return {
currentValue: this.value
}
},
computed: {
isRadio() {
return this.type === 'radio'
}
},
watch: {
value (newValue) {
this.currentValue = newValue
},
currentValue (val) {
this.$emit(EVENT_INPUT, val)
}
},
methods: {
check(option) {
if (this.isRadio) {
this.checkRadio(option)
} else {
this.checkCheckbox(option)
}
},
checkRadio(option) {
this.currentValue = option.value
},
checkCheckbox(option) {
const value = option.value
const currentValue = this.currentValue
const valueLen = currentValue.length
const min = this.min
const max = this.max
const index = currentValue.indexOf(value)
if (index > -1) {
(valueLen > min) && currentValue.splice(index, 1)
} else {
(valueLen < max) && currentValue.push(value)
}
}
},
components: {
CubeCheckerItem
}
}
</script>
......@@ -11,6 +11,7 @@ import {
// form
Checkbox,
CheckboxGroup,
Checker,
Radio,
RadioGroup,
Input,
......@@ -58,6 +59,7 @@ const components = [
// form
Checkbox,
CheckboxGroup,
Checker,
Radio,
RadioGroup,
Input,
......
......@@ -11,6 +11,7 @@ import TabPanels from './modules/tab-panels'
// Form
import Checkbox from './modules/checkbox'
import CheckboxGroup from './modules/checkbox-group'
import Checker from './modules/checker'
import RadioGroup from './modules/radio-group'
import Input from './modules/input'
import Textarea from './modules/textarea'
......@@ -58,6 +59,7 @@ const StickyEle = Sticky.Ele
const ScrollNavPanel = ScrollNav.Panel
const Tab = TabBar.Tab
const TabPanel = TabPanels.Panel
const CheckerItem = Checker.Item
export {
// style
......@@ -74,6 +76,8 @@ export {
// form
Checkbox,
CheckboxGroup,
CheckerItem,
Checker,
Radio,
RadioGroup,
Input,
......
import Checker from '../../components/checker/checker.vue'
import CheckerItem from '../../components/checker/checker-item.vue'
Checker.install = function (Vue) {
Vue.component(Checker.name, Checker)
Vue.component(CheckerItem.name, CheckerItem)
}
Checker.Item = CheckerItem
export default Checker
import Vue from 'vue2'
import Checker from '@/modules/checker'
import createVue from '../utils/create-vue'
describe('Checker.vue', () => {
let vm
afterEach(() => {
if (vm) {
vm.$parent.destroy()
vm = null
}
})
it('use', () => {
Vue.use(Checker)
expect(Vue.component(Checker.name))
.to.be.a('function')
})
it('should render radio contents', () => {
vm = createChecker('radio')
expect(vm.$el.className)
.to.include('cube-checker')
expect(vm.$el.querySelectorAll('.cube-checker-item_active').length)
.to.equal(1)
// expect(vm.$el.querySelector('.checker').className)
// .to.include('active')
})
it('should render radio contents', (done) => {
vm = createChecker('radio')
const p = vm.$parent
const options = p.options
expect(p.checkerList)
.to.equal(1)
vm.$nextTick(() => {
const items = vm.$el.querySelectorAll('.cube-checker-item')
expect(items.length)
.to.equal(options.length)
items[0].click()
vm.$nextTick(() => {
expect(p.checkerList)
.to.equal(0)
done()
})
})
})
it('should render checkbox contents', (done) => {
vm = createChecker('checkbox')
const p = vm.$parent
const options = p.options
expect(p.checkerList.join(''))
.to.equal('1')
vm.$nextTick(() => {
const items = vm.$el.querySelectorAll('.cube-checker-item')
expect(items.length)
.to.equal(options.length)
items[1].click()
items[2].click()
items[3].click()
vm.$nextTick(() => {
expect(p.checkerList.join(''))
.to.equal('23')
done()
})
})
})
})
function createChecker (type) {
const vm = createVue({
template: `
<cube-checker
v-model="checkerList"
:options="options"
:type="type">
</cube-checker>
`,
data: {
checkerList: type === 'radio' ? 1 : [1],
options: [
{
value: 0,
text: 'AAAAA'
},
{
value: 1,
text: 'BBBBB'
},
{
value: 2,
text: 'CCCCC'
},
{
value: 3,
text: 'DDDDD'
}
],
type: type,
max: 2
}
})
return vm
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册