2023年6月21日发(作者:)

ant-design实现主题暗⿊主题和亮⾊主题的切换(实现⽹站⿊⽩⽪肤)最近在使⽤vite+react + ant-design 来搭建个⼈站点,看到⽹上好多⽹站都实现了⿊⽩⽪肤的切换,并且ant-design帮我们实现了三套主题⾊,⼀个默认亮⽩⾊,暗⿊主题和紧凑主题。于是我也想来弄⼀弄。最后还是实现了,打包后也是ok的。效果思路对于⽹站需要切换主题的话,⼀般有以下⼏种办法。使⽤css覆盖的⽅式,由于css基于后⾯的css覆盖前⾯的原理,所以这⼀点也是可以的。但是这⼀点对于使⽤less和scss的码友来说,貌似不是⼀个很好的⽅法由于less⾥⾯带有⼀个的cdn,可以⽤来解析是html种使⽤less⽂件,但是这个需要注意使⽤的顺序,需要less的样式⽂件在前⾯,的引⽤在后⾯,这个对于使⽤构建⼯具的同志来说不太友好,打包后less⽂件都不见了,直接使⽤路径肯定也是不⾏。社区成熟的两个库: antd-theme-webpack-plugin和antd-theme-generator,对于我的项⽬来说貌似都不怎么合适,⾸先:antd-theme-webpack-plugin这个库是基于webpack来的,我们都知道vite是在开发环境使⽤esbuild,⽣产环境使⽤的是roallup来进⾏打包。antd-theme-generator这个库的话,把less提升到了运⾏阶段,我们代码⼀般会进⾏打包压缩等,如果使⽤这个库的话就意味着需要配置less相关的静态资源不能被打包,不然会有问题。基于上⾯的思路我做了以下的⽅法来进⾏尝试。项⽬做了以下调整:将ant-design的两个主题,默认主题和暗⿊主题引⼊到我⾃⼰的less⽂件中。然后对此就可以后序实现改动主题⾊,例如:成功,失败,警告等。如下:这个引⼊的顺序需要注意,后引⼊的变量会覆盖前⾯的。不会⾃定义的会不⽣效在我点击switch框的时候触发⽅法。做以下尝试所有的尝试都是基于下⾯的第⼆步,也就是⽅法,这⾥⾯需要做啥事情尝试⼀改变⽅法的时候直接来动态引⼊less⽂件,这样在引⼊暗⿊主题是可以实现的,但是从暗⿊主题却切换不过来了。如下:const handleSkin = (checked: boolean) => { if (checked) { //

明亮主题 import('./../assets/style/') } else { //

暗⾊主题 import('./../assets/style/') } }这个从⽩的可以切换到⿊的原因是,⿊⾊样式覆盖了前⾯⽩⾊的样式,但是如果你再⼀次覆盖却不⾏,我估计是选择器权重问题上,ant官⽅做了改动。如果需要从新切换回来也是有办法的,在明亮主题中直接(),这样是可以切换回来的,如下图:这样虽然实现了功能,体验肯定是不好的,作为⼀名前端⼯程师,肯定是需要⾮常注重体验的,不然职业⽣涯的路可能就不会很长。尝试⼆由于尝试⼀不⾏,然后我就往import动态引⼊这边考虑了,我考虑的⽅向是既然可以动态import引⼊,那么我可以再⼀次改变的时候把前⼀次引⼊的给remove掉么?但是我找遍了所有的⽂件,import导⼊的是⽆法remove掉的,import导⼊是现代浏览器⾥⾯的esm的语法。然后就去⽹上找各种⽅法,在ant-design pro中发现实现了这个功能,并且是⽆刷新的,然后就去gitup上看⼈家的源码。功夫不负有⼼⼈,然后发现⼈家是动态使⽤link引⼊css的⽅式来实现的,那么我也可以来通过link导⼊less⽂件来实现,并且使⽤的cdn来进⾏解析。添加⼀个addSkin的⽅法,毕竟需要导⼊⽂件,然后来查找原来是否存在,然后进⾏删除。//

调⽤⽅法const handleSkin = (checked: boolean) => { if (checked) { //

明亮主题 addSkin("./../../src/assets/style/") } else { //

暗⾊主题 addSkin("./../../src/assets/style/") } }//

