pinia(vuex5)的知识点——选项式风格+组合式风格——基础积累

首先,先记录两个知识点,稍后再写关于pinia的部分。

new URL引入本地图片

如果在js中引入本地图片,如果直接使用相对路径获取图片地址,则打包后会出现找不到图片的错误问题,此时可以通过new URL(./assets/xxx.png,import.meta.url)的方式来处理

new URL的第一个参数,只能是模板字符串的变量或者纯静态图片,不能直接是一个变量,否则是无法取出来参数的

defineProps的用法

defineProps({
  imgs:{
    type:Array,
    default:()=>[]
  }
})
//用法就是:props.imgs

defineEmits的用法

const emit = defineEmits(['change'])
emit('change',参数)
//相当于之前的this.$emit('change',参数)

defineExpose的两种用法

一种是setup中的写法

<script>
//父组件调用子组件中的方法时,如果调用失败,则需要查看是否需要通过expose进行方法的暴漏。
setup(props,{emit,expose}){
 function switchTo(i){xxxx}//定义切换方法
 expose({swtichTo})//子组件给父组件暴漏
 return {swtichTo}//当前组件暴漏
}
</script>

一种是setupscript标签中的写法

//如果是setup的直接写法:
<script setup>
defineExpose({switchTo})//直接这样写就可以了
</script>

pinia的基本概念

pinia基本概念,相比于vuex有什么样的优点,为什么官方推荐使用pinia?

pinia,是一个vue阵营的新的状态管理库,现在vue官方已经推荐使用Pinia来代替vuex,或者你可以把pinia看作vuex的最新的版本。
pinia是一个西班牙语,表示菠萝的意思。因为菠萝是一小块一小块组成的,这个和pinia的思想就非常的吻合,在pinia中,每个store仓库都是单独的扁平化存在的。
pinia是由vue官方团队中的一个成员开发的,最早是在2019年11月作为一项实验性工作所提出的,当时的目的是将组合API融入到vuex中,探索新版本的vuex应有的形态,随着探索的进行,最终发现pinia已经实现了vuex5大部分的提案,因此pinia就作为了最新版本的vuex,但是为了尊重作者本人,名字保持不变,仍然叫做pinia.
相比vuex,pinia的API更好而且简单,还支持组合式API,还可以和typescript一起推断类型使用

pinia优势

1.在pinia不存在mutations,只有state,getters,actions
在创建仓库中,提供了三个选项,分别是state,getters,actions
2.actions支持同步和异步来修改store,相当于将之前的mutationsactions合并

import {defineStore} from 'pinia'
export const useCounterStore = defineStore({
 actions:{
  //同步的修改仓库状态
  increment(){this.count++},
  decrement(){this.count--},
  //异步的修改
  async incrementAsync(){
   await new Promise(resolve=>setTimeout(resolve,1000))
   this.increment();
  },
  async decrementAsyn(){
    await new Promise(resolve=>setTimeout(resolve,1000))
    this.decrement();
  }
 }
})

3.可以和typescript一起使用,以此来获得类型推断的支持

import {defineStore} from 'pinia'
//这里定义了一个名为ToDo的接口
interface Todo{
 id:number,
 text:string,
 done:boolean
}
export const useTodoStore = defineStore({
 id:'todo',
 state:()=>({
  todos:[] as Todo[]
 }),
 getters:{
  completedTodos:state=>state.todos.filter(todo=>todo.done)
 },
 actions:{
   addTodoItem(text:string){
    const id = state.todos.length+1
    const newTodo = {id,text,done:false}
    state.todos.push(newTodo)
   },
   toggleTodoItem(todo:Todo){
    todo.done = !todo.done
   },
   async fetchTodos(){
     const respose = await fetch('https://jsonplaceholder.typicode.com/todos')
     const todos = await response.json() as Todo[]
     state.todos = todos
   }
 }
})

4.关于store仓库,每一个store仓库都是独立的扁平化的存在的,不再像vuex里面是通过modules嵌套
5.支持插件扩展,可以通过插件(函数)来扩展仓库的功能,为仓库添加全局属性或者全局方法

const localStoragePlugin = (context:PiniaPluginContext)=>{
 const key = 'my-app-state'
 //从loclStorage中恢复状态
 context.state = localStorage.getItem(key)||context.state
 //监听state变化,将变化保存到localStorage
 context.subscribe(mutation=>{
  localStorage.setItem(key,context.state)
 })
}
//创建pinia实例,并注册localStoragePlugin插件
const pinia = createPinia()
pinia.use(localStoragePlugin)

6.更加轻量,压缩之后体积只有1kb左右,基本上可以忽略这个文件的存在

