亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

自己動(dòng)手寫個(gè)顏色類庫(kù):掌握J(rèn)S中的位運(yùn)算符

yvonne / 1110人閱讀

摘要:在編寫的過(guò)程中,涉及到了中的各種位運(yùn)算符,對(duì)進(jìn)制色值的處理不再是循環(huán)遍歷了。只對(duì)位運(yùn)算符感興趣的建議直接閱讀目錄中的色值的快速轉(zhuǎn)換。通過(guò)閱讀類,可以知道最終屬性均為一個(gè)或構(gòu)造出來(lái)的對(duì)象,接下來(lái)就具體說(shuō)說(shuō)類中的這些位運(yùn)算符起到了什么作用。

從最近寫的一個(gè)圖表庫(kù)中多帶帶抽象出來(lái)了顏色類庫(kù),功能包括HEX、RGB/RGBA以及HSL/HSLA各種色值的轉(zhuǎn)換以及顏色明暗變化。
在編寫的過(guò)程中,涉及到了JS中的各種位運(yùn)算符,對(duì)16進(jìn)制色值的處理不再是循環(huán)遍歷了。只對(duì)位運(yùn)算符感興趣的建議直接閱讀目錄中的“HEX色值的快速轉(zhuǎn)換”。

先上兩張圖,循環(huán)了1600個(gè)div,分別設(shè)置顏色的漸變和隨機(jī)。雖然現(xiàn)在css中對(duì)顏色的處理方法越來(lái)越豐富,但在一些場(chǎng)景——例如可視化圖表中我們還是需要用JS來(lái)控制顏色。

需求分析

將各種格式的色值進(jìn)行統(tǒng)一,方便操作,也確保展示效果一致。

