首先我们来看下页面上需要实现的基本效果, 如下图所示:
因此我们可以使用如下 JS 代码来试试看, 是否能使用 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 + '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 这样单纯的改变伪类样式是行不通的. 如上有一个定位的计算方式, 如上代码, 下面我们来简单的分析下, 为什么可以这样计算, 请看如下图所示:
第一个 tab 项的时候, 小三角形的定位如下:
点击第二个 tab 项的时候, 小三角形的定位如下图所示:
点击第三个 tab 项的时候, 小三角形的定位变为如下图所示:
既然使用如上方式行不通, 我们肯定需要查找资料了, 正好看到有一篇文章 能解决改变 CSS 伪类样式, 请点击查看
因此我这边来详细总结一下, 如何做? 那么这边肯定需要分二种情况, 第一种是使用 CSS 内联 style 样式写的 CSS, 第二种是外链的 CSS, 也就是 html 和 CSS 分离的那种, 因为做项目的时候, 分离 CSS 还是很有必要的.
一: JS 动态改变 style 内联 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;
- }
- 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 中的情况, 如下所示:
或者也可以请看这篇文章说的 (), 我现在 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 代码
来源: https://www.cnblogs.com/tugenhua0707/p/10004654.html