# 效果图

# 代码

<template>
    <div>
        <video :style="checked == true ? 'filter: grayscale(100%)' : ''" id="camera" ref="camera"></video>
        <input ref="checkBox" v-model="checked" type="checkbox" id="sun_switch">
        <label for="sun_switch">
            <div class="switch">
                <div class="light light3"></div>
                <div class="light light2"></div>
                <div class="light light1"></div>
                <div class="clouds-back">
                    <div class="cloud cloud7"></div>
                    <div class="cloud cloud6"></div>
                    <div class="cloud cloud5"></div>
                    <div class="cloud cloud4"></div>
                    <div class="cloud cloud3"></div>
                    <div class="cloud cloud2"></div>
                    <div class="cloud cloud1"></div>
                </div>
                <div class="clouds-front">
                    <div class="cloud cloud7"></div>
                    <div class="cloud cloud6"></div>
                    <div class="cloud cloud5"></div>
                    <div class="cloud cloud4"></div>
                    <div class="cloud cloud3"></div>
                    <div class="cloud cloud2"></div>
                    <div class="cloud cloud1"></div>
                </div>
                <div class="stars">
                    <div></div>
                    <div></div>
                    <div></div>
                    <div></div>
                    <div></div>
                </div>
                <div class="circle">
                    <div class="moon_circle moon_circle1"></div>
                    <div class="moon_circle moon_circle2"></div>
                    <div class="moon_circle moon_circle3"></div>
                </div>
            </div>
        </label>
    </div>
</template>
<script setup>
import { watch, onMounted, ref, onBeforeUnmount } from 'vue';
const { liveTime, isDay } = defineProps({
    liveTime: {
        type: Boolean,
        default: false
    }, isDay: {
        type: Boolean,
        default: null
    }
})
const camera = ref(null)
const checked = ref(null);
const checkBox = ref(null);
let mediastream = null;
let tracks = null
onMounted(async () => {
    await startMeidaPlayer();
    if (liveTime) {
        switchStartByLiveTime();
        return;
    }
    if (isDay != null) {
        checked.value = !isDay
    }
    if (isDay == null && !liveTime) {
        checked.value = true
    }
    randomPlaceStars()
})
const randomPlaceStars = () => {
    const stars = document.querySelectorAll(".switch>.stars>div")
    console.log(stars)
    stars.forEach((e) => {
        e.classList.add("star");
        e.style.top = Math.floor(Math.random() * 80) - 40 + "px";
        e.style.left = Math.floor(Math.random() * 180) + "px";
    })
}
const switchStartByLiveTime = () => {
    let now_hour = (new Date()).getHours();
    if (now_hour > 6 && now_hour < 18) {
        //is day
        checked.value = false;
    } else {
        //is night
        checked.value = true;
    }
}
watch(checked, (newV) => {
    if (!newV) {
        camera.value.play();
    } else {
        randomPlaceStars()
        camera.value.pause();
    }
})
const startMeidaPlayer = async () => {
    mediastream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true })
    tracks = mediastream.getTracks();
    camera.value.srcObject = mediastream;
}
onBeforeUnmount(() => {
    for (let track of tracks) {
        track.stop();
    }
})
</script>
<style scoped>
#camera {
    width: 300px;
    height: 300px;
    border-radius: 50%;
}

label {
    transform: scale(0.3);
    display: block;
    position: relative;
    margin-left: -240px;
    margin-top: -80px;
}

.switch {
    position: relative;
    overflow: hidden;
    width: 314px;
    height: 120px;
    border-radius: 100px;
    box-shadow: 0 2px 4px 0px inset rgba(0, 0, 0, 0.25);
    background: rgb(0, 104, 222);
    transition: all .5s ease-in-out;
}

.circle {
    position: absolute;
    left: 15px;
    top: 15px;
    width: 90px;
    height: 90px;
    border-radius: 50%;
    box-shadow: 0px 2px 4px 0 rgba(0, 0, 0, 0.25), inset 5px 5px 8px 0px rgba(255, 255, 255, 1);
    background: rgb(255, 195, 0);
    transition: transform .25s ease-in-out;
}

