国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

自己動手寫個顏色類庫:掌握JS中的位運算符

yvonne / 986人閱讀

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

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

先上兩張圖,循環了1600個div,分別設置顏色的漸變和隨機。雖然現在css中對顏色的處理方法越來越豐富,但在一些場景——例如可視化圖表中我們還是需要用JS來控制顏色。

需求分析

將各種格式的色值進行統一,方便操作,也確保展示效果一致。

對顏色進行明暗處理,最明時為白色(#fff),最暗時為黑色(#000)。

其中顏色格式包括:

3位Hex值

6位Hex值

整數型RGB

百分比型RGB

整數型RGBA

百分比型RGBA

HSL

HSLA

常見的顏色命名,如black

流程及接口

要實現以上的功能,流程上應該包括:

通過正則表達式檢測顏色格式。

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

為每個格式化后的顏色添加“變明”、“變暗”兩個方法,并返回一個新的標準格式顏色對象,以便鏈式調用。

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

檢測顏色格式

注意,此類庫使用了部分ES6語法,如需轉化為瀏覽器可直接使用的版本,可用babel進行轉換。

檢測格式時,主要依靠的是正則表達式,具體如下:

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*)$/

對于已命名的顏色,則構建了一個named對象,key為顏色名稱,value則為16進制色值,例如:

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

通過named.hasOwnProperty方法來檢測輸入的字符串是否是已命名的顏色,如果是,則用其16進制色值替換。

實際上,我創建了3個class,分別為Color、Rgb和Hsl。以上的顏色檢測均放在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,實際可以用三元表達式替代,讓代碼更優雅緊湊。
通過閱讀Color類,可以知道最終f屬性均為一個 new Rgbnew Hsl 構造出來的對象,接下來就具體說說Color類中的這些位運算符起到了什么作用。

HEX色值的快速轉換

HSL和RGB的轉換沒有什么黑魔法,都是查Wiki之后寫的方法,大同小異,所以重點講講16進制色值是怎樣處理的。
網上資料中,大部分的HEX轉Rgb都是通過遍歷字符串,將HEX色值分隔,再轉化為10進制數字。但在閱讀d3.js的源碼后,發現還有更巧妙的處理方法。

首先補充一下HEX色值的基本概念。HEX色值可以為3位或者6位,3位可以理解為一種簡寫,如#123,實際等于#112233。
而對于一個6位的HEX色值,如#112233,在轉換為RGB時,實際是每兩位對應RGB中的一個值,即11、22、33分別對應R、G、B。

>>&

首先以6位HEX色值為例,我們通過正則表達式取出其值后,parseInt(str, 16)轉化為16進制數字,也可以通過在前面加上"0x"來達到這一效果,目的都是告訴解析器,它是一個16進制的數。依然以#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

那么>>&分別起什么作用,為什么這樣一操作就能直接取出對應數值呢?

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

那么當我們需要取中間的22和最右端的33時該怎么辦呢?這就需要用到&&是JS中位的與運算,說起來有點繞口,實際就是將兩端的值的二進制按位一一取與運算。

所以我們實際看看取22和33時發生了什么:

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

簡單的說,就是通過與0xff這個二進制最右端8均為1的數與運算,從而取出目標數最右端的八位,并舍棄其余所有位數。
總的來說,就是先用>>調整位置,再用&篩選。

<<|

我們接著處理3位HEX值,以#123為例,取出對應的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

代碼中出現的|是位的或運算符,機制和&相類似。<<則是和>>對應的左移運算符。
同樣一步一步看看|是怎么起到作用的:

// 0x123的二進制為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位時一樣,只是增加了<<|,更靈活的操作各種位運算。

剩余工作

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

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/80133.html

相關文章

  • 【譯】 JavaScript中按位操作符的有趣應用

    摘要:檢查設定位操作符還有一些其他有用的位屏蔽應用。請注意,位掩碼中的位將有效地關閉十進制數中的相應位,因為。 原文標題:Interesting use cases for JavaScript bitwise operators原文地址:https://blog.logrocket.com/in... 本文首發于公眾號:符合預期的CoyPan JavaScript提供了幾種運算符,可以對...

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

    摘要:也就是說不僅是會產生這種問題,只要是采用的浮點數編碼方式來表示浮點數時,則會產生這類問題。到這里我們都理解只要采取的浮點數編碼的語言均會出現上述問題,只是它們的標準類庫已經為我們提供了解決方案而已。 Brief 一天有個朋友問我JS中計算0.7 * 180怎么會等于125.99999999998,坑也太多了吧!那時我猜測是二進制表示數值時發生round-off error所導致,但并不...

    JerryWangSAP 評論0 收藏0
  • Express 實戰(二):Node.js 基礎

    摘要:而通過實現名為的標準模塊,完美的解決了模塊導入問題。通常都被稱為包管理器,而這也是它最大的特色。例如,接受請求發送響應。該模塊主要處理文件相關內容,其中大多數都是文件讀寫功能。 在上一篇文章中,我們簡單的介紹了 Node.js 。了解到它基于 JavaScript、天生異步、擁有大量的第三方類庫。本文將會在之前的基礎上,對 Node.js 進行更深入的介紹。其中主要內容包括: Nod...

    soasme 評論0 收藏0
  • Java 征途:行者的地圖

    摘要:老實說,當時一進入世界的大門就暈了,各種規范概念和英文縮寫詞能把人整的暈暈乎乎。等新的英文縮寫又出現了,一口老血還沒來得及噴出,又重新振作開始新的學習征程。 showImg(http://upload-images.jianshu.io/upload_images/1131767-1c5d16e39435df10.jpg?imageMogr2/auto-orient/strip%7Ci...

    dkzwm 評論0 收藏0
  • 復習js 2

    摘要:復習表達式和運算符運算符擁有如下類型的運算符。例如十進制數字用二進制表示為,位運算符就是在這個二進制表示上執行運算,但是返回結果是標準的數值。因此,用于布爾值時,當任何一個操作數為則返回如果操作數都是則返回。 復習js day2 表達式和運算符 運算符 JavaScript 擁有如下類型的運算符。本節描述了運算符和運算符的優先級。 賦值運算符(Assignment operators...

    yhaolpz 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<