This commit is contained in:
2026-01-05 12:47:14 +08:00
commit 1fc846fae3
1614 changed files with 162035 additions and 0 deletions

View File

@@ -0,0 +1,74 @@
.nut-theme-dark {
.nut-switch {
&.nut-switch-close {
background-color: $dark-background4;
}
}
}
.nut-switch {
display: inline-flex;
flex: 0 0 auto; // 防止被压缩
align-items: center;
cursor: pointer;
background-color: $primary-color;
background-repeat: no-repeat;
background-position: center center;
background-size: 100% 100%;
border-radius: $switch-border-radius;
.nut-icon-loading1 {
width: 12px;
height: 12px;
font-size: 12px;
}
&.nut-switch-close {
background-color: $switch-close-bg-color;
}
.nut-switch-button {
display: flex;
align-items: center;
justify-content: center;
background: $white;
border-radius: 50%;
transition: transform 0.3s;
.nut-switch-label {
font-size: $font-size-1;
color: $white;
&.open {
transform: translateX(-16px);
}
&.close {
transform: translateX(16px);
}
}
}
&.nut-switch-disabled {
opacity: 0.6;
}
&.nut-switch-base {
min-width: $switch-width;
height: $switch-height;
overflow: hidden;
line-height: $switch-line-height;
.nut-switch-button {
width: $switch-inside-width;
height: $switch-inside-height;
transform: $switch-inside-close-transform;
}
&.nut-switch-open {
.nut-switch-button {
transform: $switch-inside-open-transform;
}
}
}
}

View File

@@ -0,0 +1 @@
export * from './switch'

View File

@@ -0,0 +1,66 @@
import type { ExtractPropTypes } from 'vue'
import { CHANGE_EVENT, UPDATE_MODEL_EVENT } from '../_constants'
import { commonProps, isBoolean, isNumber, isString } from '../_utils'
export const switchProps = {
...commonProps,
/**
* @description 开关状态
*/
modelValue: {
type: [String, Number, Boolean],
default: false,
},
/**
* @description 禁用状态
* @deprecated 即将弃用,请使用`disabled`
*/
disable: Boolean,
/**
* @description 禁用状态
*/
disabled: Boolean,
/**
* @description 打开时的背景颜色
*/
activeColor: String,
/**
* @description 关闭时的背景颜色
*/
inactiveColor: String,
/**
* @description 打开时文字描述
*/
activeText: String,
/**
* @description 关闭时文字描述
*/
inactiveText: String,
/**
* @description 打开时组件的值
*/
activeValue: {
type: [String, Number, Boolean],
default: true,
},
/**
* @description 关闭组件的值
*/
inactiveValue: {
type: [String, Number, Boolean],
default: false,
},
/**
* @description 加载状态
*/
loading: Boolean,
}
export type SwitchProps = ExtractPropTypes<typeof switchProps>
export const switchEmits = {
[UPDATE_MODEL_EVENT]: (val: any) => isBoolean(val) || isNumber(val) || isString(val),
[CHANGE_EVENT]: (val: any, evt?: Event) => (isBoolean(val) || isNumber(val) || isString(val)) && (evt instanceof Object),
}
export type SwitchEmits = typeof switchEmits

View File

@@ -0,0 +1,88 @@
<script setup lang="ts">
import type { CSSProperties } from 'vue'
import { computed, defineComponent, watch } from 'vue'
import { CHANGE_EVENT, PREFIX, UPDATE_MODEL_EVENT } from '../_constants'
import { getMainClass, getMainStyle } from '../_utils'
import { useFormDisabled } from '../form/form'
import NutIcon from '../icon/icon.vue'
import { switchEmits, switchProps } from './switch'
const props = defineProps(switchProps)
const emit = defineEmits(switchEmits)
const legacyDisabled = computed(() => props.disabled || props.disable)
const disabled = useFormDisabled(legacyDisabled)
const isActive = computed(() => props.modelValue === props.activeValue)
const classes = computed(() => {
return getMainClass(props, componentName, {
[isActive.value ? 'nut-switch-open' : 'nut-switch-close']: true,
[`${componentName}-disabled`]: disabled.value,
[`${componentName}-base`]: true,
})
})
const styles = computed(() => {
const obj: CSSProperties = {
backgroundColor: isActive.value ? props.activeColor : props.inactiveColor,
}
return getMainStyle(props, obj)
})
let updateType = ''
function onClick(event: Event) {
if (disabled.value || props.loading)
return
const value = isActive.value ? props.inactiveValue : props.activeValue
updateType = 'click'
emit(UPDATE_MODEL_EVENT, value)
emit(CHANGE_EVENT, value, event)
}
watch(
() => props.modelValue,
(v) => {
if (updateType === 'click')
updateType = ''
else
emit(CHANGE_EVENT, v)
},
)
</script>
<script lang="ts">
const componentName = `${PREFIX}-switch`
export default defineComponent({
name: componentName,
options: {
virtualHost: true,
addGlobalClass: true,
styleIsolation: 'shared',
},
})
</script>
<template>
<view :class="classes" :style="styles" @click="(onClick as any)">
<view class="nut-switch-button">
<slot v-if="loading" name="icon">
<NutIcon name="loading1" :custom-color="activeColor" />
</slot>
<template v-if="activeText">
<view class="nut-switch-label open" :class="{ 'nut-hidden': !isActive }">
{{ activeText }}
</view>
<view class="nut-switch-label close" :class="{ 'nut-hidden': isActive }">
{{ inactiveText }}
</view>
</template>
</view>
</view>
</template>
<style lang="scss">
@import './index';
</style>