Commit 342390e691f0a67379663cc315e882aef68c54a3
Committed by
GitHub
Merge pull request #2882 from iview/pr/2867
Pr/2867
Showing
4 changed files
with
125 additions
and
54 deletions
Show diff stats
examples/routers/radio.vue
| @@ -43,12 +43,12 @@ | @@ -43,12 +43,12 @@ | ||
| 43 | data () { | 43 | data () { |
| 44 | return { | 44 | return { |
| 45 | single: true, | 45 | single: true, |
| 46 | - phone: 'apple', | 46 | + phone: '', |
| 47 | button2: '北京', | 47 | button2: '北京', |
| 48 | - } | 48 | + }; |
| 49 | }, | 49 | }, |
| 50 | methods: { | 50 | methods: { |
| 51 | 51 | ||
| 52 | } | 52 | } |
| 53 | - } | 53 | + }; |
| 54 | </script> | 54 | </script> |
src/components/radio/radio-group.vue
| 1 | <template> | 1 | <template> |
| 2 | - <div :class="classes"> | 2 | + <div :class="classes" :name="name"> |
| 3 | <slot></slot> | 3 | <slot></slot> |
| 4 | </div> | 4 | </div> |
| 5 | </template> | 5 | </template> |
| @@ -9,6 +9,10 @@ | @@ -9,6 +9,10 @@ | ||
| 9 | 9 | ||
| 10 | const prefixCls = 'ivu-radio-group'; | 10 | const prefixCls = 'ivu-radio-group'; |
| 11 | 11 | ||
| 12 | + let seed = 0; | ||
| 13 | + const now = Date.now(); | ||
| 14 | + const getUuid = () => `ivuRadioGroup_${now}_${seed++}`; | ||
| 15 | + | ||
| 12 | export default { | 16 | export default { |
| 13 | name: 'RadioGroup', | 17 | name: 'RadioGroup', |
| 14 | mixins: [ Emitter ], | 18 | mixins: [ Emitter ], |
| @@ -30,6 +34,10 @@ | @@ -30,6 +34,10 @@ | ||
| 30 | vertical: { | 34 | vertical: { |
| 31 | type: Boolean, | 35 | type: Boolean, |
| 32 | default: false | 36 | default: false |
| 37 | + }, | ||
| 38 | + name: { | ||
| 39 | + type: String, | ||
| 40 | + default: getUuid | ||
| 33 | } | 41 | } |
| 34 | }, | 42 | }, |
| 35 | data () { | 43 | data () { |
| @@ -56,12 +64,10 @@ | @@ -56,12 +64,10 @@ | ||
| 56 | }, | 64 | }, |
| 57 | methods: { | 65 | methods: { |
| 58 | updateValue () { | 66 | updateValue () { |
| 59 | - const value = this.value; | ||
| 60 | this.childrens = findComponentsDownward(this, 'Radio'); | 67 | this.childrens = findComponentsDownward(this, 'Radio'); |
| 61 | - | ||
| 62 | if (this.childrens) { | 68 | if (this.childrens) { |
| 63 | this.childrens.forEach(child => { | 69 | this.childrens.forEach(child => { |
| 64 | - child.currentValue = value == child.label; | 70 | + child.currentValue = this.value === child.label; |
| 65 | child.group = true; | 71 | child.group = true; |
| 66 | }); | 72 | }); |
| 67 | } | 73 | } |
| @@ -76,6 +82,7 @@ | @@ -76,6 +82,7 @@ | ||
| 76 | }, | 82 | }, |
| 77 | watch: { | 83 | watch: { |
| 78 | value () { | 84 | value () { |
| 85 | + this.currentValue = this.value; | ||
| 79 | this.updateValue(); | 86 | this.updateValue(); |
| 80 | } | 87 | } |
| 81 | } | 88 | } |
src/components/radio/radio.vue
| 1 | <template> | 1 | <template> |
| 2 | - <label | ||
| 3 | - :class="wrapClasses" | ||
| 4 | - :tabindex="disabled ? -1 : 0" | ||
| 5 | - @keyup.space="change"> | 2 | + <label :class="wrapClasses"> |
| 6 | <span :class="radioClasses"> | 3 | <span :class="radioClasses"> |
| 7 | <span :class="innerClasses"></span> | 4 | <span :class="innerClasses"></span> |
| 8 | <input | 5 | <input |
| 9 | type="radio" | 6 | type="radio" |
| 10 | - tabindex="-1" | ||
| 11 | :class="inputClasses" | 7 | :class="inputClasses" |
| 12 | :disabled="disabled" | 8 | :disabled="disabled" |
| 13 | :checked="currentValue" | 9 | :checked="currentValue" |
| 14 | - :name="name" | 10 | + :name="groupName" |
| 15 | @change="change" | 11 | @change="change" |
| 16 | - > | ||
| 17 | - </span><slot>{{ label }}</slot> | 12 | + @focus="onFocus" |
| 13 | + @blur="onBlur"> | ||
| 14 | + </span> | ||
| 15 | + <slot>{{ label }}</slot> | ||
| 18 | </label> | 16 | </label> |
| 19 | </template> | 17 | </template> |
| 20 | <script> | 18 | <script> |
| @@ -59,7 +57,10 @@ | @@ -59,7 +57,10 @@ | ||
| 59 | return { | 57 | return { |
| 60 | currentValue: this.value, | 58 | currentValue: this.value, |
| 61 | group: false, | 59 | group: false, |
| 62 | - parent: findComponentUpward(this, 'RadioGroup') | 60 | + groupName: this.name, |
| 61 | + parent: findComponentUpward(this, 'RadioGroup'), | ||
| 62 | + focusWrapper: false, | ||
| 63 | + focusInner: false | ||
| 63 | }; | 64 | }; |
| 64 | }, | 65 | }, |
| 65 | computed: { | 66 | computed: { |
| @@ -70,7 +71,8 @@ | @@ -70,7 +71,8 @@ | ||
| 70 | [`${prefixCls}-group-item`]: this.group, | 71 | [`${prefixCls}-group-item`]: this.group, |
| 71 | [`${prefixCls}-wrapper-checked`]: this.currentValue, | 72 | [`${prefixCls}-wrapper-checked`]: this.currentValue, |
| 72 | [`${prefixCls}-wrapper-disabled`]: this.disabled, | 73 | [`${prefixCls}-wrapper-disabled`]: this.disabled, |
| 73 | - [`${prefixCls}-${this.size}`]: !!this.size | 74 | + [`${prefixCls}-${this.size}`]: !!this.size, |
| 75 | + [`${prefixCls}-focus`]: this.focusWrapper | ||
| 74 | } | 76 | } |
| 75 | ]; | 77 | ]; |
| 76 | }, | 78 | }, |
| @@ -84,18 +86,35 @@ | @@ -84,18 +86,35 @@ | ||
| 84 | ]; | 86 | ]; |
| 85 | }, | 87 | }, |
| 86 | innerClasses () { | 88 | innerClasses () { |
| 87 | - return `${prefixCls}-inner`; | 89 | + return [ |
| 90 | + `${prefixCls}-inner`, | ||
| 91 | + { | ||
| 92 | + [`${prefixCls}-focus`]: this.focusInner | ||
| 93 | + } | ||
| 94 | + ]; | ||
| 88 | }, | 95 | }, |
| 89 | inputClasses () { | 96 | inputClasses () { |
| 90 | return `${prefixCls}-input`; | 97 | return `${prefixCls}-input`; |
| 91 | } | 98 | } |
| 92 | }, | 99 | }, |
| 93 | mounted () { | 100 | mounted () { |
| 94 | - if (this.parent) this.group = true; | ||
| 95 | - if (!this.group) { | ||
| 96 | - this.updateValue(); | ||
| 97 | - } else { | 101 | + if (this.parent) { |
| 102 | + this.group = true; | ||
| 103 | + if (this.name && this.name !== this.parent.name) { | ||
| 104 | + /* eslint-disable no-console */ | ||
| 105 | + if (console.warn) { | ||
| 106 | + console.warn('[iview] Name does not match Radio Group name.'); | ||
| 107 | + } | ||
| 108 | + /* eslint-enable no-console */ | ||
| 109 | + } else { | ||
| 110 | + this.groupName = this.parent.name; | ||
| 111 | + } | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + if (this.group) { | ||
| 98 | this.parent.updateValue(); | 115 | this.parent.updateValue(); |
| 116 | + } else { | ||
| 117 | + this.updateValue(); | ||
| 99 | } | 118 | } |
| 100 | }, | 119 | }, |
| 101 | methods: { | 120 | methods: { |
| @@ -107,30 +126,43 @@ | @@ -107,30 +126,43 @@ | ||
| 107 | const checked = event.target.checked; | 126 | const checked = event.target.checked; |
| 108 | this.currentValue = checked; | 127 | this.currentValue = checked; |
| 109 | 128 | ||
| 110 | - let value = checked ? this.trueValue : this.falseValue; | 129 | + const value = checked ? this.trueValue : this.falseValue; |
| 111 | this.$emit('input', value); | 130 | this.$emit('input', value); |
| 112 | 131 | ||
| 113 | - if (this.group && this.label !== undefined) { | ||
| 114 | - this.parent.change({ | ||
| 115 | - value: this.label, | ||
| 116 | - checked: this.value | ||
| 117 | - }); | ||
| 118 | - } | ||
| 119 | - if (!this.group) { | 132 | + if (this.group) { |
| 133 | + if (this.label !== undefined) { | ||
| 134 | + this.parent.change({ | ||
| 135 | + value: this.label, | ||
| 136 | + checked: this.value | ||
| 137 | + }); | ||
| 138 | + } | ||
| 139 | + } else { | ||
| 120 | this.$emit('on-change', value); | 140 | this.$emit('on-change', value); |
| 121 | this.dispatch('FormItem', 'on-form-change', value); | 141 | this.dispatch('FormItem', 'on-form-change', value); |
| 122 | } | 142 | } |
| 123 | }, | 143 | }, |
| 124 | updateValue () { | 144 | updateValue () { |
| 125 | this.currentValue = this.value === this.trueValue; | 145 | this.currentValue = this.value === this.trueValue; |
| 146 | + }, | ||
| 147 | + onBlur () { | ||
| 148 | + this.focusWrapper = false; | ||
| 149 | + this.focusInner = false; | ||
| 150 | + }, | ||
| 151 | + onFocus () { | ||
| 152 | + if (this.group && this.parent.type === 'button') { | ||
| 153 | + this.focusWrapper = true; | ||
| 154 | + } else { | ||
| 155 | + this.focusInner = true; | ||
| 156 | + } | ||
| 126 | } | 157 | } |
| 127 | }, | 158 | }, |
| 128 | watch: { | 159 | watch: { |
| 129 | value (val) { | 160 | value (val) { |
| 130 | - if (val !== this.trueValue && val !== this.falseValue) { | 161 | + if (val === this.trueValue || val === this.falseValue) { |
| 162 | + this.updateValue(); | ||
| 163 | + } else { | ||
| 131 | throw 'Value should be trueValue or falseValue.'; | 164 | throw 'Value should be trueValue or falseValue.'; |
| 132 | } | 165 | } |
| 133 | - this.updateValue(); | ||
| 134 | } | 166 | } |
| 135 | } | 167 | } |
| 136 | }; | 168 | }; |
src/styles/components/radio.less
| @@ -3,10 +3,16 @@ | @@ -3,10 +3,16 @@ | ||
| 3 | @radio-inner-prefix-cls: ~"@{radio-prefix-cls}-inner"; | 3 | @radio-inner-prefix-cls: ~"@{radio-prefix-cls}-inner"; |
| 4 | @radio-group-button-prefix-cls: ~"@{radio-group-prefix-cls}-button"; | 4 | @radio-group-button-prefix-cls: ~"@{radio-group-prefix-cls}-button"; |
| 5 | 5 | ||
| 6 | +.@{radio-prefix-cls}-focus { | ||
| 7 | + box-shadow: 0 0 0 2px fade(@primary-color, 20%); | ||
| 8 | + z-index: 1; | ||
| 9 | +} | ||
| 10 | + | ||
| 6 | .@{radio-group-prefix-cls} { | 11 | .@{radio-group-prefix-cls} { |
| 7 | display: inline-block; | 12 | display: inline-block; |
| 8 | font-size: @font-size-small; | 13 | font-size: @font-size-small; |
| 9 | vertical-align: middle; | 14 | vertical-align: middle; |
| 15 | + //outline: none; | ||
| 10 | &-vertical{ | 16 | &-vertical{ |
| 11 | .@{radio-prefix-cls}-wrapper { | 17 | .@{radio-prefix-cls}-wrapper { |
| 12 | display: block; | 18 | display: block; |
| @@ -28,19 +34,14 @@ | @@ -28,19 +34,14 @@ | ||
| 28 | &-disabled{ | 34 | &-disabled{ |
| 29 | cursor: @cursor-disabled; | 35 | cursor: @cursor-disabled; |
| 30 | } | 36 | } |
| 31 | - outline: 0; | ||
| 32 | - &:focus { | ||
| 33 | - & .@{radio-inner-prefix-cls} { | ||
| 34 | - box-shadow: 0 0 0 2px fade(@primary-color, 20%); | ||
| 35 | - } | ||
| 36 | - } | 37 | + //outline: none; |
| 37 | } | 38 | } |
| 38 | 39 | ||
| 39 | .@{radio-prefix-cls} { | 40 | .@{radio-prefix-cls} { |
| 40 | display: inline-block; | 41 | display: inline-block; |
| 41 | margin-right: 4px; | 42 | margin-right: 4px; |
| 42 | white-space: nowrap; | 43 | white-space: nowrap; |
| 43 | - outline: none; | 44 | + //outline: none; |
| 44 | position: relative; | 45 | position: relative; |
| 45 | line-height: 1; | 46 | line-height: 1; |
| 46 | vertical-align: middle; | 47 | vertical-align: middle; |
| @@ -177,7 +178,7 @@ span.@{radio-prefix-cls} + * { | @@ -177,7 +178,7 @@ span.@{radio-prefix-cls} + * { | ||
| 177 | height: @btn-circle-size; | 178 | height: @btn-circle-size; |
| 178 | line-height: @btn-circle-size - 2px; | 179 | line-height: @btn-circle-size - 2px; |
| 179 | margin: 0; | 180 | margin: 0; |
| 180 | - padding: 0 16px; | 181 | + padding: 0 16px - 1px; |
| 181 | font-size: @font-size-small; | 182 | font-size: @font-size-small; |
| 182 | color: @btn-default-color; | 183 | color: @btn-default-color; |
| 183 | transition: all @transition-time ease-in-out; | 184 | transition: all @transition-time ease-in-out; |
| @@ -185,26 +186,37 @@ span.@{radio-prefix-cls} + * { | @@ -185,26 +186,37 @@ span.@{radio-prefix-cls} + * { | ||
| 185 | border: 1px solid @border-color-base; | 186 | border: 1px solid @border-color-base; |
| 186 | border-left: 0; | 187 | border-left: 0; |
| 187 | background: #fff; | 188 | background: #fff; |
| 189 | + position: relative; | ||
| 188 | 190 | ||
| 189 | > span { | 191 | > span { |
| 190 | margin-left: 0; | 192 | margin-left: 0; |
| 191 | } | 193 | } |
| 192 | 194 | ||
| 193 | - &:before { | 195 | + &:before, &:after { |
| 194 | content: ''; | 196 | content: ''; |
| 197 | + display: block; | ||
| 195 | position: absolute; | 198 | position: absolute; |
| 196 | width: 1px; | 199 | width: 1px; |
| 197 | height: 100%; | 200 | height: 100%; |
| 198 | left: -1px; | 201 | left: -1px; |
| 202 | + top: 0; | ||
| 199 | background: @border-color-base; | 203 | background: @border-color-base; |
| 200 | - visibility: hidden; | 204 | + //visibility: hidden; |
| 201 | transition: all @transition-time ease-in-out; | 205 | transition: all @transition-time ease-in-out; |
| 202 | } | 206 | } |
| 203 | 207 | ||
| 208 | + &:after{ | ||
| 209 | + height: @btn-circle-size + 4px; | ||
| 210 | + left: -1px; | ||
| 211 | + top: -3px; | ||
| 212 | + background: fade(@primary-color, 20%); | ||
| 213 | + opacity: 0; | ||
| 214 | + } | ||
| 215 | + | ||
| 204 | &:first-child { | 216 | &:first-child { |
| 205 | border-radius: @btn-border-radius 0 0 @btn-border-radius; | 217 | border-radius: @btn-border-radius 0 0 @btn-border-radius; |
| 206 | border-left: 1px solid @border-color-base; | 218 | border-left: 1px solid @border-color-base; |
| 207 | - &:before { | 219 | + &:before, &:after { |
| 208 | display: none; | 220 | display: none; |
| 209 | } | 221 | } |
| 210 | } | 222 | } |
| @@ -225,10 +237,6 @@ span.@{radio-prefix-cls} + * { | @@ -225,10 +237,6 @@ span.@{radio-prefix-cls} + * { | ||
| 225 | } | 237 | } |
| 226 | } | 238 | } |
| 227 | 239 | ||
| 228 | - &:focus { | ||
| 229 | - box-shadow: 0 0 0 2px fade(@primary-color, 20%); | ||
| 230 | - } | ||
| 231 | - | ||
| 232 | .@{radio-prefix-cls}-inner, | 240 | .@{radio-prefix-cls}-inner, |
| 233 | input { | 241 | input { |
| 234 | opacity: 0; | 242 | opacity: 0; |
| @@ -241,25 +249,41 @@ span.@{radio-prefix-cls} + * { | @@ -241,25 +249,41 @@ span.@{radio-prefix-cls} + * { | ||
| 241 | border-color: @primary-color; | 249 | border-color: @primary-color; |
| 242 | color: @primary-color; | 250 | color: @primary-color; |
| 243 | box-shadow: -1px 0 0 0 @primary-color; | 251 | box-shadow: -1px 0 0 0 @primary-color; |
| 252 | + z-index: 1; | ||
| 253 | + | ||
| 254 | + &:before{ | ||
| 255 | + background: @primary-color; | ||
| 256 | + opacity: 0.1; | ||
| 257 | + } | ||
| 258 | + | ||
| 259 | + &.@{radio-prefix-cls}-focus{ | ||
| 260 | + box-shadow: -1px 0 0 0 @primary-color, 0 0 0 2px fade(@primary-color, 20%); | ||
| 261 | + transition: all @transition-time ease-in-out; | ||
| 262 | + &:after{ | ||
| 263 | + left: -3px; | ||
| 264 | + top: -3px; | ||
| 265 | + opacity: 1; | ||
| 266 | + background: fade(@primary-color, 20%); | ||
| 267 | + } | ||
| 268 | + &:first-child{ | ||
| 269 | + box-shadow: 0 0 0 2px fade(@primary-color, 20%); | ||
| 270 | + } | ||
| 271 | + } | ||
| 244 | 272 | ||
| 245 | &:first-child { | 273 | &:first-child { |
| 246 | border-color: @primary-color; | 274 | border-color: @primary-color; |
| 247 | - box-shadow: none!important; | 275 | + box-shadow: none; |
| 248 | } | 276 | } |
| 249 | 277 | ||
| 250 | &:hover { | 278 | &:hover { |
| 251 | border-color: tint(@primary-color, 20%); | 279 | border-color: tint(@primary-color, 20%); |
| 252 | - box-shadow: -1px 0 0 0 tint(@primary-color, 20%); | 280 | + //box-shadow: -1px 0 0 0 tint(@primary-color, 20%); |
| 253 | color: tint(@primary-color, 20%); | 281 | color: tint(@primary-color, 20%); |
| 254 | } | 282 | } |
| 255 | 283 | ||
| 256 | - &:focus { | ||
| 257 | - box-shadow: 0 0 0 2px fade(@primary-color, 20%)!important; | ||
| 258 | - } | ||
| 259 | - | ||
| 260 | &:active { | 284 | &:active { |
| 261 | border-color: shade(@primary-color, 5%); | 285 | border-color: shade(@primary-color, 5%); |
| 262 | - box-shadow: -1px 0 0 0 shade(@primary-color, 5%); | 286 | + //box-shadow: -1px 0 0 0 shade(@primary-color, 5%); |
| 263 | color: shade(@primary-color, 5%); | 287 | color: shade(@primary-color, 5%); |
| 264 | } | 288 | } |
| 265 | } | 289 | } |
| @@ -294,6 +318,9 @@ span.@{radio-prefix-cls} + * { | @@ -294,6 +318,9 @@ span.@{radio-prefix-cls} + * { | ||
| 294 | height: @btn-circle-size-large; | 318 | height: @btn-circle-size-large; |
| 295 | line-height: @btn-circle-size-large - 2px; | 319 | line-height: @btn-circle-size-large - 2px; |
| 296 | font-size: @font-size-base; | 320 | font-size: @font-size-base; |
| 321 | + &:after{ | ||
| 322 | + height: @btn-circle-size-large + 4px; | ||
| 323 | + } | ||
| 297 | } | 324 | } |
| 298 | 325 | ||
| 299 | .@{radio-group-button-prefix-cls}.@{radio-group-prefix-cls}-small .@{radio-prefix-cls}-wrapper{ | 326 | .@{radio-group-button-prefix-cls}.@{radio-group-prefix-cls}-small .@{radio-prefix-cls}-wrapper{ |
| @@ -301,6 +328,11 @@ span.@{radio-prefix-cls} + * { | @@ -301,6 +328,11 @@ span.@{radio-prefix-cls} + * { | ||
| 301 | line-height: @btn-circle-size-small - 2px; | 328 | line-height: @btn-circle-size-small - 2px; |
| 302 | padding: 0 12px; | 329 | padding: 0 12px; |
| 303 | font-size: @font-size-small; | 330 | font-size: @font-size-small; |
| 331 | + | ||
| 332 | + &:after{ | ||
| 333 | + height: @btn-circle-size-small + 4px; | ||
| 334 | + } | ||
| 335 | + | ||
| 304 | &:first-child { | 336 | &:first-child { |
| 305 | border-radius: @btn-border-radius-small 0 0 @btn-border-radius-small; | 337 | border-radius: @btn-border-radius-small 0 0 @btn-border-radius-small; |
| 306 | } | 338 | } |