当前位置: 首页 > article >正文

Vue3 完整学习笔记 - 第四部分

Vue3 完整学习笔记 - 第四部分

4. Pinia 状态管理与组件通信

4.1 Pinia 基础

重点掌握:

  • Store 的创建和使用
  • State、Getters、Actions 的定义
  • 组合式风格的 Store

基础 Store 示例:

// stores/counter.ts
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  // 状态
  state: () => ({
    count: 0,
    name: 'Eduardo',
    items: []
  }),

  // 计算属性
  getters: {
    doubleCount: (state) => state.count * 2,
    // 使用this访问其他getter
    doubleCountPlusOne(): number {
      return this.doubleCount + 1
    }
  },

  // 方法
  actions: {
    increment() {
      this.count++
    },
    async fetchItems() {
      const response = await fetch('/api/items')
      this.items = await response.json()
    }
  }
})

// 组合式写法
export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const name = ref('Eduardo')
  
  const doubleCount = computed(() => count.value * 2)
  
  function increment() {
    count.value++
  }
  
  return { count, name, doubleCount, increment }
})

在组件中使用:

<template>
  <div>
    <p>Count: {{ counter.count }}</p>
    <p>Double: {{ counter.doubleCount }}</p>
    <button @click="counter.increment">+1</button>
    <button @click="increment">+1 (Destructured)</button>
  </div>
</template>

<script setup>
import { useCounterStore } from '@/stores/counter'
import { storeToRefs } from 'pinia'

const counter = useCounterStore()

// 解构时保持响应性
const { count, doubleCount } = storeToRefs(counter)
const { increment } = counter

// 批量修改状态
function updateState() {
  counter.$patch({
    count: counter.count + 1,
    name: 'John'
  })
  
  // 或者使用函数形式
  counter.$patch((state) => {
    state.count++
    state.name = 'John'
  })
}

// 监听状态变化
counter.$subscribe((mutation, state) => {
  console.log(mutation.type, mutation.payload)
})
</script>

4.2 Pinia 进阶使用

重点掌握:

  • 插件开发
  • 持久化存储
  • 状态重置

示例代码:

// stores/plugins/persistence.ts
import { PiniaPluginContext } from 'pinia'

export function persistencePlugin({ store }: PiniaPluginContext) {
  // 从localStorage恢复状态
  const savedState = localStorage.getItem(`${store.$id}-state`)
  if (savedState) {
    store.$state = JSON.parse(savedState)
  }
  
  // 监听状态变化并保存
  store.$subscribe(({ storeId, state }) => {
    localStorage.setItem(`${storeId}-state`, JSON.stringify(state))
  })
}

// main.ts
const pinia = createPinia()
pinia.use(persistencePlugin)

// 自定义 Store 属性
pinia.use(({ store }) => {
  store.customProperty = 'my custom value'
  store.customMethod = () => console.log('hello')
})

4.3 组件通信方式一:Props 与 Emit

重点掌握:

  • Props 定义与验证
  • 事件发射与监听
  • v-model 的使用

示例代码:

<!-- ChildComponent.vue -->
<template>
  <div>
    <input
      :value="modelValue"
      @input="$emit('update:modelValue', $event.target.value)"
    />
    <button @click="handleClick">Click Me</button>
  </div>
</template>

<script setup lang="ts">
const props = defineProps<{
  modelValue: string
  label?: string
}>()

const emit = defineEmits<{
  (e: 'update:modelValue', value: string): void
  (e: 'customEvent',  { id: number, value: string }): void
}>()

const handleClick = () => {
  emit('customEvent', { id: 1, value: 'test' })
}
</script>

<!-- ParentComponent.vue -->
<template>
  <div>
    <ChildComponent
      v-model="inputValue"
      label="Username"
      @customEvent="handleCustomEvent"
    />
  </div>
</template>

<script setup>
import { ref } from 'vue'
import ChildComponent from './ChildComponent.vue'

const inputValue = ref('')

const handleCustomEvent = (data) => {
  console.log('Custom event received:', data)
}
</script>

4.4 组件通信方式二:Provide/Inject

重点掌握:

  • 跨层级组件通信
  • 响应式数据传递
  • 作用域插槽替代方案

示例代码:

<!-- ParentComponent.vue -->
<template>
  <div>
    <slot :data="data" :updateData="updateData"></slot>
    <ChildComponent />
  </div>
</template>

<script setup>
import { provide, ref } from 'vue'

const data = ref({ count: 0 })

// 提供响应式数据
provide('data', data)

