全部
常见问题
产品动态
精选推荐

Vue3自定义Hooks一键换肤教程

管理 管理 编辑 删除

核心

  • 使用CSS变量, 准备两套CSS颜色, 一套是在 light模式下的颜色,一套是在dark模式下的颜色
  • dark模式下的 CSS 权重要比 light 模式下的权重高, 不然当我们给html添加自定义属性[data-theme='dark']的时候, dark模式权重比light低,会一直不起效果
  • 当我们点击 dark 模式的时候, 给 html 设置自定义属性[data-theme='dark']
  • 当我们点击 light 模式的时候, 给 html 设置自定义属性[data-theme='light']
  • 在 dark 模式下, 会匹配到html[data-theme='dark']选择器下的样式
  • 在 light 模式下,由于我们没有设置html[data-theme='light']的方案, 那么他就匹配:root(即html)下的样式

两套样式代码大概如下(列了一部分):

:root {
  --color-body-bg: #ffffff;
  --color-text: #000;
  --color-secondary-bg-for-transparent: rgba(209, 209, 214, 0.28);
}

html[data-theme='dark'] {
  --color-body-bg: #222222;
  --color-text: #ffffff;
  --color-primary-bg-for-transparent: rgba(255, 255, 255, 0.12);
}

然后我们点击的时候,通过

 let theme = 'light'            // light / dark  
 document.documentElement.setAttribute('data-theme', theme)

这样就能实现简单的更换肤色功能了

什么? 你以为这就完了?好戏刚开始

跟随系统颜色

首先利用Window'matchMedia()' 方法返回一个新的 MediaQueryList 对象,表示指定的媒体查询 (en-US)字符串解析后的结果。

如运行媒体查询(max-width: 600px)并在;中显示MediaQueryListmatches属性值。如果视口的宽度小于或等于 600 像素,则输出将为 true,而如果窗口的宽度大于此宽度,则将输出 false。

523ce202402261100158558.png

let mql = window.matchMedia('(max-width: 600px)');
document.querySelector(".mq-value").innerText = mql.matches; //此时小于或等于600像素时span 里面的结果为false

利用prefers-color-scheme [CSS媒体特性] 用于检测用户是否有将系统的主题色设置为亮色或者暗色。

.day   { background: #eee; color: black; }
.night { background: #333; color: white; }

@media (prefers-color-scheme: dark) {
  .day.dark-scheme   { background:  #333; color: white; }
  .night.dark-scheme { background: black; color:  #ddd; }
}

@media (prefers-color-scheme: light) {
  .day.light-scheme   { background: white; color:  #555; }
  .night.light-scheme { background:  #eee; color: black; }
}

两者相结合

matchMedia()prefers-color-scheme 结合在一起, 我们就可以通过 js 去给系统颜色为dark或 light 的情况下更换对应的 html自定义属性, 即[data-theme='dark']
[data-theme='light']

首先,我们先去获取主题颜色, 我们还没设置的时候,就默认是系统颜色, 设置了就把他存储起来,下次直接获取这个颜色

// 获取主题变量
let appearance = ref(localStorage.getItem('appearance') || 'auto')

// 查询当前系统主题颜色
const match = window.matchMedia("(prefers-color-scheme: dark)")

// 如果主题变量为 auto, 则跟随系统主题
if (appearance.value === 'auto') {
    followSystem()
} else {
    document.documentElement.setAttribute('data-theme', appearance.value)
}

function followSystem() {
    // 当前系统颜色是亮色还是暗色 , 设置对应的html[data-theme= 'dark' 或者'light']
    const theme = match.matches ? 'dark' : 'light'
    document.documentElement.setAttribute('data-theme', theme)
}

// 监听系统主题变化,电脑主题发生改变的时候就调用followSystem函数
match.addEventListener('change', followSystem)

封装成一个hooks

暴露出一个 useThemeColor函数, 返回一个对象, 对象里面返回我们的主题变量

/ 获取主题变量
let appearance = ref(localStorage.getItem('appearance') || 'auto')
// 查询当前系统主题颜色
const match:MediaQueryList = window.matchMedia("(prefers-color-scheme: dark)")
// 监听系统主题变化
match.addEventListener('change', followSystem)

function followSystem() {
    const theme = match.matches ? 'dark' : 'light'
    document.documentElement.setAttribute('data-theme', theme)
}

watchEffect(() => {
// 如果主题变量为 auto, 则跟随系统主题
    if (appearance.value === 'auto') {
        followSystem()
    } else {
        document.documentElement.setAttribute('data-theme', appearance.value)
    }
})


export default function useThemeColor() {
    return {
        appearance,
    }
}

使用hooks

导入我们export出来的函数

import useThemeColor from '../hooks/useThemeColor'

使用函数,注意, 这里返回的 apprance 已经是一个响应式数据

const { appearance } = useThemeColor()

使用 v-model 绑定apprance,直接使用apprance , 当我们切换颜色的时候, 就会调用watchEffect里面的函数, 达到一键换肤效果

bdfa8202402261100442073.png

请登录后查看

CRMEB-慕白寒窗雪 最后编辑于2024-02-26 11:00:49

快捷回复
回复({{post_count}}) {{!is_user ? '我的回复' :'全部回复'}}
回复从新到旧

{{item.user_info.nickname ? item.user_info.nickname : item.user_name}}

作者 管理员 企业

{{item.floor}}# 同步到gitee 已同步到gitee {{item.is_suggest==1? '取消推荐': '推荐'}}
{{item.floor}}#
{{item.user_info.title}}
附件

{{itemf.name}}

{{item.created_at}}  {{item.ip_address}}
{{item.like_count}}
{{item.showReply ? '取消回复' : '回复'}}
删除
回复
回复

{{itemc.user_info.nickname}}

{{itemc.user_name}}

作者 管理员 企业

回复 {{itemc.comment_user_info.nickname}}

附件

{{itemf.name}}

{{itemc.created_at}}   {{itemc.ip_address}}
{{itemc.like_count}}
{{itemc.showReply ? '取消回复' : '回复'}}
删除
回复
回复
查看更多
回复
回复
580
{{like_count}}
{{collect_count}}
添加回复 ({{post_count}})

相关推荐

CRMEB-慕白寒窗雪 作者
社区运营专员---高冷のBoy | 呆萌のGirl

回答

2379

发布

1777

经验

46084

快速安全登录

使用微信扫码登录
{{item.label}} {{item.label}} {{item.label}} 板块推荐 常见问题 产品动态 精选推荐 首页头条 首页动态 首页推荐
加精
取 消 确 定
回复
回复
问题:
问题自动获取的帖子内容,不准确时需要手动修改. [获取答案]
答案:
提交
bug 需求 取 消 确 定

微信登录/注册

切换手机号登录

{{ bind_phone ? '绑定手机' : '手机登录'}}

{{codeText}}
切换微信登录/注册
暂不绑定
CRMEB客服

CRMEB咨询热线 咨询热线

400-8888-794

微信扫码咨询

CRMEB开源商城下载 开源下载 CRMEB官方论坛 帮助文档
返回顶部 返回顶部
CRMEB客服