简介:公司项目使用 vue3 已经大半年了,在没有 vue3 生态支持的情况下,把公司项目顺利完成了。期间很多 vue2 时的解决方案没法用呀,没办法只能自己写,期间自己相继写了vue-meta
的简易实现,vue-pdf
的简易实现,vuex-persistedstate
的简易实现,现把vuex-persistedstate
的实现记录如下。(vuex-persistedstate
已经出了支持 vue3 的 beta 版本)
本文 github 源码地址
{
"core-js": "^3.6.5",
"vue": "3.0.5",
"vuex": "^4.0.0"
}
.
├── README.md
├── babel.config.js
├── package-lock.json
├── package.json
├── public
│ ├── favicon.ico
│ └── index.html
└── src
├── App.vue
├── assets
│ └── logo.png
├── main.js
└── store
├── index.js
└── plugins
└── persistedstate.js # 核心源码实现
src/store/plugins/persistedstate.js
export default (options = {}) => {
const storage = options.storage || (window && window.localStorage)
const key = options.key || 'vuex'
// 获取state的值
const getState = (key, storage) => {
const value = storage.getItem(key)
try {
return typeof value !== 'undefined' ? JSON.parse(value) : undefined
} catch (err) {
console.log(err)
}
return undefined
}
// 设置state的值
const setState = (key, state, storage) =>
storage.setItem(key, JSON.stringify(state))
return store => {
// 初始化时获取数据,如果有的话,把原来的vuex的state替换掉
const data = getState(key, storage)
if (data) {
store.replaceState(data)
}
// 订阅 store 的 mutation。handler 会在每个 mutation 完成后调用,接收 mutation 和经过 mutation 后的状态作为参数
store.subscribe((mutation, state) => {
setState(key, state, storage)
})
}
}
src/store/index.js
import { createStore, createLogger } from 'vuex'
import createPersistedstate from './plugins/persistedstate'
const debug = process.env.NODE_ENV !== 'production'
export default createStore({
state: {
loginStatus: 0,
userInfo: {}
},
getters: {
loginStatus: state => state.loginStatus,
userInfo: state => state.userInfo
},
mutations: {
SET_USER_INFO(state, userInfo) {
state.userInfo = userInfo
},
SET_LOGIN_STATUS(state, loginStatus) {
state.loginStatus = loginStatus
}
},
actions: {
setUserInfo({ commit }, userInfo) {
commit('SET_USER_INFO', userInfo)
},
setLoginStatus({ commit }, loginStatus) {
commit('SET_LOGIN_STATUS', loginStatus)
}
},
plugins: debug
? [createLogger(), createPersistedstate()]
: [createPersistedstate()]
})
src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import store from './store'
createApp(App).use(store).mount('#app')
src/App.vue
<template>
<img class="avatar" :src="userInfo.avatar" />
<h1>我的名字叫 {{ userInfo.name }}h1>
<button v-if="!loginStatus" @click="handleLogin">登录button>
<div v-else>
<button @click="handleChange">更改身份button>
<button @click="handleLogout">退出button>
div>
template>
<script>
import { useStore } from 'vuex'
import { computed } from 'vue'
export default {
name: 'App',
setup() {
const store = useStore()
const loginStatus = computed(() => store.getters.loginStatus)
const userInfo = computed(() => store.getters.userInfo)
// 登录
const handleLogin = () => {
store.dispatch('setLoginStatus', 1)
store.dispatch('setUserInfo', {
name: '小明',
avatar: require('@/assets/logo.png')
})
}
// 更改身份
const handleChange = () => {
store.dispatch('setUserInfo', {
name: Math.random().toString(16).slice(2),
avatar: require('@/assets/logo.png')
})
}
// 退出
const handleLogout = () => {
store.dispatch('setLoginStatus', 0)
store.dispatch('setUserInfo', {})
}
return {
loginStatus,
userInfo,
handleLogout,
handleLogin,
handleChange
}
}
}
script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
#app .avatar {
width: 60px;
border-radius: 50%;
}
#app button {
width: 120px;
height: 40px;
line-height: 40px;
font-size: 16px;
background-color: #409eff;
color: #fff;
border: 0;
cursor: pointer;
margin-right: 20px;
}
#app button:focus {
border: 0;
outline: 0;
}
style>
参考链接
1.https://github.com/robinvdvleuten/vuex-persistedstate/blob/master/src/index.ts
2.https://next.vuex.vuejs.org/api/#subscribe