尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Vue3开关(Switch)

Vue3开关(Switch) Vue2开关Switch可自定义设置以下属性选中时的内容checked类型string | slot默认 undefined选中时的值checkedValue类型boolean | string | number默认 true未选中时的内容unchecked类型string | slot默认 undefined未选中时的值uncheckedValue类型boolean | string | number默认 false是否加载中loading类型boolean默认 false是否禁用disabled类型boolean默认 false开关大小size类型small | middle | large默认 middle点击时的波纹颜色rippleColor当自定义选中颜色时需要设置类型string默认 undefined圆点样式circleStyle类型CSSProperties默认 {}指定当前是否选中v-model:modelValue类型boolean | string | number默认 false效果如下图在线预览①创建开关组件Switch.vue其中引入使用了以下工具函数获取依赖注入 useInjectscript setup langts import { ref, nextTick } from vue import type { CSSProperties } from vue import { useInject } from components/utils export interface Props { checked?: string // 选中时的内容 string | slot checkedValue?: boolean | string | number // 选中时的值 unchecked?: string // 未选中时的内容 string | slot uncheckedValue?: boolean | string | number // 未选中时的值 loading?: boolean // 是否加载中 disabled?: boolean // 是否禁用 size?: small | middle | large // 开关大小 rippleColor?: string // 点击时的波纹颜色当自定义选中颜色时需要设置 circleStyle?: CSSProperties // 圆点样式 modelValue?: boolean | string | number // (v-model) 指定当前是否选中 } const props withDefaults(definePropsProps(), { checked: undefined, checkedValue: true, unchecked: undefined, uncheckedValue: false, loading: false, disabled: false, size: middle, rippleColor: undefined, circleStyle: () ({}), modelValue: false }) const wave refboolean(false) const { colorPalettes } useInject(Switch) // 主题色注入 const emit defineEmits([update:modelValue, change]) function onSwitch(): void { if (props.modelValue props.checkedValue) { emit(update:modelValue, props.uncheckedValue) emit(change, props.uncheckedValue) } else { emit(update:modelValue, props.checkedValue) emit(change, props.checkedValue) } if (wave.value) { wave.value false nextTick(() { wave.value true }) } else { wave.value true } } function onWaveEnd(): void { wave.value false } /script template div classswitch-wrap :class{ switch-loading: loading, switch-small: size small, switch-large: size large, switch-checked: modelValue checkedValue, switch-disabled: disabled } :style --switch-primary-color: ${colorPalettes[5]}; --switch-primary-color-hover: ${colorPalettes[4]}; --switch-ripple-color: ${rippleColor || colorPalettes[5]}; clickdisabled || loading ? () false : onSwitch() div classswitch-inner span classinner-checked slot namechecked{{ checked }}/slot /span span classinner-unchecked slot nameunchecked{{ unchecked }}/slot /span /div div classswitch-circle :stylecircleStyle svg v-ifloading classcircular viewBox0 0 50 50 circle classpath cx25 cy25 r20 fillnone/circle /svg slot namenode :checkedmodelValue/slot /div div v-if!disabled classswitch-wave :class{ wave-active: wave } animationendonWaveEnd/div /div /template style langless scoped .switch-wrap { position: relative; display: inline-flex; align-items: center; vertical-align: middle; min-width: 44px; height: 22px; color: rgba(0, 0, 0, 0.88); font-size: 14px; line-height: 22px; background: rgba(0, 0, 0, 0.25); border-radius: 100px; cursor: pointer; transition: all 0.2s; user-select: none; :hover:not(.switch-disabled) { background: rgba(0, 0, 0, 0.45); } .switch-inner { display: block; overflow: hidden; border-radius: 100px; height: 100%; padding-left: 24px; padding-right: 9px; transition: padding-left 0.2s ease-in-out, padding-right 0.2s ease-in-out; .inner-checked { margin-left: calc(-100% 22px - 48px); margin-right: calc(100% - 22px 48px); display: block; text-align: center; color: #fff; font-size: 14px; transition: margin-left 0.2s ease-in-out, margin-right 0.2s ease-in-out; pointer-events: none; } .inner-unchecked { margin-top: -22px; margin-left: 0; margin-right: 0; display: block; text-align: center; color: #fff; font-size: 14px; transition: margin-left 0.2s ease-in-out, margin-right 0.2s ease-in-out; pointer-events: none; } } .switch-circle { display: flex; align-items: center; justify-content: center; position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; background: #fff; border-radius: 100%; transition: all 0.2s ease-in-out; .circular { position: absolute; inset: 0; margin: auto; width: 14px; height: 14px; animation: loadingRotate 2s linear infinite; -webkit-animation: loadingRotate 2s linear infinite; keyframes loadingRotate { 100% { transform: rotate(360deg); } } .path { stroke-dasharray: 90, 150; stroke-dashoffset: 0; stroke: var(--switch-primary-color); stroke-width: 5; stroke-linecap: round; animation: loadingDash 1.5s ease-in-out infinite; -webkit-animation: loadingDash 1.5s ease-in-out infinite; keyframes loadingDash { 0% { stroke-dasharray: 1, 200; stroke-dashoffset: 0; } 50% { stroke-dasharray: 90, 150; stroke-dashoffset: -40px; } 100% { stroke-dasharray: 90, 150; stroke-dashoffset: -120px; } } } } } } .switch-loading { cursor: not-allowed; opacity: 0.65; .switch-inner, .switch-circle { box-shadow: none; cursor: not-allowed; } } .switch-small { min-width: 28px; height: 16px; line-height: 16px; .switch-inner { padding-left: 18px; padding-right: 6px; .inner-checked { font-size: 12px; margin-left: calc(-100% 16px - 36px); margin-right: calc(100% - 16px 36px); } .inner-unchecked { font-size: 12px; margin-top: -16px; } } .switch-circle { width: 12px; height: 12px; .circular { width: 10px; height: 10px; .path { stroke-width: 4; } } } } .switch-large { min-width: 60px; height: 28px; line-height: 28px; .switch-inner { padding-left: 30px; padding-right: 12px; .inner-checked { font-size: 18px; margin-left: calc(-100% 28px - 60px); margin-right: calc(100% - 28px 60px); } .inner-unchecked { font-size: 18px; margin-top: -28px; } } .switch-circle { width: 24px; height: 24px; .circular { width: 20px; height: 20px; .path { stroke-width: 6; } } } } .switch-checked { background: var(--switch-primary-color); :hover:not(.switch-disabled) { background: var(--switch-primary-color-hover); } .switch-inner { padding-left: 9px; padding-right: 24px; .inner-checked { margin-left: 0; margin-right: 0; } .inner-unchecked { margin-left: calc(100% - 22px 48px); margin-right: calc(-100% 22px - 48px); } } .switch-circle { left: calc(100% - 20px); } } .switch-small.switch-checked { .switch-inner { padding-left: 6px; padding-right: 18px; .inner-unchecked { margin-left: calc(100% - 16px 36px); margin-right: calc(-100% 16px - 36px); } } .switch-circle { left: calc(100% - 14px); } } .switch-large.switch-checked { .switch-inner { padding-left: 12px; padding-right: 30px; .inner-unchecked { margin-left: calc(100% - 28px 60px); margin-right: calc(-100% 28px - 60px); } } .switch-circle { left: calc(100% - 26px); } } .switch-disabled { cursor: not-allowed; opacity: 0.65; .switch-circle { cursor: not-allowed; } } .switch-wave { position: absolute; pointer-events: none; top: 0; right: 0; bottom: 0; left: 0; animation-iteration-count: 1; animation-duration: 0.6s; animation-timing-function: cubic-bezier(0, 0, 0.2, 1), cubic-bezier(0, 0, 0.2, 1); border-radius: inherit; } .wave-active { z-index: 1; animation-name: waveSpread, waveOpacity; keyframes waveSpread { from { box-shadow: 0 0 0.5px 0 var(--switch-ripple-color); } to { box-shadow: 0 0 0.5px 5px var(--switch-ripple-color); } } keyframes waveOpacity { from { opacity: 0.6; } to { opacity: 0; } } } /style②在要使用的页面引入其中引入使用了以下组件Vue3间距Spacescript setup langts import Switch from ./Switch.vue import { ref, watchEffect } from vue const checked ref(true) const customValue1 ref(no) const customValue2 ref(2) watchEffect(() { console.log(checked, checked.value) }) function onChange(checked: boolean) { console.log(checked, checked) } /script template div h1{{ $route.name }} {{ $route.meta.title }}/h1 h2 classmt30 mb10基本使用/h2 Switch v-modelchecked changeonChange / h2 classmt30 mb10禁用开关/h2 Switch v-modelchecked disabled / h2 classmt30 mb10三种大小/h2 Space Switch v-modelchecked sizesmall / Switch v-modelchecked / Switch v-modelchecked sizelarge / /Space h2 classmt30 mb10加载中/h2 Space Switch v-modelchecked sizesmall loading / Switch v-modelchecked loading / Switch v-modelchecked sizelarge loading / /Space h2 classmt30 mb10带 文字 / 数字 / 字母 的开关/h2 Space Switch v-modelchecked checked开 unchecked关 / Switch v-modelchecked checked1 unchecked0 / Switch v-modelchecked checkedyes uncheckedno / /Space h2 classmt30 mb10自定义图标和样式/h2 Switch classtheme-switch v-modelchecked ripple-color#faad14 :circle-style{ background: checked ? #001529 : #fff } template #node{ checked } svg v-ifchecked classsvg-dark xmlnshttp://www.w3.org/2000/svg aria-hiddentrue focusablefalse viewBox0 0 24 24 path dM12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z /path /svg svg v-else classsvg-light xmlnshttp://www.w3.org/2000/svg aria-hiddentrue focusablefalse viewBox0 0 24 24 path dM12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z /path path dM12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z/path path dM12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z/path path dM5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z /path path dM19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z /path path dM3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z/path path dM23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z/path path dM4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z /path path dM18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z /path /svg /template /Switch h2 classmt30 mb10自定义选中的值/h2 Space gaplarge Space vertical aligncenter Switch v-modelcustomValue1 checked-valueon unchecked-valueoff template #checkedon/template template #uncheckedoff/template /Switch Current Value: {{ customValue1 }} /Space Space vertical aligncenter Switch v-modelcustomValue2 :checked-value1 :unchecked-value2 template #checkedyes/template template #uncheckedno/template /Switch Current Value: {{ customValue2 }} /Space /Space /div /template style langless scoped .theme-switch { background: #faad14; :hover:not(.disabled) { background: #e8b339; } .svg-dark { width: 12px; height: 12px; fill: #fff; } .svg-light { width: 12px; height: 12px; fill: rgba(60, 60, 67, 0.75); } } /style
返回列表