Vue3 状态机配置

状态机配置

一、全局挂载 pinia

main.ts 中全局挂载 pinia 对象:

import { createPinia } from 'pinia'
const pinia = createPinia()

const app = createApp(App)
// ...
app.use(pinia);
app.mount('#app');

二、store 的基本配置

import { defineStore } from 'pinia'

const useRolesStore = defineStore('roles', {
    // 定义公共数据
    state: () => ({}),
    // 定义公共计算属性
    getters: {},
    // 定义公共的方法(同步和异步)
    actions: {}
});

export default useRolesStore;

三、state 和 action 的使用

state:用来存储数据,接收的是一个箭头函数的返回值,不能直接接收一个对象

const useRolesStore = defineStore('roles', {
    //state类似于组件的data,用来存储全局状态的
    //state必须是函数:这样是为了在服务端渲染的时候避免交叉请求导致的数据状态污染
    //必须是箭头函数,这是为了TS更好的类型推导
    state: () => ({
        rolesData: []
    }),
    getters: {},
    actions: {
        async getRolesAsync() {
            const res: any = await getRolesApi();
            if (res.code) {
                // 将请求结果保存到 state
                this.rolesData = res.data;
            }
        }
    }
});

四、组件调用 action 方法

import useRolesStore from '../../../store/roles';
const rolesStore = useRolesStore();
// ...
//注意不能使用箭头函数定义actions:因为箭头函数绑定外部this,会改变this指向
const getRoles = async () => {
    // 调用仓库的方法
    rolesStore.getRolesAsync();
    
    // 同理,actions里也可使用$patch
    this.$patch({})
    this.$patch(state=>{})
    
    //在此注意:patch和普通多次修改的区别在原理上的区别是
    // 1.涉及到数据响应式和视图更新,多次修改,修改几次视图就更新就更新几次
    // 2.patch 批量修改 视图只更新一次,更有利于性能优化
}

五、组件获取 state 数据

import useRolesStore from '../../../store/roles';
const rolesStore = useRolesStore();
// 通过计算属性接收仓库的 state
const rolesData = computed(() => {
    return rolesStore.rolesData;
})

六、getter是store的计算属性

  1. 类似于vue的计算属性

  2. 可以在getter方法中使用另外的getter方法,通过this使用

  3. 在页面中使用getter时,可以传递一个参数进去

    
    export const useMapStore = defineStore("map", {
      state: () => {
        return {
          name: "小猪课堂",
          age: 25,
          sex: "男",
        };
      },
      getters: {
        //箭头函数写法,
        getAddAge: (state) => {
          //console.log(this);	//使用箭头函数,this无效,可以通过 state.其他getters的名称 来访问别的getters
          return state.age + 100;
        },
        //箭头函数,接收参数
        getNewAge: (state) => {
            return (params) => `${state.name},q技能叫做${params}`
        }
          
        // 调用其它getter
        getNameAndAge(): string {
       	  //普通函数,this与state的值是一样的,可以通过this/state.其他getters的名称/state中其他参数名进行调用		
          return this.name + this.getAddAge; // 调用其它getter
        },
        //在页面中使用getter时,可以传递一个参数进去,通过回调函数接收
        getNewAddAge: (state) => {
          return (num: number) => state.age + num;
        },
      },
    

});


4. 在任意页面组件中

