惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Security Archives - TechRepublic
Security Archives - TechRepublic
T
The Exploit Database - CXSecurity.com
P
Proofpoint News Feed
Scott Helme
Scott Helme
NISL@THU
NISL@THU
Cisco Talos Blog
Cisco Talos Blog
C
Cybersecurity and Infrastructure Security Agency CISA
AWS News Blog
AWS News Blog
V
Vulnerabilities – Threatpost
J
Java Code Geeks
U
Unit 42
The GitHub Blog
The GitHub Blog
H
Help Net Security
T
Tenable Blog
aimingoo的专栏
aimingoo的专栏
Jina AI
Jina AI
Spread Privacy
Spread Privacy
Apple Machine Learning Research
Apple Machine Learning Research
人人都是产品经理
人人都是产品经理
L
Lohrmann on Cybersecurity
T
Threatpost
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Engineering at Meta
Engineering at Meta
A
About on SuperTechFans
I
InfoQ
Microsoft Azure Blog
Microsoft Azure Blog
B
Blog
L
LINUX DO - 最新话题
K
Kaspersky official blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
T
Threat Research - Cisco Blogs
C
Check Point Blog
T
The Blog of Author Tim Ferriss
有赞技术团队
有赞技术团队
宝玉的分享
宝玉的分享
Help Net Security
Help Net Security
Google DeepMind News
Google DeepMind News
A
Arctic Wolf
Y
Y Combinator Blog
N
News | PayPal Newsroom
M
MIT News - Artificial intelligence
Latest news
Latest news
H
Hacker News: Front Page
Blog — PlanetScale
Blog — PlanetScale
腾讯CDC
I
Intezer
爱范儿
爱范儿
F
Fortinet All Blogs
P
Palo Alto Networks Blog
C
CERT Recently Published Vulnerability Notes

一颗小树

周更的第 100 篇 改变阅读方式 宝贵的人生建议 小树的工具库 2023 读《重构》有感 仅需 10 分钟,用 GPTs 实现文章总结助手 高质量的需求交付 产品始于问题,而不是解决方案 如何更好地休息 最优解人生 与体重斗,其乐无穷 结构化 prompt = 数字员工? 持续创作的法门 如何降低知识焦虑 7 月思维碎片 N 倍生产力提升:我的 AI 助理 Indie Hacker,互联网打工人的下一个出路? 如何成就伟大事业 夏日碎片 小报编辑的自我修养 一颗小树 #49 投入真实生活 一颗小树 #48 过年杂记 一颗小树 #47 我的人生信念(2023) 一颗小树 #46 回本就卖 一颗小树 #45 规划和落地 小树的 2022 年终总结 一颗小树 #44 构建高质量信源 一颗小树 #43 我的 2022 书单 一颗小树 #42 阳了怎么办 一颗小树 #41 一人企业 一颗小树 #40 非必要别正常啦 一颗小树 #39 阅读和创造 一颗小树 #38 疫情生活碎片 一颗小树 #37 基于多维表格的可转债投资系统 一颗小树 #36 飞盘初体验 一颗小树 #35 雁栖湖半日游 一颗小树 #34 初探多维表格 一颗小树 #33 回不去的名字叫家乡 一颗小树 #32 生活需要留白 一颗小树 #31 Figma 的成功之道 一颗小树 #30 拓宽自己 拥抱善意 一颗小树 #29 有关下雨的记忆 一颗小树 #28 隐入尘烟 一颗小树 #27 找到并坚持自己的热爱 一颗小树 #26 好产品的“差”改版 一颗小树 #25 吹吹南澳岛的海风 一颗小树 #24 代码重构的一点心得 一颗小树 #23 和团队新同学的对话 一颗小树 #22 从《干法》中学到的 一颗小树 #21 阿里四年我的收获和感想 一颗小树 #20 周更半年我学到的事 一颗小树 #19 慢慢来比较快 一颗小树 #18 只规划每天最重要的三件事 一颗小树 #17 裁员潮下的反思 一颗小树 #16 纪录片的力量在于真实 一颗小树 #15 世界很小但很好 一颗小树 #14 让自己成为问题的终结者 一颗小树 #13 别忘记你的热爱 一颗小树 #12 聊聊写作这件事 一颗小树 #11 开始投资前更重要的事 一颗小树 #10 疫情囤货指南 一颗小树 #9 疫情之下 重建内心的秩序 一颗小树 #8 不要倒在黎明前 一颗小树 #7 从小孩子身上学到的事 一颗小树 #6 和自己的产品一起成长 一颗小树 #5 技术对生产力的的变革是不可阻挡的 一颗小树 #4 暴风雨的意义 一颗小树 #3 投资成功,是我们变成一个更好的人之后自然的结果 一颗小树 #2 持续学习来应对这个复杂多变的世界 一颗小树 #1 任天堂和上岭村 一颗小树 #0 这是写给你们的第一封信 游戏改变世界 把自己给开源了 构建自己的不为清单 有爱和被爱 做了一点微小的工作 小树的 2021 年终总结 小树的 2020 年终总结 与其感慨路难行,不如马上出发 阿里前端也切图?不,人工智能帮你做 如何写好简历,拿到大厂 offer 的敲门砖 任时光匆匆流去 | 2019 年终总结 聊聊在阿里远程办公那点事儿 在 D2 做主持人是怎样一种体验? 提高工作效率的几个方法 有限状态机在 CSS 动画中的应用 「译」React 项目结构和组件命名之道 编写小而美函数的艺术 使用纯粹的JS构建 Web Component 翻译计划-状态管理请三思 利用Dawn工程化工具实践MobX数据流管理方案 高性能 MobX 模式(part 3)- 用例教程 高性能 MobX 模式(part 2)- 响应变化 技术文章写法浅谈 翻译计划-用node.js开发一个可交互的命令行应用 无他,唯手熟尔-前端实习面试题篇 工欲善其事必先利其器-前端实习简历篇 我们来翻翻元素样式的族谱-getComputedStyle 翻译计划-从sass到PostCSS 把简单做好也不简单-css水平垂直居中
手把手带你用原生js实现css属性的set和get
也树 · 2017-02-05 · via 一颗小树

上一篇博文介绍了 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-tool 求一波 star~