添加⽪肤的⽅法function addSkin(path: string) { let head = mentsByTagName("head")[0]; const getLink = mentsByTagName('link'); //

查找link是否存在,存在的话需要删除dom if ( > 0) { for (let i = 0, l = ; i < l; i++) { if (getLink[i].getAttribute('data-type') === 'theme') { getLink[i].remove(); } } } //

查找script是否存在 const getScript = mentsByTagName('script'); if ( > 0) { for (let i = 0, l = ; i < l; i++) { if (getScript[i].getAttribute('data-type') === 'theme') { getScript[i].remove(); } } } //

最后加⼊对应的主题和加载less的js⽂件 let link = Element("link"); = "theme"; = path; = "stylesheet"; = "text/css"; Child(link); //

这个⼀定要放到后⾯才⾏ let script = Element('script'); = 'text/javascript'; = 'theme'; = '/ajax/libs//4.1.1/' Child(script)}这种⽅法是动态改变link标签的样式来实现的,在⽣产环境是没有任何问题,但是在开发环境就不⾏了,打包后路径不存在。肯定是不⾏的,接下来我就去找vite如何静态资源复制到打包的⽂件,⽅法找到了。但是我的less⾥⾯引⽤了antd⾥⾯的less,⾥⾯的也不⽤打包? 我觉得不太好,因此再⼀次放弃。尝试三既然直接使⽤less⽂件不⾏,那我可以使⽤css不,和ant-design pro⾥⾯⼀样的,我也来引⽤css⽂件,接下来就往这个⽅向。我直接打印了,import dark from './xxxx'.less 发现既然是⼀个字符串。是编译好的字符串,那我直接使⽤style标签就好了。说⼲就往下⼲。import dark from './../assets/style/'import lighter from './../assets/style/'//

调⽤⽅法const handleSkin = (checked: boolean) => { if (checked) { //

明亮主题 addSkin(lighter) } else { //

暗⾊主题 addSkin(dark) } }//

添加⽪肤的⽅法function addSkin(content: string) { let head = mentsByTagName("head")[0]; const getStyle = mentsByTagName('style'); //

查找style是否存在,存在的话需要删除dom if ( > 0) { for (let i = 0, l = ; i < l; i++) { if (getStyle[i].getAttribute('data-type') === 'theme') { getStyle[i].remove(); } } } //

最后加⼊对应的主题和加载less的js⽂件 let styleDom = Element("style"); = "theme"; TML = content; Child(styleDom);}这⾥有⼀个细节就是,样式导⼊必须在顶部导⼊,不然vite会检测不到,不能使⽤动态导⼊,打包会经过treeshake去掉.其实这⾥还有⼀个问题,那就是css打包后会⽐较⼤,毕竟引⼊了两份,这个问题就留给码友了,⾃⼰去vite获取其他的构建⼯具(webpack,gulp等)上找静态资源太⼤怎么处理。总结在真实的调试中肯定是不⽌这三遍尝试的,这⾥只记录⾛向成功的关键三步。More interest, less interests (多⼀些兴趣爱好的向往,少⼀些功名利禄的追求)

2023年6月21日发(作者:)

ant-design实现主题暗⿊主题和亮⾊主题的切换(实现⽹站⿊⽩⽪肤)最近在使⽤vite+react + ant-design 来搭建个⼈站点,看到⽹上好多⽹站都实现了⿊⽩⽪肤的切换,并且ant-design帮我们实现了三套主题⾊,⼀个默认亮⽩⾊,暗⿊主题和紧凑主题。于是我也想来弄⼀弄。最后还是实现了,打包后也是ok的。效果思路对于⽹站需要切换主题的话,⼀般有以下⼏种办法。使⽤css覆盖的⽅式,由于css基于后⾯的css覆盖前⾯的原理,所以这⼀点也是可以的。但是这⼀点对于使⽤less和scss的码友来说,貌似不是⼀个很好的⽅法由于less⾥⾯带有⼀个的cdn,可以⽤来解析是html种使⽤less⽂件,但是这个需要注意使⽤的顺序,需要less的样式⽂件在前⾯,的引⽤在后⾯,这个对于使⽤构建⼯具的同志来说不太友好,打包后less⽂件都不见了,直接使⽤路径肯定也是不⾏。社区成熟的两个库: antd-theme-webpack-plugin和antd-theme-generator,对于我的项⽬来说貌似都不怎么合适,⾸先:antd-theme-webpack-plugin这个库是基于webpack来的,我们都知道vite是在开发环境使⽤esbuild,⽣产环境使⽤的是roallup来进⾏打包。antd-theme-generator这个库的话,把less提升到了运⾏阶段,我们代码⼀般会进⾏打包压缩等,如果使⽤这个库的话就意味着需要配置less相关的静态资源不能被打包,不然会有问题。基于上⾯的思路我做了以下的⽅法来进⾏尝试。项⽬做了以下调整:将ant-design的两个主题,默认主题和暗⿊主题引⼊到我⾃⼰的less⽂件中。然后对此就可以后序实现改动主题⾊,例如:成功,失败,警告等。如下:这个引⼊的顺序需要注意,后引⼊的变量会覆盖前⾯的。不会⾃定义的会不⽣效在我点击switch框的时候触发⽅法。做以下尝试所有的尝试都是基于下⾯的第⼆步,也就是⽅法,这⾥⾯需要做啥事情尝试⼀改变⽅法的时候直接来动态引⼊less⽂件,这样在引⼊暗⿊主题是可以实现的,但是从暗⿊主题却切换不过来了。如下:const handleSkin = (checked: boolean) => { if (checked) { //

明亮主题 import('./../assets/style/') } else { //

暗⾊主题 import('./../assets/style/') } }这个从⽩的可以切换到⿊的原因是,⿊⾊样式覆盖了前⾯⽩⾊的样式,但是如果你再⼀次覆盖却不⾏,我估计是选择器权重问题上,ant官⽅做了改动。如果需要从新切换回来也是有办法的,在明亮主题中直接(),这样是可以切换回来的,如下图:这样虽然实现了功能,体验肯定是不好的,作为⼀名前端⼯程师,肯定是需要⾮常注重体验的,不然职业⽣涯的路可能就不会很长。尝试⼆由于尝试⼀不⾏,然后我就往import动态引⼊这边考虑了,我考虑的⽅向是既然可以动态import引⼊,那么我可以再⼀次改变的时候把前⼀次引⼊的给remove掉么?但是我找遍了所有的⽂件,import导⼊的是⽆法remove掉的,import导⼊是现代浏览器⾥⾯的esm的语法。然后就去⽹上找各种⽅法,在ant-design pro中发现实现了这个功能,并且是⽆刷新的,然后就去gitup上看⼈家的源码。功夫不负有⼼⼈,然后发现⼈家是动态使⽤link引⼊css的⽅式来实现的,那么我也可以来通过link导⼊less⽂件来实现,并且使⽤的cdn来进⾏解析。添加⼀个addSkin的⽅法,毕竟需要导⼊⽂件,然后来查找原来是否存在,然后进⾏删除。//

