vue实现switch组件
Vue 实现 Switch 组件
基本结构
使用 Vue 的单文件组件(SFC)实现一个基础的 Switch 组件。模板部分包含一个 div 包裹的 input 和 span,通过 CSS 实现开关样式。
<template>
<div class="switch" @click="toggle">
<input type="checkbox" v-model="isChecked" class="switch-input" />
<span class="slider"></span>
</div>
</template>
数据与事件
通过 v-model 实现双向绑定,监听点击事件切换状态。

<script>
export default {
props: {
value: {
type: Boolean,
default: false
}
},
data() {
return {
isChecked: this.value
};
},
methods: {
toggle() {
this.isChecked = !this.isChecked;
this.$emit('input', this.isChecked);
this.$emit('change', this.isChecked);
}
},
watch: {
value(newVal) {
this.isChecked = newVal;
}
}
};
</script>
样式设计
使用 CSS 实现滑动效果,通过伪类和过渡动画增强交互体验。
<style>
.switch {
position: relative;
display: inline-block;
width: 60px;
height: 34px;
}
.switch-input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
transition: 0.4s;
border-radius: 34px;
}
.slider:before {
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 4px;
bottom: 4px;
background-color: white;
transition: 0.4s;
border-radius: 50%;
}
.switch-input:checked + .slider {
background-color: #4CAF50;
}
.switch-input:checked + .slider:before {
transform: translateX(26px);
}
</style>
使用示例
在父组件中通过 v-model 绑定数据,监听状态变化。

<template>
<div>
<Switch v-model="isActive" @change="handleChange" />
</div>
</template>
<script>
import Switch from './Switch.vue';
export default {
components: { Switch },
data() {
return {
isActive: false
};
},
methods: {
handleChange(val) {
console.log('Switch state:', val);
}
}
};
</script>
自定义样式
通过 props 支持自定义颜色和尺寸,增强组件灵活性。
props: {
activeColor: {
type: String,
default: '#4CAF50'
},
inactiveColor: {
type: String,
default: '#ccc'
},
size: {
type: String,
default: 'medium',
validator: (val) => ['small', 'medium', 'large'].includes(val)
}
}
通过计算属性动态生成样式类:
computed: {
sliderStyle() {
return {
backgroundColor: this.isChecked ? this.activeColor : this.inactiveColor,
width: this.size === 'small' ? '40px' : this.size === 'large' ? '80px' : '60px',
height: this.size === 'small' ? '20px' : this.size === 'large' ? '40px' : '34px'
};
}
}