對(duì)顏色進(jìn)行明暗處理,最明時(shí)為白色(#fff),最暗時(shí)為黑色(#000)。

其中顏色格式包括:

3位Hex值

6位Hex值

整數(shù)型RGB

百分比型RGB

整數(shù)型RGBA

百分比型RGBA

HSL

HSLA

常見的顏色命名,如black

流程及接口

要實(shí)現(xiàn)以上的功能,流程上應(yīng)該包括:

通過(guò)正則表達(dá)式檢測(cè)顏色格式。

將顏色統(tǒng)一為一種最易操作的格式。由于我們的操作主要為明暗操作,那么RGB/RGBA格式顯然是最方便的,因此將各種格式統(tǒng)一為RGB/RGBA。

為每個(gè)格式化后的顏色添加“變明”、“變暗”兩個(gè)方法,并返回一個(gè)新的標(biāo)準(zhǔn)格式顏色對(duì)象,以便鏈?zhǔn)秸{(diào)用。

顏色對(duì)象還需要有一個(gè)輸出顏色字符串的方法,以便在所有操作完成后輸出最終的色值添加給對(duì)應(yīng)的Dom。

檢測(cè)顏色格式

注意,此類庫(kù)使用了部分ES6語(yǔ)法,如需轉(zhuǎn)化為瀏覽器可直接使用的版本,可用babel進(jìn)行轉(zhuǎn)換。

檢測(cè)格式時(shí),主要依靠的是正則表達(dá)式,具體如下:

const reHex3 = /^#([0-9a-f]{3})$/
const reHex6 = /^#([0-9a-f]{6})$/
const reRgbInteger = /^rgb(s*([-+]?d+)s*,s*([-+]?d+)s*,s*([-+]?d+)s*)$/
const reRgbPercent = /^rgb(s*([-+]?d+(?:.d+)?)%s*,s*([-+]?d+(?:.d+)?)%s*,s*([-+]?d+(?:.d+)?)%s*)$/
const reRgbaInteger = /^rgba(s*([-+]?d+)s*,s*([-+]?d+)s*,s*([-+]?d+)s*,s*([-+]?d+(?:.d+)?)s*)$/
const reRgbaPercent = /^rgba(s*([-+]?d+(?:.d+)?)%s*,s*([-+]?d+(?:.d+)?)%s*,s*([-+]?d+(?:.d+)?)%s*,s*([-+]?d+(?:.d+)?)s*)$/
const reHslPercent = /^hsl(s*([-+]?d+(?:.d+)?)s*,s*([-+]?d+(?:.d+)?)%s*,s*([-+]?d+(?:.d+)?)%s*)$/
const reHslaPercent = /^hsla(s*([-+]?d+(?:.d+)?)s*,s*([-+]?d+(?:.d+)?)%s*,s*([-+]?d+(?:.d+)?)%s*,s*([-+]?d+(?:.d+)?)s*)$/

對(duì)于已命名的顏色,則構(gòu)建了一個(gè)named對(duì)象,key為顏色名稱,value則為16進(jìn)制色值,例如:

const named = {
  aliceblue: 0xf0f8ff,
  antiquewhite: 0xfaebd7,
  ...
  yellowgreen: 0x9acd32
}

通過(guò)named.hasOwnProperty方法來(lái)檢測(cè)輸入的字符串是否是已命名的顏色,如果是,則用其16進(jìn)制色值替換。

實(shí)際上,我創(chuàng)建了3個(gè)class,分別為Color、Rgb和Hsl。以上的顏色檢測(cè)均放在Color的format方法中,將格式化之后的顏色放入Color的f屬性里,代碼如下:

class Color {
  constructor () {
    this.f = {}
  }
  format (str) {
    let m
    str = (str + "").trim().toLowerCase()
    if (reHex3.exec(str)) {
      m = parseInt(reHex3.exec(str)[1], 16)
      this.f = new Rgb((m >> 8 & 0xf) | (m >> 4 & 0x0f0), (m >> 4 & 0xf) | (m & 0xf0), ((m & 0xf) << 4) | (m & 0xf), 1)
    } else if (reHex6.exec(str)) {
      m = parseInt(reHex6.exec(str)[1], 16)
      this.f = this.rgbn(m)
    } else if (reRgbInteger.exec(str)) {
      m = reRgbInteger.exec(str)
      this.f = new Rgb(m[1], m[2], m[3], 1)
    } else if (reRgbPercent.exec(str)) {
      m = reRgbPercent.exec(str)
      const r = 255 / 100
      this.f = new Rgb(m[1] * r, m[2] * r, m[3] * r, 1)
    } else if (reRgbaInteger.exec(str)) {
      m = reRgbaInteger.exec(str)
      this.f = this.rgba(m[1], m[2], m[3], m[4])
    } else if (reRgbaPercent.exec(str)) {
      m = reRgbaPercent.exec(str)
      const r = 255 / 100
      this.f = this.rgba(m[1] * r, m[2] * r, m[3] * r, m[4])
    } else if (reHslPercent.exec(str)) {
      m = reHslPercent.exec(str)
      this.f = this.hsla(m[1], m[2] / 100, m[3] / 100, 1)
    } else if (reHslaPercent.exec(str)) {
      m = reHslaPercent.exec(str)
      this.f = this.hsla(m[1], m[2] / 100, m[3] / 100, m[4])
    } else if (named.hasOwnProperty(str)) {
      this.f = this.rgbn(named[str])
    } else if (str === "transparent") {
      this.f = new Rgb(NaN, NaN, NaN, 0)
    } else {
      this.f = null
      throw new Error("Invalid color format.")
    }
    return this.f
  }
  rgbn (n) {
    return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1)
  }
  rgba (r, g, b, a) {
    if (a <= 0) r = g = b = NaN
    return new Rgb(r, g, b, a)
  }
  hsla (h, s, l, a) {
    if (a <= 0) {
      h = s = l = NaN
    } else if (l <= 0 || l >= 1) {
      h = s = NaN
    } else if (s <= 0) {
      h = NaN
    }
    return new Hsl(h, s, l, a).rgb()
  }
}

為了方便讀者快速理解代碼,用了大量的if / else if,實(shí)際可以用三元表達(dá)式替代,讓代碼更優(yōu)雅緊湊。
通過(guò)閱讀Color類,可以知道最終f屬性均為一個(gè) new Rgbnew Hsl 構(gòu)造出來(lái)的對(duì)象,接下來(lái)就具體說(shuō)說(shuō)Color類中的這些位運(yùn)算符起到了什么作用。

HEX色值的快速轉(zhuǎn)換

HSL和RGB的轉(zhuǎn)換沒(méi)有什么黑魔法,都是查Wiki之后寫的方法,大同小異,所以重點(diǎn)講講16進(jìn)制色值是怎樣處理的。
網(wǎng)上資料中,大部分的HEX轉(zhuǎn)Rgb都是通過(guò)遍歷字符串,將HEX色值分隔,再轉(zhuǎn)化為10進(jìn)制數(shù)字。但在閱讀d3.js的源碼后,發(fā)現(xiàn)還有更巧妙的處理方法。

