js动态改变css伪类样式

首先咱们来看下页面上须要实现的基本效果,以下图所示:javascript

所以咱们可使用以下js代码来试试看,是否能使用js改变伪类?以下代码所示:css

$(function() {
  $('.listnav li').click(function(){
    var index = $(this).index();
    var offset = 11; // 左侧偏移 11像素
    var imgWidth = 240; // 图片的宽度是240
    var pos = 0;
    // 所以第一个tab项的居中位置就是 240/2 + 11
    if (index === 0) {
      pos = imgWidth / 2 + offset + 'px';
    } else {
      /*
        若是不是第一个tab项的话,那么计算方式就变为以下:
        pos = imgWidth / 2 + offset + imgWidth * index + 33 * index
      */
      pos = imgWidth / 2 + offset + imgWidth * index + 33 * index;
    }
    console.log(pos);
    $(".tab-content:before, .tab-content:after").css({ "left": pos });
  });
});

如上代码并不生效,所以能够判定使用 jquery这样单纯的改变伪类样式是行不通的。 如上有一个定位的计算方式,如上代码,下面咱们来简单的分析下,为何能够这样计算,请看以下图所示:html

第一个tab项的时候,小三角形的定位以下:java

 

点击第二个tab项的时候,小三角形的定位以下图所示:jquery

点击第三个tab项的时候,小三角形的定位变为以下图所示:git

既然使用如上方式行不通,咱们确定须要查找资料了,正好看到有一篇文章 能解决改变css伪类样式, 请点击查看github

所以我这边来详细总结一下,如何作?那么这边确定须要分二种状况,第一种是使用css内联style样式写的css,第二种是外链的css,也就是html和css分离的那种,由于作项目的时候,分离css仍是颇有必要的。chrome


一:JS动态改变style内联css写的伪类样式浏览器

以下代码:app

$(function() {
  $('.listnav li').click(function(){
    var index = $(this).index();
    var offset = 11; // 左侧偏移 11像素
    var imgWidth = 240; // 图片的宽度是240
    var pos = 0;
    // 所以第一个tab项的居中位置就是 240/2 + 11
    if (index === 0) {
      pos = imgWidth / 2 + offset + 'px';
    } else {
      /*
        若是不是第一个tab项的话,那么计算方式就变为以下:
        pos = imgWidth / 2 + offset + imgWidth * index + 33 * index
      */
      pos = imgWidth / 2 + offset + imgWidth * index + 33 * index;
    }
    var styleSheetObject = document.getElementById('colorFlipFlop');
    console.log(pos);
    changeStyle(styleSheetObject, 'left', pos);
  });
});
/*
 * @param styleSheetObject style标签的id
 * @param attr 须要改变的style属性
 * @param pos 须要改变的值
*/
function changeStyle(styleSheetObject, attr, pos) {
  var beforeIndex = 7;  // 定位到style标签中的第几行
  console.log(styleSheetObject.sheet);
  console.log(styleSheetObject.sheet.cssRules[beforeIndex]);
  // console.log(styleSheetObject.sheet.cssRules[beforeIndex].style[attr])
  styleSheetObject.sheet.cssRules[beforeIndex].style[attr] = pos + 'px';
}

咱们首先来分析下,上面的代码的含义; 在分析以前咱们首先看下css的样式代码以下:

<style type="text/css" id="colorFlipFlop">
  * {margin:0; padding: 0;}
  .operating-report-container {
    position: relative;
    width: 1000px;
    margin: 30px;
    border: 1px solid #ccc;
    overflow: hidden;
  }
  .operating-report-container .listnav {
    margin-left: 14px;
    margin-top: 24px;
    overflow: hidden;
  }
  .operating-report-container .listnav li {
    float: left;
    width: 240px;
    margin-left: 33px;
    cursor: pointer;
    overflow: hidden;
  }
  .operating-report-container .listnav li .pic {
    width: 240px;
    height: 160px;
    background: #f6f6f6;
  }
  .operating-report-container .listnav li .desc {
    display: block;
    text-align: center;
    font-size: 15px;
    color: #616161;
    margin-top: 8px;
  }
  .operating-report-container .tab-content {
    margin: 24px 30px;
    border-top: 1px solid #e6e5e5;
    position: relative;
  }
  .operating-report-container .tab-content:before, 
  .operating-report-container .tab-content:after {
    bottom: 100%;
    left: 131px;
    border: solid transparent;
    content: " ";
    height: 0;
    width: 0;
    position: absolute;
    pointer-events: none;
  }
  .operating-report-container .tab-content:before {
    border-bottom-color: #e6e5e5;
    border-width: 11px;
    margin-left: -11px;
  }
  .operating-report-container .tab-content:after {
    border-bottom-color: #fff; 
    border-width: 10px;
    margin-left: -10px;
  }
