vue 2中使用pinia

1 篇文章 0 订阅
现在Vue官网主推pinia替代vuex,而且兼容Vue2、3版本。于是想着将某个项目中的vuex去换成pinia来体验一下。就此记录一下Vue2的场景和使用感受。
	├── src  
	  ├── api
	  ├── assets
	  ├── components
	  ├── directive
	  ├── layout
	  ├── router
	  ├── pinia
		  ├── modules
		      ├── app.js
		      ├── permission.js
		      ├── settings.js
		      ├── tagsViews.js
		  ├── defineStore.js
		  ├── index.js
	  ├── utils
	  ├── views
	  ├── App.vue
	  ├── main.js
	  ├── permission.js
	  └── settings.js
使用方式

npm install @vue/composition-api pinia pinia-plugin-persistedstate -S
pinia持久化插件 ‘pinia-plugin-persistedstate’
Vue2 版本需要用到这个 PiniaVuePlugin
Vue2版本使用pinia需要安装@vue/composition-api

/** main.js */
import Vue from "vue";
import App from "@/App.vue";
Vue.config.productionTip = false

import router from "@/router";
import pinia from "@/pinia";

import { PiniaVuePlugin, setMapStoreSuffix } from 'pinia';
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
pinia.use(piniaPluginPersistedstate);
setMapStoreSuffix('_pinia'); 
Vue.use(PiniaVuePlugin);

import ElementUI from "element-ui"
import "element-ui/lib/theme-chalk/index.css";
Vue.use(ElementUI);
import "@/assets/icons";

import "@/assets/icons";
import "@/assets/css/global.scss";
import "@/assets/css/common.scss";
import '@/permission';


new Vue({
  router,
  pinia,
  render: (h) => h(App),
}).$mount("#app");
	- pinia的模块封装,有的位置需要用到构建后的pinia,在vue2中最常见就是这个createPinia这个报错提示,这个解决犯法还是github中pinia issues 中找到解决方式。
	- 还有一个目的就是为什么要二次封装一次,这个目的就是省去创建···createPinia···这个步骤。

在这里插入图片描述

对pinia进行配置
/** pinia/index.js */ 
import { createPinia } from 'pinia';

const pinia = createPinia();

export default pinia;

export { default as settings } from './modules/settings';
export { default as app } from './modules/app';
export { default as permission } from './modules/permission';
export { default as user } from './modules/user';
export { default as tagsViews } from './modules/tagsViews';
/** defineStore.js  */
import { defineStore as useStore } from 'pinia'
import pinia from '@/pinia';

/** 二次改造 defineStore */
export const defineStore = (...args) => {
  var store = useStore(...args);
  return (p = pinia) => store(p);
}
定义Store
id:唯一Key、重复定义会失效或覆盖。
state:状态库、必须是函数,否则会报错。
actions:事件逻辑区,可以通过this访问state数据,也可以使用this.$path({})设置响应式状态,重要是支持异步,async、await关键字,都能被vue-devTool获取到改变。
getters:计算属性,用于需要二次加工的属性。
persist:安装pinia持久化插件支持,当然vuex也有相应的插件,有三个主要配置属性
	- key:用于存取本地存储的key值,模块相同数据会被覆盖。
	- storage:存储方式,默认为localStorage
	- paths:存储的属性,以数组作为集合,不支持函数形式。
/** pinia/modules/user.js */
import { defineStore } from '../defineStore'
import { getInfo, login, logout } from '@/api/login'
import { getToken, setToken, removeToken } from '@/utils/auth';
export default defineStore({
  id: "user",
  state() {
    return {
      token: getToken(),
      name: '',
      avatar: '',
      roles: [],
      permissions: [],
    }
  },
  actions: {
 	    getInfo() {
      return new Promise((resolve, reject) => {
        (async () => {
          try {
            const res = await getInfo();
            const user = res.user
            const avatar = user.avatar == "" ? require("@/assets/images/profile.jpg") : process.env.VUE_APP_BASE_API + user.avatar;
            if (res.roles && res.roles.length > 0) {
              this.roles = res.roles
              this.permissions = res.permissions
            } else {
              this.roles = ['ROLE_DEFAULT']
            }
            this.name = user.userName;
            this.avatar = avatar;
            resolve(res)
          } catch (error) {
            reject(error)
          }
        })();
      })
    },
    login(userInfo) {
      return new Promise((resolve, reject) => {
        (async () => {
          try {
            const { token } = await login(userInfo);
            setToken(token);
            this.token = token
            resolve();
          } catch (error) {
            reject(error);
          }
        })();
      });
    },
    logOut() {
      return new Promise((resolve, reject) => {
        try {
          logout(this.token);
          this.token = '';
          this.roles = [];
          this.permissions = [];
          removeToken()
          resolve();
        } catch (error) {
          reject(error);
        }
      })
    },
    },
  getters: {},
  persist: {
    key: 'user-key',
    storage: window.sessionStorage,
    paths: ['token']
  },
});
组件外去使用Store
这里演示如何在组件外如何去使用pinia
	- import { settings, permission, user } from '@/pinia';。
	- 以此创建即可 const settingsStore = settings(); 不做这个步骤pinia会报一个 setting 没有 install。
	- settingsStore.setTitle(to.meta.title); 这个store表示的就是文件实例,你可以任意去使用里面的方法了。
	- permission().setTitle(to.meta.title) 这样写也是行的。有时候会出现useStore的错误,这个报错不是很明确,不做多解释。