首先補(bǔ)充一下HEX色值的基本概念。HEX色值可以為3位或者6位,3位可以理解為一種簡(jiǎn)寫,如#123,實(shí)際等于#112233。
而對(duì)于一個(gè)6位的HEX色值,如#112233,在轉(zhuǎn)換為RGB時(shí),實(shí)際是每?jī)晌粚?duì)應(yīng)RGB中的一個(gè)值,即11、22、33分別對(duì)應(yīng)R、G、B。

>>&

首先以6位HEX色值為例,我們通過(guò)正則表達(dá)式取出其值后,parseInt(str, 16)轉(zhuǎn)化為16進(jìn)制數(shù)字,也可以通過(guò)在前面加上"0x"來(lái)達(dá)到這一效果,目的都是告訴解析器,它是一個(gè)16進(jìn)制的數(shù)。依然以#112233為例,具體看看代碼:

const m = parseInt("112233", 16) // 0x112233

// 分別獲取R、G、B的值
const r = m >> 16 & 0xff // 17
const g = m >> 8 & 0xff // 34
const b = m & 0xff // 51

那么>>&分別起什么作用,為什么這樣一操作就能直接取出對(duì)應(yīng)數(shù)值呢?

>>是JS中的右移運(yùn)算符,用于將數(shù)字的二進(jìn)制右移n位。對(duì)于一個(gè)16進(jìn)制的數(shù)字而言,每一位數(shù)字都對(duì)應(yīng)4位2進(jìn)制數(shù)字,如0x112233的二進(jìn)制就是0001 0001 0010 0010 0011 0011
因此要取出最左端11對(duì)應(yīng)的10進(jìn)制數(shù)字,只需要將其右移16位,剩下左起的8位即可。

那么當(dāng)我們需要取中間的22和最右端的33時(shí)該怎么辦呢?這就需要用到&。&是JS中位的與運(yùn)算,說(shuō)起來(lái)有點(diǎn)繞口,實(shí)際就是將兩端的值的二進(jìn)制按位一一取與運(yùn)算。

所以我們實(shí)際看看取22和33時(shí)發(fā)生了什么:

// 0x112233的二進(jìn)制為0001 0001 0010 0010 0011 0011
let n = 0x112233 >> 8 // 0001 0001 0010 0010
// 將n和0xff按位與運(yùn)算,0xff的二進(jìn)制為1111 1111
n & 0xff // 0010 0010 也就是 0x22
n = 0x112233 & 0xff // 0011 0011 也就是 0x33

簡(jiǎn)單的說(shuō),就是通過(guò)與0xff這個(gè)二進(jìn)制最右端8均為1的數(shù)與運(yùn)算,從而取出目標(biāo)數(shù)最右端的八位,并舍棄其余所有位數(shù)。
總的來(lái)說(shuō),就是先用>>調(diào)整位置,再用&篩選。

<<|

我們接著處理3位HEX值,以#123為例,取出對(duì)應(yīng)的R、G、B。

const m = parseInt("123", 16) // 0x123
const r = (m >> 8 & 0xf) | (m >> 4 & 0x0f0) // 17
const g = (m >> 4 & 0xf) | (m & 0xf0) // 34
const b = ((m & 0xf) << 4) | (m & 0xf) // 51

代碼中出現(xiàn)的|是位的或運(yùn)算符,機(jī)制和&相類似。<<則是和>>對(duì)應(yīng)的左移運(yùn)算符。
同樣一步一步看看|是怎么起到作用的:

// 0x123的二進(jìn)制為0001 0010 0011
0x123 >> 8 & 0xf // 0001
0x123 >> 4 & 0x0f0 // 0001 0000
0001 | 0001 0000 // 0001 0001 也就是 0x11

0x123 >> 4 & 0xf // 0010
0x123 & 0xf0 // 0010 0000
0010 | 0010 0000 // 0010 0010 也就是 0x22

(0x123 & 0xf) << 4 // 0011 0000
0x123 & 0xf // 0011
0011 0000 | 0011 // 0011 0011 也就是 0x33

思路和6位時(shí)一樣,只是增加了<<|,更靈活的操作各種位運(yùn)算。

剩余工作

