设计思路
我能想到的主题切换方式无非两种:
- 一种是在body中加样式,对所有css进行命名空间(css前缀)处理
- 一种是类似Element自身的主题切换方式,通过编写scss改变主题
前一种方式在花裤衩同学的vue-element-admin中有具体的实现,项目主页:https://github.com/PanJiaChen/vue-element-admin
他是先将element自己提供的变量文件修改后生成新的css,然后将该css用gulp进行二次编辑增加命名空间,然后引入。也就是说他只是修改了UI框架的主题,并没有修改自己写的样式主题。
第二种方式则是element自己生成一个sass变量文件,执行命令行后生成新主题,然后让开发者自己导入。
以上两种其实都并没有实现项目本身自定义样式的主题切换,所以就产生了很多的问题。但仔细分析一下,其实我们只要将自己写的css样式也如同element官方那样打包一遍,然后动态引入就好了嘛。当然也可能是我傻,没想到还有其他方法。
介于以上总结,项目中设计的主题加载和切换方式大致流程如下:
1. 页面中仅引入基本样式
2. 页面初始化完成,动态加载主题文件
3. 用户切换主题:判断主题文件是否已经存在,存在则不操作;不存在则清空所有的主题文件,然后动态加载对应的主题文件。
主题创建
当前主题编写参考了Element的主题切换方式,通过sass进行变量修改。
# 复制基础变量文件 (src/assets/css/theme/default.scss),重命名为 blue.scss 并修改内部变量
# 在 src/assets/css 目录中创建新的主题入口文件 theme-blue.scss,并做如下引入
// 引入新主题变量文件
@import './theme/blue'
// 引入默认主题
@import './theme-default'
如此简单的便可以完成主题创建。前文说过我们需要动态引入文件,而动态引入我采用的是js读取文件路径并加载的形式,也就意味着该文件必须存在实际的物理地址,所以你需要先对项目进行打包,生成对应的静态的css文件,而不是scss文件。为了达成这个目的我们还需要对webpack进行设置。沿着这个思路我们还需要做以下工作。
配置webpack
在webpack.prod.conf.js中对入口变量做出修改,注意是prod.js
// 增加新的入口,并赋予文件名和路径
entry: {
'theme-default': './src/assets/style/theme-default.scss'
}
// 对HtmlWebpackPlugin插件增加忽略chunk设置,防止该chunk被加入到生成后的html中
new HtmlWebpackPlugin({
excludeChunks: ['theme-default']
})
配置供js使用的主题文件路径
配置好新的入口后,我们对项目进行打包,等待编译完成。当打包结束后我们应该能够看到在dist\static\css 下有新增的theme文件,这个文件就是我们的主题文件了。接下来则是为主题切换做基础。我们需要把生成的文件路径提供给js。但是要意识到,该文件在开发时是没有的,只有在打包完成后才有,所以我们需要另一个操作:改写打包文件。
在打包文件生成后,我们需要利用node循环读取dist\static\css 下的所有文件,并把所有的theme文件路径输出到html中,当然你也可以输出到公共js中,比如app.js。这里具体的实现方法请看build\themeExtract.js
写完文件后我们只需要执行它就可以了。当然了,把它直接和 npm run build 绑定到一起不是更好吗?所以在 package.json 中做如下修改即可
"scripts": {
"dev": "node build/dev-server.js",
"start": "node build/dev-server.js",
// &&代表顺序执行
"build": "node build/build.js && node build/themeExtract.js"
}
执行后,我们再看看打包后的html文件,在head部分能看到一个全局的变量themeURL,里面就是我们需要的所有的主题文件路径了。
在本篇文章发表时,本项目master分支并没有以上说的所有信息,想看的请clone本项目然后切换到dev分支
使用及调试
在上个步骤中我们已经有了全局变量themeURL,那么只需要对主题文件进行匹配即可。当更换主题时,我们先查找已经加载的主题,如果没有则直接插入主题文件,如果有则清空所有主题文件,然后再插入。至于动态插入文件的方法,项目中已对该方法进行封装,可在 src\util\changeTheme.js 中查看。
# 使用主题切换的方法示例,需要保证changeTheme()中的参数与主题文件名保持一致
@import changeTheme from '@/util/changeTheme'
export default {
loadTheme(theme){
changeTheme(theme)
}
}
因为主题文件是打包后才生成的,所以在开发环境中,主题切换并不好用,只能通过手动修改sass主题文件的方式来做切换了,这也是目前该方案最大的问题。
至于调试动态载入主题js是否成功…..唔,你先打包一份,然后把打包后的多出来的变量复制到 src\index.html 中就可以了嘛…
优势及问题
这种切换方式能够最大程度上避免CSS污染,页面也更加干净,不会产生多余的文件。
如果使用偷懒的方法,将所有自己写的样式都放到主题中(比如我),那么后期维护也异常的简单,改改变量值就可以了嘛。
如果使用繁琐的方法,抽出所有样式中的主题部分(如背景色、文字、颜色、图片等),也能极大减少主题文件的大小,就是后期维护的时候会同时看两个文件才能知道这里真正的样式是什么,而且在编辑时容易丢东西。
当前最大的问题就是在开发环境中无法调试,以及在打包生成后的文件中虽然生成了css,但也对应的生成了一份空的js,很蛋痛。如果有解决方法的话还请留言,谢谢。
源码
当前源码地址:https://github.com/harsima/vue-backend
请注意,该源码会不断更新(因为工作很忙不能保证定期更新)。源码涉及到的东西有超出本篇教程的部分,请酌情阅读。同时请暂时不要使用release版本,在解决该版本下的大部分BUG及目录优化后,会放出相对完整的release版本。更多问题可以提交issue。
|