小试页面换肤

一、可实现的方法:

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,一种思路,真正项目中就不一定适用,所以试试有没有办法改进一下。

点赞