JS媒体查询之matchMedia API 实现跟随系统主题色切换效果

📊写在前面

在网页设计中,跟随系统主题切换可以通过CSS和JavaScript实现。可以通过定义两套CSS变量,根据系统主题的颜色来切换变量的生效,从而实现不同主题下的页面样式变化。

例如,可以使用媒体查询API来获取系统主题的颜色,并根据匹配结果来适配页面的自定义属性。同时,可以注册媒体查询的change事件,当系统主题变化时重新调用函数,实现跟随系统的效果。

🖼️API简介

Window 的 matchMedia() 方法返回一个新的 MediaQueryList 对象,表示指定的媒体查询字符串解析后的结果。返回的 MediaQueryList 可被用于判定 Document 是否匹配媒体查询,或者监控一个 document 来判定它匹配了或者停止匹配了此媒体查询。

🚀实际效果

📚实例代码(HTML版)

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>JS媒体查询之matchMedia API 实现跟随系统主题色切换效果</title>
    <style>
        :root {
            --text-color: #333;
            --bg-color: #fff;
        }

        html[data-theme="dark"] {
            --text-color: #fff;
            --bg-color: #333;
        }

        html[data-theme="ligth"] {
            --text-color: #333;
            --bg-color: #fff;
        }

        html[data-theme="red"] {
            --text-color: #fff;
            --bg-color: #ff0064;
        }

        html[data-theme="green"] {
            --text-color: #fff;
            --bg-color: #67c23a;
        }

        html[data-theme="blue"] {
            --text-color: #fff;
            --bg-color: #0091db;
        }

        body {
            background-color: var(--bg-color);
            color: var(--text-color);
        }

        h1 {
            color: var(--text-color);
            text-align: center;
        }

        select {
            display: block;
            margin: 20px auto;
            font-size: 32px;
        }
    </style>
</head>

<body>
    <h1>JS媒体查询之matchMedia API 实现跟随系统主题色切换效果</h1>
    <hr>

    <select name="theme" id="theme">
        <option value="ligth">亮色</option>
        <option value="dark">暗色</option>
        <option value="os">系统跟随</option>
        <option value="red">红色</option>
        <option value="green">绿色</option>
        <option value="blue">蓝色</option>
    </select>

    <script>
        const theme = document.getElementById('theme');
        
        // 获取系统主题
        const metch = window.matchMedia('(prefers-color-scheme: dark)');

        // 设置主题
        const setTheme = (theme = '') => {
            document.documentElement.setAttribute('data-theme', theme ? theme : metch.matches ? 'dark' : 'ligth');
        };

        // 监听主题切换
        theme.addEventListener('change', (e) => {
            if ('os' === e.target.value) {
                setTheme();
                // 监听系统主题切换
                metch.addEventListener('change', setTheme);
            } else {
                setTheme(e.target.value);
                metch.removeEventListener('change', setTheme);
            }
        });
    </script>
</body>

</html>

📚实例代码(Vue3.js + TS版)

hook.ts

ts 复制代码
import { ref, watchEffect } from 'vue';

// 定义主题类型
type Theme = 'light' | 'dark' | 'os';

// 存储主题的key
const STORE_KEY = '__hteme__';

// 获取存储主题
const theme = ref<Theme>(localStorage.getItem(STORE_KEY) as Theme || 'light');

// 获取系统主题
const media = globalThis.matchMedia('(prefers-color-scheme: dark)');

// 监听系统主题变化
const listener = () => {
    document.documentElement.dataset.theme = media.matches ? 'dark' : 'light';
}

// 监听theme变量值变化
watchEffect(() => {
    // 更新存储
    localStorage.setItem(STORE_KEY, theme.value);

    if (theme.value === 'os') {
        // 设置系统主题
        listener();
        
        // 监听系统主题变化
        media.addEventListener('change', listener);

    } else {
        // 移除监听
        media.removeEventListener('change', listener);
        document.documentElement.dataset.theme = theme.value;
    }
});

export function useTheme() {
    return {
        theme
    }
};

demo.vue

html 复制代码
<script setup lang="ts">
	import { useTheme } from '@/hooks/useTheme';
	const { theme } = useTheme()
</script>

<template>
	<h1>JS媒体查询之matchMedia API 实现跟随系统主题色切换效果</h1>
    <hr>
	<select v-model="theme">
		<option value="ligth">亮色</option>
        <option value="dark">暗色</option>
        <option value="os">系统跟随</option>
        <option value="red">红色</option>
        <option value="green">绿色</option>
        <option value="blue">蓝色</option>
	 </select>
</template>

<style>
    :root {
        --text-color: #333;
        --bg-color: #fff;
    }

    html[data-theme="dark"] {
        --text-color: #fff;
        --bg-color: #333;
    }

    html[data-theme="ligth"] {
        --text-color: #333;
        --bg-color: #fff;
    }

    html[data-theme="red"] {
        --text-color: #fff;
        --bg-color: #ff0064;
    }

    html[data-theme="green"] {
        --text-color: #fff;
        --bg-color: #67c23a;
    }

    html[data-theme="blue"] {
        --text-color: #fff;
        --bg-color: #0091db;
    }

    body {
        background-color: var(--bg-color);
        color: var(--text-color);
    }

    h1 {
        color: var(--text-color);
        text-align: center;
    }

    select {
        display: block;
        margin: 20px auto;
        font-size: 32px;
    }
</style>
相关推荐
i_am_a_div_日积月累_1 年前
修改element-plus主题色
element-plus·主题色