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
src/components/radio/radio-group.vue
1 | 1 | <template> |
2 | - <div :class="classes"> | |
2 | + <div :class="classes" :name="name"> | |
3 | 3 | <slot></slot> |
4 | 4 | </div> |
5 | 5 | </template> |
... | ... | @@ -9,6 +9,10 @@ |
9 | 9 | |
10 | 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 | 16 | export default { |
13 | 17 | name: 'RadioGroup', |
14 | 18 | mixins: [ Emitter ], |
... | ... | @@ -30,6 +34,10 @@ |
30 | 34 | vertical: { |
31 | 35 | type: Boolean, |
32 | 36 | default: false |
37 | + }, | |
38 | + name: { | |
39 | + type: String, | |
40 | + default: getUuid | |
33 | 41 | } |
34 | 42 | }, |
35 | 43 | data () { |
... | ... | @@ -56,12 +64,10 @@ |
56 | 64 | }, |
57 | 65 | methods: { |
58 | 66 | updateValue () { |
59 | - const value = this.value; | |
60 | 67 | this.childrens = findComponentsDownward(this, 'Radio'); |
61 | - | |
62 | 68 | if (this.childrens) { |
63 | 69 | this.childrens.forEach(child => { |
64 | - child.currentValue = value == child.label; | |
70 | + child.currentValue = this.value === child.label; | |
65 | 71 | child.group = true; |
66 | 72 | }); |
67 | 73 | } |
... | ... | @@ -76,6 +82,7 @@ |
76 | 82 | }, |
77 | 83 | watch: { |
78 | 84 | value () { |
85 | + this.currentValue = this.value; | |
79 | 86 | this.updateValue(); |
80 | 87 | } |
81 | 88 | } | ... | ... |
src/components/radio/radio.vue
1 | 1 | <template> |
2 | - <label | |
3 | - :class="wrapClasses" | |
4 | - :tabindex="disabled ? -1 : 0" | |
5 | - @keyup.space="change"> | |
2 | + <label :class="wrapClasses"> | |
6 | 3 | <span :class="radioClasses"> |
7 | 4 | <span :class="innerClasses"></span> |
8 | 5 | <input |
9 | 6 | type="radio" |
10 | - tabindex="-1" | |
11 | 7 | :class="inputClasses" |
12 | 8 | :disabled="disabled" |
13 | 9 | :checked="currentValue" |
14 | - :name="name" | |
10 | + :name="groupName" | |
15 | 11 | @change="change" |
16 | - > | |
17 | - </span><slot>{{ label }}</slot> | |
12 | + @focus="onFocus" | |
13 | + @blur="onBlur"> | |
14 | + </span> | |
15 | + <slot>{{ label }}</slot> | |
18 | 16 | </label> |
19 | 17 | </template> |
20 | 18 | <script> |
... | ... | @@ -59,7 +57,10 @@ |
59 | 57 | return { |
60 | 58 | currentValue: this.value, |
61 | 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 | 66 | computed: { |
... | ... | @@ -70,7 +71,8 @@ |
70 | 71 | [`${prefixCls}-group-item`]: this.group, |
71 | 72 | [`${prefixCls}-wrapper-checked`]: this.currentValue, |
72 | 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 | 86 | ]; |
85 | 87 | }, |
86 | 88 | innerClasses () { |
87 | - return `${prefixCls}-inner`; | |
89 | + return [ | |
90 | + `${prefixCls}-inner`, | |
91 | + { | |
92 | + [`${prefixCls}-focus`]: this.focusInner | |
93 | + } | |
94 | + ]; | |
88 | 95 | }, |
89 | 96 | inputClasses () { |
90 | 97 | return `${prefixCls}-input`; |
91 | 98 | } |
92 | 99 | }, |
93 | 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 | 115 | this.parent.updateValue(); |
116 | + } else { | |
117 | + this.updateValue(); | |
99 | 118 | } |
100 | 119 | }, |
101 | 120 | methods: { |
... | ... | @@ -107,30 +126,43 @@ |
107 | 126 | const checked = event.target.checked; |
108 | 127 | this.currentValue = checked; |
109 | 128 | |
110 | - let value = checked ? this.trueValue : this.falseValue; | |
129 | + const value = checked ? this.trueValue : this.falseValue; | |
111 | 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 | 140 | this.$emit('on-change', value); |
121 | 141 | this.dispatch('FormItem', 'on-form-change', value); |
122 | 142 | } |
123 | 143 | }, |
124 | 144 | updateValue () { |
125 | 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 | 159 | watch: { |
129 | 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 | 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 | 3 | @radio-inner-prefix-cls: ~"@{radio-prefix-cls}-inner"; |
4 | 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 | 11 | .@{radio-group-prefix-cls} { |
7 | 12 | display: inline-block; |
8 | 13 | font-size: @font-size-small; |
9 | 14 | vertical-align: middle; |
15 | + //outline: none; | |
10 | 16 | &-vertical{ |
11 | 17 | .@{radio-prefix-cls}-wrapper { |
12 | 18 | display: block; |
... | ... | @@ -28,19 +34,14 @@ |
28 | 34 | &-disabled{ |
29 | 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 | 40 | .@{radio-prefix-cls} { |
40 | 41 | display: inline-block; |
41 | 42 | margin-right: 4px; |
42 | 43 | white-space: nowrap; |
43 | - outline: none; | |
44 | + //outline: none; | |
44 | 45 | position: relative; |
45 | 46 | line-height: 1; |
46 | 47 | vertical-align: middle; |
... | ... | @@ -177,7 +178,7 @@ span.@{radio-prefix-cls} + * { |
177 | 178 | height: @btn-circle-size; |
178 | 179 | line-height: @btn-circle-size - 2px; |
179 | 180 | margin: 0; |
180 | - padding: 0 16px; | |
181 | + padding: 0 16px - 1px; | |
181 | 182 | font-size: @font-size-small; |
182 | 183 | color: @btn-default-color; |
183 | 184 | transition: all @transition-time ease-in-out; |
... | ... | @@ -185,26 +186,37 @@ span.@{radio-prefix-cls} + * { |
185 | 186 | border: 1px solid @border-color-base; |
186 | 187 | border-left: 0; |
187 | 188 | background: #fff; |
189 | + position: relative; | |
188 | 190 | |
189 | 191 | > span { |
190 | 192 | margin-left: 0; |
191 | 193 | } |
192 | 194 | |
193 | - &:before { | |
195 | + &:before, &:after { | |
194 | 196 | content: ''; |
197 | + display: block; | |
195 | 198 | position: absolute; |
196 | 199 | width: 1px; |
197 | 200 | height: 100%; |
198 | 201 | left: -1px; |
202 | + top: 0; | |
199 | 203 | background: @border-color-base; |
200 | - visibility: hidden; | |
204 | + //visibility: hidden; | |
201 | 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 | 216 | &:first-child { |
205 | 217 | border-radius: @btn-border-radius 0 0 @btn-border-radius; |
206 | 218 | border-left: 1px solid @border-color-base; |
207 | - &:before { | |
219 | + &:before, &:after { | |
208 | 220 | display: none; |
209 | 221 | } |
210 | 222 | } |
... | ... | @@ -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 | 240 | .@{radio-prefix-cls}-inner, |
233 | 241 | input { |
234 | 242 | opacity: 0; |
... | ... | @@ -241,25 +249,41 @@ span.@{radio-prefix-cls} + * { |
241 | 249 | border-color: @primary-color; |
242 | 250 | color: @primary-color; |
243 | 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 | 273 | &:first-child { |
246 | 274 | border-color: @primary-color; |
247 | - box-shadow: none!important; | |
275 | + box-shadow: none; | |
248 | 276 | } |
249 | 277 | |
250 | 278 | &:hover { |
251 | 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 | 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 | 284 | &:active { |
261 | 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 | 287 | color: shade(@primary-color, 5%); |
264 | 288 | } |
265 | 289 | } |
... | ... | @@ -294,6 +318,9 @@ span.@{radio-prefix-cls} + * { |
294 | 318 | height: @btn-circle-size-large; |
295 | 319 | line-height: @btn-circle-size-large - 2px; |
296 | 320 | font-size: @font-size-base; |
321 | + &:after{ | |
322 | + height: @btn-circle-size-large + 4px; | |
323 | + } | |
297 | 324 | } |
298 | 325 | |
299 | 326 | .@{radio-group-button-prefix-cls}.@{radio-group-prefix-cls}-small .@{radio-prefix-cls}-wrapper{ |
... | ... | @@ -301,6 +328,11 @@ span.@{radio-prefix-cls} + * { |
301 | 328 | line-height: @btn-circle-size-small - 2px; |
302 | 329 | padding: 0 12px; |
303 | 330 | font-size: @font-size-small; |
331 | + | |
332 | + &:after{ | |
333 | + height: @btn-circle-size-small + 4px; | |
334 | + } | |
335 | + | |
304 | 336 | &:first-child { |
305 | 337 | border-radius: @btn-border-radius-small 0 0 @btn-border-radius-small; |
306 | 338 | } | ... | ... |