feat(components): el-switch add inline content support (#4091)

* refactor(components): el-swtich custom texts and icons

* fix: test

* fix: font size

* fix: example margin

* feat(components): el-switch add inline-prompt support

* revert: paly

* docs: update icons

* feat: add inner text

* fix: switch test

* refactor: icon inline
This commit is contained in:
Aex
2021-10-30 21:23:29 +08:00
committed by GitHub
parent 7fa12f92a4
commit cd646824c2
6 changed files with 151 additions and 10 deletions

View File

@@ -7,6 +7,14 @@ lang: en-US
Switch is used for switching between two opposing states.
<style lang="scss">
.example-showcase {
.el-switch + .el-switch {
margin-left: 10px;
}
}
</style>
## Basic usage
:::demo Bind `v-model` to a `Boolean` typed variable. The `active-color` and `inactive-color` attribute decides the background color in two states.
@@ -17,6 +25,8 @@ switch/basic
## Text description
You can add `active-text` and `inactive-text` attribute to show texts. use `inline-prompt` attribute to control text is displayed inside dot.
:::demo You can add `active-text` and `inactive-text` attribute to show texts.
switch/text-description
@@ -31,7 +41,7 @@ Use the `active-icon` and `active-icon` attribute to add icon. You can pass eith
:::
:::demo You can add `active-icon` and `active-icon` attribute to show icons.
:::demo You can add `active-icon` and `inactive-icon` attribute to show icons. use `inline-prompt` attribute to control icon is displayed inside dot.
switch/custom-icons
@@ -77,6 +87,7 @@ switch/prevent-switching
| disabled | whether Switch is disabled | boolean | — | false |
| loading | whether Switch is in loading state | boolean | — | false |
| width | width of Switch | number | — | 40 |
| inline-prompt | whether icon or text is displayed inside dot | boolean | — | false |
| active-icon | component of the icon displayed when in `on` state, overrides `active-text` | string / Component | — | — |
| inactive-icon | component of the icon displayed when in `off` state, overrides `inactive-text` | string / Component | — | — |
| active-text | text displayed when in `on` state | string | — | — |

View File

@@ -1,16 +1,26 @@
<template>
<el-switch v-model="value" :active-icon="active" :inactive-icon="inactive">
<el-switch v-model="value1" :active-icon="active" :inactive-icon="inactive">
</el-switch>
<br />
<el-switch
v-model="value2"
style="margin-left: 24px"
inline-prompt
:active-icon="active"
:inactive-icon="inactive"
>
</el-switch>
</template>
<script lang="ts">
import { CircleCheckFilled, CircleCloseFilled } from '@element-plus/icons'
import { Check, Close } from '@element-plus/icons'
export default {
data() {
return {
value: true,
active: CircleCheckFilled,
inactive: CircleCloseFilled,
value1: true,
value2: true,
active: Check,
inactive: Close,
}
},
}

View File

@@ -5,14 +5,25 @@
inactive-text="Pay by year"
>
</el-switch>
<br />
<el-switch
v-model="value2"
style="display: block"
active-color="#13ce66"
inactive-color="#ff4949"
active-text="Pay by month"
inactive-text="Pay by year"
/>
<br />
<el-switch v-model="value3" inline-prompt active-text="是" inactive-text="否">
</el-switch>
<el-switch
v-model="value4"
inline-prompt
active-color="#13ce66"
inactive-color="#ff4949"
active-text="Y"
inactive-text="N"
/>
</template>
<script lang="ts">
@@ -21,6 +32,8 @@ export default {
return {
value1: true,
value2: true,
value3: true,
value4: true,
}
},
}

View File

