Skip to content

Vue3 学习指南

目录

基础概念

组合式 API

javascript
// 使用 setup
import { ref, computed, onMounted } from 'vue';

export default {
  setup() {
    // 响应式状态
    const count = ref(0);
    const doubleCount = computed(() => count.value * 2);

    // 方法
    function increment() {
      count.value++;
    }

    // 生命周期钩子
    onMounted(() => {
      console.log('组件已挂载');
    });

    // 返回模板需要的数据和方法
    return {
      count,
      doubleCount,
      increment
    };
  }
};

// 使用 <script setup>
<script setup>
import { ref, computed, onMounted } from 'vue';

const count = ref(0);
const doubleCount = computed(() => count.value * 2);

function increment() {
  count.value++;
}

onMounted(() => {
  console.log('组件已挂载');
});
</script>

<template>
  <div>
    <p>Count: {{ count }}</p>
    <p>Double: {{ doubleCount }}</p>
    <button @click="increment">Increment</button>
  </div>
</template>

说明

  • setup 函数
  • 响应式 API
  • 生命周期钩子
  • 组合式函数

响应式系统

javascript
import { ref, reactive, computed, watch, watchEffect } from 'vue';

// ref
const count = ref(0);
console.log(count.value); // 0
count.value++;

// reactive
const state = reactive({
  count: 0,
  double: computed(() => state.count * 2)
});

// watch
watch(count, (newValue, oldValue) => {
  console.log('count changed:', oldValue, '->', newValue);
});

// watchEffect
watchEffect(() => {
  console.log('count is:', count.value);
});

// 响应式对象
const obj = reactive({
  nested: {
    count: 0
  }
});

// 响应式数组
const arr = reactive([1, 2, 3]);
arr.push(4);

// 响应式 Map
const map = reactive(new Map());
map.set('key', 'value');

// 响应式 Set
const set = reactive(new Set());
set.add(1);

说明

  • ref 和 reactive
  • computed 属性
  • watch 和 watchEffect
  • 响应式对象和集合

生命周期

javascript
import {
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted
} from 'vue';

export default {
  setup() {
    onBeforeMount(() => {
      console.log('组件挂载前');
    });

    onMounted(() => {
      console.log('组件已挂载');
    });

    onBeforeUpdate(() => {
      console.log('组件更新前');
    });

    onUpdated(() => {
      console.log('组件已更新');
    });

    onBeforeUnmount(() => {
      console.log('组件卸载前');
    });

    onUnmounted(() => {
      console.log('组件已卸载');
    });
  }
};

说明

  • 生命周期钩子
  • 组合式 API 中的生命周期
  • 执行顺序
  • 使用场景

组件开发

组件基础

javascript
// 组件定义
<script setup>
import { ref } from 'vue';

const props = defineProps({
  title: {
    type: String,
    required: true
  }
});

const emit = defineEmits(['update']);

const count = ref(0);

function increment() {
  count.value++;
  emit('update', count.value);
}
</script>

<template>
  <div class="my-component">
    <h1>{{ title }}</h1>
    <p>Count: {{ count }}</p>
    <button @click="increment">Increment</button>
    <slot></slot>
  </div>
</template>

<style scoped>
.my-component {
  color: #42b983;
}
</style>

// 组件使用
<template>
  <my-component
    title="Hello"
    @update="handleUpdate"
  >
    <p>Slot content</p>
  </my-component>
</template>

说明

  • 组件定义
  • Props 定义
  • 事件发射
  • 插槽使用
  • 样式作用域

组件通信

javascript
// 父组件
<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';

const message = ref('Hello from parent');

function handleUpdate(newValue) {
  message.value = newValue;
}
</script>

<template>
  <child-component
    :message="message"
    @update="handleUpdate"
  />
</template>

// 子组件
<script setup>
import { ref } from 'vue';

const props = defineProps(['message']);
const emit = defineEmits(['update']);

function updateMessage() {
  emit('update', 'Updated message');
}
</script>

<template>
  <div>
    <p>{{ message }}</p>
    <button @click="updateMessage">Update</button>
  </div>
</template>

// 依赖注入
<script setup>
import { provide, inject } from 'vue';

// 提供值
provide('message', 'Hello from parent');

// 注入值
const message = inject('message');
</script>

说明

  • Props 传递
  • 事件发射
  • 依赖注入
  • 组件通信最佳实践

Teleport

javascript
// 使用 Teleport
<template>
  <teleport to="#modal">
    <div class="modal">
      <h2>Modal Title</h2>
      <p>Modal content</p>
      <button @click="close">Close</button>
    </div>
  </teleport>
