JavaScript实现动态创建CSS样式规则方案


Posted in Javascript onSeptember 06, 2014

现在Web应用中有大量的JavaScript代码,而我们也一直在追寻各种使他们更快的解决方案。

1.我们通过 事件代理(event delegation) 让事件监听更高效,
2.我们利用 函数降频技术(function debouncing) 来限制一段时间内给定方法被调用的次数,请参考:如何防止事件函数的高频触发(中文翻译)
3.我们使用 JavaScript加载器 来加载我们确实需要的那部分资源,等等。

还有一种方式,可以让我们的页面更加的快速和高效.那就是直接通过JS动态地添加和删除样式表中的某些样式,用来取代不断地查询DOM元素,并应用各种样式。下面是它的工作原理。

获取样式表

你可以选择任意的样式表来添加样式规则。如果你有确定的样式表,则可以在HTML页面中给 <link> 或 <style> 标签添加ID属性,然后直接通过这个DOM元素的 sheet 属性就可以取得 CSSStyleSheet 对象。样式表也可以通过 document.styleSheets 遍历到:

// 返回一个类似数组的(Array-like)样式列表 StyleSheetList

var sheets = document.styleSheets;
/*

返回值类似下面这样: 
StyleSheetList 

{

    0: CSSStyleSheet,

    1: CSSStyleSheet,

    2: CSSStyleSheet,

    3: CSSStyleSheet,

    4: CSSStyleSheet,

    length: 5,

    item: function

}

*/
// 获取第一个sheet, 先不管 media属性

var sheet = document.styleSheets[0];

需要特别注意的是样式表的media属性 —— 当你想在屏幕上显示的时候,你肯定不能把CSS规则加到打印样式表中。你可以仔细的看一下CSSStyleSheet对象的属性信息:

// 控制台输出第一个样式表的信息

console.log(document.styleSheets[0]);
/*

返回值: 
CSSStyleSheet

    cssRules: CSSRuleList[对象]

    disabled: false

    href: "http://davidwalsh.name/somesheet.css"

    media: MediaList[对象]

    ownerNode: link[对象]

    ownerRule: null

    parentStyleSheet: null

    rules: CSSRuleList[对象]

    title: null

    type: "text/css"

*/
// 获取媒体类型(media type)

console.log(document.styleSheets[0].media.mediaText)

/*

返回值可能是:

    "all" 或者 "print" 或者是其他应用到此样式表的 media

*/

在各种情况下,你肯定都有办法来获取到要添加规则的样式表。

创建一个新样式表

在许多情况下,最好的方法可能是创建一个新的 <style> 元素来存放这些动态规则。这也很简单:

var sheet = (function() {

    // 创建 <style> 标签

    var style = document.createElement("style");
    // 可以添加一个媒体(/媒体查询,media query)属性

    // style.setAttribute("media", "screen")

    // style.setAttribute("media", "only screen and (max-width : 1024px)")
    // 对WebKit hack :(

    style.appendChild(document.createTextNode(""));


    // 将 <style> 元素加到页面中

    document.head.appendChild(style);
    return style.sheet;

})();

悲剧的是WebKit需要一点hack手段才能正确创建,但我们只需要关心这个sheet。

插入规则

在早期版本的IE中 Stylesheets 的 insertRule方法并不可用,虽然现在这是规则注入的标准。insertRule 方法需要编写整个CSS规则,和在样式表中是一样的写法:

sheet.insertRule("header { float: left; opacity: 0.8; }", 1);

这个JavaScript API方法虽然看起来有点土,但它确实就是这样运行的。第二个参数 index 表示要插入规则的位置(索引)。这也是非常有用的,这样你就可以插入同样的规则/代码,这可以让靠后的规则生效。默认的index是 -1 ,代表整个集合的末尾。如果想要有额外的/懒惰控制规则,你也可以添加 !important 标记到某条规则后,以避免索引的问题。

添加规则 —— 非标准的 addRule 方法

CSSStyleSheet 对象有一个 addRule 方法,允许你注册CSS规则到样式表中。 addRule 方法接受三个参数: 第一个参数是选择器(selector)、第二个参数是CSS规则代码, 第三个则是从0开始的整数索引,表示样式的位置(在同一个选择器中):

sheet.addRule("#myList li", "float: left; background: red !important;", 1);

addRule方法的返回值总是 -1,所以这个值并没有什么实际意义.
记住,这种方式的优点在于,从页面添加的元素自动拥有了应用于他们的样式,也就是说你不必将它们添加到具体的元素上,而是直接注入到页面中。当然效率更高!

安全应用规则

因为并不是所有的浏览器都支持 insertRule 方法, 所以最好创建一个包装函数来处理规则应用。下面是一个快速的土方法:

function addCSSRule(sheet, selector, rules, index) {

    if("insertRule" in sheet) {

        sheet.insertRule(selector + "{" + rules + "}", index);

    }

    else if("addRule" in sheet) {

        sheet.addRule(selector, rules, index);

    }

}
// 使用方式

addCSSRule(document.styleSheets[0], "header", "float: left");

