vue项目如何套样式_优雅地实现Vue项目的换肤功能

前言

网上关于前端项目的换肤功能,有很多文章和解决方案,我就不在这里一一列举了,下面我会根据我司项目的具体情况,来实现换肤功能的一整套计划,包括后期如何快速新增主题,减少代码量。

项目简介项目采用 vue-cli 脚手架搭建

项目基于 element-ui 组件进行开发

项目采用 scss 预处理器作为样式编写语言

换肤思考项目的换肤对象分两种:Element组件 和 项目自定义页面及组件。

Element组件样式部分由 scss 编写,主题颜色均采用变量进行编写,只需修改变量文件即可打包生成新的 .css 文件,项目根据主题名称引入相应 .css 文件即可实现Element组件的换肤功能。

在Element官方文档中,已有自定义主题的介绍: 在项目中改变 SCSS 变量 ,经实践,可以正常工作,但由于我司项目采用了 dart-scss ,开发环境在构建项目时耗时非常久,再加上多个项目都有使用自定义主题的Element项目,所以我将Element组件单独抽离出来,一般来说,主题设置好了以后也不会经常修改,所以在项目中直接引用打包好的CSS样式文件,开发更高效。

项目自定义页面及组件采用类似的方式,建立Element相应主题同样的变量文件,可在此基础上做相应调整,最大程度上保证项目视觉体验的一致性,同时在编写样式代码时尽量采用变量代替具体数值,为后期制作更多主题提供便利。

项目针对不同主题设置不同的SCSS入口文件,通过Gulp可打包生成CSS文件,项目上线后根据主题名称动态加载即可实现换肤。

在编写项目自定义页面及组件的样式时,引用一套公共变量(全部设置默认值 !default ),再手动引入相应主题的变量文件,即可实时对主题进行预览,还没有结束,可能一些页面或者组件在某个主题下的样式很特别,与其他主题没有共通点,无法用变量进行编写,可设置命名空间,即更换主题时,在顶层标签增加相应class,特殊样式写在当前的命名空间下,增加代码复用的同时不丢失个性~

项目实践:Element组件换肤Element组件换肤,可采用官方在线主题编辑器,如果觉得定制的项目不够多,也可将组件仓库克隆下来,修改变量文件并生成相应主题:

# 变量文件 >>> /packages/theme-chalk/src/common/var.scss

# 开发环境下查看效果

npm install

npm run dev

# 仅生成样式文件,生成的样式文件存放在根目录下的 /lib 和 /packages/theme-chalk/lib 下

npm run build:theme如何管理多套element主题呢?在 /packages 下找到 theme-chalk 文件夹,拷贝一份并重新命名,例如:/packages/theme-red

自然是对新建的 /theme-red 下的变量文件进行修改

修改 /build/bin/gen-cssfile.js 文件,将主题文件名添加至 themes 数组

// gen-cssfile.js

var fs = require('fs');

var path = require('path');

var Components = require('../../components.json');

var themes = [

'theme-chalk', 'theme-red'

];

Components = Object.keys(Components);

var basepath = path.resolve(__dirname, '../../packages/');

function fileExists(filePath) {

try {

return fs.statSync(filePath).isFile();

} catch (err) {

return false;

}

}

themes.forEach((theme) => {

var isSCSS = theme !== 'theme-default';

var indexContent = isSCSS ? '@import "./base.scss";\n' : '@import "./base.css";\n';

Components.forEach(function(key) {

if (['icon', 'option', 'option-group'].indexOf(key) > -1) return;

var fileName = key + (isSCSS ? '.scss' : '.css');

indexContent += '@import "./' + fileName + '";\n';

var filePath = path.resolve(basepath, theme, 'src', fileName);

if (!fileExists(filePath)) {

fs.writeFileSync(filePath, '', 'utf8');

console.log(theme, ' 创建遗漏的 ', fileName, ' 文件');

}

});

fs.writeFileSync(path.resolve(basepath, theme, 'src', isSCSS ? 'index.scss' : 'index.css'), indexContent);

});

4. 修改 package.json 文件下的 build:theme 命令,添加主题的gulp流程:

{

"build:theme": "node build/bin/gen-cssfile && gulp build --gulpfile packages/theme-chalk/gulpfile.js && cp-cli packages/theme-chalk/lib lib/theme-chalk && gulp build --gulpfile packages/theme-red/gulpfile.js && cp-cli packages/theme-red/lib lib/theme-red"

}

5. 至此,当你再使用 npm run build:theme 时,便会自动生成多套主题文件了~

6. 多说一嘴,项目在引用Element组件时,为方便开发,可视情况将element样式文件存放在 /public/theme-style/element/${theme} 目录下,这样可直接在 js 文件中通过创建 标签并设置 href 属性达到加载样式的功能:

changeElementTheme(theme) {

const head = document.head || document.getElementsByTagName('head')[0];

// 卸载原有的主题样式,设置定时器是为了防止抖动 for (let i = head.children.length - 1; i > -1; i--) {

const currentChild = head.children[i];

if (currentChild.rel === 'stylesheet' && currentChild.href.includes('theme')) {

setTimeout(() => {

currentChild.parentNode.removeChild(currentChild);

}, 500);

}

}

// '/public' 映射到 '/',各位可根据情况设置相应路径 const urls = ['/theme-style/element'];

