window.cookieStore 使用方式和注意事项 尤其注意只能在https或者本地开发中使用!!!
window.cookieStore 提供了一套基于 Promise 的现代、异步方法来操作 Cookie,彻底告别了 document.cookie 繁琐的字符串拼接和解析 。下面详细介绍其使用方式和注意事项。
💻 核心方法使用指南
在开始之前,建议先检查浏览器是否支持,以实现优雅降级:
if ('cookieStore' in window) {
console.log('支持 CookieStore API');
// 可以安全地使用 cookieStore 了
} else {
console.log('不支持,使用 document.cookie 作为降级方案');
}
cookieStore 对象主要提供以下几个方法,所有方法都返回 Promise,推荐结合 async/await 使用。
| 方法 | 描述 |
|---|---|
cookieStore.set() | 设置或修改 Cookie |
cookieStore.get() | 获取单个 Cookie 的详细信息 |
cookieStore.getAll() | 获取所有或符合过滤条件的 Cookie 列表 |
cookieStore.delete() | 删除指定的 Cookie |
cookieStore.addEventListener('change', handler) | 监听 Cookie 的变化 |
1. 设置 Cookie: set()
set() 方法有两种调用方式,非常灵活 。
// 方式一:参数分离 (name, value, options)
await cookieStore.set(
'session_id', // 键名
'abc123xyz', // 键值
{
maxAge: 3600, // 存活时间(秒),优先级高于 expires
path: '/', // 作用路径
domain: 'example.com', // 作用域
secure: true, // 仅 HTTPS 下发送
sameSite: 'lax' // 可选 'strict' | 'lax' | 'none'
}
);
// 方式二:对象参数 (更清晰,推荐)
await cookieStore.set({
name: 'user_pref',
value: 'dark_mode',
expires: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7天后过期
path: '/',
secure: true,
sameSite: 'strict'
});
注意:maxAge 和 expires 都是定义过期时间的,只需指定其中一个即可 。如果设置一个已存在的 Cookie 键名,其值会被自动覆盖 。
2. 获取 Cookie: get() 与 getAll()
获取到的 Cookie 对象会包含 name、value、domain、path、expires(时间戳)、secure 等完整属性,无需二次解析 。
// 获取单个 Cookie 的详细信息
const cookie = await cookieStore.get('session_id');
if (cookie) {
console.log('值:', cookie.value);
console.log('过期时间戳:', cookie.expires); // 如果存在的话
} else {
console.log('Cookie 不存在');
}
// 获取所有 Cookie
const allCookies = await cookieStore.getAll();
console.log('所有 Cookie 列表:', allCookies);
// 按路径过滤获取 Cookie
const rootCookies = await cookieStore.getAll({ path: '/' });
3. 删除 Cookie: delete()
删除时需要确保 path 和 domain 参数与设置该 Cookie 时完全一致,否则可能删除失败 。
// 简单删除(匹配当前页面的 path 和 domain)
await cookieStore.delete('session_id');
// 精确删除(推荐,避免错删)
await cookieStore.delete({
name: 'session_id',
path: '/',
domain: 'example.com'
});
4. 监听 Cookie 变化: change 事件
这是 CookieStore 最强大的特性之一,可以实时响应 Cookie 的新增、修改和删除,非常适合用来同步登录状态等 。
cookieStore.addEventListener('change', (event) => {
// 处理新增或修改的 Cookie
event.changed.forEach(cookie => {
console.log(`Cookie 新增/更新: ${cookie.name} = ${cookie.value}`);
});
// 处理被删除的 Cookie
event.deleted.forEach(cookie => {
console.log(`Cookie 被删除: ${cookie.name}`);
});
});
⚠️ 重要注意事项
在使用这个现代 API 时,有几个关键点需要留意:
- 安全上下文:
cookieStore只能在安全上下文(HTTPS)中可用。在本地开发时,http://localhost通常会被视为安全上下文而允许使用 。 - 同源策略:和传统的 Cookie 操作一样,你只能操作当前域名下的 Cookie,无法跨域访问 。
- 删除参数匹配:删除 Cookie 时,如果当初设置时指定了
path或domain,那么删除时也必须传入完全相同的参数,否则无法匹配删除 。 - SameSite 与 Secure 属性:
- 为了安全起见,建议敏感信息的 Cookie 设置
sameSite: 'lax'或'strict'并配合secure: true。 - 如果你的服务需要跨站共享 Cookie(如单点登录),则必须将
sameSite设置为'none',并且同时必须设置secure: true(即仅在 HTTPS 下工作)。
- 为了安全起见,建议敏感信息的 Cookie 设置
- 兼容性:尽管主流浏览器已广泛支持,但对于需要兼容老旧浏览器的项目,建议使用 polyfill(如
@ungap/cookie-store)或准备document.cookie的降级方案 。
decodeURIComponent
decodeURIComponent()方法
适用于解码URL的单个组件(如查询参数),会解码所有非保留字符:
JavaScript
复制
let encodedComponent = "name=%E4%B8%AD%E6%96%87&age=20";
let decodedComponent = decodeURIComponent(encodedComponent);
console.log(decodedComponent); // 输出: name=中文&age=20
关键特性:
- 会解码所有非保留字符,包括原本应保留的字符
- 适用于处理URL的片段(如查询字符串、路径参数)
pinia 持久化插件pinia-plugin-persistedstate高级用法
import { getUserInfo, siteLogout, siteRefresh } from "@/api/user";
import { defineStore, storeToRefs } from "pinia";
import { clearSession, CKKEY } from "@/utils/auth";
import { Message } from "@arco-design/web-vue";
import Cookies from "js-cookie";
const EXPIRETIME = 86400;
const MILLISECOND = 1000;
export default defineStore("user", {
state: () => {
return {
token: "",
appId: null, // 应用ID
userId: 0,
userInfo: null,
expire_in: EXPIRETIME * MILLISECOND, // token过期时间
timeId: null,
permissions: [],
noAuthLoginout: false
};
},
actions: {
toRefs() {
return storeToRefs(this);
},
setAppId(appId) {
this.appId = appId;
},
setToken(token) {
this.token = token;
},
setPermissions(permissions) {
this.permissions = permissions;
},
setUserInfo(userInfo) {
this.userInfo = userInfo;
this.userId = userInfo.id;
if (this.token) {
Cookies.set(CKKEY + `-${userInfo.id}`, this.token, {
expires: EXPIRETIME / (24 * 60 * 60),
path: "/"
});
}
},
setRedirect(url) {
this.redirectUrl = url;
},
async getUserInfo() {
return new Promise((resolve) => {
getUserInfo()
.then((res) => {
resolve(res.data);
this.setUserInfo(res.data);
})
.finally(() => {
resolve();
});
});
},
getUserPermissions() {
return new Promise((resolve) => {
resolve();
});
},
removeToken() {
this.token = null;
},
// 刷新token
refreshToken(time) {
this.expire_in = time * MILLISECOND;
this.timeId = setTimeout(
() => {
siteRefresh().then((res) => {
this.setToken(res.data.access_token);
this.refreshToken(res.data.expire_in);
});
},
this.expire_in - 10 * MILLISECOND
); // 过去10秒前刷新token
},
// 登出
logout() {
return new Promise((resolve) => {
siteLogout().then(() => {
this.removeToken();
Message.success("退出成功");
clearSession();
resolve();
});
});
}
},
//
persist: [
{
key: "dgig-user",
storage: sessionStorage,
paths: ["token", "userInfo", "permissions", "noAuthLoginout"]
}
// 这里可以如下使用cookie 来持久化 store state, 插件文档只写了local 和session 这俩storage
// {
// key: CKKEY,
// storage: {
// getItem: (key) => Cookies.get(key),
// setItem: (key, value) => {
// const jsonVal = JSON.parse(value);
// if (jsonVal.token !== null) {
// Cookies.set(key, value, {
// expires: EXPIRETIME / (24 * 60 * 60),
// path: "/"
// });
// } else {
// Cookies.remove(key, { path: "/" });
// }
// },
// removeItem: (key) => {
// Cookies.remove(key, { path: "/" });
// }
// },
// paths: ["token", "userId"]
// }
]
});
echarts 图例
legend: {
icon: props.l_icon,
type: props.l_type,
orient: props.l_orient, // 水平或者竖直排列
left: props.position_l[0],
top: props.position_l[1],
width: props.l_width,
height: props.l_height || 120,
itemWidth: 8,
itemHeight: 8,
itemGap: props.l_gap,
pageIconColor: "#3c7dfc",
pageTextStyle: {
color: props.textcolor
},
tooltip: {
show: true,
formatter: ({ name }) => {
const item = props.list.find((i) => {
return i.name === name;
});
return `${name} ${item.value} | ${item.rate}%`;
}
},
textStyle: {
color: props.textcolor,
rich: { // 图例文字富文本
name: {
//这里是下面格式化的key 以及具体样式
verticalAlign: "right",
align: "left",
fontSize: 14,
color: props.textcolor,
padding: props.lconfig.np,
width: props.lconfig.nw
},
percent: {
align: "left",
color: props.textcolor,
fontSize: 14,
width: props.lconfig.pw
},
line: {
color: props.llcolor,
fontSize: 14,
padding: props.lconfig.lp
},
ratio: {
align: "left",
color: props.textcolor,
fontSize: 14
}
}
},
formatter: (name) => {
const item = props.list.find((i) => {
return i.name === name;
});
const showName = echarts.format.truncateText(
name,
props.lconfig.nw,
"14px",
"…"
);
const showValue = echarts.format.truncateText(
item.value,
props.lconfig.sw,
"14px",
"…"
);
// 下面return 加上\n 可以实现换行!!!
return `{name|${showName}}{percent|${showValue}}{line||}{ratio|${item.rate}%}`;
}
},