@@ -24,6 +24,25 @@ describe('Switch.vue', () => {
expect(leftLabelWrapper.text()).toEqual('off')
})
test('inline prompt', () => {
const wrapper = mount(Switch, {
props: {
inlinePrompt: true,
activeText: 'on',
inactiveText: 'off',
activeColor: '#0f0',
inactiveColor: '#f00',
width: 100,
},
})
const vm = wrapper.vm
const coreEl = vm.$el.querySelector('.el-switch__core')
expect(coreEl.style.backgroundColor).toEqual('rgb(255, 0, 0)')
expect(coreEl.style.width).toEqual('100px')
const leftLabelWrapper = wrapper.find('.el-switch__inner span')
expect(leftLabelWrapper.text()).toEqual('o')
})
test('switch with icons', () => {
const wrapper = mount(Switch, {
props: {

View File

@@ -20,7 +20,7 @@
@keydown.enter="switchValue"
/>
<span
v-if="inactiveIcon || inactiveText"
v-if="!inlinePrompt && (inactiveIcon || inactiveText)"
:class="[
'el-switch__label',
'el-switch__label--left',
@@ -37,12 +37,48 @@
class="el-switch__core"
:style="{ width: (width || 40) + 'px' }"
>
<div v-if="inlinePrompt" class="el-switch__inner">
<template v-if="activeIcon || inactiveIcon">
<el-icon
v-if="activeIcon"
class="is-icon"
:class="checked ? 'is-show' : 'is-hide'"
>
<component :is="activeIcon" />
</el-icon>
<el-icon
v-if="inactiveIcon"
class="is-icon"
:class="!checked ? 'is-show' : 'is-hide'"
>
<component :is="inactiveIcon" />
</el-icon>
</template>
<template v-else-if="activeText || inactiveIcon">
<span
v-if="activeText"
class="is-text"
:class="checked ? 'is-show' : 'is-hide'"
:aria-hidden="!checked"
>
{{ activeText.substr(0, 1) }}
</span>
<span
v-if="inactiveText"
class="is-text"
:class="!checked ? 'is-show' : 'is-hide'"
:aria-hidden="checked"
>
{{ inactiveText.substr(0, 1) }}
</span>
</template>
</div>
<div class="el-switch__action">
<el-icon v-if="loading" class="is-loading"><loading /></el-icon>
</div>
</span>
<span
v-if="activeIcon || activeText"
v-if="!inlinePrompt && (activeIcon || activeText)"
:class="[
'el-switch__label',
'el-switch__label--right',
@@ -56,6 +92,7 @@
</span>
</div>
</template>
<script lang="ts">
import {
defineComponent,
@@ -119,6 +156,10 @@ export default defineComponent({
type: Number,
default: 40,
},
inlinePrompt: {
type: Boolean,
default: false,
},
activeIcon: {
type: [String, Object] as PropType<string | Component>,
default: '',

View File

@@ -49,7 +49,10 @@
display: inline-block;
}
.#{$namespace}-icon {
vertical-align: text-bottom;
height: inherit;
svg {
vertical-align: middle;
}
}
}
@@ -77,6 +80,27 @@
background-color var(--el-transition-duration);
vertical-align: middle;
.#{$namespace}-switch__inner {
position: absolute;
top: 1px;
left: 1px;
transition: all var(--el-transition-duration);
width: var(--el-switch-button-size);
height: var(--el-switch-button-size);
display: flex;
justify-content: center;
align-items: center;
left: 50%;
.is-icon,
.is-text {
color: var(--el-color-white);
transition: opacity var(--el-transition-duration);
position: absolute;
user-select: none;
}
}
.#{$namespace}-switch__action {
position: absolute;
top: 1px;
@@ -90,6 +114,25 @@
justify-content: center;
align-items: center;
color: var(--el-switch-off-color);
.is-icon,
.is-text {
transition: opacity var(--el-transition-duration);
position: absolute;
user-select: none;
}
}
.is-text {
font-size: 12px;
}
.is-show {
opacity: 1;
}
.is-hide {
opacity: 0;
}
}
@@ -102,6 +145,10 @@
margin-left: calc(-1px - var(--el-switch-button-size));
color: var(--el-switch-on-color);
}
.#{$namespace}-switch__inner {
left: 50%;
margin-left: calc(-1px - var(--el-switch-button-size));
}
}
}