/** src/permission.js */
import router from './router';
import { settings, permission, user } from '@/pinia';
import { Message } from 'element-ui';
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
import { getToken } from '@/utils/auth';
const whiteList = ['/login', '/auth-redirect', '/bind', '/register'];

const settingsStore = settings();
const permissionStore = permission();
const userStore = user();

NProgress.configure({ showSpinner: true });

router.beforeEach((to, from, next) => {
  NProgress.start();
  if (getToken()) {
    hasToken(to, from, next);
  } else {
    voidToken(to, from, next);
  }
});

router.afterEach(NProgress.done);
async function hasToken(to, from, next) {
  to.meta.title && settingsStore.setTitle(to.meta.title);
  if (to.path === '/login') return next({ path: '/' }), NProgress.done();
  if (userStore.roles.length !== 0) return next();
  try {
    await userStore.getInfo();
    const accessRoutes = await permissionStore.GenerateRoutes();
    accessRoutes.forEach(item => router.addRoute(item));
    next({ ...to, replace: true });
  } catch (err) {
    console.error("ERROR", err);
    await userStore.logOut();
    Message.error(err || 'Has Error');
    next({ path: '/' });
  }
}
async function voidToken(to, from, next) {
  if (whiteList.indexOf(to.path) !== -1) return next();
  next(`/login?redirect=${to.fullPath}`);
  NProgress.done();
}
组件内对Store的使用
	这里演示组件内如何去使用pinia
	mapAction:第一个参数为实例的对象,第二个是其中的方法,多个模块依次导入即可
	this.$pinia 也是可以访问到pinia对象。
/** src/layout/components/Navbar/index.vue */
<script>
import { mapState, mapActions } from 'pinia';
import { app, user, settings } from '@/pinia';
import Hamburger from './Hamburger';
import Breadcrumb from './Breadcrumb';
import TopNav from './TopNav';
import Search from './Search';
import Screenfull from './Screenfull';
export default {
  name: 'Navbar',
  components: { Hamburger, Breadcrumb, TopNav, Search, Screenfull },

  methods: {
    ...mapActions(user, ['logOut']),
    ...mapActions(settings, ['changeSetting']),
    ...mapActions(app, ['toggleSideBar']),
    async logout() {
      const confirmText = await this.$confirm('确定注销并退出系统吗?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).catch(err => err);
      if (confirmText !== 'confirm') return;
      try {
        await this.logOut();
        location.href = '/';
      } catch (error) {
        this.$message.error(error.message);
      }
    }
  },
  computed: {
    ...mapState(app, ['sidebar', 'device']),
    ...mapState(user, ['avatar', 'topNav']),
    ...mapState(settings, ['showSettings']),
    setting: {
      get() {
        return this.showSettings;
      },
      set(value) {
        this.changeSetting({ key: 'showSettings', value });
      }
    },
  }
  //  End
}
storeToRefs
		storeToRefs 这个方法是pinia解构出来的,这个使用是例子是官网的代码。
			- 传递一个defineStore实例切调用,返回值是vue3的ref响应式对象,需要使用xxx.value.properties拿到属性。
			- 可以在组件中直接修改这个响应式.value的属性,这个也能被vue-dev-tool监测到变化,无需配合actions函数。
			- 可以在vue2中体会到vue3的composition-api。
/** src/views/system/menuManagement/index.vue */
<template>
  <el-row class="mt-95" :gutter="20">

    <el-col class="" :span="8" :push="8">
      <el-switch v-model="value" :before-change="beforeChange" :loading="loading" activeValue="yes" inactiveValue="no" active-color="#13ce66" width="80" active-text="按月付费" inactive-text="按年付费" />
    </el-col>

  </el-row>
</template>

<script>
import { mapState, mapActions, storeToRefs } from 'pinia'
import { useCounterStore } from '@/pinia'
export default {
  name: 'menuManagement',
  data() {
    return {
      value: 'no',
      loading: false,
    };
  },

  methods: {
    ...mapActions(useCounterStore, ['increment']),
    beforeChange() {
      this.loading = true;
      return new Promise((resolve) => {
        setTimeout(() => {
          this.$message.success('switch success');
          resolve()
          this.loading = false;
          const { count } = storeToRefs(useCounterStore());
          console.log(count);
          this.increment();
          count.value = 100
        }, 3000)
      })
    }
  },
  computed: {
    ...mapState(useCounterStore, {
      counter: state => state.count
    })
  },
  //  End
}

</script>

<style lang='css' scoped>
</style>

最后对pinia做个总结吧,在vue2中个人感觉耦合性不是很高,报错不是清晰,有时候一个使用小错误导致整个代码阻塞,加上报错不清晰。会显得很坑。vue2还是使用vuex比较清晰。毕竟这个是vue3而设计的状态管理。

案例连接: 将vuex替换pinia

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值