这个工具方法应该涵盖了新增style规则的所有情况。如果你担心在应用中出错, 那么应该将该方法的代码用一个 try{} catch(e){} 块包起来。

插入媒体查询规则

媒体查询规则的添加有两种方式。第一个是使用标准 insertRule 方法:

sheet.insertRule(

  "@media only screen and (max-width : 1140px) { header { display: none; } }"

  );

当然,因为IE老版本不支持 insertRule,所以另一种方法就是创建一个 STYLE 元素,并指定适当的 media 属性,然后将样式添加到新的样式表中。这可能需要使用多个 STYLE 元素,但也是很容易的。我可能会创建一个对象,指定媒体查询以及索引,并那样创建/获取他们。

动态添加规则到样式表是高效的手段,可能比你想象的还要简单。请记住这种方案,可能在你的下一个大应用中需要使用,因为它能在代码和元素处理这两方面避免你掉进坑里。

Javascript 相关文章推荐
10个基于jQuery或JavaScript的WYSIWYG 编辑器整理
May 06 Javascript
JavaScript修改css样式style动态改变元素样式
Dec 16 Javascript
JS对象转换为Jquery对象示例
Jan 26 Javascript
JavaScript中使用sencha gridpanel 编辑单元格、改变单元格颜色
Nov 26 Javascript
js学习之----深入理解闭包
Nov 21 Javascript
js仿微信语音播放实现思路
Dec 12 Javascript
基于VuePress 轻量级静态网站生成器的实现方法
Apr 17 Javascript
Angular实现模版驱动表单的自定义校验功能(密码确认为例)
May 17 Javascript
JavaScript+Canvas实现彩色图片转换成黑白图片的方法分析
Jul 31 Javascript
24行JavaScript代码实现Redux的方法实例
Nov 17 Javascript
JavaScript计算正方形面积
Nov 26 Javascript
原生javascript中this几种常见用法总结
Feb 24 Javascript
JS 使用for循环遍历子节点查找元素
Sep 06 #Javascript
在JavaScript里防止事件函数高频触发和高频调用的方法
Sep 06 #Javascript
js获取页面传来参数的方法
Sep 06 #Javascript
用javascript关闭本窗口技巧小结
Sep 05 #Javascript
使用jquery解析XML示例代码
Sep 05 #Javascript
js实现按一下删除键删除整个单词附demo
Sep 05 #Javascript
JS获取当前网页大小以及屏幕分辨率等
Sep 05 #Javascript
You might like
肝肠寸断了解下!盘点史上最伤心的十大动漫
2020/03/04 日漫
php4的彩蛋
2006/10/09 PHP
php array_flip() 删除数组重复元素
2009/01/14 PHP
php 分库分表hash算法
2009/11/12 PHP
跟我学Laravel之安装Laravel
2014/10/15 PHP
php简单统计在线人数的方法
2016/05/10 PHP
详解thinkphp5+swoole实现异步邮件群发(SMTP方式)
2017/10/13 PHP
IE中直接运行显示当前网页中的图片 推荐
2006/08/31 Javascript
jquery 插件学习(二)
2012/08/06 Javascript
js修改input的type属性问题探讨
2013/10/12 Javascript
Jquery+asp.net后台数据传到前台js进行解析的方法
2014/05/11 Javascript
jQuery实现的支持IE的html滑动条
2015/03/16 Javascript
JavaScript实现自动变换表格边框颜色
2015/05/08 Javascript
JavaScript性能优化之小知识总结
2015/11/20 Javascript
jQuery实现带分组数据的Table表头排序实例分析
2015/11/24 Javascript
JS快速实现移动端拼图游戏
2016/09/05 Javascript
vue实现列表的添加点击
2016/12/29 Javascript
基于JavaScript实现图片剪切效果
2017/03/07 Javascript
jQuery length 和 size()区别总结
2018/04/26 jQuery
jQuery实现table表格信息的展开和缩小功能示例
2018/07/21 jQuery
JavaScript函数、闭包、原型、面向对象学习笔记
2018/09/06 Javascript
微信小程序生成分享海报方法(附带二维码生成)
2019/03/29 Javascript
微信小程序页面间跳转传参方式总结
2019/06/13 Javascript
layui内置模块layim发送图片添加加载动画的方法
2019/09/23 Javascript
在Vue中使用this.$store或者是$route一直报错的解决
2019/11/08 Javascript
Postman环境变量全局变量使用方法详解
2020/08/13 Javascript
element el-table表格的二次封装实现(附表格高度自适应)
2021/01/19 Javascript
[03:41]2018完美盛典-《Fight With Us》
2018/12/16 DOTA
一个基于flask的web应用诞生 使用模板引擎和表单插件(2)
2017/04/11 Python
详解python实现识别手写MNIST数字集的程序
2018/08/03 Python
python 3.6.4 安装配置方法图文教程
2018/09/18 Python
html5使用canvas画空心圆与实心圆
2014/12/15 HTML / CSS
捷克购买家具网站:JENA nábytek
2020/03/19 全球购物
投标邀请书范文
2014/01/31 职场文书
车间主任岗位职责
2014/03/16 职场文书
法定代表人授权委托书范本
2014/10/07 职场文书