From 76e23aefc6b9a1b3972cf509a8bde9c9631c28b0 Mon Sep 17 00:00:00 2001 From: neverland Date: Wed, 30 Jan 2019 20:23:26 +0800 Subject: [PATCH] [new feature] Radio: add shape prop & icon slot (#2651) --- .../test/__snapshots__/demo.spec.js.snap | 15 +++- packages/checkbox/en-US.md | 2 +- packages/checkbox/zh-CN.md | 2 +- .../test/__snapshots__/demo.spec.js.snap | 5 +- packages/radio/demo/index.vue | 27 +++++- packages/radio/en-US.md | 36 ++++++++ packages/radio/index.js | 62 +++++++++----- packages/radio/index.less | 83 +++++++++++-------- .../test/__snapshots__/demo.spec.js.snap | 44 ++++++++-- packages/radio/test/index.spec.js | 45 ++++++++++ packages/radio/zh-CN.md | 35 ++++++++ packages/style/var.less | 8 ++ 12 files changed, 294 insertions(+), 70 deletions(-) create mode 100644 packages/radio/test/index.spec.js diff --git a/packages/address-list/test/__snapshots__/demo.spec.js.snap b/packages/address-list/test/__snapshots__/demo.spec.js.snap index 1110e53a1..03d00db68 100644 --- a/packages/address-list/test/__snapshots__/demo.spec.js.snap +++ b/packages/address-list/test/__snapshots__/demo.spec.js.snap @@ -7,13 +7,19 @@ exports[`renders demo correctly 1`] = `
-
张三,13000000000
浙江省杭州市西湖区文三路 138 号东方通信大厦 7 楼 501 室
+
+
+
张三,13000000000
浙江省杭州市西湖区文三路 138 号东方通信大厦 7 楼 501 室
+
-
李四,1310000000
浙江省杭州市拱墅区莫干山路 50 号
+
+
+
李四,1310000000
浙江省杭州市拱墅区莫干山路 50 号
+
@@ -21,7 +27,10 @@ exports[`renders demo correctly 1`] = `
以下地址超出配送范围
-
王五,1320000000
浙江省杭州市滨江区江南大道 15 号
+
+
+
王五,1320000000
浙江省杭州市滨江区江南大道 15 号
+
diff --git a/packages/checkbox/en-US.md b/packages/checkbox/en-US.md index e9181a990..39d17c5b6 100644 --- a/packages/checkbox/en-US.md +++ b/packages/checkbox/en-US.md @@ -139,7 +139,7 @@ export default { | Attribute | Description | Type | Default | |------|------|------|------| | name | Checkbox name | `any` | - | -| shape | Can be set to `round` `square` | `String` | `round` | +| shape | Can be set to `square` | `String` | `round` | | v-model | Check status | `Boolean` | `false` | | disabled | Diable checkbox | `Boolean` | `false` | | label-disabled | Whether to disable label click | `Boolean` | `false` | diff --git a/packages/checkbox/zh-CN.md b/packages/checkbox/zh-CN.md index a93a55ff6..0951e9961 100644 --- a/packages/checkbox/zh-CN.md +++ b/packages/checkbox/zh-CN.md @@ -169,7 +169,7 @@ export default { |------|------|------| | change | 当绑定值变化时触发的事件 | 当前组件的值 | -### Checkbox Slot +### Checkbox 插槽 | 名称 | 说明 | slot-scope | |------|------|------| diff --git a/packages/contact-card/test/__snapshots__/demo.spec.js.snap b/packages/contact-card/test/__snapshots__/demo.spec.js.snap index f3dd42a1c..754f96573 100644 --- a/packages/contact-card/test/__snapshots__/demo.spec.js.snap +++ b/packages/contact-card/test/__snapshots__/demo.spec.js.snap @@ -13,7 +13,10 @@ exports[`renders demo correctly 1`] = `
-
张三,13000000000
+
+
+
张三,13000000000
+
diff --git a/packages/radio/demo/index.vue b/packages/radio/demo/index.vue index 1085fe5cc..cf65d767f 100644 --- a/packages/radio/demo/index.vue +++ b/packages/radio/demo/index.vue @@ -32,6 +32,21 @@ + + + {{ $t('customIcon') }} + + + + @@ -62,6 +77,7 @@ export default { radio: '单选框', text1: '未选中禁用', text2: '选中且禁用', + customIcon: '自定义图标', customColor: '自定义颜色', withCell: '与 Cell 组件一起使用' }, @@ -69,6 +85,7 @@ export default { radio: 'Radio', text1: 'Disabled', text2: 'Disabled and checked', + customIcon: 'Custom Icon', customColor: 'Custom Color', withCell: 'Inside a Cell' } @@ -78,7 +95,11 @@ export default { return { 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' + } }; } }; @@ -93,5 +114,9 @@ export default { margin-bottom: 10px; } } + + img { + height: 20px; + } } diff --git a/packages/radio/en-US.md b/packages/radio/en-US.md index 289ef2f8b..1fc7fdf34 100644 --- a/packages/radio/en-US.md +++ b/packages/radio/en-US.md @@ -46,6 +46,33 @@ export default { Radio ``` +#### Custom Icon + +Use icon slot to custom icon + +```html + + Custom Icon + + +``` + +```js +export default { + data() { + checked: true, + icon: { + normal: '//img.yzcdn.cn/icon-normal.png', + active: '//img.yzcdn.cn/icon-active.png' + } + } +} +``` + #### Inside a Cell ```html @@ -66,11 +93,13 @@ export default { | Attribute | Description | Type | Default | |------|------|------|------| | name | Radio name | `any` | - | +| shape | Can be set to `square` | `String` | `round` | | disabled | Whether to disable radio | `Boolean` | `false` | | label-disabled | Whether to disable label click | `Boolean` | `false` | | label-position | Can be set to `left` | `String` | `right` | | checked-color | Checked color | `String` | `#1989fa` | - | + ### RadioGroup API | Attribute | Description | Type | Default | @@ -83,3 +112,10 @@ export default { | Event | Description | Parameters | |------|------|------| | change | Triggered when value changed | current value | + +### Radio Slot + +| Name | Description | slot-scope | +|------|------|------| +| - | Custom label | - | +| icon | Custom icon | checked: whether to be checked | diff --git a/packages/radio/index.js b/packages/radio/index.js index 5e16175b1..3e4f9cf85 100644 --- a/packages/radio/index.js +++ b/packages/radio/index.js @@ -13,7 +13,11 @@ export default sfc({ disabled: Boolean, checkedColor: String, labelPosition: String, - labelDisabled: Boolean + labelDisabled: Boolean, + shape: { + type: String, + default: 'round' + } }, computed: { @@ -29,6 +33,16 @@ export default sfc({ isDisabled() { return this.parent ? this.parent.disabled || this.disabled : this.disabled; + }, + + iconStyle() { + const { checkedColor } = this; + if (checkedColor && this.currentValue === this.name && !this.isDisabled) { + return { + borderColor: checkedColor, + backgroundColor: checkedColor + }; + } } }, @@ -37,6 +51,12 @@ export default sfc({ }, methods: { + onClickIcon() { + if (!this.isDisabled) { + this.currentValue = this.name; + } + }, + onClickLabel() { if (!this.isDisabled && !this.labelDisabled) { this.currentValue = this.name; @@ -46,31 +66,35 @@ export default sfc({ render(h) { const checked = this.currentValue === this.name; - const { isDisabled, checkedColor } = this; - const iconStyle = checkedColor && checked && !isDisabled && { color: checkedColor }; + const CheckIcon = this.$scopedSlots.icon ? ( + this.$scopedSlots.icon({ checked }) + ) : ( + + ); + + const Label = this.$slots.default && ( + + {this.$slots.default} + + ); return (
{ this.$emit('click'); }} > - - - - - {this.$slots.default && ( - - {this.$slots.default} - - )} +
+ {CheckIcon} +
+ {Label}
); } diff --git a/packages/radio/index.less b/packages/radio/index.less index 74819970f..6db58e16c 100644 --- a/packages/radio/index.less +++ b/packages/radio/index.less @@ -4,56 +4,67 @@ overflow: hidden; user-select: none; - &__input, + &__icon, &__label { display: inline-block; vertical-align: middle; + line-height: @radio-size; } - &__input { - height: 1em; - position: relative; - font-size: @radio-size; - } + &__icon { + height: @radio-size; - &__control { - position: absolute; - top: 0; - left: 0; - opacity: 0; - margin: 0; - width: 100%; - height: 100%; + .van-icon { + font-size: 14px; + color: transparent; + text-align: center; + line-height: inherit; + width: @radio-size; + height: @radio-size; + box-sizing: border-box; + border: 1px solid @radio-border-color; + transition: @radio-transition-duration; + } + + &--round { + .van-icon { + border-radius: 100%; + } + } + + &--checked { + .van-icon { + color: @white; + border-color: @radio-checked-icon-color; + background-color: @radio-checked-icon-color; + } + } + + &--disabled { + .van-icon { + border-color: @radio-disabled-icon-color; + background-color: @radio-disabled-background-color; + } + } + + &--disabled&--checked { + .van-icon { + color: @radio-disabled-icon-color; + } + } } &__label { - line-height: @radio-size; - margin-left: 10px; + color: @radio-label-color; + margin-left: @radio-label-margin; &--left { float: left; - margin: 0 10px 0 0; + margin: 0 @radio-label-margin 0 0; } - } - .van-icon { - width: 1em; - pointer-events: none; - } - - .van-icon-checked { - color: @blue; - } - - .van-icon-circle { - color: @gray; - } - - &--disabled { - .van-icon { - color: @gray-light; - border-radius: 100%; - background-color: @background-color; + &--disabled { + color: @radio-disabled-label-color; } } } diff --git a/packages/radio/test/__snapshots__/demo.spec.js.snap b/packages/radio/test/__snapshots__/demo.spec.js.snap index cfd5841db..bd18eb15c 100644 --- a/packages/radio/test/__snapshots__/demo.spec.js.snap +++ b/packages/radio/test/__snapshots__/demo.spec.js.snap @@ -4,20 +4,42 @@ exports[`renders demo correctly 1`] = `
-
单选框 1
-
单选框 2
+
+
+
单选框 1 +
+
+
+
单选框 2 +
-
单选框 1
-
单选框 2
+
+
+
单选框 1 +
+
+
+
单选框 2 +
-
+
+
+
单选框 -
+
+
+
+
+
+
+ 自定义图标 + +
@@ -25,13 +47,19 @@ exports[`renders demo correctly 1`] = `
单选框1
-
+
+
+
+
单选框2
-
+
+
+
+
diff --git a/packages/radio/test/index.spec.js b/packages/radio/test/index.spec.js new file mode 100644 index 000000000..571b6ae3e --- /dev/null +++ b/packages/radio/test/index.spec.js @@ -0,0 +1,45 @@ +import Radio from '..'; +import RadioGroup from '../../radio-group'; +import { mount } from '../../../test/utils'; + +test('radio-group change', () => { + const wrapper = mount({ + template: ` + + + label + + + `, + components: { + Radio, + RadioGroup + }, + data() { + return { + result: 'a', + list: ['a', 'b', 'c', 'd'] + }; + } + }); + + const icons = wrapper.findAll('.van-radio__icon'); + const labels = wrapper.findAll('.van-radio__label'); + + icons.at(2).trigger('click'); + expect(wrapper.vm.result).toEqual('c'); + expect(wrapper.emitted('change')[0][0]).toEqual('c'); + + labels.at(1).trigger('click'); + expect(wrapper.vm.result).toEqual('b'); + expect(wrapper.emitted('change')[1][0]).toEqual('b'); + + icons.at(3).trigger('click'); + labels.at(3).trigger('click'); + expect(wrapper.vm.result).toEqual('b'); +}); diff --git a/packages/radio/zh-CN.md b/packages/radio/zh-CN.md index 20c235507..95e6b1f9a 100644 --- a/packages/radio/zh-CN.md +++ b/packages/radio/zh-CN.md @@ -48,6 +48,33 @@ export default { 复选框 ``` +#### 自定义图标 + +通过 icon 插槽自定义图标,可以通过 `slot-scope` 判断是否为选中状态 + +```html + + 自定义图标 + + +``` + +```js +export default { + data() { + checked: true, + icon: { + normal: '//img.yzcdn.cn/icon-normal.png', + active: '//img.yzcdn.cn/icon-active.png' + } + } +} +``` + #### 与 Cell 组件一起使用 此时你需要再引入`Cell`和`CellGroup`组件。 @@ -70,6 +97,7 @@ export default { | 参数 | 说明 | 类型 | 默认值 | 版本 | |------|------|------|------|------| | name | 标识符 | 任意类型 | - | - | +| shape | 形状,可选值为 `square` | `String` | `round` | 1.5.8 | | disabled | 是否为禁用状态 | `Boolean` | `false` | - | | label-disabled | 是否禁用文本内容点击 | `Boolean` | `false` | 1.1.13 | | label-position | 文本位置,可选值为 `left` | `String` | `right` | 1.1.13 | @@ -87,3 +115,10 @@ export default { | 事件名称 | 说明 | 回调参数 | |------|------|------| | change | 当绑定值变化时触发的事件 | 当前选中项的 name | + +### Radio 插槽 + +| 名称 | 说明 | slot-scope | +|------|------|------| +| - | 自定义文本 | - | +| icon | 自定义图标 | checked: 是否为选中状态 | diff --git a/packages/style/var.less b/packages/style/var.less index 530df54ea..edd33aa1c 100644 --- a/packages/style/var.less +++ b/packages/style/var.less @@ -97,6 +97,14 @@ // 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; // Swipe @swipe-indicator: 6px;