</template>

<script setup>
function close() {
  // 关闭模态框
}
</script>

<style scoped>
.modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: white;
  padding: 20px;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
</style>

说明

  • Teleport 用途
  • 目标选择器
  • 样式处理
  • 使用场景

状态管理

Pinia

javascript
// store/counter.js
import { defineStore } from 'pinia';

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0
  }),
  getters: {
    doubleCount: (state) => state.count * 2
  },
  actions: {
    increment() {
      this.count++;
    },
    async incrementAsync() {
      await new Promise(resolve => setTimeout(resolve, 1000));
      this.count++;
    }
  }
});

// 组件中使用
<script setup>
import { useCounterStore } from '@/stores/counter';

const counter = useCounterStore();

// 访问状态
console.log(counter.count);
console.log(counter.doubleCount);

// 调用 action
counter.increment();
counter.incrementAsync();
</script>

说明

  • Store 定义
  • State 管理
  • Getters 计算
  • Actions 操作
  • 组合式 API 集成

Provide/Inject

javascript
// 提供值
<script setup>
import { provide, ref } from 'vue';

const count = ref(0);
provide('count', count);

function increment() {
  count.value++;
}
provide('increment', increment);
</script>

// 注入值
<script setup>
import { inject } from 'vue';

const count = inject('count');
const increment = inject('increment');
</script>

<template>
  <div>
    <p>Count: {{ count }}</p>
    <button @click="increment">Increment</button>
  </div>
</template>

说明

  • 提供值
  • 注入值
  • 响应式
  • 默认值

路由管理

Vue Router 4

javascript
// router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import Home from '../views/Home.vue';

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: () => import('../views/About.vue')
  },
  {
    path: '/user/:id',
    name: 'User',
    component: () => import('../views/User.vue'),
    props: true
  }
];

const router = createRouter({
  history: createWebHistory(),
  routes
});

// 导航守卫
router.beforeEach((to, from, next) => {
  if (to.meta.requiresAuth && !isAuthenticated) {
    next('/login');
  } else {
    next();
  }
});

export default router;

// 组件中使用
<script setup>
import { useRouter, useRoute } from 'vue-router';

const router = useRouter();
const route = useRoute();

function goToHome() {
  router.push('/');
}

function goToUser(id) {
  router.push({ name: 'User', params: { id } });
}

// 访问路由参数
console.log(route.params.id);
</script>

说明

  • 路由配置
  • 动态路由
  • 导航守卫
  • 组合式 API 集成

新特性

Suspense

javascript
// 异步组件
<script setup>
import { defineAsyncComponent } from 'vue';

const AsyncComponent = defineAsyncComponent(() =>
  import('./AsyncComponent.vue')
);
</script>

<template>
  <Suspense>
    <template #default>
      <AsyncComponent />
    </template>
    <template #fallback>
      <div>Loading...</div>
    </template>
  </Suspense>
</template>

// 异步 setup
<script setup>
async function setup() {
  const data = await fetchData();
  return { data };
}
</script>

说明

  • 异步组件
  • 加载状态
  • 错误处理
  • 使用场景

Fragments

javascript
<template>
  <div>First</div>
  <div>Second</div>
  <div>Third</div>
</template>

说明

  • 多根节点
  • 不需要包装元素
  • 样式处理
  • 使用场景

Custom Renderer

javascript
import { createRenderer } from 'vue';

const { render, createApp } = createRenderer({
  createElement(type) {
    // 创建元素
  },
  insert(el, parent) {
    // 插入元素
  },
  remove(el) {
    // 移除元素
  },
  patchProp(el, key, prevValue, nextValue) {
    // 更新属性
  }
});

// 使用自定义渲染器
const app = createApp({
  // 应用配置
});

说明

  • 自定义渲染器
  • 平台适配
  • 性能优化
  • 使用场景

最佳实践

1. 代码组织

  • 使用组合式 API
  • 模块化管理
  • 遵循命名规范
  • 保持组件简洁

2. 性能优化

  • 合理使用响应式
  • 避免不必要的渲染
  • 使用 Suspense
  • 懒加载组件

3. 开发技巧

  • 使用 Vue Devtools
  • 编写单元测试
  • 使用 TypeScript
  • 遵循 Vue 风格指南

学习资源

官方文档

视频课程

  • 慕课网
  • 极客时间
  • B站技术区
  • YouTube 技术频道

工具推荐

启航团队技术文档