【uni-app】JS动态修改scss样式变量
'# 【uni-app】JS动态修改scss样式变量
一、背景与问题
在uni-app开发中,我们常常需要根据用户行为或系统状态动态调整UI样式。传统做法是通过JS直接操作DOM的style属性,但这种方式存在诸多局限:
- 需要维护大量冗余的样式代码
- 缺乏样式复用机制
- 无法实现全局样式统一控制
- 在复杂组件中难以维护
SCSS作为CSS预处理器,提供了变量、嵌套、混入等强大功能,但其变量在编译时就已经确定,无法在运行时动态修改。这导致在需要动态样式调整的场景中,开发者往往陷入两难。
二、基本原理
在uni-app中实现动态修改SCSS变量的核心原理是:利用CSS变量(Custom Properties)的运行时可变性,结合SCSS的预处理能力,构建可动态修改的样式系统。
SCSS变量在编译时会被转换为CSS变量,而CSS变量在运行时可以通过JavaScript动态修改。这种混合使用SCSS变量和CSS变量的方式,既保留了SCSS的可维护性,又实现了动态控制。
三、环境准备
在开始前需要准备以下环境:
- uni-app项目结构(使用Vue3)
- 安装依赖:
npm install sass 配置
vue.config.js支持SCSS:module.exports = { css: { loaderOptions: { sass: { data: `@import "@/assets/variables.scss";` // 全局SCSS变量文件 } } } }
四、核心实现
1. SCSS变量定义(variables.scss)
// 定义CSS变量
:root {
--primary-color: #007AFF;
--secondary-color: #FF4081;
--text-color: #333;
}2. 在组件中使用CSS变量
/* component.scss */
.container {
background-color: var(--primary-color);
color: var(--text-color);
}3. JS动态修改CSS变量
// 修改变量值
function updateTheme(color) {
document.documentElement.style.setProperty('--primary-color', color);
}4. 完整代码示例
<template>
<view class="container">
<text>当前主题色:{{ currentColor }}</text>
<button @click="toggleTheme">切换主题</button>
</view>
</template>
<script>
export default {
data() {
return {
currentColor: '#007AFF'
};
},
methods: {
toggleTheme() {
const newColor = this.currentColor === '#007AFF' ? '#FF4081' : '#007AFF';
this.currentColor = newColor;
document.documentElement.style.setProperty('--primary-color', newColor);
}
}
};
</script>五、完整案例:动态主题切换系统
1. 项目结构
src/
├── assets/
│ └── variables.scss
├── components/
│ └── ThemeSwitcher.vue
├── pages/
│ └── index.vue
└── App.vue2. 全局SCSS变量(assets/variables.scss)
:root {
--primary-color: #007AFF;
--secondary-color: #FF4081;
--text-color: #333;
}3. 组件样式(components/ThemeSwitcher.vue)
<template>
<view class="theme-switcher">
<text>当前主题:{{ theme }}</text>
<button @click="toggleTheme">切换主题</button>
</view>
</template>
<script>
export default {
data() {
return {
theme: 'light'
};
},
methods: {
toggleTheme() {
const newTheme = this.theme === 'light' ? 'dark' : 'light';
this.theme = newTheme;
if (newTheme === 'dark') {
document.documentElement.style.setProperty('--primary-color', '#FF4081');
document.documentElement.style.setProperty('--text-color', '#fff');
} else {
document.documentElement.style.setProperty('--primary-color', '#007AFF');
document.documentElement.style.setProperty('--text-color', '#333');
}
}
}
};
</script>
<style>
.theme-switcher {
padding: 20px;
background-color: var(--secondary-color);
color: var(--text-color);
}
</style>4. 页面使用(pages/index.vue)
<template>
<view>
<ThemeSwitcher />
<view class="main-content">
<text>动态样式示例</text>
</view>
</view>
</template>
<script>
import ThemeSwitcher from '@/components/ThemeSwitcher.vue';
export default {
components: {
ThemeSwitcher
}
};
</script>
<style>
.main-content {
padding: 20px;
background-color: var(--primary-color);
color: var(--text-color);
}
</style>六、源码解析
SCSS变量编译:
- 在编译过程中,SCSS的
@import会将variables.scss中的变量注入到document.documentElement的style中 :root选择器确保变量在全局作用域生效
- 在编译过程中,SCSS的
动态修改机制:
document.documentElement.style.setProperty()会直接修改根元素的CSS变量- 所有使用
var(--variable-name)的样式会自动更新
响应式更新:
- Vue的响应式系统会自动触发视图更新
- 需要确保样式中的变量引用是
var(--variable-name)格式
七、进阶使用
1. 动态类名结合CSS变量
<view :class="{'dark-theme': isDark}">
<!-- 内容 -->
</view>.dark-theme {
--primary-color: #FF4081;
--text-color: #fff;
}2. 动态样式绑定
<view :style="{ backgroundColor: `var(--primary-color)` }">
<!-- 内容 -->
</view>3. 多级变量控制
:root {
--base-color: #007AFF;
--primary-color: var(--base-color);
--secondary-color: #FF4081;
}4. 响应式变量控制
function updateResponsiveVariables(width) {
if (width < 768) {
document.documentElement.style.setProperty('--primary-color', '#FF4081');
} else {
document.documentElement.style.setProperty('--primary-color', '#007AFF');
}
}八、性能与工程实践
1. 性能优化
避免频繁更新:
let isUpdating = false; function updateTheme(color) { if (isUpdating) return; isUpdating = true; requestAnimationFrame(() => { document.documentElement.style.setProperty('--primary-color', color); isUpdating = false; }); }批量更新:
function updateMultipleVariables(vars) { Object.entries(vars).forEach(([key, value]) => { document.documentElement.style.setProperty(key, value); }); }
2. 异常处理
try {
document.documentElement.style.setProperty('--invalid-var', 'red');
} catch (e) {
console.error('无效的CSS变量:', e);
}3. 安全考虑
- XSS防护:避免直接拼接用户输入作为变量值
- 变量校验:对关键变量进行类型和范围校验
- 最小权限:限制对关键变量的修改权限
九、常见问题与踩坑
1. 常见错误
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 修改无效 | 变量未正确注入 | 检查SCSS编译配置 |
| 部分样式未更新 | 样式未使用var() | 确保所有样式使用CSS变量 |
| 跨平台不一致 | 不同平台样式处理差异 | 使用uni:style自定义样式 |
| 动画卡顿 | 频繁触发重排 | 使用requestAnimationFrame |
2. 环境差异
| 平台 | 特点 | 注意事项 |
|---|---|---|
| H5 | 支持CSS变量 | 可直接使用 |
| App | 支持CSS变量 | 需确认uni-app版本 |
| 小程序 | 仅支持部分CSS特性 | 需用wx.createSelectorQuery操作 |
3. 常见陷阱
- SCSS变量未正确注入:确保
@import路径正确 - 变量作用域问题:
document.documentElement是根元素 - 样式覆盖问题:注意CSS层叠顺序
- 移动端适配:需考虑不同设备的像素比
十、最佳实践
1. 标准化命名规范
:root {
--base: #007AFF;
--primary: var(--base);
--secondary: #FF4081;
--text: #333;
}2. 模块化管理
// colors.scss
:root {
--primary: #007AFF;
--secondary: #FF4081;
}
// typography.scss
:root {
--font-size: 16px;
--line-height: 1.5;
}3. 动态控制策略
// 主题管理器
export default {
currentTheme: 'light',
updateTheme(theme) {
this.currentTheme = theme;
if (theme === 'dark') {
this.setVariables({
'--primary': '#FF4081',
'--text': '#fff'
});
} else {
this.setVariables({
'--primary': '#007AFF',
'--text': '#333'
});
}
},
setVariables(vars) {
Object.entries(vars).forEach(([key, value]) => {
document.documentElement.style.setProperty(key, value);
});
}
};十一、总结
在uni-app中动态修改SCSS样式变量需要结合CSS变量的运行时特性,通过SCSS预处理构建可维护的样式系统。这种方案在需要动态样式控制的场景中具有显著优势,但需要注意以下几点:
- 适用场景:主题切换、动态样式控制、多环境样式适配
- 不适用场景:样式固定不变的普通页面
- 注意事项:确保变量正确注入,注意跨平台兼容性,避免频繁更新
- 性能优化:使用防抖/节流,批量更新变量,避免不必要的重排
通过合理的设计和实践,我们可以构建出既灵活又可维护的动态样式系统,提升uni-app项目的可维护性和用户体验。
评论已关闭