Skip to content

Commit

Permalink
refactor(components): [switch] switch to script-setup syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
chenxch committed Jun 21, 2022
1 parent 5bfa42c commit 9d3317b
Show file tree
Hide file tree
Showing 2 changed files with 166 additions and 146 deletions.
Expand Up @@ -5,6 +5,8 @@ import { debugWarn } from '@element-plus/utils'
import { Checked, CircleClose } from '@element-plus/icons-vue'
import { ElFormItem } from '@element-plus/components/form'
import Switch from '../src/switch.vue'
import type { VueWrapper } from '@vue/test-utils'
import type { SwitchInstance } from '../src/switch'

vi.mock('@element-plus/utils/error', () => ({
debugWarn: vi.fn(),
Expand Down Expand Up @@ -117,7 +119,7 @@ describe('Switch.vue', () => {
</div>
`,
methods: {
handleChange(val) {
handleChange(val: boolean) {
this.target = val
},
},
Expand Down Expand Up @@ -189,6 +191,33 @@ describe('Switch.vue', () => {
expect(vm.value).toEqual('100')
})

test('default switch active-value is false', async () => {
const wrapper = mount({
components: {
'el-switch': Switch,
},
template: `
<div>
<el-switch v-model="value" :active-value="onValue" :inactive-value="offValue"></el-switch>
</div>
`,
data() {
return {
value: false,
onValue: false,
offValue: true,
}
},
})
const vm = wrapper.vm

const coreWrapper = wrapper.find('.el-switch__core')
await coreWrapper.trigger('click')
expect(vm.value).toEqual(true)
await coreWrapper.trigger('click')
expect(vm.value).toEqual(false)
})

test('value is the single source of truth', async () => {
const wrapper = mount({
components: {
Expand All @@ -202,7 +231,8 @@ describe('Switch.vue', () => {
})
const vm = wrapper.vm
const coreWrapper = wrapper.find('.el-switch__core')
const switchWrapper = wrapper.findComponent(Switch)
const switchWrapper: VueWrapper<SwitchInstance> =
wrapper.findComponent(Switch)
const switchVm = switchWrapper.vm
const inputEl = vm.$el.querySelector('input')

Expand All @@ -228,7 +258,8 @@ describe('Switch.vue', () => {
})
const vm = wrapper.vm
const coreWrapper = wrapper.find('.el-switch__core')
const switchWrapper = wrapper.findComponent(Switch)
const switchWrapper: VueWrapper<SwitchInstance> =
wrapper.findComponent(Switch)
const switchVm = switchWrapper.vm
const inputEl = vm.$el.querySelector('input')

Expand Down
275 changes: 132 additions & 143 deletions packages/components/switch/src/switch.vue
Expand Up @@ -81,8 +81,8 @@
</div>
</template>

<script lang="ts">
import { computed, defineComponent, nextTick, onMounted, ref, watch } from 'vue'
<script lang="ts" setup>
import { computed, nextTick, onMounted, ref, watch } from 'vue'
import { isPromise } from '@vue/shared'
import { addUnit, debugWarn, isBoolean, throwError } from '@element-plus/utils'
import ElIcon from '@element-plus/components/icon'
Expand All @@ -100,162 +100,151 @@ import {
useSize,
} from '@element-plus/hooks'
import { switchEmits, switchProps } from './switch'
import type { CSSProperties } from 'vue'
const COMPONENT_NAME = 'ElSwitch'
export default defineComponent({
name: COMPONENT_NAME,
components: { ElIcon, Loading },
props: switchProps,
emits: switchEmits,
setup(props, { emit }) {
const { formItem } = useFormItem()
const switchDisabled = useDisabled(computed(() => props.loading))
const ns = useNamespace('switch')
const { inputId } = useFormItemInputId(props, {
formItemContext: formItem,
})
const switchSize = useSize()
const isModelValue = ref(props.modelValue !== false)
const input = ref<HTMLInputElement>()
const core = ref<HTMLSpanElement>()
const switchKls = computed(() => [
ns.b(),
ns.m(switchSize.value),
ns.is('disabled', switchDisabled.value),
ns.is('checked', checked.value),
])
defineOptions({
name: 'ElSwitch',
})
const coreStyle = computed<CSSProperties>(() => ({
width: addUnit(props.width),
}))
const props = defineProps(switchProps)
const emit = defineEmits(switchEmits)
watch(
() => props.modelValue,
() => {
isModelValue.value = true
}
)
const { formItem } = useFormItem()
const ns = useNamespace('switch')
watch(
() => props.value,
() => {
isModelValue.value = false
}
)
const { inputId } = useFormItemInputId(props, {
formItemContext: formItem,
})
const actualValue = computed(() => {
return isModelValue.value ? props.modelValue : props.value
})
const switchSize = useSize()
const switchDisabled = useDisabled(computed(() => props.loading))
const isControlled = ref(props.modelValue !== false)
const input = ref<HTMLInputElement>()
const core = ref<HTMLSpanElement>()
const switchKls = computed(() => [
ns.b(),
ns.m(switchSize.value),
ns.is('disabled', switchDisabled.value),
ns.is('checked', checked.value),
])
const coreStyle = computed<CSSProperties>(() => ({
width: addUnit(props.width),
}))
watch(
() => props.modelValue,
() => {
isControlled.value = true
}
)
watch(
() => props.value,
() => {
isControlled.value = false
}
)
const actualValue = computed(() => {
return isControlled.value ? props.modelValue : props.value
})
const checked = computed(() => actualValue.value === props.activeValue)
const checked = computed(() => actualValue.value === props.activeValue)
if (![props.activeValue, props.inactiveValue].includes(actualValue.value)) {
emit(UPDATE_MODEL_EVENT, props.inactiveValue)
emit(CHANGE_EVENT, props.inactiveValue)
emit(INPUT_EVENT, props.inactiveValue)
}
if (![props.activeValue, props.inactiveValue].includes(actualValue.value)) {
emit(UPDATE_MODEL_EVENT, props.inactiveValue)
emit(CHANGE_EVENT, props.inactiveValue)
emit(INPUT_EVENT, props.inactiveValue)
}
watch(checked, () => {
input.value!.checked = checked.value
watch(checked, (val) => {
input.value!.checked = val
if (props.activeColor || props.inactiveColor) {
setBackgroundColor()
}
if (props.activeColor || props.inactiveColor) {
setBackgroundColor()
}
if (props.validateEvent) {
formItem?.validate?.('change').catch((err) => debugWarn(err))
}
})
if (props.validateEvent) {
formItem?.validate?.('change').catch((err) => debugWarn(err))
}
})
const handleChange = (): void => {
const val = checked.value ? props.inactiveValue : props.activeValue
emit(UPDATE_MODEL_EVENT, val)
emit(CHANGE_EVENT, val)
emit(INPUT_EVENT, val)
nextTick(() => {
input.value!.checked = checked.value
const handleChange = () => {
const val = checked.value ? props.inactiveValue : props.activeValue
emit(UPDATE_MODEL_EVENT, val)
emit(CHANGE_EVENT, val)
emit(INPUT_EVENT, val)
nextTick(() => {
input.value!.checked = checked.value
})
}
const switchValue = () => {
if (switchDisabled.value) return
const { beforeChange } = props
if (!beforeChange) {
handleChange()
return
}
const shouldChange = beforeChange()
const isPromiseOrBool = [
isPromise(shouldChange),
isBoolean(shouldChange),
].includes(true)
if (!isPromiseOrBool) {
throwError(
COMPONENT_NAME,
'beforeChange must return type `Promise<boolean>` or `boolean`'
)
}
if (isPromise(shouldChange)) {
shouldChange
.then((result) => {
if (result) {
handleChange()
}
})
}
const switchValue = (): void => {
if (switchDisabled.value) return
const { beforeChange } = props
if (!beforeChange) {
handleChange()
return
}
const shouldChange = beforeChange()
const isExpectType = [
isPromise(shouldChange),
isBoolean(shouldChange),
].some((i) => i)
if (!isExpectType) {
throwError(
COMPONENT_NAME,
'beforeChange must return type `Promise<boolean>` or `boolean`'
)
}
if (isPromise(shouldChange)) {
shouldChange
.then((result) => {
if (result) {
handleChange()
}
})
.catch((e) => {
debugWarn(COMPONENT_NAME, `some error occurred: ${e}`)
})
} else if (shouldChange) {
handleChange()
}
}
const setBackgroundColor = (): void => {
const newColor = checked.value ? props.activeColor : props.inactiveColor
const coreEl = core.value
if (props.borderColor) coreEl!.style.borderColor = props.borderColor
else if (!props.borderColor) coreEl!.style.borderColor = newColor
coreEl!.style.backgroundColor = newColor
;(coreEl!.children[0] as HTMLDivElement).style.color = newColor
}
const focus = (): void => {
input.value?.focus?.()
}
onMounted(() => {
if (props.activeColor || props.inactiveColor || props.borderColor) {
setBackgroundColor()
}
input.value!.checked = checked.value
})
.catch((e) => {
debugWarn(COMPONENT_NAME, `some error occurred: ${e}`)
})
} else if (shouldChange) {
handleChange()
}
}
const setBackgroundColor = (): void => {
const newColor = checked.value ? props.activeColor : props.inactiveColor
const coreEl = core.value
if (props.borderColor) coreEl!.style.borderColor = props.borderColor
else if (!props.borderColor) coreEl!.style.borderColor = newColor
coreEl!.style.backgroundColor = newColor
;(coreEl!.children[0] as HTMLDivElement).style.color = newColor
}
const focus = (): void => {
input.value?.focus?.()
}
onMounted(() => {
if (props.activeColor || props.inactiveColor || props.borderColor) {
setBackgroundColor()
}
input.value!.checked = checked.value
})
return {
ns,
input,
inputId,
core,
switchDisabled,
checked,
switchKls,
coreStyle,
handleChange,
switchValue,
focus,
}
},
defineExpose({
/**
* @description manual focus to the switch component
**/
focus,
})
</script>

0 comments on commit 9d3317b

Please sign in to comment.