main.js中使用pinia

import {createPinia} from 'pinia';
//创建pinia实例
const pinia = createPinia();
createApp(App).use(router).use(pinia).mount('#app');

在仓库文件中的写法

import {defineStore} from 'pinia';
//第二个参数支持两种风格:options api以及composition api
export const useCounterStore = defineStore('counter',{
	state:()=>{
		return{
			num:0
		}
	}
})

组件中的使用

import {useCounterStore} from '@/store/useCounterStore.js'
const store = useCounterStore();//拿到仓库
//接下来我们可以从仓库中解构数据出来
import {storeToRefs} from 'pinia';//为了保证从store中获取的数据具有响应式,则需要通过storeToRefs包裹参数后进行取值,才能保证不破坏响应式数据
const {num} = storeToRefs(store);

pinia异步的写法

async asyncIncrement(){
	await new Promise(resolve=>setTimeout(resolve,1000));
	this.increment();
},
increment(){
	this.num++;
}

store.$reset()重置方法——可以进行store数据的重置

store.$patch()变更方法

除了用store.count++直接改变store,你还可以调用$patch方法,它允许用一个state的补丁对象在同一个时间更改多个属性:

store.$patch({
 count:store.count+1,
 age:20,
 name:'D10'
})

不过,用这种语法的话,有些变更真的很难实现或者很耗时,任何集合的修改(例如,向数组中添加/移除一个元素或是做splice操作)都需要你创建一个新的集合,因此,$patch方法也接受一个函数来组合这种难以用补丁对象实现的变更。

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

两种变更store方法的主要区别在于,$patch允许你将多个变更归入devtools的同一个条目中,同时请注意,直接修改state.$patch()也会出现在devtools中,而且可以进行timetravel

pinia选项式风格

该风格基本上跟之前的vuex是非常相似的,只不过没有mutation,无论是同步的方法还是异步的方法,都写在actions里面。
在组件中使用仓库数据时,如果是要获取数据,为了保持数据的响应式,应该使用storeToRefs方法。

import {storeToRefs} from 'pinia';
const {num,doubleCount} = storeToRefs(store);

在组件中使用仓库数据时,首先引入仓库方法,并执行该方法:

import {useCounterStore} from '@/store/useCounterStore.js'
const store = useCounterStore();//拿到仓库

如果是获取方法,则直接从store里面解构出来即可。

const {increment,asyncIncrement,asyncDecrement} = store;

另外,仓库还提供了两个好用的api

store.$reset:重置state
store.$patch:变更state

pinia组合式风格

import {defineStore} from 'pinia';
import {reactive,computed} from 'vue';
export const useListStore = defineStore('list',()=>{
	//组合式api风格
	//创建仓库数据,类似于state
	const list = reactive({
		items:[
			{
				text:'学习 Pinia',
				isCompleted:true,
			},{
				text:'打羽毛球',
				isCompleted:false
			}
		],
		counter:100
	})
	const doubleCounter = computed(()=>list.counter*2);
	function addItem(item){
		list.items.push({
			text:item,
		});
	}
	function completeHandle(index){
		list.items[index].isCompleted == !list.items[index].isCompleted;
	}
	function delItem(index){
		list.items.splice(index,1);
	}
	
	return {list,addItem,completeHandle,delItem};
})

使用方法:

import {useListStore} from '@/store/useListStore.js';
import {storeToRefs} from 'pinia';
//获取到仓库
const store = useListStore();
//从仓库解构数据出来
const {list,doubleCounter} = storeToRefs(store);
const {addItem,completeHandle,delItem} = store;
const newItem = ref("");
//添加新的待办事项
function addHandle(){
	//首先拿到用户的输入,添加到状态仓库里面
	if(newItem.value){
		//list.items.push(newItem.value);//通过newItem.value可以拿到用户输入的值
		addItem(newItem.value);
		newItem.value = '';
	}
}
function delHandle(index){
	if(window.confirm(`是否要删除当前项目:\n
		${list.value.items[index].text}\n
		完成状态:${list.value.items[index].isCompleted?'已完成':'未完成'}
	`)){
		delItem(index);
	}
}

引入其他仓库

import {useCounterStore} from './useCounterStore.js'
const useCounter = useCounterStore();
const otherCounter = computed(()=>useCounter.counter*3);

组合式风格和vue3中的使用方法是一样的,通过ref或者reactive来定义仓库数据。
通过普通的方法来操作仓库数据,无论是数据还是方法最终需要导出出去。

你可能感兴趣的:(pinia,vue技能提升,vue基础知识,pinia,vuex5)