最近正在学习vue3小兔鲜
下面是学习笔记
建议大家先去看我第一篇小兔鲜的文章,强烈建议,非常建议,十分建议,从头开始看更完整。
**目标:**能够理解小兔鲜项目中的路由设计
内容:
一级路由有登录 Login 和布局容器 Layout
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v3gF56aX-1668072603824)(media/image-20211229174027074.png)]
路径 | 组件(功能) | 嵌套级别 |
---|---|---|
/ | 首页布局容器 Layout | 1级 |
/login | 登录 | 1级 |
/category/:id | 分类 | 2级 |
/product/:id | 商品详情 | 2级 |
/cart | 购物车 | 2级 |
/checkout | 填写订单 | 2级 |
/pay | 支付 | 2级 |
/pay/result | 支付结果 | 2级 |
eslint
规则/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution');
module.exports = {
root: true,
+ // 自定义规则
+ rules: {
+ // vue组件必须用组合词: 关闭
+ 'vue/multi-word-component-names': 'off',
+ },
extends: [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-typescript/recommended',
'@vue/eslint-config-prettier',
],
env: {
'vue/setup-compiler-macros': true,
},
};
**目标:**能够配置小兔鲜儿项目中的路由
核心代码:
views/Layout/index.vue
layout布局容器组件
views/Login/index.vue
login登录页组件
router/index.ts
import { createRouter, createWebHashHistory } from "vue-router";
const router = createRouter({
history: createWebHashHistory(),
routes: [
{
path: "/",
component: () => import("@/views/Layout/index.vue"),
},
{
path: "/login",
component: () => import("@/views/Login/index.vue"),
},
],
});
export default router;
main.ts
中导入import { createApp } from 'vue'
import App from './App.vue'
import 'normalize.css'
import '@/assets/styles/common.less'
+ import router from './router'
const app = createApp(App)
+ app.use(router)
app.mount('#app')
App.vue
,预留路由出口
-
布局容器
-
登录页
注意事项:
**目标:**能够完成Layout组件的顶部通栏布局
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sFBuqXxT-1668072603840)(media/image-20211229175807388.png)]
核心步骤:
index.html
引入字体图标文件
+
小兔鲜儿
Layout/components/app-topnav.vue
3)在 src/views/Layout.vue
中导入使用
<script setup lang="ts">
import AppTopnav from "./components/app-topnav.vue";
script>
<template>
<AppTopnav />
template>
<style lang="less" scoped>style>
**目标:**能够完成Layout组件的头部布局
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yQkMqWoj-1668072603841)(media/image-20211229180517464.png)]
核心代码
Layout/components/
下新建 app-header.vue
组件,基础布局如下:
src/views/Layout.vue
中导入使用。
+
拷贝素材到项目中
assets/images/
中提供图片,在素材中已经提供nav
组件拆分因为在后面的吸顶交互里,我们需要复用导航部分,所以这里我们先直接把他拆分出来,拆分成一个单独的组件
Layout/compoennts/
下,新建app-header-nav.vue
组件
Layout/components/app-header.vue
中
小兔鲜
+
// ...
**目标:**能够完成Layout布局的底部布局效果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Culk46GH-1668072603842)(media/image-20211229182504728.png)]
Layout/components
下,新建/app-footer.vue
组件,基础布局如下:
src/views/Layout.vue
中导入使用。
pinia
管理数据目标: 通过 pinia
管理项目中的数据。
核心步骤:
main.ts
中注册 pinia
import { createApp } from 'vue'
import App from './App.vue'
import 'normalize.css'
import '@/assets/styles/common.less'
import router from './router'
+ import { createPinia } from 'pinia'
+ const pinia = createPinia()
const app = createApp(App)
app.use(router)
+ app.use(pinia)
app.mount('#app')
store/modules/home.ts
,用于管理home模块的数据import { defineStore } from 'pinia';
import { ref } from 'vue';
export const useHomeStore = defineStore('home', () => {
// 准备响应式数据
const money = ref(14000);
// 记得 return 返回
return { money };
});
store/index.ts
统一管理所有的模块export * from './modules/home';
Layout/index.vue
中测试import useHomeStore from '@/store'
const home = useHomeStore()
console.log(home.money)
Pinia
获取头部分类导航**目标:**能够发送请求完成分类导航的渲染
核心代码:
store/modules/home.ts
中提供 state 和 actionsconst useHomeStore = defineStore('home', {
state: () => ({
categoryList: []
}),
actions: {
async getAllCategory() {
const res = await request.get('/home/category/head')
console.log(res)
}
}
})
Layout/index.vue
中发送请求
定义类型声明
src\types\modules\home.d.ts
中定义数据类型// 分类数据单项类型
export interface Goods {
desc: string;
id: string;
name: string;
picture: string;
price: string;
title: string;
alt: string;
};
export interface Children {
id: string;
name: string;
picture: string;
goods: Goods[];
};
export interface Category {
id: string;
name: string;
picture: string;
children: Children[];
goods: Goods[];
};
// 分类数据列表类型
export type CategoryList = Category[];
类型出口统一
src\types\index.d.ts
// 统一导出所有类型文件
export * from "./api/home";
应用
store/modules/home.ts
,给 axios
请求增加泛型import { defineStore } from "pinia";
import request from "@/utils/request";
import type { CategoryList } from "@/types";
const useHomeStore = defineStore("home", {
state: () => ({
categoryList: [] as CategoryList,
}),
actions: {
async getAllCategory() {
const res = await request.get("/home/category/head");
this.categoryList = res.data.result;
},
},
});
export default useHomeStore;
Layout/components/app-header-nav.vue
中
目标:改写 Axios 返回值的 TS 类型
Axios
二次封装,让 Axios
和 TS
类型组合使用时更方便。
// 1. Axios 实例类型
export class Axios {
// ...省略
request<T = any, R = AxiosResponse<T>>(config): Promise<R>;
get<T = any, R = AxiosResponse<T>>(url: string, config): Promise<R>;
}
// 2. AxiosResponse 返回值类型
export interface AxiosResponse<T = any, D = any> {
data: T;
// ...省略
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kj996dNM-1668072603843)(media/image-20220218165657044.png)]
import { defineStore } from "pinia";
import request from "@/utils/request";
import type { CategoryList } from "@/types";
+ interface ApiRes {
+ msg: string;
+ result: T;
+ }
const useHomeStore = defineStore({
id: "home",
state: () => ({
categoryList: [] as CategoryList,
}),
actions: {
async getAllCategory() {
- // 能用, res.data 的返回值类型为 any
- const res = await request.get("/home/category/head");
+ // 恭喜已经有 TS 类型提醒了,res.data 能提示 result 和正确的类型
+ const res = await request.get>("/home/category/head");
this.categoryList = res.data.result;
},
},
});
export default useHomeStore;
参考代码
src\utils\request.ts
- import axios from "axios";
+ import axios, { type Method } from "axios";
const instance = axios.create({
baseURL: "http://pcapi-xiaotuxian-front-devtest.itheima.net/",
timeout: 5000,
});
// 添加请求拦截器
instance.interceptors.request.use(
function (config) {
// 在发送请求之前做些什么
return config;
},
function (error) {
// 对请求错误做些什么
return Promise.reject(error);
}
);
// 添加响应拦截器
instance.interceptors.response.use(
function (response) {
return response;
},
function (error) {
// 对响应错误做点什么
return Promise.reject(error);
}
);
+ // 后端返回的接口数据格式
+ interface ApiRes {
+ msg: string;
+ result: T;
+ }
+/**
+ * axios 二次封装,整合 TS 类型
+ * @param url 请求地址
+ * @param method 请求类型
+ * @param submitData 对象类型,提交数据
+ */
+export const http = (method: Method, url: string, submitData?: object) => {
+ return instance.request>({
+ url,
+ method,
+ // 自动设置合适的 params/data 键名称,如果 method 为 get 用 params 传请求参数,否则用 data
+ [method.toUpperCase() === "GET" ? "params" : "data"]: submitData,
+ });
+};
export default instance;
使用
import { defineStore } from "pinia";
-import request from "@/utils/request";
+import { http } from "@/utils/request";
const useHomeStore = defineStore({
id: "home",
state: () => ({
categoryList: [] as CategoryList,
}),
actions: {
async getAllCategory() {
- const res = await request.get>("/home/category/head");
+ // 使用起来简洁很多
+ const res = await http("GET", "/home/category/head");
this.categoryList = res.data.result;
},
},
});
export default useHomeStore;
电商网站的首页内容会比较多,页面比较长,为了能让用户在滚动浏览内容的过程中都能够快速的切换到其它分类。需要分类导航一直可见,所以需要一个吸顶导航的效果。
核心步骤:
目标: 完成头部组件吸顶效果的实现
交互要求
实现思路
核心代码:
Layout/components/
下,新建 app-header-sticky.vue
组件
品牌
专题
+
+
+
+
在滚动到 78px
完成显示效果(添加类名)
通过滚动事件的触发,判断当前是否已经滚动了
78px
,如果大于则添加类名,否则移除类名
document.documentElement.scrollTop
获取滚动距离:class
动态控制类名显示
组件src/views/Layout/components/app-header-sticky.vue
+
// ...
目标: 使用 vueuse/core
重构吸顶功能
vueuse/core
: 组合式API
常用复用逻辑的集合https://vueuse.org/core/useWindowScroll/
核心步骤
1)安装 @vueuse/core
包,它封装了常见的一些交互逻辑
yarn add @vueuse/core
2)在吸顶导航中使用
src/components/app-header-sticky.vue
// ...
常见疑问:
vue2
项目中能使用 @vueuse/core
吗?
@vue/composition-api
让 Vue2
老项目支持 组合式API。@vueuse/core
只能以 组合式API 形式使用。**目标:**配置首页的路由,首页 Home
组件属于二级路由
核心步骤:
src/views/Home/index.vue
Home组件
{
path: '/',
component: () => import('@/views/Layout/index.vue'),
children: [
{
path: '/',
component: () => import('@/views/Home/index.vue'),
},
],
},
任务目标:
从整体角度按照模块功能进行组件拆分
1)拆分左侧分类组件
Home/components/home-category.vue
<script setup lang="ts">script>
<template>
<div class="home-category">分类组件div>
template>
<style lang="less" scoped>style>
2)拆分banner组件
Home/components/home-banner.vue
<script setup lang="ts">script>
<template>
<div class="home-banner">bannerdiv>
template>
<style scoped lang="less">
.home-banner {
width: 1240px;
height: 500px;
position: absolute;
left: 0;
top: 0;
z-index: 98;
}
style>
3)home组件中引入使用
<script setup lang="ts">
import HomeBanner from "./components/home-banner.vue";
import HomeCategory from "./components/home-category.vue";
script>
<template>
<div class="page-home">
<div class="home-entry">
<div class="container">
<HomeCategory />
<HomeBanner />
div>
div>
div>
template>
<style lang="less" scoped>style>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5gjbmqFn-1668072603845)(media/left.png)]
Home/components/home-category.vue
<script setup lang="ts">
import useStore from "@/store";
import { RouterLink } from "vue-router";
// 获取 Pinia 中的 home 模块,分类数据为 home.categoryList
const { home } = useStore();
script>
<template>
<div class="home-category">
<ul class="menu">
<li v-for="item in home.categoryList" :key="item.id">
<RouterLink to="/">{{ item.name }}RouterLink>
<RouterLink to="/">{{ "茶咖酒具" }}RouterLink>
<RouterLink to="/">{{ "水具杯壶" }}RouterLink>
li>
ul>
div>
template>
实现步骤
代码落地
1)准备布局
<div class="layer">
<h4>分类推荐 <small>根据您的购买或浏览记录推荐small>h4>
<ul>
<li v-for="i in 9" :key="i">
<RouterLink to="/">
<img src="https://yanxuan-item.nosdn.127.net/5a115da8f2f6489d8c71925de69fe7b8.png" alt="">
<div class="info">
<p class="name ellipsis-2">【定金购】严选零食大礼包(12件)p>
<p class="desc ellipsis">超值组合装,满足馋嘴欲p>
<p class="price"><i>¥i>100.00p>
div>
RouterLink>
li>
ul>
div>
2)导入新增goods字段
const list = computed(() => {
return home.categoryList.map((item) => {
return {
id: item.id,
name: item.name,
children: item.children.slice(0, 2),
// 添加 goods 字段
goods: item.goods,
}
})
})
3)渲染模板视图
<div class="layer">
<h4>分类推荐 <small>根据您的购买或浏览记录推荐small>h4>
<ul>
<li v-for="goods in item.goods" :key="goods.id">
<RouterLink to="/">
<img :src="goods.picture" alt="" />
<div class="info">
<p class="name ellipsis-2">
{{ goods.name }}
p>
<p class="desc ellipsis">{{ goods.desc }}p>
<p class="price"><i>¥i>{{ goods.price }}p>
div>
RouterLink>
li>
ul>
div>
XtxUI
组件库任务目标: 把组件库从素材文件夹,复制到项目中使用。
核心步骤:
components
文件夹下所有 XtxUI
组件,放到 src/components
中。yarn lint
或 npm run lint
格式化文件。新建测试页面:src\views\Test\index.vue
任务目标: 组件库中封装了统一出口,修改导入组件库组件的方式。
-
-
+
+ 按钮
+
**任务目标:**以插件的形式注册全局组件
核心步骤:
components/index.ts
import type { App, Plugin } from 'vue'
import Skeleton from './Skeleton/Skeleton.vue'
const XtxUI: Plugin = {
install(app: App) {
app.component(`XtxSkeleton`, Skeleton);
},
};
export default XtxUI;
main.ts
中全局注册import XtxUI from "./components/XtxUI";
const app = createApp(App)
app.use(XtxUI)
+
按钮
任务目标: 为全局组件书写对应的 TS 类型声明文件。
element-plus
源码 Element-Plus 源码链接Volar
插件说明:Volar 插件说明新建类型声明文件: src\components\XtxUI\global.d.ts
,准备基本结构
// 全局组件类型声明文件 for Volar
declare module 'vue' {
// 全局组件需要定义 interface GlobalComponents
export interface GlobalComponents {
全局组件名: 组件类型;
}
}
export { }
添加全局组件类型声明:
+// 导入 .vue 源文件
+import Button from "./Button/index.vue";
+import Skeleton from "./Skeleton/Skeleton.vue";
// 全局组件类型声明文件 for Volar
declare module "vue" {
// 全局组件需要定义 interface GlobalComponents
export interface GlobalComponents {
+ // typeof 获取 TS 类型
+ XtxButton: typeof Button;
+ XtxSkeleton: typeof Skeleton;
}
}
export {};
任务目标: 在分类模块中使用我们定义好的骨架组件增强用户体验
核心步骤:
XtxSkeleton
的使用
**任务目标:**能够使用骨架组件优化首页的分类展示
核心步骤
Home/components/home-category.vue
中优化左侧分类的展示
Layout/components/app-header-nav.vue
中优化头部导航的展示
注意:
Vue2
和 Vue3
的情况不同,Vue3
中 v-if
的优先级比 v-for
更高v-if
和 v-for
,建议配合template
标签进行处理。参考资料任务目标: 基于 pinia
获取轮播图数据
核心代码:
store/modules/home.ts
文件中封装接口,获取轮播图数据const useHomeStore = defineStore('home', {
actions: {
// ...
// 获取轮播图数据
async getBannerList() {
const res = await http('GET', '/home/banner');
console.log('/home/banner', res);
},
}
})
export default useHomeStore
Home/components/home-banner.vue
src\types\api\home.d.ts
文件中定义对应的 TS 类型声明。// 轮播图类型
export interface Banner {
id: string;
imgUrl: string;
hrefUrl: string;
type: string;
}
export type BannerList = Banner[];
store/modules/home.ts
文件中,完善 TS 类型声明。-import type { CategoryList } from '@/types'
+import type { CategoryList, BannerList } from '@/types'
const useHomeStore = defineStore('home', {
state: () => ({
// ...
// 轮播图数据
+ bannerList: [] as BannerList
}),
actions: {
// ...
// 获取轮播图数据
async getBannerList() {
- const res = await http("GET", "/home/banner");
+ const res = await http("GET", "/home/banner");
+ this.bannerList = res.data.result;
},
}
})
export default useHomeStore
**任务目标:**基于封装好的轮播图组件快速实现 Banner 模块
Home/components/home-banner.vue
新鲜好物、人气推荐俩个模块的布局结构上非常类似,我们可以抽离出一个通用的面板组件来进行复用
任务目标: 封装一个通用的面板组件。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NUzI4WPP-1668072603846)(media/panel.png)]
思路分析
核心代码
Home/components/home-panel.vue
<script setup lang="ts">
defineProps<{
title: string;
subTitle?: string;
}>();
script>
<template>
<div class="home-panel">
<div class="container">
<div class="head">
<h3>
{{ title }}<small>{{ subTitle }}small>
h3>
<slot name="right">slot>
div>
<slot>slot>
div>
div>
template>
<style scoped lang="less">
.home-panel {
background-color: #fff;
.head {
padding: 40px 0;
display: flex;
align-items: flex-end;
h3 {
flex: 1;
font-size: 32px;
font-weight: normal;
margin-left: 6px;
height: 35px;
line-height: 35px;
small {
font-size: 16px;
color: #999;
margin-left: 20px;
}
}
}
}
style>
Home/index.vue
<script setup lang="ts">
import HomeBanner from './components/home-banner.vue';
import HomeCategory from './components/home-category.vue';
import HomePanel from './components/home-panel.vue';
script>
<template>
<div class="page-home">
<div class="home-entry">
<div class="container">
<HomeCategory />
<HomeBanner />
div>
div>
<HomePanel title="大标题" sub-title="副标题">
<template #right>
<XtxMore />
template>
<h2>我是主体内容-默认插槽h2>
HomePanel>
div>
template>
<style lang="less" scoped>style>
目标:封装一个新鲜好物的组件,用于处理新鲜好物模块。
Home/components/home-new.vue
-
情侣款时尚户外轻型徒步鞋环保大底
¥364.00
src\views\Home\index.vue
,引入并使用组件。
...
store/modules/home.ts
文件中封装请求// ...
const useHomeStore = defineStore('home', {
// ...
actions: {
// ...
async getNewGoodsList() {
const res = await http('GET', '/home/new');
console.log('/home/new', res);
}
}
})
Home\components\home-new.vue
组件中,调用 actions 获取数据
// 电商网站商品的类型基本一致,可以复用
export interface Goods {
id: string;
name: string;
desc: string;
price: string;
picture: string;
orderNum: number;
}
// 商品列表类型(可以复用)
export type GoodsList = Goods[];
store/modules/home.ts
文件中的类型import { defineStore } from 'pinia'
import { http } from '@/utils/request'
-import type { CategoryList, BannerList } from '@/types'
+import type { CategoryList, BannerList, GoodsList } from '@/types'
const useHomeStore = defineStore('home', {
state: () => ({
// ...
+ newGoodsList: [] as GoodsList
}),
actions: {
// ...
async getNewGoodsList() {
- const res = await http("GET", "/home/new");
+ const res = await http("GET", "/home/new");
+ this.newGoodsList = res.data.result
}
}
})
export default useHomeStore
Home\components\home-new.vue
组件中,完成列表渲染
-
{{ item.name }}
¥{{ item.price }}
温馨提示:人气推荐的逻辑和新鲜好物的逻辑基本一致
(1)发送请求,获取数据 src/store/modules/home.ts
const useHomeStore = defineStore('home', {
state: () => ({
+ hotGoodsList: [] as GoodsList
}),
actions: {
+ async getHotGoodsList() {
+ const res = await http("GET", "/home/hot");
+ this.hotGoodsList = res.data.result
+ }
}
})
(2)创建组件Home/components/home-hot.vue
-
{{ item.title }}
{{ item.alt }}
(3)首页中渲染src/views/home/index.vue
电商项目核心优化技术手段:组件数据懒加载 (首屏渲染优化)
说明:电商类网站的首页内容会有好几屏,如果直接加载并渲染所有屏的数据,会比较浪费性能。
优化:应该 当模块进入到 可视区 ,再发请求获取数据
。
任务目标:
了解如何检测目标元素的可见性
技术方案:
我们可以使用 @vueuse/core
中的 useIntersectionObserver
来实现监听组件进入可视区域行为,
需要配合 vue3
的组合 API
的方式才能实现
https://vueuse.org/core/useIntersectionObserver/
先分析下这个useIntersectionObserver
函数:
我是目标元素
我们以新鲜好物模块为例演示一下这个函数的使用方式
1)通过 ref
属性获得组件实例并测试
2)使用useIntersectionObserver
监听函数
<script setup lang="ts">
import HomePanel from "./home-panel.vue";
import { ref } from "vue";
import { useIntersectionObserver } from "@vueuse/core";
import useStore from "@/store";
const { home } = useStore();
// 通过 ref 获得组件实例
const target = ref(null);
const { stop } = useIntersectionObserver(
// target 被检测的目标元素
target,
// isIntersecting 是否进入可视区域
([{ isIntersecting }]) => {
// 在此处可根据isIntersecting来判断,然后做业务
console.log('是否进入可视区域', isIntersecting);
if (isIntersecting) {
home.getHotGoodsList();
stop();
}
}
);
script>
<template>
<div class="home-hot">
<HomePanel ref="target" title="人气推荐" sub-title="人气爆款 不容错过">
...
HomePanel>
div>
template>
3)测试效果
打开浏览器,人气推荐模块还未进入到可视区,打印值为false,
然后我们滑动页面,当人气模块
组件进入可视区中时,再次发生打印,此时为true,
到此我们就可以判断组件进入和离开可视区了
**特别注意:**每次被监听的dom进入离开可视区时都会触发一次,而不是只触发一次, 可以stop关闭监听
任务目标:
利用我们捋清楚的发送请求的位置实现业务数据拉取完成实际业务功能
实现步骤
isIntersecting
为true时触发代码落地
<script setup lang="ts">
// ...省略
script>
<HomePanel ref="target" title="人气推荐" sub-title="人气爆款 不容错过">...HomePanel>
本节目标:
抽离组件数据懒加载可复用的逻辑
首页中,很多地方都应该使用组件数据懒加载这个功能,不管是哪个模块使用,下面代码都会重复书写
事实上,唯一可能会随着业务使用发生变化的是 ajax接口的调用
其余的部分我们进行重复使用,抽离为可复用逻辑
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tNzOgAbJ-1668072603847)(media/cma1.png)]
1)抽离逻辑
src/hooks/index.ts
import { useIntersectionObserver } from "@vueuse/core";
import { ref } from "vue";
/**
* 请求按需加载
* @param apiFn 发送请求函数
* @returns target 用于模板绑定
*/
export const useObserver = (apiFn: () => void) => {
// 准备个 ref 用于绑定模板中的某个目标元素(DOM节点或组件)
const target = ref(null);
const { stop } = useIntersectionObserver(target, ([{ isIntersecting }]) => {
console.log("是否进入可视区域", isIntersecting);
if (isIntersecting) {
// 当目标元素进入可视区域时,才发送请求
apiFn();
// 请求已发送,主动停止检查
stop();
}
});
// 返回 ref 用于模板绑定,建议返回对象格式支持解构获取
return { target };
};
2)业务改写
骨架组件 - 优化默认显示结构
-
Pinia
持久化存储 - 首页数据缓存目标: 通过 Pinia
插件快速实现持久化存储。
插件文档:点击查看
安装
yarn add pinia-plugin-persistedstate
# 或
npm i pinia-plugin-persistedstate
使用插件
+ import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia();
+ pinia.use(piniaPluginPersistedstate);
app.use(pinia);
模块开启持久化
const useHomeStore = defineStore("home",{
+ persist: true
state:()=>({})
// ...省略
});
Vue2
能不能用 Pinia
和 持久化存储插件。
@vue/composition-api
先让 Vue2
老项目支持 组合式API
。Pinia
能在 组合式API
中使用。需求:不想所有数据都持久化处理,能不能按需持久化所需数据,怎么办?
import { defineStore } from 'pinia'
export const useStore = defineStore('main', {
state: () => ({
someState: 'hello pinia',
nested: {
data: 'nested pinia',
},
}),
// 所有数据持久化
// persist: true,
// 持久化存储插件其他配置
persist: {
// 修改存储中使用的键名称,默认为当前 Store的 id
key: 'storekey',
// 修改为 sessionStorage,默认为 localStorage
storage: window.sessionStorage,
// 按需持久化,默认不写会存储全部
paths: ['nested.data'],
},
})