IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> pinia原理 -> 正文阅读

[JavaScript知识库]pinia原理

pinia原理

创建项目

  • 新建项目vite-pinia
  • 创建vite项目
  • 安装pinia
mkdir vite-pinia
cd vite-pinia
yarn create vite
yarn add pinia
code .

使用pinia

  • main.js
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import { createPinia } from 'pinia'
const app = createApp(App)
app.use(createPinia()).mount('#app')

  • scr/store/index.js
import { defineStore } from "pinia";
export const useStore = defineStore({
  id: "main",
  state: () => {
    return {
      a: 1,
    };
  },
  getters: {
    double: (store) => {
      return store.a * 2;
    },
  },
  actions: {
    add(num) {
      this.a += 1;
    },
  },
});

  • app.vue
<script setup>
import { useStore } from './store/index'
const counter = useStore()

const counterAdd = (num)=>{
  counter.add(num)
}
</script>

<template>
  <div>
    {{counter.a}}
    {{counter.double}}
    <button @click="counter.a++">直接累加</button>
    <button @click="counterAdd(1)">点击</button>
    </div>

</template>

<style scoped>

</style>

使用自己的pinia

  • vite.config.js中添加@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  resolve:{
    //设置路径别名
    alias: {
      '@': path.resolve(__dirname, './src'),
      }
  }
})

  • mian.js修改为@/pinia
import { createApp } from 'vue'
// import './style.css'
import App from './App.vue'
import { createPinia } from '@/pinia'
const app = createApp(App)
app.use(createPinia()).mount('#app')
  • store/index.js
import { defineStore } from "@/pinia";
export const useStore = defineStore({
  id: "main",
  state: () => {
    return {
      a: 1,
    };
  },
  getters: {
    double: (store) => {
      return store.a * 2;
    },
  },
  actions: {
    add(num) {
      this.a += 1;
    },
  },
});

  • src下新增pinia文件夹,添加index.js

实现pinia的store

  • pinia/index.js
  • 导出两个方法,defineStore定义store,createPinia创建一个pinia
import { defineStore } from "./defineStore";

import { createPinia } from "./createPinia";

export {
    defineStore,
    createPinia
}
  • defineStore.js
import { effectScope, getCurrentInstance, inject, reactive } from "vue";
import { SymbolPinia } from "./rootStore";

export function defineStore(idOrOptions, setup) {
    // 第一个参数可能是id,或者对象
  let id;
  let options;

  if (typeof idOrOptions === "string") {
    id = idOrOptions;
    options = setup;
  } else {
    options = idOrOptions;
    id = idOrOptions.id;
  }

  function useStore() {
    // 获取当前vue运行的实例
    const currentInstance = getCurrentInstance();
    const pinia = currentInstance && inject(SymbolPinia);
    // 如果实例存在,用inject注册到当前实例上

    if (!pinia._s.has(id)) {
        // 判断当前store上面有没有已经注册过的id
      createOptionsStore(id, options, pinia);
    }
    const store = pinia._s.get(id);
    return store;
  }
  return useStore;
}

function createOptionsStore(id, options, pinia) {
  let { state, getters, actions } = options;

  let scope;

  const store = reactive({});

  function setup() {
    // pinia.state是一个ref 要用value接受值
    pinia.state.value[id] = state ? state() : {};
    const localState = pinia.state.value[id];

    return localState;
  }

  const setupStore = pinia._e.run(() => {
    scope = effectScope();
    return scope.run(() => setup());
  });
  

//   把当前的setupStore 合并到reactive里面,确保是一个响应式
  Object.assign(store, setupStore);

  pinia._s.set(id, store);
}
  • createPinia.js
import { effectScope, markRaw, ref } from "vue";
import { SymbolPinia } from "./rootStore";

export function createPinia() {
  const scope = effectScope(true);
  const state = scope.run(() => ref({}));
  const pinia = markRaw({
    install(app) {
      pinia._a = app;
      app.provide(SymbolPinia, pinia);
      app.config.globalProperties.$pinia = pinia;
    },
    _a: null,
    state,
    // 管理整个应用
    _e: scope,
    // 记录所有的store
    _s: new Map(),
  });

  return pinia
}
  • 测试页面是否能展示出来 a 的值

实现pinia的getters

  • setup方法
