zoukankan      html  css  js  c++  java
  • css var实现网页换肤

    前情

    最近在做需求开发,要求根据后台传来的配置对网页换肤,按以往的换肤思路应该是写好几套样式做切换达到换肤效果,但是现在想做到能根据后台配置动态修改。

    原理

    通过css3新增变量特性,把颜色定义为变量再全局使用,在想更改颜色的时候,我们只要修改对应变量对应的颜色就能全局换肤,主要原理演示代码如下:

    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width">
      <title>JS Bin</title>
      <style type="text/css">
    		:root {
          --main-bg-color: red;
        }
        .test{
           500px;
          height: 100px;
          background-color: green;
          background-color: var(--main-bg-color);
        }
      </style>
    </head>
    <body>
      <div class="test"></div>
    </body>
    </html>
    

    演示地址:https://jsbin.com/lozizajuva/edit?html,output

    换肤实战

    1. 通过颜色配置表生成一个包含所有css变量的style插入到head中
    2. 所有css中需要进行颜色替换的都通过css变量来设置
    3. 动态更换主题的话只要替换上面生成style里的内容即可

    演示代码

    html结构

    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width">
      <title>JS Bin</title>
      <style>
        body{
          --test-var: 'green';
        }
        .test{
           500px;
          height: 100px;
          /* 低版本不兼容的浏览器也有个默认颜色 */
          background-color: blue;
          background-color: var(--main-color)
        }
        .test_in{
           100px;
          height: 50px;
          line-height: 50px;
          font-size: 14px;
          background-color: #dddddd;
          /* 低版本不兼容的浏览器也有个默认颜色 */
          color: blue;
          color: var(--main-color);
        }
      </style>
    </head>
    <body>
      <div class="test">
        <div class="test_in">css var换肤</div>
      </div>
      
      <select id="themeSelect">
        <option value ="deault">默认</option>
        <option value ="red">红色</option>
        <option value="green">绿色</option>
    </select>
    </body>
    </html>
    

    javascript

    // 颜色配置表,测试数据,正常是从服务端过来的
    const THEME_CONFIG = {
      "default": {
        "--main-color": "blue"
      },
      "red": {
        "--main-color": "red"
      },
      "green": {
        "--main-color": "green"
      }
    }
    
    // 存储当前用的是什么色系
    let currentConfig = THEME_CONFIG['default'];
    // 备份styles
    let stylesBackups = null;
    
    /**
     * 生成主题代码段
     * @param {Object} config 
     * @returns 
     */
    function createThemeStyle(config) {
      let result = `
      :root {
        --main-color: ${config['--main-color']};
      }`
      return result;
    }
    
    /**
     * 插入主题style段
     * @param {String} styleString
     */
    function insertThemeStyle(styleString) {
      let styleTag = document.querySelector('#themeStyleTag');
      if (!styleTag) {
        styleTag = document.createElement('style');
        styleTag.id = 'themeStyleTag';
        styleTag.setAttribute('type', 'text/css');
        document.getElementsByTagName('head')[0].insertBefore(styleTag, document.getElementsByTagName('style')[0]);
      }
      styleTag.innerHTML = styleString;
    }
    
    /**
     * 判断css变量是否被支持
     */
    function cssVarIsSupport() {
      var testVar = getComputedStyle(document.body).getPropertyValue("--test-var");
      return testVar ? true : false;
    }
    
    /**
     * 解决兼容,根据主题配置生成正则
     * @returns string
     */
    function createStyleRegex() {
      let regexStr = '';
      let varList = Object.keys(currentConfig);
      for(let i=0,len=varList.length; i<len; i++) {
        regexStr += `var\(${varList[i]}\)${i<len-1 ? '|' : ''}`;
      };
      return regexStr;
    }
    
    /**
     * css变量兼容处理-第一次
     */
    function compatibleProcessingCssVar() {
      let styles = document.getElementsByTagName('head')[0].getElementsByTagName('style');
      stylesBackups = {};
      // 生成正则匹配规则字符串
      let regexStr = createStyleRegex();
      // 遍历所有style标签替换
      for(let i=1,len=styles.length; i<len; i++) {
        let item = styles[i];
        let replaceReg = new RegExp(regexStr, 'g');
        let styleStr = item.innerHTML;
        if (!replaceReg.test(styleStr)) {
          continue;
        }
        if (!stylesBackups['theme'+i]) {
          item.setAttribute('id', 'theme'+i);
          stylesBackups['theme'+i] = styleStr;
        }
        styleStr = styleStr.replace(replaceReg, function(mactchStr) {
          return currentConfig[mactchStr.split(/(|)/)[1]];
        });
        item.innerHTML = styleStr;
      }
    }
    
    /**
     * 解决兼容浏览器的动态换肤问题
     * css变量兼容处理-后面不需再去获取所有style,通过从内存中拿缓存的style来做字符串替换
     */
     function compatibleProcessingCssVarFromCache() {
      // 生成正则匹配规则字符串
      let regexStr = createStyleRegex();
      let styleKeys = Object.keys(stylesBackups);
      // 遍历所有style标签替换
      for(let i=1,len=styleKeys.length; i<len; i++) {
        let key = styleKeys[i];
        let styleStr = stylesBackups[key];
        let replaceReg = new RegExp(regexStr, 'g');
        styleStr = styleStr.replace(replaceReg, function(mactchStr) {
          return currentConfig[mactchStr.split(/(|)/)[1]];
        });
        document.getElementById(key).innerHTML = styleStr;
      }
    }
    
    /**
     * 适配主题
     * @param {string} theme 
     */
    function adaptationTheme(theme) {
      // 获取颜色列表
      currentConfig = THEME_CONFIG[theme];
      // 对于兼容css var的浏览器
      if (cssVarIsSupport()) {
        // 生成style
        let styleString = createThemeStyle(currentConfig);
        // 插入style中
        insertThemeStyle(styleString)
      } else {
        // 对于不兼容css var的浏览器(chrome49、ie15以下)
        if (stylesBackups) {
          compatibleProcessingCssVarFromCache();
          return;
        }
        compatibleProcessingCssVar();
      }
    }
    window.onload = function(){
      adaptationTheme('default');
      
      // 动态更换主题
      document.querySelector('#themeSelect').addEventListener('change', function() {
        adaptationTheme(this.value)
      }, false)
    }
    

    注意事项:

    如果想兼容低版本浏览器则需要所有样式通过style写入,因为在做兼容处理的时候,是通过js代码替换掉style标签里的css变量来做兼容处理的,上面代码有做低版本兼容,对于不需要兼容低版本浏览器的,上面代码可以删减掉兼容代码。

    演示地址:https://jsbin.com/tetuguxifi/1/edit?html,js,output

    好好学习!天天向上!
  • 相关阅读:
    SkylineGlobe 如何实现绘制圆形Polygon和对图层的圆形范围选择查询
    如何修改Oracle服务IP地址
    TerraGate软件安装后,不能启动的解决办法
    SkylineGlobe SFS发布的WFS和WMS服务测试
    SkylineGlobe 如何实现二次开发加载KML文件
    如何屏蔽SkylineGlobe提供的三维地图控件上的快捷键
    SkylineGlobe 如何实现FlyTo定位到目标点之后触发的事件函数
    转子百度知道:LTE上行采用DC子载波,而下行置零,为什么?
    转载:LTE小区搜索过程
    dB dBc dBi dBd dBm dBW 定义
  • 原文地址:https://www.cnblogs.com/xwwin/p/15193320.html
Copyright © 2011-2022 走看看