urls.forEach(site => {

const link = document.createElement('link');

link.rel = 'stylesheet';

link.type = 'text/css';

link.href = `${site}/${theme}.css`;

head.appendChild(link);

});

}

项目实践:自定义页面及组件换肤合理组织项目样式目录

├── styles

| ├── common // 公用文件(包含工具class和基础变量)

| ├── components // 公共组件样式

| ├── layout // 布局样式

| ├── mixins // 混入样式(包括mixins.scss, utils.scss等)

| ├── theme // 主题变量文件及打包入口文件

| | ├── red

| | └── default

| ├── views // 页面样式

| | ├── ...pages

| | └── login

| └── base.scss // 公用样式入口

2. 开发模式下,手动加载 /styles/theme/${themne}/theme-${theme}.scss 文件:

// theme-red.scss

@import "variables.scss";

@import "../../base.scss";

3. base.scss 文件包括了各个公用模块的引用

// base.scss

@import "common/global-class";

@import "layout/index.scss";

@import "components/chart.scss";

@import "views/person/index.scss";

4. 在页面组件的样式编写中,采用 BEM 风格对 class 进行命名,关于 BEM 的mixin方法网上很多,各位可以自行搜索实现下,项目的样式代码编写方式如下,这样编写的好处在于,单一页面针对不同主题的样式都在一个文件里完成,因为引用了公共变量,所以大部分代码都不用调整,针对需要调整的部分可通过命名空间的方式来解决:

// styles/layout/index.scss

@import "../../../../common/var.scss";

@import "../../../../mixins/mixins.scss";

// BEM 风格代码@includeb(person-detail) {

width: 100px;

height: 100px;

@includee(main) {

width: 100px;

}

@includee(content) {

width: 100%;

height: 20px;

}

// 针对特定主题的样式,在变量范围外,通过此方法进行混入 @includetheme-rule(red) {

border: 1px solid $--color-primary;

}

// 引入组件样式,该组件为页面下的独有组件 @import "alias-chart.scss";

}

// >>>> 生成的 CSS 文件

.person-detail {

width: 100px;

height: 100px;

}

.person-detail__main {

width: 100px;

}

.person-detail__content {

width: 100%;

height: 20px;

background-color: #409EFF;

}

.person-detail .alias-chart {

background: red;

}

.person-detail .alias-chart .main-test {

width: 1px;

}

.theme-red .person-detail {

border: 1px solid #409EFF;

}

5. 至此,项目样式代码编写规范已经完成,开发模式下,通过在项目中手动引入指定主题文件的入口文件 /src/styles/theme/${themne}/theme-${theme}.scss 文件,再设置theme的默认值,便于本地开发:

export default {

name: 'App',

computed: {

theme() {

return this.$store.state.user.theme || 'default';

}

},

watch: {

theme: {

immediate: true,

handler(val) {

this.changeElementTheme(val);

}

}

},

methods: {

handleSwitch() {

this.theme = this.theme === 'default' ? 'red' : 'default';

},

changeElementTheme(theme) {

const head = document.head || document.getElementsByTagName('head')[0];

for (let i = head.children.length - 1; i > -1; i--) {

const currentChild = head.children[i];

if (currentChild.rel === 'stylesheet' && currentChild.href.includes('theme')) {

setTimeout(() => {

currentChild.parentNode.removeChild(currentChild);

}, 500);

}

}

urls.forEach(site => {

const link = document.createElement('link');

link.rel = 'stylesheet';

link.type = 'text/css';

link.href = `${site}/${theme}.css`;

head.appendChild(link);

});

}

}

};

关于Vue项目的换肤功能,这是我目前找到的最适合自己的方法,如果你有更好的解决方法,欢迎评论或者私信讨论~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现Vue换肤功能,您可以使用CSS变量和Vue的计算属性结合起来。这样,当用户选择不同的主题时,您只需要改变CSS变量的值,就能实现换肤效果。 首先,在您的Vue组件的样式中定义一些CSS变量: ``` <style> :root { --primary-color: #007bff; --secondary-color: #6c757d; } </style> ``` 在这个例子中,我们定义了两个CSS变量:`--primary-color`和`--secondary-color`。接下来,您可以在组件中使用这些变量: ``` <template> <div> <button :style="{ backgroundColor: primaryColor }">Primary Button</button> <button :style="{ backgroundColor: secondaryColor }">Secondary Button</button> </div> </template> <script> export default { computed: { primaryColor() { return getComputedStyle(document.documentElement).getPropertyValue('--primary-color'); }, secondaryColor() { return getComputedStyle(document.documentElement).getPropertyValue('--secondary-color'); } } } </script> ``` 在这个例子中,我们使用Vue的计算属性来获取CSS变量的值,并将其应用到组件中的两个按钮上。当用户选择不同的主题时,您只需要通过JavaScript代码改变`--primary-color`和`--secondary-color`的值,就能实现换肤效果。 例如,当用户选择蓝色主题时,您可以使用以下代码改变CSS变量的值: ``` document.documentElement.style.setProperty('--primary-color', '#007bff'); document.documentElement.style.setProperty('--secondary-color', '#6c757d'); ``` 这将使所有使用这些CSS变量的元素都应用新的颜色值,从而实现换肤效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值