diff --git a/examples/sites/demos/mobile/app/switch/true-false-value.vue b/examples/sites/demos/mobile/app/switch/base.vue similarity index 69% rename from examples/sites/demos/mobile/app/switch/true-false-value.vue rename to examples/sites/demos/mobile/app/switch/base.vue index 38cf19c28..a0cf0b148 100644 --- a/examples/sites/demos/mobile/app/switch/true-false-value.vue +++ b/examples/sites/demos/mobile/app/switch/base.vue @@ -1,7 +1,7 @@ @@ -14,7 +14,7 @@ export default { }, data() { return { - value: 'no' + value1: '1' } } } diff --git a/examples/sites/demos/mobile/app/switch/disabled.vue b/examples/sites/demos/mobile/app/switch/disabled.vue index e1c49f18b..60ecf31e5 100644 --- a/examples/sites/demos/mobile/app/switch/disabled.vue +++ b/examples/sites/demos/mobile/app/switch/disabled.vue @@ -1,15 +1,9 @@ @@ -19,49 +13,12 @@ import { Switch } from '@opentiny/vue' export default { components: { TinySwitch: Switch - }, - data() { - return { - value: true - } } } diff --git a/examples/sites/demos/mobile/app/switch/switch-event-change.vue b/examples/sites/demos/mobile/app/switch/event.vue similarity index 54% rename from examples/sites/demos/mobile/app/switch/switch-event-change.vue rename to examples/sites/demos/mobile/app/switch/event.vue index 4de0dc99b..e34ebb7bc 100644 --- a/examples/sites/demos/mobile/app/switch/switch-event-change.vue +++ b/examples/sites/demos/mobile/app/switch/event.vue @@ -1,6 +1,8 @@ @@ -13,13 +15,13 @@ export default { }, data() { return { - value: true + value1: '1', + status: '已开启' } }, methods: { handleChange(val) { - let msg = val ? '已开启' : '已关闭' - console.log(msg) + this.status = val ? '已开启' : '已关闭' } } } @@ -29,4 +31,8 @@ export default { .switch-wrap { padding: 20px; } + +.status { + margin-left: 20px; +} diff --git a/examples/sites/demos/mobile/app/switch/loading.vue b/examples/sites/demos/mobile/app/switch/loading.vue new file mode 100644 index 000000000..834209efd --- /dev/null +++ b/examples/sites/demos/mobile/app/switch/loading.vue @@ -0,0 +1,44 @@ + + + + + diff --git a/examples/sites/demos/mobile/app/switch/mini.vue b/examples/sites/demos/mobile/app/switch/mini.vue new file mode 100644 index 000000000..92030ec73 --- /dev/null +++ b/examples/sites/demos/mobile/app/switch/mini.vue @@ -0,0 +1,22 @@ + + + + + diff --git a/examples/sites/demos/mobile/app/switch/scenario.vue b/examples/sites/demos/mobile/app/switch/scenario.vue deleted file mode 100644 index 445e7b1ba..000000000 --- a/examples/sites/demos/mobile/app/switch/scenario.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/examples/sites/demos/mobile/app/switch/webdoc/switch.js b/examples/sites/demos/mobile/app/switch/webdoc/switch.js index a4cc20828..e9693b149 100644 --- a/examples/sites/demos/mobile/app/switch/webdoc/switch.js +++ b/examples/sites/demos/mobile/app/switch/webdoc/switch.js @@ -3,52 +3,64 @@ export default { owner: '', demos: [ { - demoId: 'disabled', + demoId: 'base', name: { - 'zh-CN': '是否禁用', + 'zh-CN': '基础用法', 'en-US': 'button type' }, desc: { - 'zh-CN': '

是否禁用

', - 'en-US': '

button type

' + 'zh-CN': '

基础用法

', + 'en-US': '

base

' + }, + codeFiles: ['base.vue'] + }, + { + demoId: 'disabled', + name: { + 'zh-CN': '状态不可用', + 'en-US': 'disabled' + }, + desc: { + 'zh-CN': '

状态不可用

', + 'en-US': '

disabled

' }, codeFiles: ['disabled.vue'] }, { - demoId: 'switch-event-change', + demoId: 'loading', name: { - 'zh-CN': '值改变事件', - 'en-US': 'button round' + 'zh-CN': '加载状态', + 'en-US': 'loading' }, desc: { - 'zh-CN': '

值改变事件

', - 'en-US': '

button round

' + 'zh-CN': '

加载中状态

', + 'en-US': '

loading

' }, - codeFiles: ['switch-event-change.vue'] + codeFiles: ['loading.vue'] }, { - demoId: 'scenario', + demoId: 'mini', name: { - 'zh-CN': '应用场景', - 'en-US': 'events' + 'zh-CN': '小尺寸', + 'en-US': 'mini' }, desc: { - 'zh-CN': '

应用场景

', - 'en-US': '

bbutton click

' + 'zh-CN': '

小尺寸

', + 'en-US': '

mini

' }, - codeFiles: ['scenario.vue'] + codeFiles: ['mini.vue'] }, { - demoId: 'true-false-value', + demoId: 'event', name: { - 'zh-CN': '自定义打开关闭的值', - 'en-US': 'true-false-value' + 'zh-CN': '开关状态改变事件', + 'en-US': 'switch status event' }, desc: { - 'zh-CN': '

自定义打开关闭的值

', - 'en-US': '

bbutton click

' + 'zh-CN': '

开关的状态改变事件

', + 'en-US': '

switch status event

' }, - codeFiles: ['true-false-value.vue'] + codeFiles: ['event.vue'] } ], apis: [ @@ -58,7 +70,7 @@ export default { properties: [ { name: 'disabled', - type: 'Boolean', + type: 'boolean', defaultValue: 'false', desc: { 'zh-CN': '

是否禁用,该属性默认为false

', @@ -68,33 +80,43 @@ export default { }, { name: 'false-value', - type: 'String', + type: 'string', defaultValue: 'false', desc: { 'zh-CN': '

switch 关闭时的值,该属性默认为false

', 'en-US': 'display different button' }, - demoId: 'true-false-value' + demoId: 'base' }, { name: 'true-value', - type: 'String', + type: 'string', defaultValue: 'true', desc: { 'zh-CN': '

switch 打开时的值,该属性默认为true

', 'en-US': 'display different button' }, - demoId: 'true-false-value' + demoId: 'base' }, { - name: 'value', - type: 'String', + name: 'v-model', + type: 'string', defaultValue: '', desc: { 'zh-CN': '

绑定值

', 'en-US': 'display different button' }, - demoId: 'switch-event-change' + demoId: 'base' + }, + { + name: 'mini', + type: 'boolean', + defaultValue: 'false', + desc: { + 'zh-CN': '

小尺寸

', + 'en-US': 'mini' + }, + demoId: 'mini' } ], events: [ @@ -106,7 +128,7 @@ export default { 'zh-CN': '

switch 状态发生变化时的回调函数,可获取新状态的值

', 'en-US': 'Click' }, - demoId: 'switch-event-change' + demoId: 'event' } ] } diff --git a/packages/renderless/src/switch/index.ts b/packages/renderless/src/switch/index.ts index 9e115235f..77491aba4 100644 --- a/packages/renderless/src/switch/index.ts +++ b/packages/renderless/src/switch/index.ts @@ -34,15 +34,17 @@ export const toggle = export const computedWarpClasses = ({ prefixCls, props, state }: Pick) => - (): ISwitchClass => [ - { - [prefixCls]: true, - [`${prefixCls}-checked`]: state.currentValue === props.trueValue, - [`${prefixCls}-disabled`]: state.disabled, - mini: props.mini, - disabled: state.disabled - } - ] + (): ISwitchClass => { + return [ + { + [prefixCls]: true, + [`${prefixCls}-checked`]: state.currentValue === props.trueValue, + [`${prefixCls}-disabled`]: state.disabled, + mini: props.mini, + disabled: state.disabled + } + ] + } export const computedInnerClasses = ({ prefixCls }: Pick) => diff --git a/packages/renderless/src/switch/vue.ts b/packages/renderless/src/switch/vue.ts index 0b5b5a81f..aad876ffe 100644 --- a/packages/renderless/src/switch/vue.ts +++ b/packages/renderless/src/switch/vue.ts @@ -36,7 +36,7 @@ export const renderless = ( wrapClasses: computed(() => api.computedWarpClasses()), style: computed(() => api.computedStyle()), formDisabled: computed(() => (parent.tinyForm || {}).disabled), - disabled: computed(() => props.disabled || state.formDisabled || state.isDisplayOnly), + disabled: computed(() => props.disabled || state.formDisabled || state.isDisplayOnly || props.loading), isDisplayOnly: computed(() => props.displayOnly || (parent.tinyForm || {}).displayOnly), showText: computed(() => { // 用户没传showText属性时,aurora默认是展示文本 diff --git a/packages/theme-mobile/src/switch/index.less b/packages/theme-mobile/src/switch/index.less index 8c09f513c..737bacdcc 100644 --- a/packages/theme-mobile/src/switch/index.less +++ b/packages/theme-mobile/src/switch/index.less @@ -14,13 +14,25 @@ @import './vars.less'; @switch-prefix-cls: ~'@{css-prefix}mobile-switch'; +@btn-size: var(--ti-mobile-switch-btn-size-normal, 18px); +@btn-size-half: calc(@btn-size / 2); +@loading-size: calc(@btn-size - 6px); +@loading-size-half: calc(@loading-size / 2); +@btn-padding: 3px; +@loading-left: calc(calc(@btn-size-half - @loading-size-half) + @btn-padding); + +@btn-size-mini: var(--ti-mobile-switch-btn-size-mini, 16px); +@btn-size-half-mini: calc(@btn-size-mini / 2); +@loading-size-mini: calc(@btn-size-mini - 6px); +@loading-size-half-mini: calc(@loading-size-mini / 2); +@btn-padding-mini: 2px; +@loading-left-mini: calc(calc(@btn-size-half-mini - @loading-size-half-mini) + @btn-padding-mini); .@{switch-prefix-cls} { - width: var(--ti-mobile-switch-width, 50px); - height: var(--ti-mobile-switch-height, 30px); - border: 1px solid var(--ti-mobile-switch-border-color, #e5e5e5); - border-radius: var(--ti-mobile-switch-border-radius, 40px); - background-color: var(--ti-mobile-switch-bgcolor, #fff); + width: var(--ti-mobile-switch-width-normal, 40px); + height: var(--ti-mobile-switch-height-mormal, 24px); + border-radius: 999px; + background-color: var(--ti-mobile-switch-bg-color-default, #c2c2c2); position: relative; cursor: pointer; display: inline-block; @@ -28,36 +40,38 @@ outline: none; transition: all 0.2s ease-in-out; + &.mini { + width: var(--ti-mobile-switch-width-small, 36px); + height: var(--ti-mobile-switch-height-small, 20px); + } + &.disabled { - background-color: var(--ti-mobile-switch-disabled-bgcolor, #f5f5f5); + background-color: var(--ti-mobile-switch-bg-color-disabled, #dbdbdb); cursor: not-allowed; - &::after { - border-color: var(--ti-mobile-switch-after-border-color, #ccc); + &:after { cursor: not-allowed; } &.@{switch-prefix-cls}-checked { - background-color: var(--ti-mobile-switch-disabled-checked-bgcolor, #b3eee0); - border-color: var(--ti-mobile-switch-disabled-checked-bgcolor, #b3eee0); + background-color: var(--ti-mobile-switch-bg-color-checked-disabled, #b3d6ff); - &::after { - border-color: rgba(0, 0, 0, 0.1); + &:after { + border-color: rgb(0 0 0 / 10%); } } } - &::after { + &:after { content: ''; - width: 28px; - height: 28px; + width: @btn-size; + height: @btn-size; border-radius: 50%; background-color: var(--ti-mobile-switch-font-color, #fff); - box-shadow: 0 3px 3px rgba(0, 0, 0, 0.1); - border: 1px solid var(--ti-mobile-switch-after-border-color, #ccc); + box-shadow: 0 3px 3px rgb(0 0 0 / 10%); position: absolute; - left: -1px; - top: 0; + left: @btn-padding; + top: calc(calc(var(--ti-mobile-switch-height-mormal) - @btn-size) / 2); cursor: pointer; transition: left 0.2s ease-in-out, @@ -65,13 +79,84 @@ box-sizing: border-box; } + &.mini:after { + width: @btn-size-mini; + height: @btn-size-mini; + top: calc(calc(var(--ti-mobile-switch-height-mini, 20px) - @btn-size-mini) / 2); + left: @btn-padding-mini; + } + &&-checked { - border-color: var(--ti-mobile-switch-checked-color, #00c696); - background-color: var(--ti-mobile-switch-checked-color, #00c696); + background-color: var(--ti-mobile-switch-bg-color-checked, #1476ff); &:after { - left: calc(~'100% - 28px'); - border-color: var(--ti-mobile-switch-bgcolor, #fff); + left: calc(calc(100% - @btn-size) - @btn-padding); + } + } + + &&-checked.mini:after { + left: calc(calc(100% - @btn-size-mini) - @btn-padding-mini); + } + + &.mini.checked { + &:after { + left: calc(calc(100% - @btn-size-mini) - @btn-padding-mini); + } + } + + &-loading { + width: @loading-size; + height: @loading-size; + position: absolute; + z-index: 2; + top: calc(50% - @loading-size-half); + left: @loading-left; + + border-radius: 50%; + background-image: conic-gradient(#dbdbdb01, #dbdbdb); + + animation: circle 1.5s linear infinite; + display: inline-block; + + &-inner { + width: @btn-size-half; + height: @btn-size-half; + border-radius: 50%; + background-color: #fff; + position: absolute; + top: 2px; + left: 2px; + } + } + + &.mini &-loading { + width: @loading-size-mini; + height: @loading-size-mini; + top: calc(50% - @loading-size-half-mini); + left: @loading-left-mini; + + &-inner { + width: @btn-size-half-mini; + height: @btn-size-half-mini; + } + } + + &&-checked &-loading { + left: calc(calc(@loading-left + 50%) - @btn-padding); + background-image: conic-gradient(#b3d6ff01, #b3d6ff); + } + + &&-checked.mini &-loading { + left: calc(calc(@loading-left-mini + 50%) - @btn-padding-mini); + } + + @keyframes circle { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); } } } diff --git a/packages/theme-mobile/src/switch/vars.less b/packages/theme-mobile/src/switch/vars.less index a9a660b5d..0e49be809 100644 --- a/packages/theme-mobile/src/switch/vars.less +++ b/packages/theme-mobile/src/switch/vars.less @@ -1,12 +1,22 @@ :root { - --ti-mobile-switch-width: 50px; - --ti-mobile-switch-height: 30px; - --ti-mobile-switch-border-radius: 40px; - --ti-mobile-switch-border-color: #e5e5e5; - --ti-mobile-switch-bgcolor: var(--ti-mobile-base-color-light, #fff); - --ti-mobile-switch-disabled-bgcolor: var(--ti-mobile-base-color-selected-background, #f5f5f5); - --ti-mobile-switch-disabled-after-border-color: #ccc; - --ti-mobile-switch-disabled-checked-bgcolor: #b3eee0; - --ti-mobile-switch-after-border-color: #ccc; - --ti-mobile-switch-checked-color: #00c696; + // 默认尺寸宽度 + --ti-mobile-switch-width-normal: calc(var(--ti-mobile-base-size-width-small) + 4px); + // 默认尺寸高度 + --ti-mobile-switch-height-mormal: var(--ti-mobile-base-size-height-mini, 24px); + // 小尺寸宽度 + --ti-mobile-switch-width-mini: var(--ti-mobile-base-size-width-small, 36px); + // 小尺寸高度 + --ti-mobile-switch-height-mini: calc(var(--ti-mobile-base-size-height-mini) - 4px); + // 默认尺寸按钮大小 + --ti-mobile-switch-btn-size-normal: calc(var(--ti-mobile-base-size-width-min) - 6px); + // 小尺寸按钮大小 + --ti-mobile-switch-btn-size-mini: calc(var(--ti-mobile-base-size-width-min) - 8px); + // 默认关状态背景色 + --ti-mobile-switch-bg-color-default: var(--ti-mobile-color-bg-control-default, #c2c2c2); + // 禁用状态下背景色 + --ti-mobile-switch-bg-color-disabled: var(--ti-mobile-color-bg-control-disable-1, #dbdbdb); + // 开状态禁用背景色 + --ti-mobile-switch-bg-color-checked-disabled: var(--ti-mobile-color-bg-control-disable-2, #b3d6ff); + // 开状态背景色 + --ti-mobile-switch-bg-color-checked: var(--ti-mobile-color-bg-control-active, #1476ff); } diff --git a/packages/vue/src/switch/src/index.ts b/packages/vue/src/switch/src/index.ts index ac3a05e57..1128ca362 100644 --- a/packages/vue/src/switch/src/index.ts +++ b/packages/vue/src/switch/src/index.ts @@ -65,6 +65,10 @@ export const switchProps = { displayOnly: { type: Boolean, default: false + }, + loading: { + type: Boolean, + default: false } } diff --git a/packages/vue/src/switch/src/mobile.vue b/packages/vue/src/switch/src/mobile.vue index efb3a978b..314e55b4f 100644 --- a/packages/vue/src/switch/src/mobile.vue +++ b/packages/vue/src/switch/src/mobile.vue @@ -10,7 +10,11 @@ * -->