之后要做的主要就是一些HSL轉(zhuǎn)換、明暗變化以及各種錯(cuò)誤處理,都是比較常規(guī)的做法,這里不多做贅述,有興趣的可以看看代碼:https://github.com/Yuyz0112/v...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/80133.html

相關(guān)文章

  • 【譯】 JavaScript中按位操作符的有趣應(yīng)用

    摘要:檢查設(shè)定位操作符還有一些其他有用的位屏蔽應(yīng)用。請(qǐng)注意,位掩碼中的位將有效地關(guān)閉十進(jìn)制數(shù)中的相應(yīng)位,因?yàn)椤? 原文標(biāo)題:Interesting use cases for JavaScript bitwise operators原文地址:https://blog.logrocket.com/in... 本文首發(fā)于公眾號(hào):符合預(yù)期的CoyPan JavaScript提供了幾種運(yùn)算符,可以對(duì)...

    oneasp 評(píng)論0 收藏0
  • JS魔法堂:徹底理解0.1 + 0.2 === 0.30000000000000004的背后

    摘要:也就是說(shuō)不僅是會(huì)產(chǎn)生這種問(wèn)題,只要是采用的浮點(diǎn)數(shù)編碼方式來(lái)表示浮點(diǎn)數(shù)時(shí),則會(huì)產(chǎn)生這類問(wèn)題。到這里我們都理解只要采取的浮點(diǎn)數(shù)編碼的語(yǔ)言均會(huì)出現(xiàn)上述問(wèn)題,只是它們的標(biāo)準(zhǔn)類庫(kù)已經(jīng)為我們提供了解決方案而已。 Brief 一天有個(gè)朋友問(wèn)我JS中計(jì)算0.7 * 180怎么會(huì)等于125.99999999998,坑也太多了吧!那時(shí)我猜測(cè)是二進(jìn)制表示數(shù)值時(shí)發(fā)生round-off error所導(dǎo)致,但并不...

    JerryWangSAP 評(píng)論0 收藏0
  • Express 實(shí)戰(zhàn)(二):Node.js 基礎(chǔ)

    摘要:而通過(guò)實(shí)現(xiàn)名為的標(biāo)準(zhǔn)模塊,完美的解決了模塊導(dǎo)入問(wèn)題。通常都被稱為包管理器,而這也是它最大的特色。例如,接受請(qǐng)求發(fā)送響應(yīng)。該模塊主要處理文件相關(guān)內(nèi)容,其中大多數(shù)都是文件讀寫功能。 在上一篇文章中,我們簡(jiǎn)單的介紹了 Node.js 。了解到它基于 JavaScript、天生異步、擁有大量的第三方類庫(kù)。本文將會(huì)在之前的基礎(chǔ)上,對(duì) Node.js 進(jìn)行更深入的介紹。其中主要內(nèi)容包括: Nod...

    soasme 評(píng)論0 收藏0
  • Java 征途:行者的地圖

    摘要:老實(shí)說(shuō),當(dāng)時(shí)一進(jìn)入世界的大門就暈了,各種規(guī)范概念和英文縮寫詞能把人整的暈暈乎乎。等新的英文縮寫又出現(xiàn)了,一口老血還沒(méi)來(lái)得及噴出,又重新振作開始新的學(xué)習(xí)征程。 showImg(http://upload-images.jianshu.io/upload_images/1131767-1c5d16e39435df10.jpg?imageMogr2/auto-orient/strip%7Ci...

    dkzwm 評(píng)論0 收藏0
  • 復(fù)習(xí)js 2

    摘要:復(fù)習(xí)表達(dá)式和運(yùn)算符運(yùn)算符擁有如下類型的運(yùn)算符。例如十進(jìn)制數(shù)字用二進(jìn)制表示為,位運(yùn)算符就是在這個(gè)二進(jìn)制表示上執(zhí)行運(yùn)算,但是返回結(jié)果是標(biāo)準(zhǔn)的數(shù)值。因此,用于布爾值時(shí),當(dāng)任何一個(gè)操作數(shù)為則返回如果操作數(shù)都是則返回。 復(fù)習(xí)js day2 表達(dá)式和運(yùn)算符 運(yùn)算符 JavaScript 擁有如下類型的運(yùn)算符。本節(jié)描述了運(yùn)算符和運(yùn)算符的優(yōu)先級(jí)。 賦值運(yùn)算符(Assignment operators...

    yhaolpz 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<