</style>

首先js代码 var styleSheetObject = document.getElementById('colorFlipFlop'); 这句代码是获取 style标签的,由于style标签上有一个id元素叫 'colorFlipFlop'。

而后咱们看下打印下 console.log(styleSheetObject.sheet);这个;看看他有哪些属性,以下图所示:

而后打印 console.log(styleSheetObject.sheet.cssRules[beforeIndex]);,代码中 beforeIndex 为何等于7呢?所以 tab-content:before 的样式在 style标签的第八行,所以为了找到 style标签的中的具体元素的位置。由于是从0开始的。以下图所示

所以最后一句代码,找到对应的元素对应的属性从新赋值,如代码:

styleSheetObject.sheet.cssRules[beforeIndex].style[attr] = pos + 'px';

以下图所示:

查看效果请点击我

二:JS动态改变使用link标签引入的伪类样式

2.1)理解 insertRule 方法的使用

首先咱们先要来理解下 insertRule() 和 addRule() 这两个方法,可能不少人以前对这js中这两个方法并不熟悉,其实在研究以前,我也并不知道这两个方法的,这两个方法的做用是:向现有的样式表中添加新规则,在firefox,safari,opera和chrome中使用 insertRule()方法,该方法接收两个参数,规则文本 和 表示在哪里插入规则的索引。好比下面简单的demo:
insertRule.html 代码以下:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<link type="text/css" rel="stylesheet" href="./css/insertRule.css" />
<script type="text/javascript" src="./js/jquery.js"></script>
</head>
<body>    
    <div class="container" id="container">
      欢迎光临
    </div>
    <script type="text/javascript" src="./js/insertRule.js"></script>
</body>
</html>

/css/insertRule.css 中的代码以下:

* {margin:0; padding: 0;}

js/insertRule.js 代码以下:

function getStyleSheet(element) {
    return element.sheet || element.styleSheet;
}
var link = document.getElementsByTagName("link")[0];
var sheet = getStyleSheet(link);
console.log(sheet)
sheet.insertRule("body { background-color: red }", 0);  //DOM方法

如上js代码,先获取到页面上第一个link标签,而后对代码进行插入body的背景色的样式便可:在firefox下的效果以下:

再看看firefox下的代码以下:

而后在safari下查看下效果以下:

如上js代码,console.log(sheet) 打印的信息在firefox以下:

以前咱们说过 insertRule 该方法在 firefox,safari,opera 和 chrome是支持的,可是在mac电脑下(我电脑目前是mac电脑),Chrome 66 之后的版本是不支持该属性的。以下是在我chrome中的状况,以下所示:

或者也能够请看这篇文章说的(https://www.noxxxx.com/uncaught-domexception-failed-to-execute-insertrule-on-cssstylesheet.html), 我如今chrome版本是70版本的,那也是不支持,以下个人chrome版本:

文章中说须要手动建立 style 标签插入。 所以咱们的 insertRule.js 代码变为以下:

/*
function getStyleSheet(element) {
    return element.sheet || element.styleSheet;
}
var link = document.getElementsByTagName("link")[0];
var sheet = getStyleSheet(link);
console.log(sheet);
sheet.insertRule("body { background-color: red }", 0);  //DOM方法
*/

var stylesheet = createStyleSheet();
stylesheet.insertRule("body { background-color: red }", 0);  //DOM方法

function createStyleSheet() {
  var style = document.createElement('style');
  style.appendChild(document.createTextNode(""));
  document.head.appendChild(style);
  return style.sheet;
}

咱们继续运行下,如今在firefox,safari,和 chrome浏览器下都支持了。chrome浏览器下的效果以下:

2.2)理解 addRule() 方法的使用

