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 | 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 | 3 | <slot></slot> |
| 10 | 4 | </div> |
| 11 | 5 | </template> |
| ... | ... | @@ -15,6 +9,10 @@ |
| 15 | 9 | |
| 16 | 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 | 16 | export default { |
| 19 | 17 | name: 'RadioGroup', |
| 20 | 18 | mixins: [ Emitter ], |
| ... | ... | @@ -36,13 +34,16 @@ |
| 36 | 34 | vertical: { |
| 37 | 35 | type: Boolean, |
| 38 | 36 | default: false |
| 37 | + }, | |
| 38 | + name: { | |
| 39 | + type: String, | |
| 40 | + default: getUuid | |
| 39 | 41 | } |
| 40 | 42 | }, |
| 41 | 43 | data () { |
| 42 | 44 | return { |
| 43 | 45 | currentValue: this.value, |
| 44 | - childrens: [], | |
| 45 | - preventDefaultTab: true | |
| 46 | + childrens: [] | |
| 46 | 47 | }; |
| 47 | 48 | }, |
| 48 | 49 | computed: { |
| ... | ... | @@ -63,12 +64,10 @@ |
| 63 | 64 | }, |
| 64 | 65 | methods: { |
| 65 | 66 | updateValue () { |
| 66 | - const value = this.value; | |
| 67 | 67 | this.childrens = findComponentsDownward(this, 'Radio'); |
| 68 | - | |
| 69 | 68 | if (this.childrens) { |
| 70 | 69 | this.childrens.forEach(child => { |
| 71 | - child.currentValue = value === child.label; | |
| 70 | + child.currentValue = this.value === child.label; | |
| 72 | 71 | child.group = true; |
| 73 | 72 | }); |
| 74 | 73 | } |
| ... | ... | @@ -79,55 +78,11 @@ |
| 79 | 78 | this.$emit('input', data.value); |
| 80 | 79 | this.$emit('on-change', data.value); |
| 81 | 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 | 83 | watch: { |
| 130 | 84 | value () { |
| 85 | + this.currentValue = this.value; | |
| 131 | 86 | this.updateValue(); |
| 132 | 87 | } |
| 133 | 88 | } | ... | ... |
src/components/radio/radio.vue
| 1 | 1 | <template> |
| 2 | - <label | |
| 3 | - :class="wrapClasses" | |
| 4 | - :tabindex="disabled || group ? -1 : 0"> | |
| 2 | + <label :class="wrapClasses" ref="label"> | |
| 5 | 3 | <span :class="radioClasses"> |
| 6 | - <span :class="innerClasses"></span> | |
| 4 | + <span :class="innerClasses" ref="inner"></span> | |
| 7 | 5 | <input |
| 8 | 6 | type="radio" |
| 9 | - tabindex="-1" | |
| 10 | 7 | :class="inputClasses" |
| 11 | 8 | :disabled="disabled" |
| 12 | 9 | :checked="currentValue" |
| 13 | - :name="name" | |
| 10 | + :name="groupName" | |
| 14 | 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 | 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,33 @@ |
| 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 | + 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 | 113 | this.parent.updateValue(); |
| 114 | + } else { | |
| 115 | + this.updateValue(); | |
| 99 | 116 | } |
| 100 | 117 | }, |
| 101 | 118 | methods: { |
| ... | ... | @@ -107,30 +124,43 @@ |
| 107 | 124 | const checked = event.target.checked; |
| 108 | 125 | this.currentValue = checked; |
| 109 | 126 | |
| 110 | - let value = checked ? this.trueValue : this.falseValue; | |
| 127 | + const value = checked ? this.trueValue : this.falseValue; | |
| 111 | 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 | 138 | this.$emit('on-change', value); |
| 121 | 139 | this.dispatch('FormItem', 'on-form-change', value); |
| 122 | 140 | } |
| 123 | 141 | }, |
| 124 | 142 | updateValue () { |
| 125 | 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 | 157 | watch: { |
| 129 | 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 | 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 | 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; |
| 10 | - //outline: 0; | |
| 15 | + //outline: none; | |
| 11 | 16 | &-vertical{ |
| 12 | 17 | .@{radio-prefix-cls}-wrapper { |
| 13 | 18 | display: block; |
| ... | ... | @@ -29,20 +34,14 @@ |
| 29 | 34 | &-disabled{ |
| 30 | 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 | 40 | .@{radio-prefix-cls} { |
| 42 | 41 | display: inline-block; |
| 43 | 42 | margin-right: 4px; |
| 44 | 43 | white-space: nowrap; |
| 45 | - outline: none; | |
| 44 | + //outline: none; | |
| 46 | 45 | position: relative; |
| 47 | 46 | line-height: 1; |
| 48 | 47 | vertical-align: middle; |
| ... | ... | @@ -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 | 229 | .@{radio-prefix-cls}-inner, |
| 236 | 230 | input { |
| 237 | 231 | opacity: 0; |
| ... | ... | @@ -247,7 +241,7 @@ span.@{radio-prefix-cls} + * { |
| 247 | 241 | |
| 248 | 242 | &:first-child { |
| 249 | 243 | border-color: @primary-color; |
| 250 | - box-shadow: none!important; | |
| 244 | + //box-shadow: none!important; | |
| 251 | 245 | } |
| 252 | 246 | |
| 253 | 247 | &:hover { |
| ... | ... | @@ -256,10 +250,6 @@ span.@{radio-prefix-cls} + * { |
| 256 | 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 | 253 | &:active { |
| 264 | 254 | border-color: shade(@primary-color, 5%); |
| 265 | 255 | //box-shadow: -1px 0 0 0 shade(@primary-color, 5%); | ... | ... |