调⽤⽅法const handleSkin = (checked: boolean) => { if (checked) { //

明亮主题 addSkin("./../../src/assets/style/") } else { //

暗⾊主题 addSkin("./../../src/assets/style/") } }//

添加⽪肤的⽅法function addSkin(path: string) { let head = mentsByTagName("head")[0]; const getLink = mentsByTagName('link'); //

查找link是否存在,存在的话需要删除dom if ( > 0) { for (let i = 0, l = ; i < l; i++) { if (getLink[i].getAttribute('data-type') === 'theme') { getLink[i].remove(); } } } //

查找script是否存在 const getScript = mentsByTagName('script'); if ( > 0) { for (let i = 0, l = ; i < l; i++) { if (getScript[i].getAttribute('data-type') === 'theme') { getScript[i].remove(); } } } //

最后加⼊对应的主题和加载less的js⽂件 let link = Element("link"); = "theme"; = path; = "stylesheet"; = "text/css"; Child(link); //

这个⼀定要放到后⾯才⾏ let script = Element('script'); = 'text/javascript'; = 'theme'; = '/ajax/libs//4.1.1/' Child(script)}这种⽅法是动态改变link标签的样式来实现的,在⽣产环境是没有任何问题,但是在开发环境就不⾏了,打包后路径不存在。肯定是不⾏的,接下来我就去找vite如何静态资源复制到打包的⽂件,⽅法找到了。但是我的less⾥⾯引⽤了antd⾥⾯的less,⾥⾯的也不⽤打包? 我觉得不太好,因此再⼀次放弃。尝试三既然直接使⽤less⽂件不⾏,那我可以使⽤css不,和ant-design pro⾥⾯⼀样的,我也来引⽤css⽂件,接下来就往这个⽅向。我直接打印了,import dark from './xxxx'.less 发现既然是⼀个字符串。是编译好的字符串,那我直接使⽤style标签就好了。说⼲就往下⼲。import dark from './../assets/style/'import lighter from './../assets/style/'//

调⽤⽅法const handleSkin = (checked: boolean) => { if (checked) { //

明亮主题 addSkin(lighter) } else { //

暗⾊主题 addSkin(dark) } }//

添加⽪肤的⽅法function addSkin(content: string) { let head = mentsByTagName("head")[0]; const getStyle = mentsByTagName('style'); //

查找style是否存在,存在的话需要删除dom if ( > 0) { for (let i = 0, l = ; i < l; i++) { if (getStyle[i].getAttribute('data-type') === 'theme') { getStyle[i].remove(); } } } //

最后加⼊对应的主题和加载less的js⽂件 let styleDom = Element("style"); = "theme"; TML = content; Child(styleDom);}这⾥有⼀个细节就是,样式导⼊必须在顶部导⼊,不然vite会检测不到,不能使⽤动态导⼊,打包会经过treeshake去掉.其实这⾥还有⼀个问题,那就是css打包后会⽐较⼤,毕竟引⼊了两份,这个问题就留给码友了,⾃⼰去vite获取其他的构建⼯具(webpack,gulp等)上找静态资源太⼤怎么处理。总结在真实的调试中肯定是不⽌这三遍尝试的,这⾥只记录⾛向成功的关键三步。More interest, less interests (多⼀些兴趣爱好的向往,少⼀些功名利禄的追求)