前端加密常用的幾種方式匯總
前言
隨著信息和數(shù)據(jù)安全重要性的日益凸顯,如何保證信息數(shù)據(jù)在傳輸?shù)倪^程中的安全成為開發(fā)者重點(diǎn)關(guān)注的內(nèi)容。前端加密通常是指在瀏覽器中對(duì)各種傳輸?shù)臄?shù)據(jù)進(jìn)行各種加密操作。然而前端加密更多的是用來對(duì)傳輸?shù)臄?shù)據(jù)進(jìn)行簡(jiǎn)單的混淆,為了確保數(shù)據(jù)在傳輸過程中不被輕易的篡改和讀取??晒┪覀冞x擇的加密方式有很多種,需要我們?cè)陂_發(fā)過程中根據(jù)實(shí)際的場(chǎng)景選擇適合自己的加密解決方案。那么,本文將結(jié)合應(yīng)用場(chǎng)景來介紹一下前端開發(fā)中常用的加密方法。
一、Base64編碼
嚴(yán)格意義上來說,Base64并不是一種加密方式,它是一種編碼方式。Base64就是一種基于64個(gè)可打印字符來表示二進(jìn)制數(shù)據(jù)的方法。Base64,就是包括小寫字母a-z、大寫字母A-Z、數(shù)字0-9、符號(hào)"+“、”/"一共64個(gè)字符的字符集,任何符號(hào)都可以轉(zhuǎn)換成這個(gè)字符集中的字符,這個(gè)轉(zhuǎn)換過程就叫做base64編碼。
Base64編碼是從二進(jìn)制到字符的過程,可用于在HTTP環(huán)境下傳遞較長的標(biāo)識(shí)信息。采用Base64編碼具有不可讀性,需要解碼后才能閱讀。Base64由于以上優(yōu)點(diǎn)被廣泛應(yīng)用于計(jì)算機(jī)的各個(gè)領(lǐng)域。JavaScript中可以使用內(nèi)置的btoa函數(shù)進(jìn)行Base64編碼。btoa函數(shù)可以將二進(jìn)制數(shù)據(jù)轉(zhuǎn)換為Base64編碼的字符串,同樣也可使用內(nèi)置函數(shù)atob對(duì)編碼后的字符串進(jìn)行解碼。
// 編碼 const base64Str = window.btoa('Hello World!'); console.log(base64Str); // SGVsbG8gV29ybGQh // 解碼 const str = window.atob(base64Str); console.log(str); // Hello World!
當(dāng)然,我們也可以使用base64插件。
pnpm add js-base64
使用方法:
import { Base64 } from 'js-base64'; // 編碼 const encode = Base64.encode('Hello World!');? console.log(encode); // 解碼 const decode = Base64.decode(encode);? console.log(decode);
二、哈希算法
散列算法(Hash Algorithm),又稱哈希算法,雜湊算法,是一種從任意文件中創(chuàng)造小的數(shù)字”指紋“的方法。與指紋一樣,散列算法就是一種以較短的信息來保證文件唯一性的標(biāo)志,這種標(biāo)志與文件的每一個(gè)字節(jié)都相關(guān),而且難以找到逆向規(guī)律。因此,當(dāng)原有文件發(fā)生改變時(shí),其標(biāo)志值也會(huì)發(fā)生改變,從而告訴文件使用者當(dāng)前的文件已經(jīng)不是你所需求的文件。
Hash 算法能將將任意長度的二進(jìn)制明文映射為較短的二進(jìn)制串的算法,并且不同的明文很難映射為相同的 Hash 值。
哈希算法(Hash Algorithm)是一種將任意長度的消息映射為固定長度的消息摘要(Message Digest)的算法。哈希算法可以將任意長度的輸入數(shù)據(jù)轉(zhuǎn)換為固定長度的輸出,通常稱為哈希值(Hash Value)或摘要(Digest),并且滿足以下特性:
(1) 確定性:對(duì)于相同的輸入數(shù)據(jù),哈希算法會(huì)生成相同的哈希值。
(2) 不可逆性:無法從哈希值中推導(dǎo)出原始的輸入數(shù)據(jù)。
(3) 唯一性:不同的輸入數(shù)據(jù)生成的哈希值應(yīng)盡可能不同。
(4) 散列性:即使輸入數(shù)據(jù)僅有微小的變化,生成的哈希值應(yīng)該有很大的差異。
因此,哈希算法廣泛應(yīng)用于密碼學(xué)、數(shù)據(jù)完整性校驗(yàn)、數(shù)字簽名、數(shù)據(jù)分片等領(lǐng)域。
(1) 數(shù)字簽名:將原始數(shù)據(jù)的哈希值與簽名一起存儲(chǔ),以驗(yàn)證簽名的完整性和正確性。
(2) 密碼存儲(chǔ):將用戶密碼的哈希值存儲(chǔ)在數(shù)據(jù)庫中,以避免直接存儲(chǔ)明文密碼,提高安全性。
(3) 數(shù)據(jù)完整性校驗(yàn):將原始數(shù)據(jù)的哈希值與傳輸過程中的哈希值進(jìn)行比對(duì),以判斷數(shù)據(jù)是否被篡改。
(4) 數(shù)據(jù)分片:將原始數(shù)據(jù)分成若干個(gè)塊,對(duì)每個(gè)塊分別計(jì)算哈希值,以便快速檢測(cè)數(shù)據(jù)塊的正確性。
比較常見的哈希算法有MD5、SHA-1、SHA-256和SHA-512等。
安裝crypto-js:
pnpm add crypto-js
使用方法:
import CryptoJS from "crypto-js"; // MD5 const hash = CryptoJS.MD5('Message'); // SHA-1 const hash = CryptoJS.SHA1('Message'); // SHA-256 const hash = CryptoJS.SHA256('Message'); // SHA-512 const hash = CryptoJS.SHA512('Message');
三、對(duì)稱加密(AES/DES)
DES全稱為Data Encryption Standardy即數(shù)據(jù)加密標(biāo)準(zhǔn),是一種使用密鑰加密的算法。
AES全稱為Advanced Encryption Standard,AES 算法使用分組密碼體制,將明文按照固定大小進(jìn)行分組,然后對(duì)每一分組進(jìn)行加密。在加密過程中,AES 算法采用了多輪加密的方式,每一輪加密都包含了四種操作:SubBytes、ShiftRows、MixColumns 和 AddRoundKey。通過這些操作,AES 算法可以更加安全高效地對(duì)數(shù)據(jù)進(jìn)行加密。
AES和DES加密算法是一種對(duì)稱加密方式,所謂對(duì)稱加密就是加密與解密使用的秘鑰(一組字符串)是一個(gè)。加密和解密端必須使用同一個(gè)密鑰的才可以進(jìn)行加密和解密。
AES 加密最常用的模式就是 ECB模式和CBC模式,當(dāng)然還有很多其它模式,它們都屬于AES加密。ECB模式和CBC模式倆者區(qū)別就是 ECB 不需要 iv偏移量,而CBC需要。
ECB是一種基礎(chǔ)的加密方式,密文被分割成分組長度相等的塊(不足補(bǔ)齊),然后單獨(dú)一個(gè)個(gè)加密,一個(gè)個(gè)輸出組成密文。CBC是一種循環(huán)模式,前一個(gè)分組的密文和當(dāng)前分組的明文異或或操作后再加密,這樣做的目的是增強(qiáng)破解難度。
參數(shù)Mode為DES/AES的工作方式。
參數(shù)padding為填充模式,如果加密后密文長度如果達(dá)不到指定整數(shù)倍(8個(gè)字節(jié)、16個(gè)字節(jié)),填充對(duì)應(yīng)字符,padding的賦值固定為CryptoJS.pad.Pkcs7即可。
import CryptoJS from "crypto-js"; //秘鑰 const secretKey = CryptoJS.enc.Utf8.parse("12345678ABCDEFGH"); //16位 // iv偏移量 const iv = CryptoJS.enc.Utf8.parse("ABCDEFGH12345678"); // 需要加密的參數(shù),數(shù)據(jù)類型為bytes const secretMessage = "Hello World!"; // 加密 const encrypt = CryptoJS.AES.encrypt(secretMessage, secretKey, { iv: iv, mode: CryptoJS.mode.CBC,? padding: CryptoJS.pad.Pkcs7? }).tostring(); console.log(encrypt); //解密 const decrypt = CryptoJS.AES.decrypt(encrypt, secretKey, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }).toString(CryptoJS.enc.Utf8); console.log(decrypt);
四、非對(duì)稱加密(RSA)
非對(duì)稱加密,加密和解密的秘鑰不是同一個(gè)秘鑰,這里需要兩把鑰匙,一個(gè)公鑰, 一個(gè)私鑰, 公鑰發(fā)送給客戶端。發(fā)送端用公鑰對(duì)數(shù)據(jù)進(jìn)行加密,再發(fā)送給接收端,接收端使用私鑰來對(duì)數(shù)據(jù)解密。由于私鑰只存放在接受端這邊,所以即使數(shù)據(jù)被截獲了,也是無法進(jìn)行解密的。
公鑰與私鑰是一對(duì),因?yàn)榧用芎徒饷苁褂玫氖莾蓚€(gè)不同的密鑰,所以這種算法叫作非對(duì)稱加密算法。使用時(shí)都是使用公匙加密使用私匙解密。公匙可以公開,私匙自己保留。這個(gè)公鑰和私鑰其實(shí)就是一組數(shù)字,其二進(jìn)制位長度可以是1024位或者2048位。長度越長其加密強(qiáng)度越大,相對(duì)就比較安全。所以目前為止,這種加密算法一直被廣泛使用。
常見的非對(duì)稱加密算法有RSA,DSA等等,本文我們就介紹一個(gè)RSA加密,也是最常見的一種加密方案。
jsencrypt就是一個(gè)基于RSA加解密的js庫。
npm install jsencrypt? import JSEncrypt from 'jsencrypt'? // RSA加密 // 創(chuàng)建加密對(duì)象實(shí)例 const encryptor = new JSEncrypt();? //之前ssl生成的公鑰,復(fù)制的時(shí)候要小心不要有空格 const pubKey = '-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC1QQRl0HlrVv6kGqhgonD6A9SU6ZJpnEN+Q0blT/ue6Ndt97WRfxtSAs0QoquTreaDtfC4RRX4o+CU6BTuHLUm+eSvxZS9TzbwoYZq7ObbQAZAY+SYDgAA5PHf1wNN20dGMFFgVS/y0ZWvv1UNa2laEz0I8Vmr5ZlzIn88GkmSiQIDAQAB-----END PUBLIC KEY-----'; //設(shè)置公鑰 encryptor.setPublicKey(pubKey); // 對(duì)內(nèi)容進(jìn)行加密 const encrypted = encryptor.encrypt('要加密的內(nèi)容')? // RSA解密 //創(chuàng)建解密對(duì)象實(shí)例 const decrypt = new JSEncrypt(); //之前ssl生成的秘鑰 const priKey ?= '-----BEGIN RSA PRIVATE KEY-----MIICXAIBAAKBgQC1QQRl0HlrVv6kGqhgonD6A9SU6ZJpnEN+Q0blT/ue6Ndt97WRfxtSAs0QoquTreaDtfC4RRX4o+CU6BTuHLUm+eSvxZS9TzbwoYZq7ObbQAZAY+SYDgAA5PHf1wNN20dGMFFgVS/y0ZWvv1UNa2laEz0I8Vmr5ZlzIn88GkmSiQIDAQABAoGBAKYDKP4AFlXkVlMEP5hS8FtuSrUhwgKNJ5xsDnFV8sc3yKlmKp1a6DETc7N66t/Wdb3JVPPSAy+7GaYJc7IsBRZgVqhrjiYiTO3ZvJv3nwAT5snCoZrDqlFzNhR8zvUiyAfGD1pExBKLZKNH826dpfoKD2fYlBVOjz6i6dTKBvCJAkEA/GtL6q1JgGhGLOUenFveqOHJKUydBAk/3jLZksQqIaVxoB+jRQNOZjeSO9er0fxgI2kh0NnfXEvH+v326WxjBwJBALfTRar040v71GJq1m8eFxADIiPDNh5JD2yb71FtYzH9J5/d8SUHI/CUFoROOhxr3DpagmrnTn28H0088vubKe8CQDKMOhOwx/tS5lqvN0YQj7I6JNKEaR0ZzRRuEmv1pIpAW1S5gTScyOJnVn1tXxcZ9xagQwlT2ArfkhiNKxjrf5kCQAwBSDN5+r4jnCMxRv/Kv0bUbY5YWVhw/QjixiZTNn81QTk3jWAVr0su4KmTUkg44xEMiCfjI0Ui3Ah3SocUAxECQAmHCjy8WPjhJN8y0MXSX05OyPTtysrdFzm1pwZNm/tWnhW7GvYQpvE/iAcNrNNb5k17fCImJLH5gbdvJJmCWRk=-----END RSA PRIVATE KEY----'; //設(shè)置秘鑰 decrypt.setPrivateKey(priKey); //解密之前拿公鑰加密的內(nèi)容 const uncrypted = decrypt.decrypt(encrypted)
RSA加解密可以應(yīng)用在用戶注冊(cè)或登錄的時(shí)候,用公鑰對(duì)密碼進(jìn)行加密,再去傳給后臺(tái),后臺(tái)用私鑰對(duì)加密的內(nèi)容進(jìn)行解密,然后進(jìn)行密碼校驗(yàn)或者保存到數(shù)據(jù)庫。
- 對(duì)稱加密
- 雙方共享密鑰(碼)(secret key,あんごう),加密傳輸基于密鑰安全而非算法安全。
- 加密與解密使用同一算法。
- 破解難度主要取決于密鑰復(fù)雜度。
- 非對(duì)稱加密(公開密鑰加密)
- 使用密鑰對(duì)(公鑰 publickey、私鑰 privatekey)。
- 不傳遞私鑰。
- 加解密可能使用多種規(guī)則和算法。
- 安全性既不依賴算法的保密,也不依賴于傳遞密鑰的途徑。
比特幣和以太坊加密技術(shù)
大量使用對(duì)稱加密和非對(duì)稱加密,以及相關(guān)技術(shù)。
- 加密、解密(如上述)
- Hash、Message digest(哈希,SHA256, RIPEMD160)
- Checksum(校驗(yàn)和)
- 編碼(Base64,Base58)
^ Hash: 摘要,對(duì)不定長度的數(shù)據(jù)進(jìn)行換算,計(jì)算出固定長度的不容易沖突的結(jié)果。
^ Checksum:校驗(yàn)和,對(duì)數(shù)據(jù)進(jìn)行冗余校驗(yàn)和完整性檢查。
^ 編碼:將二進(jìn)制數(shù)據(jù)轉(zhuǎn)化為普通字符,更易于閱讀和判別。
五、加鹽
加鹽是指在密碼哈希過程中引入一個(gè)隨機(jī)生成的字符串,稱為鹽(salt),并將其與密碼進(jìn)行組合后再進(jìn)行哈希計(jì)算。這個(gè)鹽值會(huì)與每個(gè)用戶的密碼單獨(dú)關(guān)聯(lián),并且將其存儲(chǔ)在數(shù)據(jù)庫中。加鹽可以增加密碼哈希的復(fù)雜度,提高密碼的安全性,即使兩個(gè)用戶使用相同的密碼,由于使用了不同的鹽值,其哈希結(jié)果也會(huì)有所區(qū)別。這樣即使黑客獲得了哈希值,也很難找到原始的密碼。
鹽值其實(shí)就是我們添加的一串隨機(jī)字符串(這個(gè)值可以是固定值、隨機(jī)數(shù)、uuid……),相同的字符串每次都會(huì)被加密為完全不同的字符串。
使用加鹽加密時(shí)需要注意以下兩點(diǎn):
(1)短鹽值(Short Slat)
如果鹽值太短,攻擊者可以預(yù)先制作針對(duì)所有可能的鹽值的查詢表。例如,如果鹽值只有三個(gè) ASCII 字符,那么只有 95x95x95=857,375 種可能性,加大了被攻擊的可能性。還有,不要使用可預(yù)測(cè)的鹽值,比如用戶名,因?yàn)獒槍?duì)某系統(tǒng)用戶名是唯一的且被經(jīng)常用于其他服務(wù)。
(2)鹽值復(fù)用(Salt Reuse)
在項(xiàng)目開發(fā)中,有時(shí)會(huì)遇到將鹽值寫死在程序里或者只有第一次是隨機(jī)生成的,之后都會(huì)被重復(fù)使用,這種加鹽方法是不起作用的。以登錄密碼為例,如果兩個(gè)用戶有相同的密碼,那么他們就會(huì)有相同的哈希值,攻擊者就可以使用反向查表法對(duì)每個(gè)哈希值進(jìn)行字典攻擊,使得該哈希值更容易被破解。
所以正確的加鹽方法如下:
(1)鹽值應(yīng)該使用加密的安全偽隨機(jī)數(shù)生成器( Cryptographically Secure Pseudo-Random Number Generator,CSPRNG )產(chǎn)生,比如 C 語言的 rand() 函數(shù),這樣生成的隨機(jī)數(shù)高度隨機(jī)、完全不可預(yù)測(cè);
(2)鹽值混入目標(biāo)文本中,一起使用標(biāo)準(zhǔn)的加密函數(shù)進(jìn)行加密;
(3)鹽值要足夠長(經(jīng)驗(yàn)表明:鹽值至少要跟哈希函數(shù)的輸出一樣長)且永不重復(fù);
(4)鹽值最好由服務(wù)端提供,前端取值使用。
我們一起SHA-256為例實(shí)現(xiàn)加鹽加密。
安裝js-sha256
pnpm install js-sha256
使用方法:
import { sha256 } from 'js-sha256'; const generateSalt = () => { const randomBytes = new Uint8Array(16); crypto.getRandomValues(randomBytes); return Array.from(randomBytes, (byte) => byte.toString(16).padStart(2, '0') ).join(''); }; // 鹽值 const salt = generateSalt(); // 假如一個(gè)密碼 const password = 'admin123456'; // 鹽值和密碼進(jìn)行組合 const saltedPassword = salt + password; // 哈希計(jì)算 const hash = sha256(saltedPassword); console.log(hash);
六、Web Cryptography API
Web Cryptography API(WebCrypto API)是現(xiàn)代瀏覽器內(nèi)置的一個(gè)加密標(biāo)準(zhǔn),可以用于更安全的密碼學(xué)操作。這個(gè)API允許我們?cè)赪eb應(yīng)用中實(shí)現(xiàn)加密、解密、數(shù)字簽名等安全功能,而無需依賴第三方庫或插件。
WebCrypto API是W3C的標(biāo)準(zhǔn),它提供了一套低級(jí)別的接口用于執(zhí)行各種密碼學(xué)操作。這些接口包括:
生成和管理密鑰:如RSA、AES和HMAC等。
加密和解密:支持多種對(duì)稱和非對(duì)稱加密算法。
摘要和哈希:如SHA-1、SHA-256和MD5等。
數(shù)字簽名和驗(yàn)證:用于確保數(shù)據(jù)的完整性和來源真實(shí)性。
隨機(jī)數(shù)生成:用于創(chuàng)建安全的隨機(jī)數(shù)。
window.crypto.subtle就是SubtleCrypto接口,主流最新瀏覽器基本都已經(jīng)支持該接口,并且一致,除了safari需要注意。
// fix safari crypto namespace if (window.crypto && !window.crypto.subtle && window.crypto.webkitSubtle) { window.crypto.subtle = window.crypto.webkitSubtle;? } /** * Detect Web Cryptography API * @return {Boolean} true, if success? */ function isWebCryptoAPISupported() { return 'crypto' in window && 'subtle' in window.crypto; }
getRandomValues 同步方法,獲取隨機(jī)數(shù),因?yàn)樾阅芤?,這是一個(gè)偽隨機(jī)數(shù)生成器(PRNG)。瀏覽器也通過添加系統(tǒng)級(jí)別的種子來提高熵(不確定性的量度),來滿足密碼學(xué)使用要求。
const size = 10; const array = new Uint8Array(size); window.crypto.getRandomValues(array); // print values to console for (let i=0; i!==array.length; ++i) { ? console.log(array[i]); }
SubtleCrypto接口:
encrypt、decrypt(加解密方法),算法支持:RSA-OAEP、AES-CTR、AES-CBC、AES-GCM、AES-CFB。
Sign、verify(簽名驗(yàn)簽發(fā)方法),算法支持:RSASSA-PKCS1-v1.5、RSA-PSS、ECDSA、AES-CMAC、HMAC。
Digest(摘要方法),算法支持:SHA-1、SHA-256、SHA-384、SHA-512。
GenerateKey:生成對(duì)稱/非對(duì)稱的密鑰(CryptoKey對(duì)象)。
DeriveKey 和 deriveBits:從原密鑰或是從偽隨機(jī)函數(shù)生成的密碼/口令中生成出一個(gè)密鑰。
WrapKey 和 unwrapKey:用來保護(hù)在不安全信道或不可信環(huán)境存儲(chǔ)的密鑰的方法。
ImportKey 和 exportKey:導(dǎo)入密鑰,轉(zhuǎn)換再導(dǎo)出不同格式。
上面的方法都會(huì)返回Promise。
以下是使用WebCrypto API實(shí)現(xiàn)一個(gè)簡(jiǎn)單的加密,代碼如下:
// 生成公鑰和私鑰 const keyPair = await window.crypto.subtle.generateKey( { name: "RSA-OAEP", // 使用RSA-OAEP算法 modulusLength: 2048, // 密鑰長度為2048位 publicExponent: new Uint8Array([1, 0, 1]), // 公共指數(shù)為65537 hash: "SHA-256" // 哈希算法為SHA-256 }, true, // 生成可導(dǎo)出的密鑰對(duì) ["encrypt", "decrypt"] // 可用于加密和解密操作 ); keyPair.then(function(result) { // 處理生成的密鑰對(duì) console.log(result.publicKey); // 打印公鑰 console.log(result.privateKey); // 打印私鑰 }).catch(function(error) { // 處理錯(cuò)誤 console.error(error); }); // 加密 async function encryptByRSA(message, publicKey) { // 將消息編碼為Uint8Array格式 const encodedMessage = new TextEncoder().encode(message); // 使用Web Crypto API的encrypt()方法對(duì)消息進(jìn)行加密 const encrypted = await window.crypto.subtle.encrypt( { name: "RSA-OAEP" // 加密算法為RSA-OAEP }, publicKey, // 使用傳入的公鑰進(jìn)行加密 encodedMessage // 要加密的消息 ); // 將加密后的數(shù)據(jù)轉(zhuǎn)換為Base64編碼的字符串 return window.btoa(String.fromCharCode(...new Uint8Array(encrypted))); } // 解密 使用RSA私鑰對(duì)密文進(jìn)行解密 async function decryptByRSA(ciphertext, privateKey) { // 將Base64編碼的密文解碼為Uint8Array格式 const decodedCiphertext = Uint8Array.from( atob(ciphertext), c => c.charCodeAt(0) ); // 使用Web Crypto API的decrypt()方法對(duì)密文進(jìn)行解密 const decrypted = await window.crypto.subtle.decrypt( { name: "RSA-OAEP" // 解密算法為RSA-OAEP }, privateKey, // 使用傳入的私鑰進(jìn)行解密 decodedCiphertext // 要解密的密文 ); // 將解密后的數(shù)據(jù)轉(zhuǎn)換為字符串 return new TextDecoder().decode(decrypted); }
七、總結(jié)
以上幾種加密方法提供了基本的前端加密方法。大部分時(shí)候,為了確保數(shù)據(jù)的安全性,會(huì)將一些敏感數(shù)據(jù)(如手機(jī)號(hào)、身份證號(hào)、銀行卡號(hào)等)發(fā)送到服務(wù)端,然后再服務(wù)端進(jìn)行加密。前端加密并不能確保數(shù)據(jù)的安全性,因?yàn)榭蛻舳耸潜┞督o用戶的,任何混淆或加密措施都可能被繞過(前端加密防君子不放小人)。正確的做法是在保證數(shù)據(jù)傳輸過程中通過HTTPS等協(xié)議加密,并在服務(wù)端進(jìn)行必要的安全校驗(yàn)和加密處理。
到此這篇關(guān)于前端加密常用的幾種方式匯總的文章就介紹到這了,更多相關(guān)前端加密方式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript實(shí)現(xiàn)點(diǎn)贊功能的示例
本文主要介紹了JavaScript實(shí)現(xiàn)點(diǎn)贊功能的示例,分享給大家2014-04-04javascript 兼容FF的onmouseenter和onmouseleave的代碼
經(jīng)過測(cè)試發(fā)現(xiàn),例子1 在 ff下抖動(dòng)的厲害,ie下稍微有點(diǎn)。 具體原因 其實(shí)就是 mouseout 的冒泡機(jī)制 引起的。2008-07-07js 判斷計(jì)算字符串長度/判斷空的簡(jiǎn)單方法
這篇文章介紹了判斷計(jì)算字符串長度/判斷空的簡(jiǎn)單方法,有需要的朋友可以參考一下2013-08-08原生js實(shí)現(xiàn)的觀察者和訂閱者模式簡(jiǎn)單示例
這篇文章主要介紹了原生js實(shí)現(xiàn)的觀察者和訂閱者模式,結(jié)合簡(jiǎn)單實(shí)例形式分析了js觀察者和訂閱者模式的相關(guān)原理與實(shí)現(xiàn)技巧,需要的朋友可以參考下2020-04-04JavaScript常見事件對(duì)象與操作實(shí)例總結(jié)
這篇文章主要介紹了JavaScript常見事件對(duì)象與操作,結(jié)合實(shí)例形式總結(jié)分析了javascript針對(duì)DOM、IE及跨瀏覽器事件對(duì)象的相關(guān)操作技巧,需要的朋友可以參考下2019-01-01js 與 php 通過json數(shù)據(jù)進(jìn)行通訊示例
這篇文章主要介紹了js與php通過json數(shù)據(jù)進(jìn)行通訊的具體實(shí)現(xiàn),需要的朋友可以參考下2014-03-03javascript瀑布流式圖片懶加載實(shí)例解析與優(yōu)化
這篇文章主要針對(duì)javascript瀑布流式圖片懶加載實(shí)例進(jìn)行解析與優(yōu)化,感興趣的小伙伴們可以參考一下2016-02-02JavaScript檢測(cè)瀏覽器是否支持CSS變量代碼實(shí)例
這篇文章主要介紹了JavaScript檢測(cè)瀏覽器是否支持CSS變量代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04