Skip to content

Commit

Permalink
feat(switch): 支持新属性规范
Browse files Browse the repository at this point in the history
  • Loading branch information
hdx committed May 22, 2024
1 parent 537be20 commit 04bf207
Show file tree
Hide file tree
Showing 3 changed files with 257 additions and 17 deletions.
8 changes: 7 additions & 1 deletion packages/uni-components/src/vue/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,13 @@ import Slider from './slider/index'
//#endif
import Swiper, { UniSwiperElement } from './swiper/index'
import SwiperItem, { UniSwiperItemElement } from './swiper-item/index'
import Switch, { UniSwitchElement } from './switch/index'
//#if _X_
// @ts-expect-error
import Switch, { UniSwitchElement } from './switch/index-x'
//#else
// @ts-expect-error
import Switch from './switch/index'
//#endif
import Text, { UniTextElement } from './text/index'
import Textarea, { UniTextareaElement } from './textarea/index'
import View, { UniViewElement } from './view/index'
Expand Down
240 changes: 240 additions & 0 deletions packages/uni-components/src/vue/switch/index-x.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
import {
inject,
onBeforeUnmount,
onMounted,
onUnmounted,
ref,
watch,
} from 'vue'
import type { ExtractPropTypes, Ref } from 'vue'
import { defineBuiltInComponent } from '../../helpers/component'
import { useCustomEvent } from '../../helpers/useEvent'
import type { EmitEvent } from '../../helpers/useEvent'

import { uniFormKey } from '../form'
import type { UniFormCtx } from '../form'
import { uniLabelKey } from '../label'
import type { UniLabelCtx } from '../label'
import { useListeners } from '../../helpers/useListeners'
import { useBooleanAttr } from '../../helpers/useBooleanAttr'
import { UniElement } from '../../helpers/UniElement'
import {
ICON_PATH_SUCCESS_NO_CIRCLE,
createSvgIconVNode,
} from '@dcloudio/uni-core'

const props = {
name: {
type: String,
default: '',
},
checked: {
type: [Boolean, String],
default: false,
},
type: {
type: String,
default: 'switch',
},
id: {
type: String,
default: '',
},
disabled: {
type: [Boolean, String],
default: false,
},
color: {
type: String,
default: '',
},
backgroundColor: {
type: String,
default: '#e9e9ea',
},
activeBackgroundColor: {
type: String,
default: '',
},
foregroundColor: {
type: String,
default: '',
},
activeForegroundColor: {
type: String,
default: '',
},
}

type SwitchProps = ExtractPropTypes<typeof props>

export class UniSwitchElement extends UniElement {}
export default /*#__PURE__*/ defineBuiltInComponent({
name: 'Switch',
props,
emits: ['change'],
rootElement: {
name: 'uni-switch',
class: UniSwitchElement,
},
setup(props, { emit }) {
const rootRef = ref<HTMLElement | null>(null)
const switchChecked = ref(props.checked)

const uniLabel = useSwitchInject(rootRef, props, switchChecked)
const trigger = useCustomEvent<EmitEvent<typeof emit>>(rootRef, emit)

watch(
() => props.checked,
(val) => {
switchChecked.value = val
}
)

const _onClick = ($event: Event) => {
if (props.disabled) {
return
}
switchChecked.value = !switchChecked.value
trigger('change', $event, {
value: switchChecked.value,
})
}

if (!!uniLabel) {
uniLabel.addHandler(_onClick)
onBeforeUnmount(() => {
uniLabel.removeHandler(_onClick)
})
}

useListeners(props, { 'label-click': _onClick })

let checkedCache = ref(switchChecked.value)
watch(
() => switchChecked.value,
(val) => {
checkedCache.value = val
}
)
onMounted(() => {
const rootElement = rootRef.value as UniSwitchElement
Object.defineProperty(rootElement, 'checked', {
get() {
return checkedCache.value
},
set(val) {
checkedCache.value = val
},
})
rootElement.attachVmProps(props)
})

return () => {
const {
activeBackgroundColor,
activeForegroundColor,
backgroundColor,
color,
foregroundColor,
type,
} = props
const booleanAttrs = useBooleanAttr(props, 'disabled')
const switchInputStyle: {
backgroundColor?: string
borderColor?: string
} = {}
const fixColor = activeBackgroundColor || color
const bgColor = switchChecked.value ? fixColor : backgroundColor
if (bgColor) {
switchInputStyle['backgroundColor'] = bgColor
switchInputStyle['borderColor'] = bgColor
}

const thumbStyle: {
backgroundColor?: string
} = {}
const fgColor = switchChecked.value
? activeForegroundColor
: foregroundColor
if (fgColor) {
thumbStyle['backgroundColor'] = fgColor
}

let realCheckValue: boolean | string
realCheckValue = checkedCache.value

return (
<uni-switch
id={props.id}
ref={rootRef}
{...booleanAttrs}
onClick={_onClick}
>
<div class="uni-switch-wrapper">
<div
v-show={type === 'switch'}
class="uni-switch-input"
// @ts-expect-error
class={[switchChecked.value ? 'uni-switch-input-checked' : '']}
style={switchInputStyle}
>
<div
class="uni-switch-thumb"
// @ts-expect-error
class={[switchChecked.value ? 'uni-switch-thumb-checked' : '']}
style={thumbStyle}
/>
</div>

<div v-show={type === 'checkbox'} class="uni-checkbox-input">
{realCheckValue
? createSvgIconVNode(
ICON_PATH_SUCCESS_NO_CIRCLE,
props.color,
22
)
: ''}
</div>
</div>
</uni-switch>
)
}
},
})

function useSwitchInject(
rootRef: Ref<HTMLElement | null>,
props: SwitchProps,
switchChecked: Ref<string | boolean>
) {
const initialCheckedValue: boolean = props.checked as boolean
const uniForm = inject<UniFormCtx>(uniFormKey, false as unknown as UniFormCtx)
const uniLabel = inject<UniLabelCtx>(
uniLabelKey,
false as unknown as UniLabelCtx
)

const formField = {
submit: () => {
const data: [string, any] = ['', null]
if (props.name) {
data[0] = props.name
data[1] = (rootRef.value as UniSwitchElement as any).checked
}
return data
},
reset: () => {
switchChecked.value = initialCheckedValue
},
}

if (!!uniForm) {
uniForm.addField(formField)
onUnmounted(() => {
uniForm.removeField(formField)
})
}

return uniLabel
}
26 changes: 10 additions & 16 deletions packages/uni-components/style-x/switch.css
Original file line number Diff line number Diff line change
Expand Up @@ -36,29 +36,23 @@ uni-switch[disabled] .uni-switch-input {
transition: background-color 0.1s, border 0.1s;
}

.uni-switch-input:after {
content: ' ';
position: absolute;
top: 0;
left: 0;
width: 28px;
height: 28px;
border-radius: 15px;
background-color: #ffffff;
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.06);
transition: transform 0.3s;
}

.uni-switch-input.uni-switch-input-checked {
border-color: #007aff;
background-color: #007aff;
}

.uni-switch-input.uni-switch-input-checked:before {
transform: scale(0);
uni-switch .uni-switch-thumb {
width: 28px;
height: 28px;
background-color: #fff;
border-radius: 15px;
transition-duration: 0.3s;
transition-property: transform;
transform: translateX(0px);
overflow: visible;
}

.uni-switch-input.uni-switch-input-checked:after {
uni-switch .uni-switch-thumb-checked {
transform: translateX(20px);
}

Expand Down

0 comments on commit 04bf207

Please sign in to comment.