【样式效果】Vue3实现仿制iOS按钮动态效果
iOS开关效果
定义变量:
<style scoped lang="scss">.layout {// 按钮宽度$button-width: 500px;// 按钮高度$button-height: 250px;// 按钮里面圆形直径$circle-diameter: 200px;// 按钮背景与里面圆形间距$button-circle-offset:calc(($button-height - $circle-diameter) / 2);// 里面圆形阴影大小$circle-shadow-size: 10px;// 里面圆形在长按情况下的宽度$circle-wider-size: 350px;// 浅灰色$light-gray: #e0e0e0;// 深灰色$dark-gray: #616161;// 绿色$green: #4caf50;}
</style>
绘制按钮图形:
<template><div class="layout"><div class="button"></div></div>
</template><style scoped lang="scss">
.layout {// 上面👆定义的变量display: flex;justify-content: center;align-items: center;min-height: 100vh;.button{width: $button-width;height: $button-height;background: $light-gray;border-radius:calc($button-width / 2);}
}
</style>
里面的圆形使用伪类选择器
&:after{content: '';display: block;width: $circle-diameter;height: $circle-diameter;border-radius: $circle-diameter;background-color: #fff;
}
给元素添加上定位让圆形固定到指定位置:
.button{// ...其他效果;position: relative;&:after{// ...其他效果;position: absolute;top:$button-circle-offset;transform: translateX($button-circle-offset); // 为了后面方便做动画,所以使用translateX
box-shadow:$button-circle-offset 0 calc($circle-shadow-size * 4) $dark-gray ;}}
处理点击效果:
<template>
<div class="layout"><div class="button" @click="clickBtn" :class="{ 'btnClick': isActive }" ></div></div>
</template><script setup lang="ts">import {ref} from "vue";const isActive = ref(false)const clickBtn = () => {isActive.value = !isActive.value}
</script><style scoped lang="scss">.btnClick {background: $green;&:after{transform: translateX( calc( $button-width - $circle-diameter - $button-circle-offset ) );box-shadow: calc( $button-circle-offset * -1 ) 0 calc($circle-shadow-size * 4) $dark-gray ;}}
</style>
加入transition
动画:
.button{transition:.3s all ease-in-out;&:after{transition:.3s all ease-in-out;}
}
接下来处理长按效果:
.button{&:active:after{width: $circle-wider-size;}
}
.btnClick {&:active:after{transform: translateX( calc( $button-width - $circle-wider-size - $button-circle-offset ) );}
}
这样按钮效果就实现啦🎉
完整代码:
<template><div class="layout"><div class="button" @click="clickBtn" :class="{ 'btnClick': isActive }" ></div></div>
</template><script setup lang="ts">
import {ref} from "vue";
const isActive = ref(false)const clickBtn = () => {isActive.value = !isActive.value
}
</script><style scoped lang="scss">
.layout {// 按钮宽度$button-width: 500px;// 按钮高度$button-height: 250px;// 按钮里面圆形直径$circle-diameter: 200px;// 按钮背景与里面圆形间距$button-circle-offset:calc(($button-height - $circle-diameter) / 2);// 里面圆形阴影大小$circle-shadow-size: 10px;// 里面圆形在长按情况下的宽度$circle-wider-size: 350px;// 浅灰色$light-gray: #e0e0e0;// 深灰色$dark-gray: rgba(97, 97, 97, 0.34);// 绿色$green: #71d575;display: flex;justify-content: center;align-items: center;min-height: 100vh;.button{width: $button-width;height: $button-height;background: $light-gray;border-radius:calc($button-width / 2);position: relative;transition:.3s all ease-in-out;&:after{content: '';display: block;width: $circle-diameter;height: $circle-diameter;border-radius: $circle-diameter;background-color: #fff;position: absolute;top:$button-circle-offset;transform: translateX($button-circle-offset); // 为了后面方便做动画,所以使用translateXbox-shadow:$button-circle-offset 0 calc($circle-shadow-size * 4) $dark-gray ;transition:.3s all ease-in-out;}&:active:after{width: $circle-wider-size;}}.btnClick {background: $green;&:after{transform: translateX( calc( $button-width - $circle-diameter - $button-circle-offset ) );box-shadow: calc( $button-circle-offset * -1 ) 0 calc($circle-shadow-size * 4) $dark-gray ;}&:active:after{transform: translateX( calc( $button-width - $circle-wider-size - $button-circle-offset ) );}}
}
</style>