Commit 79964596878615e93d3cdce6b019b2d2a499ec86
1 parent
36d24701
Use native w3c
Showing
4 changed files
with
79 additions
and
104 deletions
Show diff stats
examples/routers/radio.vue
src/components/radio/radio-group.vue
1 | <template> | 1 | <template> |
2 | - <div | ||
3 | - :class="classes" tabindex="0" | ||
4 | - @keydown.left="onLeft" | ||
5 | - @keydown.right="onRight" | ||
6 | - @keydown.up="onUp" | ||
7 | - @keydown.down="onDown" | ||
8 | - @keydown.tab="onTab"> | 2 | + <div :class="classes" :name="name"> |
9 | <slot></slot> | 3 | <slot></slot> |
10 | </div> | 4 | </div> |
11 | </template> | 5 | </template> |
@@ -15,6 +9,10 @@ | @@ -15,6 +9,10 @@ | ||
15 | 9 | ||
16 | const prefixCls = 'ivu-radio-group'; | 10 | const prefixCls = 'ivu-radio-group'; |
17 | 11 | ||
12 | + let seed = 0; | ||
13 | + const now = Date.now(); | ||
14 | + const getUuid = () => `ivuRadioGroup_${now}_${seed++}`; | ||
15 | + | ||
18 | export default { | 16 | export default { |
19 | name: 'RadioGroup', | 17 | name: 'RadioGroup', |
20 | mixins: [ Emitter ], | 18 | mixins: [ Emitter ], |
@@ -36,13 +34,16 @@ | @@ -36,13 +34,16 @@ | ||
36 | vertical: { | 34 | vertical: { |
37 | type: Boolean, | 35 | type: Boolean, |
38 | default: false | 36 | default: false |
37 | + }, | ||
38 | + name: { | ||
39 | + type: String, | ||
40 | + default: getUuid | ||
39 | } | 41 | } |
40 | }, | 42 | }, |
41 | data () { | 43 | data () { |
42 | return { | 44 | return { |
43 | currentValue: this.value, | 45 | currentValue: this.value, |
44 | - childrens: [], | ||
45 | - preventDefaultTab: true | 46 | + childrens: [] |
46 | }; | 47 | }; |
47 | }, | 48 | }, |
48 | computed: { | 49 | computed: { |
@@ -63,12 +64,10 @@ | @@ -63,12 +64,10 @@ | ||
63 | }, | 64 | }, |
64 | methods: { | 65 | methods: { |
65 | updateValue () { | 66 | updateValue () { |
66 | - const value = this.value; | ||
67 | this.childrens = findComponentsDownward(this, 'Radio'); | 67 | this.childrens = findComponentsDownward(this, 'Radio'); |
68 | - | ||
69 | if (this.childrens) { | 68 | if (this.childrens) { |
70 | this.childrens.forEach(child => { | 69 | this.childrens.forEach(child => { |
71 | - child.currentValue = value === child.label; | 70 | + child.currentValue = this.value === child.label; |
72 | child.group = true; | 71 | child.group = true; |
73 | }); | 72 | }); |
74 | } | 73 | } |
@@ -79,55 +78,11 @@ | @@ -79,55 +78,11 @@ | ||
79 | this.$emit('input', data.value); | 78 | this.$emit('input', data.value); |
80 | this.$emit('on-change', data.value); | 79 | this.$emit('on-change', data.value); |
81 | this.dispatch('FormItem', 'on-form-change', data.value); | 80 | this.dispatch('FormItem', 'on-form-change', data.value); |
82 | - }, | ||
83 | - findRadio(value) { | ||
84 | - return this.childrens && this.childrens.length ? this.childrens.find((child) => child.value === value) : undefined; | ||
85 | - }, | ||
86 | - findIndexRadio(value) { | ||
87 | - return this.childrens && this.childrens.length ? this.childrens.findIndex((child) => child.value === value) : -1; | ||
88 | - }, | ||
89 | - includesRadio(value) { | ||
90 | - return this.childrens && this.childrens.length ? this.childrens.includes((child) => child.value === value) : false; | ||
91 | - }, | ||
92 | - nextRadio() { | ||
93 | - if (this.includesRadio(this.currentValue)) { | ||
94 | - console.log('get next'); | ||
95 | - } else { | ||
96 | - return this.childrens && this.childrens.length ? this.childrens[0] : undefined; | ||
97 | - } | ||
98 | - }, | ||
99 | - onLeft() { | ||
100 | - console.log('left', this.currentValue); | ||
101 | - }, | ||
102 | - onRight() { | ||
103 | - console.log('right', this.currentValue); | ||
104 | - }, | ||
105 | - onUp() { | ||
106 | - console.log('up', this.currentValue); | ||
107 | - }, | ||
108 | - onDown() { | ||
109 | - console.log('down', this.currentValue); | ||
110 | - }, | ||
111 | - onTab(event) { | ||
112 | - if (!this.preventDefaultTab) { | ||
113 | - return; | ||
114 | - } | ||
115 | - | ||
116 | - event.preventDefault(); | ||
117 | - this.preventDefaultTab = false; | ||
118 | - this.currentValue = this.nextRadio(); | ||
119 | - if (this.currentValue) { | ||
120 | - this.change({ | ||
121 | - value: this.currentValue.label | ||
122 | - }); | ||
123 | - } | ||
124 | - | ||
125 | - console.log('tab', this); | ||
126 | - | ||
127 | - }, | 81 | + } |
128 | }, | 82 | }, |
129 | watch: { | 83 | watch: { |
130 | value () { | 84 | value () { |
85 | + this.currentValue = this.value; | ||
131 | this.updateValue(); | 86 | this.updateValue(); |
132 | } | 87 | } |
133 | } | 88 | } |
src/components/radio/radio.vue
1 | <template> | 1 | <template> |
2 | - <label | ||
3 | - :class="wrapClasses" | ||
4 | - :tabindex="disabled || group ? -1 : 0"> | 2 | + <label :class="wrapClasses" ref="label"> |
5 | <span :class="radioClasses"> | 3 | <span :class="radioClasses"> |
6 | - <span :class="innerClasses"></span> | 4 | + <span :class="innerClasses" ref="inner"></span> |
7 | <input | 5 | <input |
8 | type="radio" | 6 | type="radio" |
9 | - tabindex="-1" | ||
10 | :class="inputClasses" | 7 | :class="inputClasses" |
11 | :disabled="disabled" | 8 | :disabled="disabled" |
12 | :checked="currentValue" | 9 | :checked="currentValue" |
13 | - :name="name" | 10 | + :name="groupName" |
14 | @change="change" | 11 | @change="change" |
15 | - @focus="$el.focus()" | ||
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,33 @@ | @@ -84,18 +86,33 @@ | ||
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 | + if (console.warn) { | ||
105 | + console.warn('[iview] Name does not match Radio Group name.'); | ||
106 | + } | ||
107 | + } else { | ||
108 | + this.groupName = this.parent.name; | ||
109 | + } | ||
110 | + } | ||
111 | + | ||
112 | + if (this.group) { | ||
98 | this.parent.updateValue(); | 113 | this.parent.updateValue(); |
114 | + } else { | ||
115 | + this.updateValue(); | ||
99 | } | 116 | } |
100 | }, | 117 | }, |
101 | methods: { | 118 | methods: { |
@@ -107,30 +124,43 @@ | @@ -107,30 +124,43 @@ | ||
107 | const checked = event.target.checked; | 124 | const checked = event.target.checked; |
108 | this.currentValue = checked; | 125 | this.currentValue = checked; |
109 | 126 | ||
110 | - let value = checked ? this.trueValue : this.falseValue; | 127 | + const value = checked ? this.trueValue : this.falseValue; |
111 | this.$emit('input', value); | 128 | this.$emit('input', value); |
112 | 129 | ||
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) { | 130 | + if (this.group) { |
131 | + if (this.label !== undefined) { | ||
132 | + this.parent.change({ | ||
133 | + value: this.label, | ||
134 | + checked: this.value | ||
135 | + }); | ||
136 | + } | ||
137 | + } else { | ||
120 | this.$emit('on-change', value); | 138 | this.$emit('on-change', value); |
121 | this.dispatch('FormItem', 'on-form-change', value); | 139 | this.dispatch('FormItem', 'on-form-change', value); |
122 | } | 140 | } |
123 | }, | 141 | }, |
124 | updateValue () { | 142 | updateValue () { |
125 | this.currentValue = this.value === this.trueValue; | 143 | this.currentValue = this.value === this.trueValue; |
144 | + }, | ||
145 | + onBlur () { | ||
146 | + this.focusWrapper = false; | ||
147 | + this.focusInner = false; | ||
148 | + }, | ||
149 | + onFocus () { | ||
150 | + if (this.group && this.parent.type === 'button') { | ||
151 | + this.focusWrapper = true; | ||
152 | + } else { | ||
153 | + this.focusInner = true; | ||
154 | + } | ||
126 | } | 155 | } |
127 | }, | 156 | }, |
128 | watch: { | 157 | watch: { |
129 | value (val) { | 158 | value (val) { |
130 | - if (val !== this.trueValue && val !== this.falseValue) { | 159 | + if (val === this.trueValue || val === this.falseValue) { |
160 | + this.updateValue(); | ||
161 | + } else { | ||
131 | throw 'Value should be trueValue or falseValue.'; | 162 | throw 'Value should be trueValue or falseValue.'; |
132 | } | 163 | } |
133 | - this.updateValue(); | ||
134 | } | 164 | } |
135 | } | 165 | } |
136 | }; | 166 | }; |
src/styles/components/radio.less
@@ -3,11 +3,16 @@ | @@ -3,11 +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; |
10 | - //outline: 0; | 15 | + //outline: none; |
11 | &-vertical{ | 16 | &-vertical{ |
12 | .@{radio-prefix-cls}-wrapper { | 17 | .@{radio-prefix-cls}-wrapper { |
13 | display: block; | 18 | display: block; |
@@ -29,20 +34,14 @@ | @@ -29,20 +34,14 @@ | ||
29 | &-disabled{ | 34 | &-disabled{ |
30 | cursor: @cursor-disabled; | 35 | cursor: @cursor-disabled; |
31 | } | 36 | } |
32 | - outline: 0; | ||
33 | - &:focus { | ||
34 | - & .@{radio-inner-prefix-cls} { | ||
35 | - box-shadow: 0 0 0 2px fade(@primary-color, 20%); | ||
36 | - z-index: 1; | ||
37 | - } | ||
38 | - } | 37 | + //outline: none; |
39 | } | 38 | } |
40 | 39 | ||
41 | .@{radio-prefix-cls} { | 40 | .@{radio-prefix-cls} { |
42 | display: inline-block; | 41 | display: inline-block; |
43 | margin-right: 4px; | 42 | margin-right: 4px; |
44 | white-space: nowrap; | 43 | white-space: nowrap; |
45 | - outline: none; | 44 | + //outline: none; |
46 | position: relative; | 45 | position: relative; |
47 | line-height: 1; | 46 | line-height: 1; |
48 | vertical-align: middle; | 47 | vertical-align: middle; |
@@ -227,11 +226,6 @@ span.@{radio-prefix-cls} + * { | @@ -227,11 +226,6 @@ span.@{radio-prefix-cls} + * { | ||
227 | } | 226 | } |
228 | } | 227 | } |
229 | 228 | ||
230 | - &:focus { | ||
231 | - box-shadow: 0 0 0 2px fade(@primary-color, 20%); | ||
232 | - z-index: 1; | ||
233 | - } | ||
234 | - | ||
235 | .@{radio-prefix-cls}-inner, | 229 | .@{radio-prefix-cls}-inner, |
236 | input { | 230 | input { |
237 | opacity: 0; | 231 | opacity: 0; |
@@ -247,7 +241,7 @@ span.@{radio-prefix-cls} + * { | @@ -247,7 +241,7 @@ span.@{radio-prefix-cls} + * { | ||
247 | 241 | ||
248 | &:first-child { | 242 | &:first-child { |
249 | border-color: @primary-color; | 243 | border-color: @primary-color; |
250 | - box-shadow: none!important; | 244 | + //box-shadow: none!important; |
251 | } | 245 | } |
252 | 246 | ||
253 | &:hover { | 247 | &:hover { |
@@ -256,10 +250,6 @@ span.@{radio-prefix-cls} + * { | @@ -256,10 +250,6 @@ span.@{radio-prefix-cls} + * { | ||
256 | color: tint(@primary-color, 20%); | 250 | color: tint(@primary-color, 20%); |
257 | } | 251 | } |
258 | 252 | ||
259 | - &:focus { | ||
260 | - box-shadow: 0 0 0 2px fade(@primary-color, 20%)!important; | ||
261 | - } | ||
262 | - | ||
263 | &:active { | 253 | &:active { |
264 | border-color: shade(@primary-color, 5%); | 254 | border-color: shade(@primary-color, 5%); |
265 | //box-shadow: -1px 0 0 0 shade(@primary-color, 5%); | 255 | //box-shadow: -1px 0 0 0 shade(@primary-color, 5%); |