一、可实现的方法:
1、通过动态改变link
标签的href
2、添加新的link
标签覆盖原来的css
3、自定义主题、如: element UI Demo
二、实现思路:
1、生成多份css
,通过添加新的link
标签更换其href
达到换肤效果,但是不可能自己单独写两份
css
,这样的工作量是很大的,所以使用sass
,我们在全局scss
文件配置好颜色等变量,其他scss
文件引用这些变量,如果想生成新的主题,只需要改变变量的值,再编译就好了
2、为了方便管理,建立一个主文件main.scss
,这个文件引入所有的其他scss
,包括全局scss
文
件,mixin
,及组件的scss
,如同下面的树状图:
项目目录为:
这里主要介绍第二种办法
Tips:确保已安装sass
环境,如没有详见:传送门
1.创建项目 create-react-app theme --scripts-version=react-scripts-ts
在src目录下新建sass
文件夹,文件夹下新建main.scss文件 这个文件是所有的scss
文件的入口文件
入口文件引入所有的scss
文件
main.scss
//引入全局的sass mixin
@import "./Mixin/GlobalMixin";
//引入全局的sass文件
@import "./GlobalSass/global";
//引入组件的sass文件
@import "./Components/_components.topbar";
@import "./Components/_components.content";
@import "./Components/_components.leftslider";
@import "./Components/_components.rightcontent";
tips:后面不能省略分号
这里主要说global.scss
文件(demo效果,实际情况不一样)
global.scss
//白天模式颜色
//网站所有颜色值
$mineColor:#b93e3e;
$topFontColor:white;
$textColor:#606253;
$textBgColor:#eee;
$segmenteLine:#e2e0e0;
$bodyBgcolor:white;
这里定义了一些变量存颜色值,这些颜色就是你所有要用到的颜色,其他文件引用这些颜色
.article_title {
color: $textColor;
}
按照这样的套路,组件的scss
文件都是引用的global
的颜色值
现在编译一下
这里就不配置webpack
了直接使用ruby
实时编译(前提安装sass环境)
在Sass
文件夹下面打开命令行窗口
输入 sass --watch main.scss:myDay.css
对当前目录下的
main.scss
实时监听,如果变化了编译成myDay.css
进入App.tsx
文件中,引入编译好的css
import './Sass/myNight.css'
如果想要变换主题,命令行结束当前监听,进入global.scss
改变颜色色值,改好后再一次编译成css
输入sass --watch main.scss:myNight.css
tips:第二次编译的
css
文件名字不能和第一次相同,不然会覆盖
这样我们就有两份css
了
现在要实现的是动态改变。首先默认为白天,App.tsx
引入白天的css
,然后点击按钮生成一个新的link
标签,这个标签用于切换白天,黑夜两个主题
创建link
标签
index.tsx
import * as React from 'react'
import * as ReactDOM from 'react-dom'
import App from './App'
import registerServiceWorker from './registerServiceWorker'
import './index.css'
function createLink():any{
let linkNode:any = document.createElement('link')
linkNode.setAttribute('href','')
linkNode.setAttribute('rel','stylesheet')
linkNode.setAttribute('class','skinStyle')
document.getElementsByTagName('head')[0].appendChild(linkNode)
}
ReactDOM.render(
<App />,
document.getElementById('root') as HTMLElement,
createLink()
)
registerServiceWorker()
切换按钮组件:
import * as React from 'react'
import { Switch } from 'antd'
export default class ChangeSkin extends React.Component<any,any>{
constructor(props:any){
super(props)
this.state={
styleStatu:'myDay'
}
}
handleChangeSkin(statu:boolean){ // 改变状态 Switch change回调函数,返回true,false
(statu) ? (this.setState({
styleStatu:'myNight'
},()=>{
this.changeStyle(this.state.styleStatu)
})) : (this.setState({
styleStatu:'myDay'
},()=>{
this.changeStyle(this.state.styleStatu)
}))
}
componentDidMount () {
this.handleChangeSkin(false) // 初始为day主题,将会把App.tsx中引入的myNight.css覆盖,减少延迟
}
changeStyle(type:string){ // 改变link标签的href
let linkDom = document.getElementsByClassName('skinStyle')[0]
linkDom.setAttribute('href','./static/css/'+type+'.css')
}
render(){
return(
<div className='changeSkin'>
<div className='changeSkin_Btnwrap'>
<div>
<Switch
onChange={this.handleChangeSkin.bind(this)}
checkedChildren="夜"
unCheckedChildren="白"
className="skinSwitch"
/ >
</div>
</div>
</div>
)
}
}
运行npm run build
打包项目,将之前两个css
放入static/css
文件夹下面
打开index.html
DEMO地址
当然这只是简单的demo,一种思路,真正项目中就不一定适用,所以试试有没有办法改进一下。