.ligth {
    position: absolute;
    border-radius: 50%;
    width: 216px;
    height: 216px;
    transition: transform .5s ease-in-out, all .5s ease-in-out;
}

.light1 {
    left: -49px;
    top: -48px;
    background: rgb(48, 145, 255);
}

.light2 {
    left: -6px;
    top: -50px;
    background: rgb(29, 130, 245);
}

.light3 {
    left: 38px;
    top: -44px;
    background: rgb(16, 116, 230);
}

.clouds-front {
    background: #fff;
}

.clouds-back {
    background: rgba(255, 255, 255, 0.5);
    transform: translate(-10px, -15px);
}

.cloud {
    position: absolute;
    border-radius: 50%;
    background: inherit;
}

.cloud1 {
    left: 13px;
    top: 95px;
    width: 65px;
    height: 65px;
}

.cloud2 {
    left: 71px;
    top: 95px;
    width: 51px;
    height: 51px;
}

.cloud3 {
    left: 115px;
    top: 73px;
    width: 76px;
    height: 76px;
}

.cloud4 {
    left: 174px;
    top: 90px;
    width: 76px;
    height: 76px;
}

.cloud5 {
    left: 201px;
    top: 70px;
    width: 72px;
    height: 68px;
}

.cloud6 {
    left: 252px;
    top: 36px;
    width: 136px;
    height: 136px;
}

.cloud7 {
    left: 278px;
    top: 0px;
    width: 136px;
    height: 136px;
}

.moon_circle {
    position: absolute;
    border-radius: 50%;
    background: rgb(168, 168, 168);
    box-shadow: inset 0 0 2px rgba(0, 0, 0, 0.25);
}

.moon_circle1 {
    left: 55px;
    top: 56px;
    width: 16px;
    height: 16px;
}

.moon_circle2 {
    left: 15px;
    top: 39px;
    width: 25px;
    height: 25px;
}

.moon_circle3 {
    left: 51px;
    top: 21px;
    width: 12px;
    height: 12px;
}

#sun_switch:not(:checked)~* .moon_circle1,
#sun_switch:not(:checked)~* .moon_circle2,
#sun_switch:not(:checked)~* .moon_circle3 {
    display: none;
}

#sun_switch {
    opacity: 0;
    width: 0px;
    height: 0px;
}

#sun_switch:checked~* .circle {
    background: #ccc;
    transform: translate(195px, 0);
}

#sun_switch:checked~* .switch {
    background: #000;
}

#sun_switch:checked~* .light1 {
    background: #555;
    transform: translate(195px, 0);
}

#sun_switch:checked~* .light2 {
    background: #333;
    transform: translate(115px, 0);
}

#sun_switch:checked~* .light3 {
    background: #222;
    transform: translate(30px, 0);
}

.star {
    position: relative;
    height: 20px;
    width: 20px;
    background: #fff;
    clip-path: path('M 5 0 C 5 5 4 10 0 10 C 4 10 5 15 5 20 C 5 15 6 10 10 10 C 6 10 5 5 5 0');
}

#sun_switch:not(:checked)~* .star {
    animation: rise forwards ease-out .5s;
}

@keyframes rise {
    to {
        transform: translateY(-100%);
        opacity: 0%;
    }
}
</style>

# 简述

简单编写了获取用户摄像头和音频,以及一个相当不错的主题切换按钮!

# 属性

props 描述 类型 默认
isDay 设置初始切换按钮状态 Boolean null
liveTime 是否以当前时间作为初始按钮状态,同时与 isDay 存在时以 isDay 优先 Boolean false

# 未来计划

  • 根据当前时间默认 switch 值。 √
  • 更改部分元素为范围内随机位置。 √
  • 接入公共气象 api 对样式添加雨天阴天效果。

# BUG

如果发现 bug 或者其他需求可以联系作者 也十分欢迎 pr 前往 github (opens new window)