VUE+CSS变量模拟组件库switch开关
1.HTML结构:
<template>
*<!-- 父相子绝定位,父元素添加点击事件 -->*
<div class="switch" ref="switchElement" @click="clickHandler">
<div ref="icon" class="icon"></div>
</div>
</template>
2.CSS样式:
<style scoped>
/*
将公共CSS变量设置在父元素中,子元素可以直接使用
分别设置switch的 on off CSS样式,便于组件调用者
控制样式风格
*/
.switch {
margin: 0;
/* switch元素的宽度,子元素根据该值的固定比例计算实际尺寸 */
--switch-width: 80px;
/* off状态的switch背景色 */
--switch-deactive-color: #fff;
/* on 状态的 switch背景色 */
--switch-active-color: #1677fe;
/* on / off状态的开关滑块背景色 */
--switch-icon-active-color: #fff;
--switch-icon-deactive-color: #ccc;
/* 使用CSS变量 */
width: var(--switch-width);
/* 大胆点,你可以使用calc(var(--switch-width) * 0.5) 得到动态计算值 */
height: calc(var(--switch-width) * 0.5);
background-color: var(--switch-deactive-color);
border-radius: 20px;
position: relative;
/* 别忘了过渡动画 */
transition: all .5s ease-in-out;
}
/* 子元素可以使用父级元素里的CSS变量 */
.icon {
margin: 0;
position: absolute;
/* 根据switch元素的 CSS变量动态计算*/
width: calc(var(--switch-width) * 0.5);
height: calc(var(--switch-width) * 0.5);
border-radius: 50%;
background-color: var(--switch-icon-deactive-color);
left: 0;
top: 0;
/* 别忘了开关滑块的过渡效果 */
transition: all .5s ease-in-out;
}
</style>
3.js部分:
<script lang="ts" setup>
import { ref, onMounted } from 'vue';
//指定onChange回调函数,向外传递switch是否选中
const emit = defineEmits<{ (e: 'onChange', bool: boolean): void }>()
//定义接收的属性并设置默认值
const props = defineProps({
defaultChecked: {
type: Boolean,
default: false
},
// 禁用属性默认为false,可用状态
disable: {
type: Boolean,
default: false
}
})
//组件内switch是否开启的状态
const bool = ref<boolean>(false)
//ref获取元素
const icon = ref<HTMLDivElement | null>(null)
const switchElement = ref<HTMLElement | null>(null)
onMounted(() => {
// 组件挂载后获取传入的默认是否选中并修改组件的是否选中的状态
// 将defaultChecked的值和bool值保持一致是不错的选择
if (bool.value !== props.defaultChecked) bool.value = props.defaultChecked
// 修改switch对应样式,无论是否禁用都要先根据传入值修改对应样式,
colorCtrl()
})
// 样式控制器函数
const colorCtrl = () => {
// 如果禁用状态设置透明度,组件挂载后要执行一下下面对应样式的变化,所以不要return
if (props.disable) switchElement.value!.style.opacity = '0.8'
//控制switchElement的背景色
switchElement.value!.style.backgroundColor = !bool.value ? 'var(--switch-deactive-color)' : 'var(--switch-active-color)';
// 控制switchElement的边框
switchElement.value!.style.border = !bool.value ? '1px solid #ccc' : 'none';
//控制内部开关的位置
icon.value!.style.left = !bool.value ? '0' : 'calc(var(--switch-width) * 0.5)';
//控制开关的背景色
icon.value!.style.backgroundColor = !bool.value ? 'var(--switch-icon-deactive-color)' : 'var(--switch-icon-active-color)';
}
//点击事件的回调函数
const clickHandler = () => {
//如果switch禁用就不向下进行
if (props.disable) return
//修改组件的switch状态
bool.value = !bool.value
// 修改样式
colorCtrl()
//向外传递boolean
emit('onChange', bool.value)
}
</script>
4.使用它:
<SwitchComp :default-checked="false" :style="{'--switch-active-color':'pink','--switch-icon-active-color':'purple'}" @on-change="onChange" />
5.禁用状态:
<SwitchComp :default-checked="false" disable :style="{'--switch-active-color':'pink','--switch-icon-active-color':'purple'}" @on-change="onChange" />
6.CSS变量/自定义属性使用的一些点:
-
document.querySelector(':root') === document.docuement //true
-
:root伪类会匹配DOM树的根元素,相对于html文件它代表html*
优先级略高,除此之外与html选择器相同,你可以认为是:root伪类
选择器权重10大于元素选择器1
-
内联行内选择器的优先级更高,且三者基本关系是内联样式>:root选择器>html选择器
-
当内联样式或者js设置的值时:document.documentElement.style.getPropertyValue
获取到的是实际的值
-
当只有:root选择器或者html选择器设置样式时时,document.documentElement.style.getPropertyValue
获取到的值是空,因为无法获取元素的内部外部样式表的样式
-
虽然js无法获取到样式表的CSS变量值,但是不影响document.documentElement.style.setProperty('property',value)*
因为js设置的CSS样式是行内样式
-
.getComputedStyle(document.documentElement).getPropertyValue(attribute)获取到的始终是
实际值
-
四种方式赋值时,如果值包含多个空格,都是总会把多余的空格变成一个
应该时类似于html页面的元素会将多余空格变成一个空格
真是服了,掘金的编辑器不会用,想搞个图文并茂的没弄明白,复制粘贴自己看吧