function setup() {
    // pinia.state是一个ref 要用value接受值
    pinia.state.value[id] = state ? state() : {};
    //  localState 的值要转换响应式,否则getter不能响应
    const localState = toRefs(pinia.state.value[id]);
    return Object.assign(
      localState,
      actions,
      Object.keys(getters || {}).reduce((computedCetters, name) => {
        computedCetters[name] = computed(() => {
            // 获取当前的store
           return getters[name].call(store,store)
        });
        return computedCetters
      },{})
    );
  }

实现pinia的actions

  • createOptionsStore方法
function createOptionsStore(id, options, pinia) {
  let { state, getters, actions } = options;

  let scope;

  const store = reactive({});

  function setup() {
    // pinia.state是一个ref 要用value接受值
    pinia.state.value[id] = state ? state() : {};
    const localState = pinia.state.value[id];

    return Object.assign(localState, actions);
  }

  const setupStore = pinia._e.run(() => {
    scope = effectScope();
    return scope.run(() => setup());
  });

  function warpAction(name, action) {
    return function () {
      // 触发action
      let ret = action.apply(store, arguments);
      return ret;
    };
  }

  for (let key in setupStore) {
    const prop = setupStore[key];
    if (typeof prop === "function") {
      // 解决 action中this的问题  解构赋值时候,this会改变
      // const counter = useStore()
      // const {add} = counter
      // const counterAdd = (num)=>{
      //   add(num)
      // }
      setupStore[key] = warpAction(key, prop);
    }
  }

  //   把当前的setupStore 合并到reactive里面,确保是一个响应式
  Object.assign(store, setupStore);

  pinia._s.set(id, store);
}

pinia的参数是函数的时候

  • 修改store/index.js
import { defineStore } from "@/pinia";
import { computed, reactive, toRefs } from "vue";
export const useStore = defineStore('mian',()=>{
  const state = reactive({a:1})
  const double = computed(()=>{
    return state.a*2
  })
  const add = (num)=> state.a +=num
  return { ...toRefs(state),double,add }
})
  • 修改defineStore.js
import {
  computed,
  effectScope,
  getCurrentInstance,
  inject,
  reactive,
  toRefs,
} from "vue";
import { SymbolPinia } from "./rootStore";

export function defineStore(idOrOptions, setup) {
  // 第一个参数可能是id,或者对象
  let id;
  let options;

  if (typeof idOrOptions === "string") {
    id = idOrOptions;
    options = setup;
  } else {
    options = idOrOptions;
    id = idOrOptions.id;
  }

  const isSetupStore = typeof setup === "function";

  function useStore() {
    // 获取当前vue运行的实例
    const currentInstance = getCurrentInstance();
    const pinia = currentInstance && inject(SymbolPinia);
    // 如果实例存在,用inject注册到当前实例上

    if (!pinia._s.has(id)) {
      // 判断当前store上面有没有已经注册过的id
      if (isSetupStore) {
        createSetupStore(id, setup, pinia);
      } else {
        createOptionsStore(id, options, pinia);
      }
    }
    const store = pinia._s.get(id);
    return store;
  }
  return useStore;
}

function createSetupStore(id,setup,pinia){
    const store = reactive({});
    let scope;
    const setupStore = pinia._e.run(() => {
        scope = effectScope();
        return scope.run(() => setup());
      });
      function warpAction(name, action) {
        return function () {
          // 触发action
          let ret = action.apply(store, arguments);
          return ret;
        };
      }
      for (let key in setupStore) {
        const prop = setupStore[key];
        if (typeof prop === "function") {
          // 解决 action中this的问题  解构赋值时候,this会改变
          // const counter = useStore()
          // const {add} = counter
          // const counterAdd = (num)=>{
          //   add(num)
          // }
          setupStore[key] = warpAction(key, prop);
        }
      }
      //   把当前的setupStore 合并到reactive里面,确保是一个响应式
      Object.assign(store, setupStore);
      pinia._s.set(id, store);
      return store
}

function createOptionsStore(id, options, pinia) {
  let { state, getters, actions } = options;
  function setup() {
    // pinia.state是一个ref 要用value接受值
    pinia.state.value[id] = state ? state() : {};
    const localState = toRefs(pinia.state.value[id]);
    return Object.assign(
      localState,
      actions,
      Object.keys(getters || {}).reduce((computedCetters, name) => {
        computedCetters[name] = computed(() => {
          // 获取当前的store
          return getters[name].call(store, store);
        });
        return computedCetters;
      }, {})
    );
  }
  const store = createSetupStore(id,setup,pinia)
  return store

}

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-09-13 11:05:12  更:2022-09-13 11:08:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 10:20:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码