// 提供方法
const updateData = () => {
  data.value.count++
}
provide('updateData', updateData)

// 提供只读数据
provide('readonlyData', readonly(data))
</script>

<!-- ChildComponent.vue -->
<template>
  <div>
    <p>Count: {{ data.count }}</p>
    <button @click="updateData">Update</button>
  </div>
</template>

<script setup>
import { inject } from 'vue'

// 注入数据和方法
const data = inject('data')
const updateData = inject('updateData')

// 使用默认值
const theme = inject('theme', 'light')
</script>

4.5 组件通信方式三:Event Bus (mitt)

重点掌握:

  • 事件总线的使用
  • 事件监听与清理
  • 适用场景

示例代码:

// eventBus.ts
import mitt from 'mitt'

export const emitter = mitt()

// 类型定义
type Events = {
  'item-click': { id: number; data: any }
  'data-updated': void
}

export const typedEmitter = mitt<Events>()

// ComponentA.vue
<script setup>
import { onMounted, onUnmounted } from 'vue'
import { emitter } from './eventBus'

// 监听事件
onMounted(() => {
  emitter.on('item-click', (event) => {
    console.log('Item clicked:', event)
  })
})

// 清理事件监听
onUnmounted(() => {
  emitter.off('item-click')
})

// 发送事件
const handleClick = () => {
  emitter.emit('item-click', { id: 1,  'test' })
}
</script>

// ComponentB.vue
<script setup>
import { emitter } from './eventBus'

// 发送事件
const notifyUpdate = () => {
  emitter.emit('data-updated')
}
</script>

4.6 异步组件与动态组件

重点掌握:

  • 异步组件的加载
  • 动态组件切换
  • 加载状态处理

示例代码:

<template>
  <div>
    <!-- 异步组件 -->
    <Suspense>
      <template #default>
        <AsyncComponent />
      </template>
      <template #fallback>
        <div>Loading...</div>
      </template>
    </Suspense>

    <!-- 动态组件 -->
    <component 
      :is="currentComponent"
      @change="handleChange"
    />
    
    <button @click="toggleComponent">Switch Component</button>
  </div>
</template>

<script setup>
import { ref, defineAsyncComponent } from 'vue'

// 异步组件定义
const AsyncComponent = defineAsyncComponent({
  loader: () => import('./HeavyComponent.vue'),
  loadingComponent: LoadingComponent,
  errorComponent: ErrorComponent,
  delay: 200,
  timeout: 3000
})

// 动态组件
const components = {
  'comp-a': defineAsyncComponent(() => import('./ComponentA.vue')),
  'comp-b': defineAsyncComponent(() => import('./ComponentB.vue'))
}

const currentComponent = ref('comp-a')

const toggleComponent = () => {
  currentComponent.value = currentComponent.value === 'comp-a' ? 'comp-b' : 'comp-a'
}
</script>

http://www.kler.cn/a/533042.html

相关文章:

  • OpenGL学习笔记(五):Textures 纹理
  • 请解释 Java 中的 IO 和 NIO 的区别,以及 NIO 如何实现多路复用?
  • 毕业设计:基于深度学习的高压线周边障碍物自动识别与监测系统
  • Spring Boot框架下的单元测试
  • 自动驾驶---两轮自行车的自主导航
  • 给AI加知识库
  • TCP 丢包恢复策略:代价权衡与优化迷局
  • LeetCode:583.两个字符串的删除操作
  • [leetcode·回溯算法]回溯算法解题套路框架
  • Kubernetes学习之网络
  • Github 2025-02-04 Python开源项目日报 Top10
  • Rust语言的并发编程
  • 青少年编程与数学 02-008 Pyhon语言编程基础 18课题、标准模块
  • 详解u3d之AssetBundle
  • CCF-GESP 等级考试 2023年12月认证C++八级真题解析
  • 2.7学习记录
  • 基于python的体育新闻数据可视化及分析
  • 6. k8s二进制集群之各节点部署
  • 神经网络常见激活函数 1-sigmoid函数
  • 11.8 LangChain记忆系统设计解析:BaseMemory与BaseChatMessageMemory的继承体系与实战应用
  • 大模型高级工程师实践 - 将课程内容转为视频
  • 司库建设:财务资金管理制度及风险管控要点
  • 数据库课程设计使用Java+JDBC+MySQL+Swing实现的会议预约管理系统源代码+数据库
  • 第二十三章 MySQL锁之表锁
  • wsl+phpstorm+xdebug|windows子系统配置phpstorm开发调试|断点调试
  • 基于“蘑菇书”的强化学习知识点(五):条件期望