vue项目的pinia存储封装
2022年1月16日大约 4 分钟约 1075 字
安装本章依赖包
在store/user.js
文件中使用了用户的密码md5加密,需要安装md5依赖包
npm install --save js-md5
存储封装
store/index.js
import { createPinia } from 'pinia'
const pinia = createPinia()
export default pinia
// 这里需要单独创建一个pinia实例,并在main.ts中注册,也可以被其他模块引用
// 如果直接在main.ts中创建并注册,那么可能在注册前就需要使用pinia就会报错,比如在permissions.js中使用
store/system.js
// 关于系统内部的使用
import { defineStore } from 'pinia'
const useSystemStore = defineStore('system', () => {
// 标签栏数据,里面是route对象列表
const tagsViewList = ref([])
// 将route对象添加进列表
function addTagsViewList(route) {
const isFind = tagsViewList.value.find(item => {
return item.path === route.path
})
// 处理重复
if (!isFind) {
tagsViewList.value.push(route)
}
}
// 关闭标签也
function removeTagsView(payload) {
// 关闭指定页面
if (payload.type === 'index') {
tagsViewList.value.splice(payload.index, 1)
return
// 关闭其他所有页面
} else if (payload.type === 'other') {
tagsViewList.value.splice(
payload.index + 1,
tagsViewList.value.length - payload.index + 1
)
tagsViewList.value.splice(0, payload.index)
// 关闭右侧所有页面
} else if (payload.type === 'right') {
tagsViewList.value.splice(
payload.index + 1,
tagsViewList.value.length - payload.index + 1
)
}
}
return { tagsViewList, addTagsViewList, removeTagsView }
})
export default useSystemStore
store/settings.js
// 关于项目的配置信息
import { defineStore } from 'pinia'
const useSettingStore = defineStore('setting', () => {
// 侧边栏是否打开
const sidebarOpened = ref(true) // 侧边栏伸缩
// 侧边栏伸缩
function triggerSidebarOpened() {
sidebarOpened.value = !sidebarOpened.value
}
return { sidebarOpened, triggerSidebarOpened }
})
export default useSettingStore
store/theme.js
// 关于项目的主题配置
import { defineStore } from 'pinia'
const useThemeStore = defineStore('theme', () => {
// 主题色
const themeName = ref('克莱因蓝')
const mainBg = ref('rgb(27,55,121)')
const secondaryBg = ref('rgb(27,55,121)')
const mainText = ref('rgb(242,240,235)')
const secondaryText = ref('rgb(242,240,235)')
const activeText = ref('rgb(255,255,255)')
// 本地主题列表
const themeList = [
{
name: '朱砂红',
mainBg: 'rgb(242,25,33)',
secondaryBg: 'rgb(242,25,33)',
mainText: 'rgb(252,240,235)',
secondaryText: 'rgb(255,240,235)',
activeText: '#93ACBC'
}
]
// 返回主题名称列表
function getThemeNameList() {
nameList = []
themeList.forEach(theme => nameList.push(theme.name))
return nameList
}
// 修改主题
function changeTheme(name) {
themeList.forEach(theme => {
if (theme.name === name) {
// 如果查询到该主题,则将属性一个个替换掉
for (let key in theme) {
this[key] = theme[key]
}
}
})
}
return { mainBg, secondaryBg, mainText, secondaryText, activeText, changeTheme, getThemeNameList }
})
export default useThemeStore
store/user.js
import { defineStore } from 'pinia'
import { ref, computed, reactive, toRefs, shallowRef } from 'vue'
import router from '../router'
import md5 from 'js-md5' // npm install js-md5
import request from '@/api/index.ts'
const useUserStore = defineStore(
'user',
() => {
// ref 代替 state属性
const username = ref(localStorage.username) || ref('') // 用户名
const userinfo_init = { avatar: '', permission: {}, role: {}, title: '', username: '' }
const userinfo = shallowRef({})
const name = ref('张三') // 昵称
const age = ref(localStorage.age) || ref(0) // 年龄
const token = ref(localStorage.token) || ref('')
const refresh = ref(localStorage.refresh) || ref('')
// const failure_time = ref(localStorage.failure_time) || ref('2022-01-01') // token过期时间
// const permissions = ref(localStorage.permissions) || ref(['', '', '']) // 权限
// computed 代替 getters属性,用来封装计算属性
// 判断是否登录
const hasLogin = computed(() => {
return !!token.value
})
// 判断是否存在用户信息
const hasUserinfo = computed(() => {
// return JSON.stringify(userinfo.value) !== '{}'
// return JSON.stringify(userinfo) !== JSON.stringify(userinfo_init)
return false
})
// function 代替 actions属性,编辑业务逻辑
function login(data) {
const { username, password } = data
const password_md5 = md5(password)
return new Promise((resolve, reject) => {
// 通过 mock 进行登录
// request.post('/login', data, { baseURL: '/' })
request
.post('/sys/login', { username: username, password: password_md5 })
.then(res => {
console.log(res.access)
console.log(res.refresh)
localStorage.setItem('token', res.token)
// localStorage.setItem('refresh', res.refresh) // 刷新码
this.token = res.token
// this.refresh = res.refresh
// token.value = res.access
// refresh.value = res.refresh
router.push('/')
resolve()
})
.catch(error => {
reject(error)
})
})
}
function logout() {
// pinia中使用setup风格定义的store不能使用$reset()方法
token.value = ''
localStorage.clear()
// 清空session
sessionStorage.clear()
router.push('/login')
console.log('退出登录完成。')
}
async function getUserinfo(context) {
const res = await request.get('/sys/profile')
console.log('已获取用户信息')
this.userinfo = res
return res
}
function setAge(data) {
age.value = data
}
return { username, name, age, token, hasLogin, login, logout, getUserinfo, setAge, refresh, userinfo, hasUserinfo }
},
{
// 第三个参数作为其他插件配置
persist: {
enabled: true // 开启缓存,默认会存储在本地localstorage,且是整个store都存储
// storage: sessionStorage, // 缓存使用方式
// paths:[], // 需要缓存键
// strategies: [
// { storage: sessionStorage, paths: ['firstName', 'lastName'] }, // firstName 和 lastName字段用sessionStorage存储
// { storage: localStorage, paths: ['accessToken'] }, // accessToken字段用 localstorage存储
// ],
}
}
)
export default useUserStore
网络上有一些自定义的
store.reset()
,几乎都会导致pinia
中ref(object)
不可用的Bug
本章总结
本章至此,只需要store/index.js
和store/user.js
文件就可以正常启动项目。
启动项目:npm run dev
访问主页(会自动跳转到登录页面):
- http://localhost:8080
访问其他页面时需要在permission.js
文件中配置白名单。
访问其他页面:
- http://localhost:8080/#/user
- http://localhost:8080/#/user/role
如果启动项目后Tailwind CSS
发出了警告,可能是项目中还没有使用过TailwindCSS代码,可以不用管。