前言
對於前端來講,我們在操作cookie
時往往都是基於document.cookie
,但它有一個缺點就是操作複雜,它並沒有像localStorage
那樣提供一些get
或set
等方法供我們使用。對與cookie的操作一切都是基於字串來進行的。為了讓cookie
的操作更簡便, Chrome87率先引入了cookieStore
方法。
document.cookie
document.cookie
可以獲取並設定當前文件關聯的cookie
獲取cookie
const cookie = document.cookie
在上面的程式碼中,cookie
被賦值為一個字串,該字串包含所有的 Cookie,每條 cookie 以"分號和空格 (; )"分隔 (即, key=value
鍵值對)。
但這拿到的是一整個字串,如果你想獲取cookie中的某一個欄位,還需要自己處理
const converter = {
read: function (value) {
if (value[0] === '"') {
value = value.slice(1, -1);
}
return value.replace(/(%[\dA-F]{2})+/gi, decodeURIComponent)
},
write: function (value) {
return encodeURIComponent(value).replace(
/%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g,
decodeURIComponent
)
}
}
function getCookie (key) {
const cookies = document.cookie ? document.cookie.split('; ') : [];
const jar = {};
for (let i = 0; i < cookies.length; i++) {
const parts = cookies[i].split('=');
const value = parts.slice(1).join('=');
try {
const foundKey = decodeURIComponent(parts[0]);
jar[foundKey] = converter.read(value, foundKey);
if (key === foundKey) {
break
}
} catch (e) {}
}
return key ? jar[key] : jar
}
console.log(getCookie('name')) // 前端南玖
比如上面這段程式碼就是用來獲取單個cookie
值的
設定cookie
document.cookie = `name=前端南玖;`
它的值是一個鍵值對形式的字串。需要注意的是,用這個方法一次只能對一個 cookie 進行設定或更新。
比如:
document.cookie = `age=18; city=shanghai;`
這樣只有age
能夠設定成功
以下可選的 cookie 屬性值可以跟在鍵值對後,用來具體化對 cookie 的設定/更新,使用分號以作分隔:
;path=path
(例如 '/', '/mydir') 如果沒有定義,預設為當前文件位置的路徑。;domain=domain
(例如 'example.com', 'subdomain.example.com') 如果沒有定義,預設為當前文件位置的路徑的域名部分。與早期規範相反的是,在域名前面加 . 符將會被忽視,因為瀏覽器也許會拒絕設定這樣的 cookie。如果指定了一個域,那麼子域也包含在內。;max-age=max-age-in-seconds
(例如一年為 606024*365);expires=date-in-GMTString-format
如果沒有定義,cookie 會在對話結束時過期
- 這個值的格式參見Date.toUTCString() (en-US)
;secure
(cookie 只透過 https 協議傳輸)
- cookie 的值字串可以用encodeURIComponent() (en-US)來保證它不包含任何逗號、分號或空格 (cookie 值中禁止使用這些值).
function assign (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
target[key] = source[key];
}
}
return target
}
function setCookie (key, value, attributes) {
if (typeof document === 'undefined') {
return
}
attributes = assign({}, { path: '/' }, attributes);
if (typeof attributes.expires === 'number') {
attributes.expires = new Date(Date.now() + attributes.expires * 864e5);
}
if (attributes.expires) {
attributes.expires = attributes.expires.toUTCString();
}
key = encodeURIComponent(key)
.replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent)
.replace(/[()]/g, escape);
var stringifiedAttributes = '';
for (var attributeName in attributes) {
if (!attributes[attributeName]) {
continue
}
stringifiedAttributes += '; ' + attributeName;
if (attributes[attributeName] === true) {
continue
}
stringifiedAttributes += '=' + attributes[attributeName].split(';')[0];
}
return (document.cookie =
key + '=' + converter.write(value, key) + stringifiedAttributes)
}
setCookie('course', 'fe', { expires: 365 })
這裡是js-cookie
庫對setCookie
方法的封裝
刪除cookie
function removeCookie (key, attributes) {
setCookie(
key,
'',
assign({}, attributes, {
expires: -1
})
);
}
removeCookie('course')
新方法cookieStore
以上就是透過document.cookie
來操作cookie
的方法,未封裝方法之前操作起來都非常的不方便。現在我們再來了解一下新方法cookieStore
,它是一個類似localStorage
的全域性物件。
它提供了一些方法可以讓我們更加方便的操作cookie
獲取單個cookie
cookieStore.get(name)
該方法可以獲取對應key
的單個cookie,並且以promise
形式返回對應的值
async function getCookie (key) {
const name = await cookieStore.get(key)
console.log('【name】', name)
}
getCookie('name')
當獲取的cookie
不存在時,則會返回null
獲取所有cookie
cookieStore.getAll()
該方法可以獲取所有匹配的cookie
,並且以promise
形式返回一個列表
async function getAllCookies () {
const cookies = await cookieStore.getAll()
console.log('【cookies】', cookies)
}
getAllCookies()
當cookie
不存在時,則會返回一個空陣列
設定cookie
cookieStore.set()
該方法可以設定cookie,並且會返回一個promise狀態,表示是否設定成功
function setCookie (key, value) {
cookieStore.set(key, value).then(res => {
console.log('設定成功')
}).catch(err => {
console.log('設定失敗')
})
}
setCookie('site', 'https://bettersong.github.io/nanjiu/')
如果想要設定更多的屬性,比如:過期時間、路徑、域名等,可以傳入一個物件
function setCookie (key, value) {
cookieStore.set({
name: key,
value: value,
path: '/',
expires: new Date(2024, 2, 1)
}).then(res => {
console.log('設定成功')
}).catch(err => {
console.log('設定失敗')
})
}
setCookie('site', 'https://bettersong.github.io/nanjiu/')
刪除cookie
cookieStore.delete(name)
該方法可以用來刪除指定的cookie,同樣會返回一個promise狀態,來表示是否刪除成功
function removeCookie (key) {
cookieStore.delete(key).then(res => {
console.log('刪除成功')
}).catch(err => {
console.log('刪除失敗')
})
}
removeCookie('site')
需要注意的是:即使刪除一個不存在的cookie也會返回刪除成功狀態
監聽cookie
cookieStore.addEventListener('change', (event) => {
console.log(event)
});
可以透過change
事件來監聽cookie的變化,無論是透過cookieStore
操作的,還是透過document.cookie
來操作的都能夠監聽到。
該方法的返回值有兩個欄位比較重要,分別是:change
盒delete
,它們都是陣列型別。用來存放改變和刪除的cookie資訊
監聽修改
呼叫set
方法時,會觸發change
事件,修改或設定的cookie會存放在change
陣列中
cookieStore.addEventListener('change', (event) => {
const type = event.changed.length ? 'change' : 'delete';
const data = (event.changed.length ? event.changed : event.deleted).map((item) => item.name);
console.log(`【${type}】, cookie:${JSON.stringify(data)}`);
});
function setCookie (key, value) {
cookieStore.set(key, value).then(res => {
console.log('設定成功')
}).catch(err => {
console.log('設定失敗')
})
}
setCookie('site', 'https://bettersong.github.io/nanjiu/')
⚠️需要注意的是:
- 透過
document.cookie
設定或刪除cookie時,都是會觸發change
事件,不會觸發delete
事件 - 即使兩次設定cookie的
name
和value
都相同,也會觸發change
事件
監聽刪除
呼叫delete
方法時,會觸發change
事件,刪除的cookie會存放在delete
陣列中
cookieStore.addEventListener('change', (event) => {
const type = event.changed.length ? 'change' : 'delete';
const data = (event.changed.length ? event.changed : event.deleted).map((item) => item.name);
console.log(`【${type}】, cookie:${JSON.stringify(data)}`);
});
function removeCookie (key) {
cookieStore.delete(key).then(res => {
console.log('刪除成功')
}).catch(err => {
console.log('刪除失敗')
})
}
removeCookie('site')
⚠️需要注意的是:
- 如果刪除一個不存在的cookie,則不會觸發
change
事件
相容性
在使用該方法時需要注意瀏覽器的相容性
總結
cookieStore
提供的方法比起直接操作document.cookie
要簡便許多,不僅支援增刪改查,還支援透過change事件來監聽cookie的變化,但是在使用過程需要注意相容性問題。