addRule方法是IE支持的一个相似的方法,该方法也是接收两个必选参数和一个可选参数:
第一个参数为:选择符文本。第二个参数为:css样式信息,第三个参数是可选的,表示的含义是:插入规则的位置,和insertRule()方法中的第二个参数相似。

基本使用方式以下:sheet.addRule("body", "background-color: red", 0); // 仅仅对IE有效

所以为了跨浏览器支持向样式表中插入规则,咱们能够封装一个方法,既支持IE,也支持标准浏览器,以下代码:

/*
function getStyleSheet(element) {
    return element.sheet || element.styleSheet;
}
var link = document.getElementsByTagName("link")[0];
var sheet = getStyleSheet(link);
console.log(sheet);
sheet.insertRule("body { background-color: red }", 0);  //DOM方法
*/
/*
var stylesheet = createStyleSheet();
stylesheet.insertRule("body { background-color: red }", 0);  //DOM方法

function createStyleSheet() {
  var style = document.createElement('style');
  style.appendChild(document.createTextNode(""));
  document.head.appendChild(style);
  return style.sheet;
}
*/
function createStyleSheet() {
  var style = document.createElement('style');
  style.appendChild(document.createTextNode(""));
  document.head.appendChild(style);
  return style.sheet;
}
function insertRule(selectorText, cssText, position) {
  var stylesheet = createStyleSheet();
  if (stylesheet.insertRule) {
    stylesheet.insertRule(selectorText + "{" + cssText + "}", position);
  } else if (stylesheet.addRule) {
    stylesheet.addRule(selectorText, cssText, position);
  }
}
insertRule("body", "background-color: red", 0);

请点击查看效果

因此咱们如今可使用如上的知识点,去作那个切换的demo了,index2.html代码以下

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="./css/index2.css" />
<script type="text/javascript" src="./js/jquery.js"></script>
</head>
<body>    
    <div class="operating-report-container" id="operating-report">
      <ul class="listnav">
        <li>
          <div class="pic"></div>
          <div class="desc">铜板街2018年度各月运营报告</div>
        </li>
        <li>
          <div class="pic"></div>
          <div class="desc">铜板街2018年度各月运营报告</div>
        </li>
        <li>
          <div class="pic"></div>
          <div class="desc">铜板街2018年度各月运营报告</div>
        </li>
      </ul>
      <div class="tab-content" id="tab-content">
        
      </div>
    </div>
    <script type="text/javascript" src="./js/index2.js"></script>
</body>
</html>

index2.js 代码以下:

$(function() {
  $('.listnav li').click(function(){
    var index = $(this).index();
    var offset = 11; // 左侧偏移 11像素
    var imgWidth = 240; // 图片的宽度是240
    var pos = 0;
    // 所以第一个tab项的居中位置就是 240/2 + 11
    if (index === 0) {
      pos = imgWidth / 2 + offset;
    } else {
      /*
        若是不是第一个tab项的话,那么计算方式就变为以下:
        pos = imgWidth / 2 + offset + imgWidth * index + 33 * index
      */
      pos = imgWidth / 2 + offset + imgWidth * index + 33 * index;
    }
    addRule(".operating-report-container .tab-content:before", {
      left: pos + 'px'
    });
    addRule(".operating-report-container .tab-content:after", {
      left: pos + 'px'
    });
  });
});
function createStyleSheet() {
  var style = document.createElement('style');
  style.appendChild(document.createTextNode(""));
  document.head.appendChild(style);
  return style.sheet;
}
var stylesheet = createStyleSheet();
function addRule(selector, css) {
  var propText = typeof css === "string" ? css : Object.keys(css).map(function (p) {
      console.log(p)
      return p + ":" + (p === "content" ? "'" + css[p] + "'" : css[p]);
  }).join(";");

  if (stylesheet.insertRule) {
    // 标准浏览器支持的
    stylesheet.insertRule(selector + "{" + propText + "}", stylesheet.cssRules.length);

  } else if(stylesheet.addRule) {
    // IE支持的
    stylesheet.addRule(selector, propText, stylesheet.cssRules.length);
  }
}

如上代码封装好了的,点击查看效果

注意:如上demo目前在mac电脑上的firfox,safari,chrome测试过的,由于是mac电脑,因此在IE下尚未测试过,若是有问题能够留言哦!

查看github代码

相关文章
相关标签/搜索