做者:Icarus
原文连接:手把手带你用原生js实现css属性的set和getjavascript
上一篇博文介绍了getComputedStyle方法,接下来,咱们就来实现一个简易版的小插件,可以在不借助jQuery的状况下实现css属性的获取和设置。css
首先建立一个 css-tool.js
文件,一开始他是这个样子的:html
;(function (window,undefined) {
"use strict";
var cssTool = function () {
return new cssTool.prototype.init();
}
cssTool.prototype = {
init: function() {
console.log('init success');
return this;
},
}
cssTool.prototype.init.prototype = cssTool.prototype;
// 暴露接口
window.cssTool = cssTool;
})(window);复制代码
全局做用域能够看做是一栋公寓楼,咱们建立一个当即执行的匿名函数,至关因而公寓楼中的一间公寓,咱们在屋子里作的事情就都是隐秘的,也就是起到隔离做用域的做用,避免和外部变量产生冲突。把 window
做为参数拿到屋子里来,之后就不用再重复去外面找 window
来用。最前面的分号是为了保证在文件合并压缩后不产生语法错误。 undefined
在老版本浏览器中不被支持,所以考虑到兼容性添加一个形参。java
咱们建立了一个叫 cssTool
的私有方法,至关于咱们在屋子里找了一个小房间来放 get
和 set
等方法。接下来咱们在原型上新增一个 init
方法,用于初始化。以后咱们仿照 jQuery
的方式,将init
的 prototype
指向 cssTool
的 prototype
,这样咱们在用init
做为构造函数创造实例时,可使插件拥有两种调用方式:git
var ct = new cssTool()
构建 cssTool
实例cssTool()
,同样返回 cssTool
实例window.getComputedStyle(elem,null).getPropertyValue(attr)复制代码
elem.currentStyle.getAttribute(camelCase(attr))复制代码
对 currentStyle
来讲,在IE6浏览器中他很专注,只喜欢以驼峰命名法命名的变量,而IE78中就有点朝秦暮楚,驼峰命名法和中间带'-'的都照单全收,为了兼容和操做的简便,咱们统一转换为驼峰命名法。github
/** * 驼峰命名法转换,IE678使用 * font-size --> fontSize * @param {String} attr * @param {String} match 匹配到的字符串,如-c * @param {String} originText (\w)是一个捕获,这里是捕获到的字符,如c * @return 返回驼峰命名方式的css属性名 */
function camelCase (attr){
return attr.replace(/\-(\w)/g, function (match,originText) {
return originText.toUpperCase();
});
}复制代码
IE678的透明度是经过 filter:alpha(opacity=0)
来设置的,咱们利用正则表达式匹配到此时透明度的值,因为此时获得的是0-100之间的数值,因此须要换算为咱们常见的0-1的形式。正则表达式
/** * IE678下获取透明度的值 * @param elem 获取值的 dom * @return {Number} 透明度的值,默认为1 * IE678下设置透明度 filter: alpha(opacity=0) 取值为0-100 */
function getFilter(elem) {
var _filter = elem.currentStyle.getAttribute('filter').match(/alpha\(opacity=(.*)\)/i);
var value = parseFloat(_filter[1]);
if(!isNaN(value)){
// 转化为0-1
return value ? value/100 : 0;
}
return 1;
}复制代码
上一篇博客中提到,因为 float
是 ECMAScript 的一个保留字。因此在各浏览器中都会有代替的写法,好比说在现代浏览器中为 cssFloat
,而在 IE678 中为 styleFloat
。经测试,在现代浏览器中直接使用 getPropertyValue("float")
也能够获取到 float
的值。而 IE678 则不行,因此针对 float
,须要简单的hack。浏览器
对于一个没有设定高宽的元素而言,在 IE678 下直接获取获得的值是 auto
。而现代浏览器会直接返回它的 px 值,咱们的目标就是在 IE 下也返回 px 值。dom
// 直接获取外部样式表未设置的 width 和 height 返回值为 auto
// 为了获取精确的 px 值,使用 getBoundingClientRect 方法
// getBoundingClientRect 能够得到元素四个点相对于文档视图左上角
// 的 top、left、bottom、right值,进行简单计算便可
var condition = attr === 'width'
|| attr === 'height'
&& elem.currentStyle[attr] === 'auto';
if(condition){
var clientRect = elem.getBoundingClientRect();
return (attr === 'width' ?
clientRect.right - clientRect.left :
clientRect.bottom - clientRect.top
) + 'px';
}复制代码
set 方法相较于 get 方法要简便的多,由于咱们有 cssText
这个跨越 IE6+ 和现代浏览器的神器。
经过elem.style.cssText
能够对元素的样式进行读写,实际上操做的是 html 标签上的 style
属性的值。所以不能直接对其赋值,否则就把整个 style
属性的值给覆盖掉了。咱们采用累加的方式来修改属性。
另外,在IE浏览器还有个小坑,若是 cssText 不为空,返回值最后一个分号会被删掉,所以咱们须要在累加的属性前加上一个分号。函数
/** * 设置元素css样式值 * @param elem 设置值的dom元素 * @param {String} attr 设置样式名称,如font-size * @param {String} value 设置样式的值,如16px */
set: function (elem, attr, value){
// IE78 设置透明度需特殊处理
if(attr === 'opacity'){
// 针对 IE7 的 hack
// filter 滤镜要求 hasLFooout=true 才能执行
// IE浏览器且 hasLFooout=false 时执行
if(!!elem.currentStyle && !elem.currentStyle.hasLFooout){
elem.style.zoom = 1;
attr = 'filter';
value = 'alpha(opacity=' + value * 100 + ')';
}
}
// 通用方式
elem.style.cssText += ';' + (attr + ':' + value) + ';';
}复制代码
var Foo = function() {
return new Foo.prototype.init();
}
Foo.prototype = {
init: function() {
this.age = 18;
return this;
},
age: 20
}
console.log(Foo().age); // 18
console.log(Foo.prototype.age); // 20复制代码
var Foo = function() {
return Foo.prototype.init();
}
Foo.prototype = {
init: function() {
this.age = 18;
return this;
},
age: 20
}
console.log(Foo().age); // 18
console.log(Foo.prototype.age); // 18复制代码
使用 new 操做符时,是把 init
当成构造函数来调用,在 init
内部会建立一个隐式对象并用 this
指向它,此时的 this.age=18
表示在这个隐式对象上增长一个 age 属性,最后 return this
不是必需的,构造函数默认会返回 this
。此时Foo.prototype.age
不受影响。
当不使用 new 操做符时,至关于一个普通对象上的函数调用,this
指向了 init
所属的对象,即 Foo.prototype
,this.age=18
至关于对 Foo.prototype.age
赋值,和使用 new 操做符是有本质区别的。
到这里,教程也就要告一段落了。一个 jQuery 中常见的 css()
方法背后涵盖了很是多的知识点,跨浏览器的兼容性也是咱们这次讨论的重点,此次只是实现了一个很是简易的 css 操做插件。学问尚浅,若是有不清楚或者有错误的地方,欢迎各位留言或者提issue来帮助我改进这个小插件。
最后,完整的项目地址:github.com/xdlrt/css-t…求一波star~