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 相关文章推荐
jQuery AjaxQueue改进步骤
Oct 06 Javascript
JavaScript实现多维数组的方法
Nov 20 Javascript
jQuery setTimeout传递字符串参数报错的解决方法
Jun 09 Javascript
使用AngularJS创建单页应用的编程指引
Jun 19 Javascript
使用jQuery监听DOM元素大小变化
Feb 24 Javascript
JS模仿手机端九宫格登录功能实现代码
Apr 28 Javascript
Jquery实现跨域异步上传文件总结
Feb 03 Javascript
vue 实现类似淘宝星级评分的示例
Mar 01 Javascript
详解JavaScript原生封装ajax请求和Jquery中的ajax请求
Feb 14 jQuery
vue实现element表格里表头信息提示功能(推荐)
Nov 20 Javascript
详解Vue3中对VDOM的改进
Apr 23 Javascript
Element Backtop回到顶部的具体使用
Jul 27 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
IIS6.0+PHP5.x+MySQL5.x+Zend3.0x+GD+phpMyAdmin2.8x通用安装实例(已经完成)
2006/12/06 PHP
php防止站外远程提交表单的方法
2014/10/20 PHP
thinkPHP下的widget扩展用法实例分析
2015/12/26 PHP
PHP如何使用Memcached
2016/04/05 PHP
laravel 框架结合关联查询 when()用法分析
2019/11/22 PHP
JavaScript高级程序设计(第3版)学习笔记7 js函数(上)
2012/10/11 Javascript
js运动框架_包括图片的淡入淡出效果
2013/05/11 Javascript
offsetHeight在OnLoad中获取为0的现象
2013/07/22 Javascript
在js文件中写el表达式取不到值的原因及解决方法
2013/12/23 Javascript
json的使用小结
2016/06/08 Javascript
JavaScript如何实现图片懒加载(lazyload) 提高用户体验(增强版)
2016/11/30 Javascript
JavaScript中捕获/阻止捕获、冒泡/阻止冒泡方法
2016/12/07 Javascript
Bootstrap基本插件学习笔记之轮播幻灯片(23)
2016/12/08 Javascript
canvas滤镜效果实现代码
2017/02/06 Javascript
Vue.js 2.0窥探之Virtual DOM到底是什么?
2017/02/10 Javascript
Angular.js 4.x中表单Template-Driven Forms详解
2017/04/25 Javascript
Sublime Text新建.vue模板并高亮(图文教程)
2017/10/26 Javascript
移动前端图片压缩上传的实例
2017/12/06 Javascript
详解小程序原生使用ES7 async/await语法
2018/08/06 Javascript
vue项目在webpack2实现移动端字体自适配功能
2020/06/02 Javascript
[01:04]不如跳舞!DOTA2新英雄玛尔斯的欢乐日常
2019/03/11 DOTA
Pandas 对Dataframe结构排序的实现方法
2018/04/10 Python
python机器学习实现决策树
2019/11/11 Python
使用Python发现隐藏的wifi
2020/03/04 Python
Python 爬虫的原理
2020/07/30 Python
使用OpenCV校准鱼眼镜头的方法
2020/11/26 Python
HTML5新增元素如何兼容旧浏览器有哪些方法
2014/05/09 HTML / CSS
美国知名男士服饰品牌:Brooks Brothers(布克兄弟)
2016/08/25 全球购物
迷你唐卡软皮鞋:Minnetonka Moccasin
2018/05/01 全球购物
采购部经理岗位职责
2014/02/10 职场文书
企业党员个人自我评价
2014/09/20 职场文书
人事代理委托书
2014/09/27 职场文书
婚宴邀请函
2015/01/30 职场文书
高中议论文(范文2篇)
2019/08/19 职场文书
Python何绘制带有背景色块的折线图
2022/04/23 Python
CentOS7设置ssh服务以及端口修改方式
2022/12/24 Servers