diff --git a/example/pages/checkbox/index.js b/example/pages/checkbox/index.js index 7637a633..9491352e 100644 --- a/example/pages/checkbox/index.js +++ b/example/pages/checkbox/index.js @@ -30,8 +30,8 @@ Page({ }, toggle(event) { - const { name } = event.currentTarget.dataset; - const checkbox = this.selectComponent(`.checkboxes-${name}`); + const { index } = event.currentTarget.dataset; + const checkbox = this.selectComponent(`.checkboxes-${index}`); checkbox.toggle(); }, diff --git a/example/pages/checkbox/index.wxml b/example/pages/checkbox/index.wxml index 6efa759d..271e5c2f 100644 --- a/example/pages/checkbox/index.wxml +++ b/example/pages/checkbox/index.wxml @@ -86,10 +86,10 @@ title="复选框{{ item }}" value-class="value-class" clickable - data-name="{{ item }}" + data-index="{{ index }}" bind:click="toggle" > - + diff --git a/example/pages/radio/index.js b/example/pages/radio/index.js index 26086c32..44984d30 100644 --- a/example/pages/radio/index.js +++ b/example/pages/radio/index.js @@ -4,7 +4,14 @@ Page({ data: { radio1: '1', radio2: '2', - radio3: '1' + radio3: '1', + icon: { + normal: + 'https://img.yzcdn.cn/public_files/2017/10/13/c547715be149dd3faa817e4a948b40c4.png', + active: + 'https://img.yzcdn.cn/public_files/2017/10/13/793c77793db8641c4c325b7f25bf130d.png' + }, + list: ['1', '2', '3', '4'] }, onChange(event) { @@ -13,9 +20,9 @@ Page({ }, onClick(event) { - const { value } = event.currentTarget.dataset; + const { name } = event.currentTarget.dataset; this.setData({ - radio3: value + radio3: name }); } }); diff --git a/example/pages/radio/index.wxml b/example/pages/radio/index.wxml index 493c9c15..45d7c6e1 100644 --- a/example/pages/radio/index.wxml +++ b/example/pages/radio/index.wxml @@ -34,14 +34,31 @@ + + + 自定义图标 + + + + - - - - - + + diff --git a/example/pages/radio/index.wxss b/example/pages/radio/index.wxss index e662d41d..5ce39d49 100644 --- a/example/pages/radio/index.wxss +++ b/example/pages/radio/index.wxss @@ -5,3 +5,11 @@ .demo-radio { margin-bottom: 10px; } + +.value-class { + flex: none !important; +} + +.icon { + width: 20px; +} diff --git a/packages/checkbox-group/index.ts b/packages/checkbox-group/index.ts index 6cffcfdb..bf321ae3 100644 --- a/packages/checkbox-group/index.ts +++ b/packages/checkbox-group/index.ts @@ -7,32 +7,41 @@ VantComponent({ name: 'checkbox', type: 'descendant', linked(target: Weapp.Component) { - const { value, disabled } = this.data; - target.set({ - value: value.indexOf(target.data.name) !== -1, - disabled: disabled || target.data.disabled - }); + this.children = this.children || []; + this.children.push(target); + this.updateChild(target); + }, + unlinked(target: Weapp.Component) { + this.children = this.children.filter( + (child: Weapp.Component) => child !== target + ); } }, props: { max: Number, - value: Array, - disabled: Boolean + value: { + type: Array, + observer: 'updateChildren' + }, + disabled: { + type: Boolean, + observer: 'updateChildren' + } }, - watch: { - value(value) { - const children = this.getRelationNodes('../checkbox/index'); - children.forEach(child => { - child.set({ value: value.indexOf(child.data.name) !== -1 }); - }); + methods: { + updateChildren() { + (this.children || []).forEach((child: Weapp.Component) => + this.updateChild(child) + ); }, - disabled(disabled: boolean) { - const children = this.getRelationNodes('../checkbox/index'); - children.forEach(child => { - child.set({ disabled: disabled || child.data.disabled }); + updateChild(child: Weapp.Component) { + const { value, disabled } = this.data; + child.set({ + value: value.indexOf(child.data.name) !== -1, + disabled: disabled || child.data.disabled }); } } diff --git a/packages/checkbox/README.md b/packages/checkbox/README.md index a7603222..5211bb9c 100644 --- a/packages/checkbox/README.md +++ b/packages/checkbox/README.md @@ -29,6 +29,20 @@ es5 复选框 ``` +```js +Page({ + data: { + checked: true + }, + + onChange(event) { + this.setData({ + checked: event.detail + }); + } +}); +``` + #### 禁用状态 ```html @@ -119,7 +133,7 @@ Page({ #### 设置最大可选数 ```html - + - + @@ -165,8 +180,8 @@ Page({ } toggle(event) { - const { name } = event.currentTarget.dataset; - const checkbox = this.selectComponent(`.checkboxes-${name}`); + const { index } = event.currentTarget.dataset; + const checkbox = this.selectComponent(`.checkboxes-${index}`); checkbox.toggle(); }, @@ -174,16 +189,23 @@ Page({ }); ``` + +```css +.value-class { + flex: none !important; +} +``` + ### Checkbox API | 参数 | 说明 | 类型 | 默认值 | |-----------|-----------|-----------|-------------| -| name | 标识 Checkbox 名称 | `any` | - | +| name | 标识 Checkbox 名称 | `String` | - | +| shape | 形状,可选值为 `round` `square` | `String` | `round` | | value | 是否为选中状态 | `Boolean` | `false` | | disabled | 是否禁用单选框 | `Boolean` | `false` | | label-disabled | 是否禁用单选框内容点击 | `Boolean` | `false` | | label-position | 文本位置,可选值为 `left` | `String` | `right` | -| shape | 形状,可选值为 `round` `square` | `String` | `round` | | use-icon-slot | 是否使用 icon slot | `Boolean` | `false` | | checked-color | 选中状态颜色 | `String` | `#1989fa` | @@ -202,6 +224,14 @@ Page({ |-----------|-----------|-----------| | bind:change | 当绑定值变化时触发的事件 | 当前组件的值 | +### Checkbox 外部样式类 + +| 类名 | 说明 | +|-----------|-----------| +| custom-class | 根节点样式类 | +| icon-class | 图标样式类 | +| label-class | 描述信息样式类 | + ### CheckboxGroup Event | 事件名 | 说明 | 回调参数 | @@ -210,10 +240,10 @@ Page({ ### Checkbox Slot -| 名称 | 说明 | slot-scope | -|-----------|-----------|-----------| -| - | 自定义文本 | - | -| icon | 自定义图标 | checked: 是否为选中状态 | +| 名称 | 说明 | +|-----------|-----------| +| - | 自定义文本 | +| icon | 自定义图标 | ### Checkbox 方法 diff --git a/packages/checkbox/index.less b/packages/checkbox/index.less index cdc295e1..efe06e24 100644 --- a/packages/checkbox/index.less +++ b/packages/checkbox/index.less @@ -14,10 +14,6 @@ flex: none; } - &__label { - word-break: break-all; - } - &__icon { display: block; width: @checkbox-size; @@ -52,6 +48,7 @@ &__label { margin-left: @checkbox-label-margin; color: @checkbox-label-color; + word-break: break-all; &--left { float: left; diff --git a/packages/checkbox/index.ts b/packages/checkbox/index.ts index 73234ee8..90ba0cfc 100644 --- a/packages/checkbox/index.ts +++ b/packages/checkbox/index.ts @@ -1,17 +1,28 @@ import { VantComponent } from '../common/component'; +function emit(target: Weapp.Component, value: boolean | any[]) { + target.$emit('input', value); + target.$emit('change', value); +} + VantComponent({ field: true, relation: { name: 'checkbox-group', - type: 'ancestor' + type: 'ancestor', + linked(target) { + this.parent = target; + }, + unlinked() { + this.parent = null; + } }, classes: ['icon-class', 'label-class'], props: { - value: null, + value: Boolean, disabled: Boolean, useIconSlot: Boolean, checkedColor: String, @@ -24,49 +35,47 @@ VantComponent({ }, methods: { - emitChange(value) { - const parent = this.getRelationNodes('../checkbox-group/index')[0]; - if (parent) { - this.setParentValue(parent, value); + emitChange(value: boolean) { + if (this.parent) { + this.setParentValue(this.parent, value); } else { - this.$emit('input', value); - this.$emit('change', value); + emit(this, value); } }, toggle() { - if (!this.data.disabled) { - this.emitChange(!this.data.value); + const { disabled, value } = this.data; + if (!disabled) { + this.emitChange(!value); } }, onClickLabel() { - if (!this.data.disabled && !this.data.labelDisabled) { - this.emitChange(!this.data.value); + const { labelDisabled, disabled, value } = this.data; + if (!disabled && !labelDisabled) { + this.emitChange(!value); } }, - setParentValue(parent, value) { + setParentValue(parent: Weapp.Component, value: boolean) { const parentValue = parent.data.value.slice(); const { name } = this.data; + const { max } = parent.data; if (value) { - if (parent.data.max && parentValue.length >= parent.data.max) { + if (max && parentValue.length >= max) { return; } - /* istanbul ignore else */ + if (parentValue.indexOf(name) === -1) { parentValue.push(name); - parent.$emit('input', parentValue); - parent.$emit('change', parentValue); + emit(parent, parentValue); } } else { const index = parentValue.indexOf(name); - /* istanbul ignore else */ if (index !== -1) { parentValue.splice(index, 1); - parent.$emit('input', parentValue); - parent.$emit('change', parentValue); + emit(parent, parentValue); } } } diff --git a/packages/common/style/var.less b/packages/common/style/var.less index c3acc58e..256a67ab 100644 --- a/packages/common/style/var.less +++ b/packages/common/style/var.less @@ -53,6 +53,17 @@ @checkbox-disabled-label-color: @gray; @checkbox-disabled-background-color: @border-color; +// Radio +@radio-size: 20px; +@radio-border-color: @gray-light; +@radio-transition-duration: .2s; +@radio-label-margin: 10px; +@radio-label-color: @text-color; +@radio-checked-icon-color: @blue; +@radio-disabled-icon-color: @gray; +@radio-disabled-label-color: @gray; +@radio-disabled-background-color: @border-color; + // Collapse @collapse-item-transition-duration: .3s; @collapse-item-content-padding: 15px; diff --git a/packages/radio-group/index.ts b/packages/radio-group/index.ts index 330ecd9a..4dc46d21 100644 --- a/packages/radio-group/index.ts +++ b/packages/radio-group/index.ts @@ -7,31 +7,40 @@ VantComponent({ name: 'radio', type: 'descendant', linked(target: Weapp.Component) { - const { value, disabled } = this.data; - target.set({ - value: value, - disabled: disabled || target.data.disabled - }); + this.children = this.children || []; + this.children.push(target); + this.updateChild(target); + }, + unlinked(target: Weapp.Component) { + this.children = this.children.filter( + (child: Weapp.Component) => child !== target + ); } }, props: { - value: null, - disabled: Boolean + value: { + type: null, + observer: 'updateChildren' + }, + disabled: { + type: Boolean, + observer: 'updateChildren' + } }, - watch: { - value(value) { - const children = this.getRelationNodes('../radio/index'); - children.forEach(child => { - child.set({ value }); - }); + methods: { + updateChildren() { + (this.children || []).forEach((child: Weapp.Component) => + this.updateChild(child) + ); }, - disabled(disabled: boolean) { - const children = this.getRelationNodes('../radio/index'); - children.forEach(child => { - child.set({ disabled: disabled || child.data.disabled }); + updateChild(child: Weapp.Component) { + const { value, disabled } = this.data; + child.set({ + value, + disabled: disabled || child.data.disabled }); } } diff --git a/packages/radio/README.md b/packages/radio/README.md index d3235643..d8b3281c 100644 --- a/packages/radio/README.md +++ b/packages/radio/README.md @@ -33,6 +33,20 @@ es5 ``` +```js +Page({ + data: { + radio: '1' + }, + + onChange(event) { + this.setData({ + checked: event.detail + }); + } +}); +``` + #### 禁用状态 通过`disabled`属性禁止选项切换,在`van-radio`上设置`diabled`可以禁用单个选项 @@ -50,6 +64,38 @@ es5 复选框 ``` +#### 自定义图标 + +通过 icon 插槽自定义图标 + +```html + + 自定义图标 + + +``` + +```js +Page({ + data: { + radio: true, + icon: { + normal: '//img.yzcdn.cn/icon-normal.png', + active: '//img.yzcdn.cn/icon-active.png' + } + }, + + onChange(event) { + this.setData({ + radio: event.detail + }); + } +}); +``` + #### 与 Cell 组件一起使用 此时你需要再引入`Cell`和`CellGroup`组件。 @@ -57,25 +103,66 @@ es5 ```html - + - + ``` +```js +Page({ + data: { + radio: '1' + }, + + onChange(event) { + this.setData({ + radio: event.detail + }); + }, + + onClick(event) { + const { name } = event.currentTarget.dataset; + this.setData({ + radio: name + }); + } +}); +``` + +```css +.value-class { + flex: none !important; +} +``` + ### Radio API | 参数 | 说明 | 类型 | 默认值 | |-----------|-----------|-----------|-------------| -| name | 标识 Radio 名称 | `any` | - | +| name | 标识 Radio 名称 | `String` | - | | value | 当前选中项的 name | `any` | - | +| shape | 形状,可选值为 `round` `square` | `String` | `round` | | disabled | 是否为禁用状态 | `Boolean` | `false` | | label-disabled | 是否禁用文本内容点击 | `Boolean` | `false` | | label-position | 文本位置,可选值为 `left` | `String` | `right` | +| use-icon-slot | 是否使用 icon slot | `Boolean` | `false` | | checked-color | 选中状态颜色 | `String` | `#1989fa` | ### Radio Event @@ -105,9 +192,3 @@ es5 | 事件名 | 说明 | 回调参数 | |-----------|-----------|-----------| | bind:change | 当绑定值变化时触发的事件 | 当前选中项的 name | - -### RadioGroup 外部样式类 - -| 类名 | 说明 | -|-----------|-----------| -| custom-class | 根节点样式类 | diff --git a/packages/radio/index.less b/packages/radio/index.less index 2952e104..17aa91e5 100644 --- a/packages/radio/index.less +++ b/packages/radio/index.less @@ -1,65 +1,66 @@ @import '../common/style/var.less'; -@radio-size: 20px; - .van-radio { + display: flex; overflow: hidden; - line-height: 1; user-select: none; - &__input, + &__icon-wrap, &__label { - display: inline-block; - vertical-align: middle; - } - - &__input { - position: relative; - font-size: @radio-size; - } - - &__control { - z-index: 1; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - margin: 0; - opacity: 0; - } - - &__label { - margin-left: 10px; - color: @text-color; - font-size: 16px; line-height: @radio-size; + } + + &__icon-wrap { + flex: none; + } + + &__icon { + display: block; + width: @radio-size; + height: @radio-size; + font-size: 14px; + color: transparent; + text-align: center; + border: 1px solid @radio-border-color; + box-sizing: border-box; + transition: @radio-transition-duration; + + &--round { + border-radius: 100%; + } + + &--checked { + color: @white; + background-color: @radio-checked-icon-color; + border-color: @radio-checked-icon-color; + } + + &--disabled { + background-color: @radio-disabled-background-color; + border-color: @radio-disabled-icon-color; + } + + &--disabled&--checked { + color: @radio-disabled-icon-color; + } + } + + &__label { + margin-left: @radio-label-margin; + color: @radio-label-color; + word-break: break-all; &--left { - margin: 0 10px 0 0; float: left; + margin: 0 @radio-label-margin 0 0; + } + + &--disabled { + color: @radio-disabled-label-color; } &:empty { margin: 0; } } - - &__icon { - pointer-events: none; - display: block; - line-height: 0; - - &--disabled { - color: @gray-light; - } - - &--checked { - color: @blue; - } - - &--check { - color: @gray; - } - } } diff --git a/packages/radio/index.ts b/packages/radio/index.ts index ce4a28ef..16969085 100644 --- a/packages/radio/index.ts +++ b/packages/radio/index.ts @@ -5,34 +5,46 @@ VantComponent({ relation: { name: 'radio-group', - type: 'ancestor' + type: 'ancestor', + linked(target: Weapp.Component) { + this.parent = target; + }, + unlinked() { + this.parent = null; + } }, classes: ['icon-class', 'label-class'], props: { - name: null, value: null, disabled: Boolean, - labelDisabled: Boolean, + useIconSlot: Boolean, + checkedColor: String, labelPosition: String, - checkedColor: String + labelDisabled: Boolean, + shape: { + type: String, + value: 'round' + } }, methods: { - emitChange(value) { - const instance = this.getRelationNodes('../radio-group/index')[0] || this; + emitChange(value: boolean) { + const instance = this.parent || this; instance.$emit('input', value); instance.$emit('change', value); }, onChange(event: Weapp.Event) { - this.emitChange(event.detail.value); + console.log(event); + this.emitChange(this.data.name); }, onClickLabel() { - if (!this.data.disabled && !this.data.labelDisabled) { - this.emitChange(this.data.name); + const { disabled, labelDisabled, name } = this.data; + if (!disabled && !labelDisabled) { + this.emitChange(name); } } } diff --git a/packages/radio/index.wxml b/packages/radio/index.wxml index fde5f2e8..e842b211 100644 --- a/packages/radio/index.wxml +++ b/packages/radio/index.wxml @@ -1,23 +1,18 @@ - - - - + + - +