```ts
<p>调用其它getter:{{ mapStore.getNameAndAge }}</p>
<p>向getter传递参数,新年龄:{{ store.getNewAddAge(1100) }}</p>

<script>
import {computed} from 'vue';
import useMapStore from "@/stores/map";
const mapStore = useMapStore();

const nameAndAge = computed(() => mapStore.getNameAndAge);
const newAge = computed(() => mapStore.getNewAge('位移'))
</script>

七、利用插件pinia-plugin-persist持久化

enabled:开启后,默认会对整个storestate内容进行储存

key:自定义存储的key,默认是store.$id的值

storage:可以指定任何 extends Storage的实例,默认是sessionStorage

paths:state中的字段名,按组打包储存

第一步:安装插件pinia-plugin-persist
npm install pinia-plugin-persist --save
第二步:修改store文件夹下的index.ts
import { createPinia } from "pinia"
import piniaPluginPersist from 'pinia-plugin-persist'

const store = createPinia()
store.use(piniaPluginPersist)

export default store
第三步:修改user.ts,为其添加persist
import {defineStore} from "pinia"

export const useUserStore = defineStore({
    id: "user",
    state: () => {
        return {
            name: '',
            age: 0
        }
    },
    persist: {
        enabled: true,
        strategies: [
            {
                key: 'wego_user',
                storage: localStorage,
                //通过在strategies中可以指定对哪些数据进行缓存
                paths: ['token', 'name']
            }
        ]
    }
})
storage属性可以是任何继承自Storage协议的对象,自定义存储对象也可以
cookiesStorage举例:
import Cookies from 'js-cookie'

const cookiesStorage: Storage = {
	setItem(key, state){
		return Cookies.set('accessToken', state.accessToken, {expires: 3})
	},
	getItem(key){
		return JSON.stringify({
			accessToken: Cookies.getJSON('accessToken'),
		})
	}
}

export const useStore = defineStore("YourStore", () => {
	const foo = ref("foo")
	const bar = ref("bar")
	const accessToken = ref("xxx")
	return {foo, bar, accessToken}
}, {
	enabled: true,
	strategies: [{
		key: 'token',
		storage: cookiesStorage,
		paths: ["accessToken"]
	}]
})
源码解读
type Store = PiniaPluginContext['store'];
type PartialState = Partial<Store['$state']>;

export const updateStorage = (strategy: PersistStrategy, store: Store) => {

  // 默认使用 sessionStorage
  const storage = strategy.storage || sessionStorage
  
  // 默认存储 key 为 store.$id
  const storeKey = strategy.key || store.$id

  if (strategy.paths) {
  
    // 遍历 paths 将对应的属性收集到 finalObj 中
    const partialState = strategy.paths.reduce((finalObj, key) => {
      finalObj[key] = store.$state[key]
      return finalObj
    }, {} as PartialState)
    
    // 执行存储
    storage.setItem(storeKey, JSON.stringify(partialState))
  } else {
  
    // 如果没有 paths,则按整个 store.$state 存储
    storage.setItem(storeKey, JSON.stringify(store.$state))
  }
}


export default ({ options, store }: PiniaPluginContext): void => {

  // 判断插件功能是否开启
  if (options.persist?.enabled) {
  
    // 默认策略实例
    const defaultStrat: PersistStrategy[] = [{
      key: store.$id,
      storage: sessionStorage,
    }]

    const strategies = options.persist?.strategies?.length ? options.persist?.strategies : defaultStrat

    strategies.forEach((strategy) => {
      const storage = strategy.storage || sessionStorage
      const storeKey = strategy.key || store.$id
      const storageResult = storage.getItem(storeKey)

      if (storageResult) {
      
        // 如果 storage 中存在同步数据
        store.$patch(JSON.parse(storageResult))
        updateStorage(strategy, store)
      }
    })

    store.$subscribe(() => {
    
      // 监听 state 变化,同步更新 storage
      strategies.forEach((strategy) => {
        updateStorage(strategy, store)
      })
    })
  }
}

API

storeToRefs():解构state中的数据,并成为响应式数据

import useMapStore from "@/stores/map";
import { storeToRefs } from 'pinia';
const mapStore = useMapStore();

const { name, age } = storeToRefs(mapStore);

store.$reset():重置仓库数据

使用场景:用户填了一部分表单,想重置为最初始数据

<button @click="reset">重置</button>

const reset = () => {
     mapStore.$reset();
}

store.$patch():批量更改数据

可以传递一个对象,也可以传递一个回调函数,参数为仓库中的state,可以实现一部分修改

<button @click="patchStore">批量修改数据</button>

const patchStore = () => {
    mapStore.$patch((state) => {
        state.items.push({ name: 'shoes', quantity: 1 })
  	  state.hasChanged = true
    })
}

store.$subscribe 对state订阅监听

import {defineStore} from "pinia"
 
const appStore = defineStore('appStore', {
    state: () => ({
        baseUrl: 'https://www.baidu.com/'
    }),
    actions: {
        changeState(params) {
            // console.log('接收到的参数===>', params)
            this.baseUrl = params
        }
    }
})
 
export default appStore
<template>
  <div>
    {{ baseUrl }}
  </div>
  <div v-show="isShow">
    该我出现了
  </div>
  <button @click="changeData">
    通过actions改变数据
  </button>
</template>
 
<script>
import appStore from "@/store/app"
import {storeToRefs} from "pinia"
import {ref} from "vue"
 
export default {
  name: "PiniaSubscribe",
  setup() {
    const store = appStore()
    const {baseUrl} = storeToRefs(store)
    const afterChangeUrl = 'https://www.taobao.com/'
    let isShow = ref(false)
 
    const subscribe = store.$subscribe((mutation, state) => {
      /*
      * mutation主要包含三个属性值:
      *   events:当前state改变的具体数据,包括改变前的值和改变后的值等等数据
      *   storeId:是当前store的id
      *   type:用于记录这次数据变化是通过什么途径,主要有三个分别是
      *         “direct” :通过 action 变化的
      *         ”patch object“ :通过 $patch 传递对象的方式改变的
      *         “patch function” :通过 $patch 传递函数的方式改变的
      *
      * */
      // 我们就可以在此处监听store中值的变化,当变化为某个值的时候,去做一些业务操作之类的
      console.log(mutation)
      console.log(state.baseUrl)
      if (state.baseUrl === afterChangeUrl) isShow.value = true
      else isShow.value = false
    }, {detached: false})  //第二个参数options对象,是各种配置参数
    //detached:布尔值,默认是 false,正常情况下,当订阅所在的组件被卸载时,订阅将被停止删除,
    // 如果设置detached值为 true 时,即使所在组件被卸载,订阅依然在生效
    //参数还有immediate,deep,flush等等参数 和vue3 watch的参数是一样的,多的就不介绍了,用到再看文档吧
 
    // 停止订阅
    // subscribe()  //调用上方声明的变量值,示例(subscribe),即可以停止订阅
 
    function changeData() {
      store.changeState(afterChangeUrl)
    }
 
    return {
      isShow,
      baseUrl,
      changeData
    }
  }
}
</script>

https://blog.csdn.net/qq_42543244/article/details/123461832?ops_request_misc=&request_id=&biz_id=102&utm_term=%E7%9B%91%E5%90%ACpinia%E4%B8%ADstate%E5%8F%98%E5%8C%96&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-0-123461832.142v80insert_down38,201v4add_ask,239v2insert_chatgpt&spm=1018.2226.3001.4187

store.$onAction 对actions订阅监听

因为在订阅的时候,有错误异常的执行函数,所以,我们这里直接写上一个promise,当isError为false的时候,直接抛出异常

import {defineStore} from "pinia"
 
const userMainStore = defineStore('mainStore', {
    state: () => ({
        name: '小明'
    }),
    actions: {
        changeName(name, isError) {
            return new Promise((resolve, reject) => {
                this.name = name
                if (isError) {
                    resolve(`姓名:${this.name}`)
                } else {
                    reject('error')
                }
            })
        }
        ,
    },
})
export default userMainStore
<template>
  <div>
    {{ name }}
  </div>
  <button @click="changeNameHong">改变名字为小红</button>
  <button @click="changeNameMi">改变名字为小米</button>
</template>
 
<script>
import userMainStore from "@/store/main"
import {computed} from "vue";
 
export default {
  name: "ActionSubcribe",
  setup() {
    const mainStore = userMainStore();
 
    async function changeNameHong() {
      let result = await mainStore.changeName('小红', true)
      // console.log(result)  //姓名:小红
    }
 
    async function changeNameMi() {
      try {
        let result = await mainStore.changeName('小米', false)
        // console.log(result)
      } catch (e) {
        // console.log(e)  // error
      }
    }
 
    const unsubscribe = mainStore.$onAction((
            {
              name,  //action 函数的名称
              store,  //store 实例,这里是 mainStore
              args, //action 函数参数数组
              after,  //钩子函数,在action函数执行完成返回或者resolves后执行
              onError // 钩子函数,在action函数报错或者rejects后执行
            }) => {
          console.log('name===>', name)
          console.log('args===>', args)
          console.log('store===>', store)
 
          after(result => {
            console.log('after result===>', result)
          })
 
          onError(error => {
            console.log('onError error===>', error)
          })
        },
        false  //默认是false,设置为true的时候,组件卸载时,订阅依然有效
    )
    // 同样可以通过调用store.$onAction返回值,即unsubscribe 进行停止订阅
    // unsubscribe() // 手动停止订阅
 
    return {
      name: computed(() => mainStore.name),
      changeNameHong,
      changeNameMi
    }
  }
}
</script>

八、使用函数的方式定义store

使用函数定义store时,所有的composition Api都可以使用

### 回答1: Vue 3D飞机航线地图是一种基于Vue技术的交互式地图,其主要特点是以3D形式呈现飞机的航线。该地图通常包括飞机的起点、终点、途经站点等信息,用户可以通过地图导航功能轻松地查找飞机航线信息。与传统的二维平面地图不同,Vue 3D飞机航线地图使用了实时互动的3D模型,使得用户能够更加真实地感受到航线的飞行轨迹和飞行高度。同时,该地图也可以添加其他地标信息,如城市、酒店、景点等,从而为用户提供更详细的地图信息和指引。Vue 3D飞机航线地图还可实现实时更新和多用户共享功能,让用户始终得到最新的航线和地图信息。此外,该地图还具有可定制化的设计,开发者可以根据自己的需求进行个性化地图设计。总之,Vue 3D飞机航线地图是一种多功能、互动性强、可实现实时更新和定制化的地图,为用户提供了更好的导航和定位服务。 ### 回答2: Vue 3D飞机航线地图是一种基于Vue.js框架的前端Web开发技术,它可以结合地图功能和3D飞机动画效果,在页面上呈现出逼真的航线地图。这种技术往往被用于航空航天、旅游行业等领域。 Vue 3D飞机航线地图的实现过程需要借助现成的地图API和3D动画库,如著名的Cesium.js和Three.js。通过引入相关的库,并配置一些参数,就可以实现地图的展示和3D飞机的运动轨迹。 在实际应用中,Vue 3D飞机航线地图能够帮助用户快速了解航班信息、景点导览等内容。同时,它还可以实现与后端服务器的数据交互,比如动态更新航班状态、价格等信息。 总体来说,Vue 3D飞机航线地图是一种兼具技术性和美观性的Web开发技术,有助于丰富前段页面展示效果,提高用户体验。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值