资讯专栏INFORMATION COLUMN

手把手带你用原生js实现css属性的set和get

derek_334892 / 2768人阅读

摘要:而现代浏览器会直接返回它的值,我们的目标就是在下也返回值。通过可以对元素的样式进行读写,实际上操作的是标签上的属性的值。因此不能直接对其赋值,不然就把整个属性的值给覆盖掉了。我们采用累加的方式来修改属性。

上一篇博文介绍了getComputedStyle方法,接下来,我们就来实现一个简易版的小插件,能够在不借助jQuery的情况下实现css属性的获取和设置。

作者:Icarus
原文链接:手把手带你用原生js实现css属性的set和get

Let"s start

首先创建一个 css-tool.js 文件,一开始他是这个样子的:

;(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 在老版本浏览器中不被支持,因此考虑到兼容性添加一个形参。

我们创建了一个叫 cssTool 的私有方法,相当于我们在屋子里找了一个小房间来放 getset 等方法。接下来我们在原型上新增一个 init 方法,用于初始化。之后我们仿照 jQuery 的方式,将initprototype 指向 cssToolprototype ,这样我们在用init作为构造函数创造实例时,可以使插件拥有两种调用方式:

var ct = new cssTool()构建 cssTool 实例

直接调用cssTool(),一样返回 cssTool 实例

get方法 通用方式 现代浏览器和IE9+
window.getComputedStyle(elem,null).getPropertyValue(attr)
IE678
elem.currentStyle.getAttribute(camelCase(attr))
兼容处理 驼峰命名法转换-camelCase

currentStyle 来说,在IE6浏览器中他很专一,只喜欢以驼峰命名法命名的变量,而IE78中就有点朝三暮四,驼峰命名法和中间带"-"的都照单全收,为了兼容和操作的简便,我们统一转换为驼峰命名法。

/**
 * 驼峰命名法转换,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();
  });
}
透明度获取-getFilter

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 值的获取

上一篇博客中提到,由于 float 是 ECMAScript 的一个保留字。所以在各浏览器中都会有代替的写法,比如说在现代浏览器中为 cssFloat,而在 IE678 中为 styleFloat 。经测试,在现代浏览器中直接使用 getPropertyValue("float") 也可以获取到 float 的值。而 IE678 则不行,所以针对 float ,需要简单的hack。

width | height 样式的获取

对于一个没有设定高宽的元素而言,在 IE678 下直接获取得到的值是 auto 。而现代浏览器会直接返回它的 px 值,我们的目标就是在 IE 下也返回 px 值。

// 直接获取外部样式表未设置的 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方法

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) + ";";
}
补充 简单解释new操作符的作用
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.prototypethis.age=18相当于对 Foo.prototype.age 赋值,和使用 new 操作符是有本质区别的。

小结

到这里,教程也就要告一段落了。一个 jQuery 中常见的 css() 方法背后涵盖了非常多的知识点,跨浏览器的兼容性也是我们此次讨论的重点,这次只是实现了一个非常简易的 css 操作插件。学问尚浅,如果有不清楚或者有错误的地方,欢迎各位留言或者提issue来帮助我改进这个小插件。
最后,完整的项目地址:https://github.com/xdlrt/css-...
求一波star~

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/50395.html

相关文章

  • 把手你用原生js实现css属性setget

    摘要:而现代浏览器会直接返回它的值,我们的目标就是在下也返回值。通过可以对元素的样式进行读写,实际上操作的是标签上的属性的值。因此不能直接对其赋值,不然就把整个属性的值给覆盖掉了。我们采用累加的方式来修改属性。 上一篇博文介绍了getComputedStyle方法,接下来,我们就来实现一个简易版的小插件,能够在不借助jQuery的情况下实现css属性的获取和设置。 作者:Icarus原文链接...

    AZmake 评论0 收藏0
  • 库,组件,框架 - 收藏集 - 掘金

    摘要:哈哈,我理解,架构就是骨架,如下图所示译年月个有趣的和库前端掘金我们创办的使命是让你及时的了解开发中最新最酷的趋势。 翻译 | 上手 Webpack ? 这篇就够了! - 掘金译者:小 boy (沪江前端开发工程师) 本文原创,转载请注明作者及出处。 原文地址:https://www.smashingmagazine.... JavaSrip... 读 Zepto 源码之代码结构 - ...

    tommego 评论0 收藏0
  • javascript知识点

    摘要:模块化是随着前端技术的发展,前端代码爆炸式增长后,工程化所采取的必然措施。目前模块化的思想分为和。特别指出,事件不等同于异步,回调也不等同于异步。将会讨论安全的类型检测惰性载入函数冻结对象定时器等话题。 Vue.js 前后端同构方案之准备篇——代码优化 目前 Vue.js 的火爆不亚于当初的 React,本人对写代码有洁癖,代码也是艺术。此篇是准备篇,工欲善其事,必先利其器。我们先在代...

    Karrdy 评论0 收藏0
  • JavaScript - 收藏集 - 掘金

    摘要:插件开发前端掘金作者原文地址译者插件是为应用添加全局功能的一种强大而且简单的方式。提供了与使用掌控异步前端掘金教你使用在行代码内优雅的实现文件分片断点续传。 Vue.js 插件开发 - 前端 - 掘金作者:Joshua Bemenderfer原文地址: creating-custom-plugins译者:jeneser Vue.js插件是为应用添加全局功能的一种强大而且简单的方式。插....

    izhuhaodev 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<