使用Vue3封装的切换主题开关
组件介绍
第一次封装正经组件,更加深刻地感受到了Vue的强大及其带来的便利,记录一下😄打算多搞几个练Vue3
这是一个绑定了两个自定义事件、两个具名插槽的组件,可以切换白天、黑夜两种状态,因为放了两个slot插槽因此支持自定义状态标识
食用方法
- 由于使用的是具名插槽,因此需要在该组件注册至父组件后,在组件内放入两个带有
v-slot
的template
标签 - 需要通过
v-slot
传值day
、night
来分别表示白天与黑夜的主题 day
与night
需要是一个函数- 若插槽内不传入任何内容,则默认补充汉字“日”与“月”
代码
组件:
- 组件内对可能会发生样式变化的容器设置了
transition
并设置在0.3s完成过渡 - 组件内使用了ref来获取DOM节点
- 为了增加稍微丝滑一点的效果,开关中间的圆形按钮会变宽后变窄
situation
是非常重要的变量,表示目前的主题状态,当发生改变时将调用父组件传入的对应函数day
或night
,且容器样式将会发生改变
<template lang="">
<div class="slip-outer">
<div class="slip-block" ref="block"></div>
<div class="inner">
<div class="day" ref="day" @click="changeToDay">
<slot name="day">日</slot>
</div>
<div class="night" ref="night" @click="changeToNight">
<slot name="night">月</slot>
</div>
</div>
</div>
</template>
<script>
import { ref, watch } from 'vue'
export default {
name: 'ChangeStyle',
setup(props, context) {
let situation = ref(true)
const block = ref(null)
const day = ref(null)
const night = ref(null)
function changeToDay() {
if (!situation.value) {
situation.value = true
}
}
function changeToNight() {
if (situation.value) {
situation.value = false
}
}
function changeWidth() {
block.value.style.width = '50px'
setTimeout(() => {
block.value.style.width = '30px'
}, 80)
}
watch(situation, (newValue) => {
changeWidth()
if (newValue === true) {
context.emit('day')
block.value.style.left = '2px'
block.value.style.backgroundColor='#fff'
night.value.style.color = '#000'
} else {
context.emit('night')
block.value.style.left = '38px'
block.value.style.backgroundColor='#000'
night.value.style.color = '#fff'
}
})
return {
changeToDay,
changeToNight,
block,
night,
day,
situation
}
}
}
</script>
<style scoped>
.slip-outer {
height: 30px;
width: 70px;
border-radius: 15px;
background-color: rgb(221, 221, 221);
box-shadow: 0px 2px 5px rgb(140, 140, 140) inset;
position: relative;
}
.slip-block {
height: 26px;
width: 30px;
border-radius: 13px;
background-color: #fff;
position: absolute;
z-index: 0;
top: 2px;
left: 2px;
box-shadow: 0px 2px 2px rgb(140, 140, 140);
transition: 0.3s;
}
.inner {
display: flex;
width: 70px;
cursor: pointer;
}
.inner div {
z-index: 1;
width: 50%;
line-height: 30px;
text-align: center;
}
</style>
使用实例:
- 该实例展示的是父组件中使用如上组件的情况
- 可以像下方实例那样使用CSS变量来更方便地控制主题色(
:root
与.demo
中背景色的内容) - 函数
day
与night
在控制CSS变量以快速且方便地控制主题色
<template lang="">
<div>
<ChangeStyle @day="day" @night="night">
<template v-slot:day>
231
</template>
<template v-slot:night>
132
</template>
</ChangeStyle>
<div class="demo" ref:demo></div>
</div>
</template>
<script>
import ChangeStyle from './ChangeStyle.vue';
import { ref } from 'vue'
export default {
name: 'DemoDoc',
components: {
ChangeStyle
},
setup(props) {
const demo = ref(null)
function day() {
console.log('day');
document.documentElement.style.setProperty('--theme','#fff')
}
function night() {
console.log('night');
document.documentElement.style.setProperty('--theme','#000')
}
return {
day,
night,
demo
}
}
}
</script>
<style scoped>
:root {
--theme: '#fff';
}
.demo {
width: 100px;
height: 100px;
background-color: var(--theme);
border: 1px solid #000;
}
</style>
转载自:https://juejin.cn/post/7147550044961374244