Vue3 是 Vue.js 框架的最新主要版本,于 2020 年 9 月正式发布。它带来了许多重大改进和新特性:
性能提升:更快的渲染速度,更小的包体积
Composition API:全新的代码组织方式
更好的 TypeScript 支持
新的响应式系统:基于 Proxy 实现
Fragment、Teleport、Suspense 等新特性
npm create vite@latest my-vue-app --template vue
cd my-vue-app
npm install
npm run dev
npm install -g @vue/cli
vue create my-vue-app
# 选择 Vue 3 预设
cd my-vue-app
npm run serve
{{ message }}
链接
Vue3 提供了两种创建响应式数据的方式:
export default {
data() {
return {
count: 0
}
},
methods: {
increment() {
this.count++
}
}
}
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
function increment() {
count.value++
}
return {
count,
increment
}
}
}
setup()
是 Composition API 的入口点,在组件创建之前执行。
import { ref } from 'vue'
export default {
setup(props, context) {
// props 是响应式的,不能解构
console.log(props)
// context 包含 attrs, slots, emit
console.log(context.attrs)
const count = ref(0)
return {
count
}
}
}
用于创建响应式的基本类型数据
import { ref } from 'vue'
const count = ref(0)
console.log(count.value) // 访问值需要使用 .value
用于创建响应式的对象
import { reactive } from 'vue'
const state = reactive({
count: 0,
user: {
name: 'John'
}
})
console.log(state.count) // 直接访问
创建计算属性
import { ref, computed } from 'vue'
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
监听数据变化
import { ref, watch, watchEffect } from 'vue'
const count = ref(0)
// 监听特定数据源
watch(count, (newVal, oldVal) => {
console.log(`count changed from ${oldVal} to ${newVal}`)
})
// 自动追踪依赖
watchEffect(() => {
console.log(`count is now: ${count.value}`)
})
import { onMounted, onUpdated, onUnmounted } from 'vue'
setup() {
onMounted(() => {
console.log('组件挂载')
})
onUpdated(() => {
console.log('组件更新')
})
onUnmounted(() => {
console.log('组件卸载')
})
}
import { createApp } from 'vue'
import App from './App.vue'
import MyComponent from './components/MyComponent.vue'
const app = createApp(App)
app.component('MyComponent', MyComponent)
app.mount('#app')
import ComponentA from './ComponentA.vue'
export default {
components: {
ComponentA
}
}
// 子组件
export default {
props: {
title: {
type: String,
required: true,
default: '默认标题'
},
likes: Number
},
setup(props) {
console.log(props.title)
}
}
// 子组件
setup(props, { emit }) {
const handleClick = () => {
emit('custom-event', '事件数据')
}
return {
handleClick
}
}
// 父组件
默认内容
自定义内容
标题
主要内容
页脚
-
{{ slotProps.item.name }}
将组件渲染到 DOM 树的指定位置
这是一个模态框
处理异步组件加载状态
加载中...
// 全局指令
app.directive('focus', {
mounted(el) {
el.focus()
}
})
// 局部指令
export default {
directives: {
highlight: {
mounted(el, binding) {
el.style.backgroundColor = binding.value || 'yellow'
},
updated(el, binding) {
el.style.backgroundColor = binding.value || 'yellow'
}
}
}
}
// myPlugin.js
export default {
install(app, options) {
// 添加全局方法或属性
app.config.globalProperties.$myMethod = () => {
console.log('这是插件添加的方法')
}
// 添加全局指令
app.directive('my-directive', {
mounted(el, binding) {
// 指令逻辑
}
})
// 注入全局可用的值
app.provide('pluginOptions', options)
}
}
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import myPlugin from './myPlugin'
const app = createApp(App)
app.use(myPlugin, { someOption: true })
app.mount('#app')
Pinia 是 Vue3 推荐的状态管理库
npm install pinia
// stores/counter.js
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
getters: {
doubleCount: (state) => state.count * 2
},
actions: {
increment() {
this.count++
}
}
})
// main.js
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const app = createApp(App)
app.use(createPinia())
app.mount('#app')
// 组件中使用
import { useCounterStore } from '@/stores/counter'
export default {
setup() {
const counter = useCounterStore()
return {
counter,
count: computed(() => counter.count),
doubleCount: computed(() => counter.doubleCount)
}
}
}
npm install vue-router@4
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import About from '../views/About.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: About
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(router)
app.mount('#app')
首页
关于
使用 v-once
渲染静态内容
使用 v-memo
优化列表渲染
合理使用 computed
和 watch
组件懒加载
使用 keep-alive
缓存组件
import { createRenderer } from 'vue'
const { render, createApp } = createRenderer({
patchProp,
insert,
remove,
createElement,
// ...其他平台特定API
})
// 然后可以使用这个自定义的 createApp
const app = createApp(App)
// 定义 Props 类型
interface Props {
title: string
count?: number
}
export default defineComponent({
props: {
title: {
type: String as PropType,
required: true
},
count: {
type: Number as PropType,
default: 0
}
},
setup(props: Props) {
// 现在 props 有类型提示了
}
})
-
{{ todo.text }}
确保使用 ref
或 reactive
创建响应式数据
对于对象,避免直接替换整个对象,应该修改其属性
对于数组,使用可响应的方法如 push
, pop
, splice
等
确保在 setup()
函数中正确注册钩子
检查组件是否被 keep-alive
缓存
明确声明 props 和 emits 的类型
使用 as PropType
为复杂类型提供类型注解
使用 !
非空断言操作符时要谨慎
Vue3 官方文档
Vue3 迁移指南
Vue Mastery Vue3 课程
Pinia 官方文档
Vue Router 4 文档