vue实现多窗口主题样式切换以及跟随系统切换

vue实现多窗口主题样式切换以及跟随系统切换

自我记录

一.知识点链接:https://developer.mozilla.org/zh-CN/docs/Web/CSS/@media/prefers-color-scheme
一.知识点链接:https://www.runoob.com/jsref/met-win-matchmedia.html
二.监听 storage 变动 (跨页签通信)
三.watchEffect 侦听器

一.js+css 去匹配系统主题颜色

// 使用matchMedia API 去匹配css的媒体查询的 系统的主题是否为案(dark)颜色 (也可以去匹配屏幕的宽度高度等)
const match = matchMedia('(prefers-color-scheme:dark)')
console.log(match,'match');

在这里插入图片描述

二. 跨标签通信

window.addEventListener('storage', (event) => {
    
    
      console.log(event.newValue)
    })

A页面存储发生变化时B页面可以监听到
在这里插入图片描述

三.监听本地存储的变化并赋值

watchEffect(() => {
    
    
 localStorage.setItem(LOCAL_KEY, theme.value)
 document.documentElement.className = theme.value
})

四.全部代码

<template>
  <a-layout-header class="head-box" :style="{ position: 'fixed', zIndex: 1, width: '100%' }">
    <a-row :gutter="{ xs: 24, sm: 24, md: 24, lg: 24 }">
      <a-col :xs="7" :sm="7" :md="7" :lg="7">奔跑的代码!</a-col>
      <a-col :xs="6" :sm="6" :md="6" :lg="6">奔跑的代码!</a-col>
      <a-col :xs="6" :sm="6" :md="6" :lg="6">奔跑的代码!</a-col>
      <a-col :xs="5" :sm="5" :md="5" :lg="5">
        <!-- 开关切换主题 -->
        <a-switch v-model:checked="checked" checked-children="经典" un-checked-children="深夜" @change="onChange" />
      </a-col>
    </a-row>
  </a-layout-header>
</template>
<script setup>
import {
    
     ref, watchEffect } from 'vue'

const checked = ref(false)
// 切换主题样式
// 'light' | 'dark'
const LOCAL_KEY = '__theme__'
const theme = ref(localStorage.getItem(LOCAL_KEY) || 'light')
// 使用matchMedia API 去匹配css的媒体查询的 系统的主题是否为案(dark)颜色 (也可以去匹配屏幕的宽度高度等)
const match = matchMedia('(prefers-color-scheme:dark)')
console.log(match,'match');
// 跟随系统
const followOs = () => {
    
    
  // 如果当前系统时暗色 
  if (match.matches) {
    
    
  	// 本地存储重新赋值
    localStorage.setItem(LOCAL_KEY, 'dark')
    // html 的class 重新赋值
    document.documentElement.className = 'dark'
    // 优化了 页面滑块按钮的赋值
    checked.value = true
  } else {
    
    
    localStorage.setItem(LOCAL_KEY, 'light')
    document.documentElement.className = 'light'
    checked.value = false
  }
}
// matchMedia 的API 当 matchMedia('(prefers-color-scheme:dark)') 查询结果有变化时
// 监听主题的变化 
match.addEventListener('change', followOs)

watchEffect(() => {
    
    
  // 仅需要多个标签页联动 用这俩  
  // localStorage.setItem(LOCAL_KEY, theme.value)
  // document.documentElement.className = theme.value
  // 使用跟随系统功能 用这个函数
  followOs()
})
// 这个是antd滑块的事件 
const onChange = (value) => {
    
    
  const temp = value ? 'dark' : 'light'
  if (value) {
    
    
    theme.value = temp
    localStorage.setItem(LOCAL_KEY, temp)
    document.documentElement.className = temp
  } else {
    
    
    theme.value = temp
    localStorage.setItem(LOCAL_KEY, temp)
    document.documentElement.className = temp
  }


};
// 监听本地存储的变化 为了实现多个标签页联动
addEventListener('storage', event => {
    
    
  console.log(event, 'ev');
  document.documentElement.className = event.newValue
  checked.value = event.newValue === 'light' ? false : true
})

</script>
<style lang="less" scoped>
.head-box {
    
    
  width: 100%;
  height: 64px;
  background: @bgc-head-color;
  padding: 0 20px;
}
</style>

element Plus主题切换

最终展示效果

实现功能所用的代码API都在上面 大家也可以根据自己的喜好实现 想要的功能
起初只实现了一个主题切换功能 昨天有个朋友突然跟我说她的神仙产品经理要一个跟element Plus一样的多个标签页联动主题切换功能
接下来就有了上面的代码 如果帮到你了 请点赞收藏多多支持!

扫描二维码关注公众号,回复: 16524482 查看本文章

下面是我记录一下 简单配置vite+vue3+antd的主题切换

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
vite.config.js

import {
    
    defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue' //是vite 对vue 对支持插件
import Components from 'unplugin-vue-components/vite'
import path from 'path'
import themePreprocessorPlugin from "@zougt/vite-plugin-theme-preprocessor";
import VueSetupExtend from 'vite-plugin-vue-setup-extend'
import {
    
     AntDesignVueResolver } from 'unplugin-vue-components/resolvers'

// https://vitejs.dev/config/
export default defineConfig(({
     
      mode }) => {
    
    
    return {
    
    
        plugins: [
            vue(),
            VueSetupExtend(),
            Components({
    
    
                resolvers: [
                    AntDesignVueResolver({
    
    
                        importStyle: 'less', // 一定要开启这个配置项
                    }),
                ],
            }),
            themePreprocessorPlugin({
    
    
                less: {
    
    
                    // 各个主题文件的位置
                    multipleScopeVars: [
                        {
    
    
                            scopeName: "light",
                            path: path.resolve("src/assets/style/light.less"),
                        },
                        {
    
    
                            scopeName: "dark",
                            path: path.resolve("src/assets/style/dark.less"),
                        },
                    ],
                },
            }),
        ],
        base: "./",//公共基础路径 打包路径
        resolve: {
    
    
            alias: {
    
    
                '@': path.resolve(__dirname, './src')//别名设置
            },
            extensions: ['.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
        },
        server: {
    
    
            // host: 'localhost',
            port: 8081,//启动端口
            // https: true, // 开启https
            open: true, // 自动开启窗口
            proxy: {
    
     // 代理配置
                '/api': {
    
    
                    target: 'xxx',//后端服务地址
                    changeOrigin: true,
                    rewrite: (path) => path.replace(/^\/api/, '') // 重写路径
                }
            },
        },
        css: {
    
    
            preprocessorOptions: {
    
    
                less: {
    
    
                    // modifyVars:
                    //     {
    
    
                    //         'primary-color': '#1DA57A',
                    //         'link-color': '#1DA57A',
                    //         'border-radius-base': '2px',
                    // },
                    additionalData: `@import './src/assets/style/index.less';`,
                    javascriptEnabled: true,
                },
                stylus: {
    
    
                    /*vite  根据官档  @import 引入stylus不生效 需要通过绝对路径导入 */
                    // imports: [path.resolve(__dirname, 'src/stylus/...styl')]  //配置全局变量
                }
            },
        },
    }
})

总结不易,希望对各位有所帮助.希望可以共同学习与进步.

猜你喜欢

转载自blog.csdn.net/zhgweb/article/details/131004125