2026/1/15 19:32:48
网站建设
项目流程
网站建设服务8,wordpress禁用响应,jsp做的网站可以用的,国外 网站 源码Vue3新特性实战指南
引言
Vue.js 3.0带来了革命性的更新#xff0c;不仅在性能上有显著提升#xff0c;更在开发体验和功能特性上有重大突破。本文将通过实际代码示例#xff0c;全面介绍Vue3的新特性#xff0c;帮助你快速上手这些强大的功能。
目录
Composition APIF…Vue3新特性实战指南引言Vue.js 3.0带来了革命性的更新不仅在性能上有显著提升更在开发体验和功能特性上有重大突破。本文将通过实际代码示例全面介绍Vue3的新特性帮助你快速上手这些强大的功能。目录Composition APIFragment组件Teleport传送门Suspense异步组件响应式系统增强组件通信新方式全局API变化生命周期钩子更新模板语法改进性能优化特性迁移指南1. Composition APIComposition API是Vue3最重要的新特性它提供了一种全新的组件逻辑组织方式。1.1 基本用法template div classuser-profile h2{{ user.name }}/h2 p{{ user.email }}/p button clickupdateUser更新用户/button /div /template script setup import { ref, reactive } from vue // 使用ref创建响应式基本类型 const count ref(0) // 使用reactive创建响应式对象 const user reactive({ name: 张三, email: zhangsanexample.com }) // 方法 const updateUser () { user.name 李四 count.value } // 暴露给模板 /script style scoped .user-profile { padding: 20px; border: 1px solid #ddd; } /style1.2 逻辑复用// composables/useCounter.jsimport{ref,computed}fromvueexportfunctionuseCounter(initialValue0){constcountref(initialValue)constdoublecomputed(()count.value*2)constincrement()count.valueconstdecrement()count.value--constreset()count.valueinitialValuereturn{count,double,increment,decrement,reset}}!-- 使用组合式函数 -- template div pCount: {{ count }}/p pDouble: {{ double }}/p button clickincrement1/button button clickdecrement-1/button button clickresetReset/button /div /template script setup import { useCounter } from ./composables/useCounter const { count, double, increment, decrement, reset } useCounter(10) /script1.3 逻辑组合示例template div classuser-management h2用户管理/h2 !-- 搜索 -- input v-modelsearchQuery placeholder搜索用户... / !-- 筛选 -- select v-modelfilterRole option value所有角色/option option valueadmin管理员/option option valueuser普通用户/option /select !-- 用户列表 -- div v-ifloading加载中.../div div v-else-iferror{{ error }}/div ul v-else li v-foruser in filteredUsers :keyuser.id {{ user.name }} - {{ user.role }} /li /ul /div /template script setup import { ref, computed, onMounted, onUnmounted } from vue // 组合式函数用户数据 function useUsers() { const users ref([]) const loading ref(false) const error ref(null) const fetchUsers async () { loading.value true error.value null try { const response await fetch(/api/users) users.value await response.json() } catch (e) { error.value e.message } finally { loading.value false } } return { users, loading, error, fetchUsers } } // 组合式函数搜索和筛选 function useSearch(items) { const searchQuery ref() const filterRole ref() const filteredItems computed(() { let result items.value if (searchQuery.value) { result result.filter(item item.name.toLowerCase().includes(searchQuery.value.toLowerCase()) ) } if (filterRole.value) { result result.filter(item item.role filterRole.value) } return result }) return { searchQuery, filterRole, filteredItems } } // 组合式函数窗口尺寸 function useWindowSize() { const width ref(window.innerWidth) const height ref(window.innerHeight) const handleResize () { width.value window.innerWidth height.value window.innerHeight } onMounted(() { window.addEventListener(resize, handleResize) }) onUnmounted(() { window.removeEventListener(resize, handleResize) }) return { width, height } } // 组合所有逻辑 const { users, loading, error, fetchUsers } useUsers() const { searchQuery, filterRole, filteredUsers } useSearch(users) const { width, height } useWindowSize() // 组件挂载时获取数据 onMounted(() { fetchUsers() }) /script1.4 与Options API对比Options APIVue2风格export default { data() { return { users: [], searchQuery: , filterRole: , loading: false, error: null } }, computed: { filteredUsers() { let result this.users if (this.searchQuery) { result result.filter(user user.name.includes(this.searchQuery) ) } if (this.filterRole) { result result.filter(user user.role this.filterRole) } return result } }, methods: { async fetchUsers() { // 数据获取逻辑 } }, mounted() { this.fetchUsers() } }Composition API优势✅ 逻辑相关代码可以放在一起✅ 逻辑可以轻松提取为可复用函数✅ 类型推断更好✅ 更好的Tree-shaking2. Fragment组件2.1 多根节点支持Vue3支持组件有多个根节点无需额外的div包裹。!-- UserProfile.vue -- template header h1{{ title }}/h1 /header main p{{ content }}/p /main footer smallcopy; 2023/small /footer /template script setup defineProps({ title: String, content: String }) /script style scoped header, main, footer { padding: 1rem; } /style!-- 使用组件 -- template UserProfile title我的标题 content这里是内容 / /template2.2 动态多根节点template div header v-if$slots.header slot nameheader / /header main slot / /main footer v-if$slots.footer slot namefooter / /footer /div /template3. Teleport传送门Teleport允许我们将组件渲染到DOM的任意位置。3.1 模态框示例!-- Modal.vue -- template Teleport tobody div v-ifisOpen classmodal-overlay clickcloseModal div classmodal-content click.stop header h3{{ title }}/h3 button clickcloseModaltimes;/button /header main slot / /main footer button clickcloseModal关闭/button button clickconfirm确认/button /footer /div /div /Teleport /template script setup import { computed } from vue const props defineProps({ isOpen: Boolean, title: String }) const emit defineEmits([close, confirm]) const closeModal () emit(close) const confirm () emit(confirm) /script style scoped .modal-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; } .modal-content { background: white; border-radius: 8px; max-width: 500px; width: 100%; } /style3.2 通知组件!-- Notification.vue -- template Teleport to#notifications transition-group namenotification tagdiv classnotifications div v-fornotif in notifications :keynotif.id :class[notification, notif.type] clickremoveNotification(notif.id) {{ notif.message }} /div /transition-group /Teleport /template script setup import { ref } from vue const notifications ref([]) const addNotification (message, type info, duration 3000) { const id Date.now() notifications.value.push({ id, message, type }) if (duration 0) { setTimeout(() { removeNotification(id) }, duration) } } const removeNotification (id) { const index notifications.value.findIndex(n n.id id) if (index -1) { notifications.value.splice(index, 1) } } // 暴露方法给父组件 defineExpose({ addNotification }) // 事件总线或全局状态管理 /script style scoped .notifications { position: fixed; top: 20px; right: 20px; z-index: 9999; } .notification { padding: 1rem; margin-bottom: 10px; border-radius: 4px; color: white; cursor: pointer; box-shadow: 0 2px 8px rgba(0,0,0,0.2); } .notification.info { background: #2196F3; } .notification.success { background: #4CAF50; } .notification.warning { background: #FF9800; } .notification.error { background: #F44336; } .notification-enter-active, .notification-leave-active { transition: all 0.3s ease; } .notification-enter-from, .notification-leave-to { opacity: 0; transform: translateX(100%); } /style!-- index.html --bodydividapp/divdividnotifications/div/body4. Suspense异步组件Suspense让我们优雅地处理异步组件的加载状态。4.1 基本用法!-- SuspenseExample.vue -- template Suspense !-- 异步组件 -- template #default AsyncUserProfile / /template !-- 加载中显示的组件 -- template #fallback div classloading加载中.../div /template /Suspense /template script setup import { defineAsyncComponent } from vue // 方式1使用defineAsyncComponent const AsyncUserProfile defineAsyncComponent(() import(./AsyncUserProfile.vue) ) // 方式2在组件内部使用 // AsyncUserProfile.vue /script style scoped .loading { padding: 2rem; text-align: center; font-size: 1.2rem; } /style4.2 异步组件加载配置script setup import { defineAsyncComponent } from vue const AsyncUserProfile defineAsyncComponent({ // 工厂函数 loader: () import(./AsyncUserProfile.vue), // 加载时组件 loadingComponent: LoadingSpinner, // 加载失败组件 errorComponent: ErrorComponent, // 在显示loadingComponent之前的延迟时间毫秒 delay: 200, // 如果提供了timeout并且加载时间超过此值将显示错误组件 timeout: 3000 }) /script4.3 多个异步依赖template Suspense template #default div AsyncUserProfile / AsyncUserPosts / AsyncUserSettings / /div /template template #fallback div classloading-container div classspinner/div p正在加载用户数据.../p /div /template /Suspense /template style scoped .loading-container { display: flex; flex-direction: column; align-items: center; padding: 2rem; } .spinner { width: 40px; height: 40px; border: 4px solid #f3f3f3; border-top: 4px solid #3498db; border-radius: 50%; animation: spin 1s linear infinite; } keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } /style5. 响应式系统增强5.1 ref vs reactiveimport{ref,reactive,toRefs}fromvue// ref适用于基本类型和对象constcountref(0)constuserref({name:John,age:30})// 访问时需要.valueconsole.log(count.value)// 0count.value// reactive仅适用于对象conststatereactive({count:0,user:{name:John,age:30}})// 访问时不需要.valueconsole.log(state.count)// 0state.count5.2 toRef和toRefstemplate div p{{ name }}/p p{{ age }}/p button clickupdateName更新姓名/button /div /template script setup import { reactive, toRef, toRefs } from vue const state reactive({ name: 张三, age: 25 }) // toRef创建单个ref const name toRef(state, name) // toRefs将整个对象转换为refs const { age } toRefs(state) const updateName () { name.value 李四 } /script5.3 computedimport{ref,computed}fromvueconstfirstNameref(John)constlastNameref(Doe)// 只读计算属性constfullNamecomputed((){return${firstName.value}${lastName.value}})// 可写计算属性constfullNameWritablecomputed({get(){return${firstName.value}${lastName.value}},set(value){[firstName.value,lastName.value]value.split( )}})fullNameWritable.valueJane Smithconsole.log(firstName.value)// Janeconsole.log(lastName.value)// Smith5.4 watch和watchEffectimport{ref,watch,watchEffect}fromvueconstcountref(0)// watch监听特定响应式引用watch(count,(newValue,oldValue){console.log(Count changed from${oldValue}to${newValue})})// watchEffect自动收集依赖watchEffect((){console.log(Count is:${count.value})})// 监听多个源constfirstNameref(John)constlastNameref(Doe)watch([firstName,lastName],([newFirst,newLast],[oldFirst,oldLast]){console.log(Name changed from${oldFirst}${oldLast}to${newFirst}${newLast})})6. 组件通信新方式6.1 defineProps和defineEmits!-- ChildComponent.vue -- template div p从父组件接收到的消息{{ message }}/p button clicksendMessage发送消息给父组件/button /div /template script setup // 方式1使用字符串数组 // defineProps([message]) // 方式2使用对象定义推荐 const props defineProps({ message: { type: String, required: true, default: 默认消息 }, count: { type: Number, default: 0 } }) // 方式3TypeScript类型定义 // const props defineProps{ message: string, count?: number }() const emit defineEmits([updateMessage, childClick]) // 或者使用对象定义 // const emit defineEmits({ // updateMessage: (value: string) { // return typeof value string // }, // childClick: () true // }) const sendMessage () { emit(updateMessage, 来自子组件的消息) emit(childClick) } /script6.2 defineExpose!-- ChildComponent.vue -- template div p{{ content }}/p /div /template script setup import { ref } from vue const content ref(子组件内容) const count ref(0) const increment () { count.value } const getMessage () { return content.value } // 暴露给父组件 defineExpose({ content, count, increment, getMessage }) /script!-- 父组件 -- template div ChildComponent refchildRef / button clickcallChildMethod调用子组件方法/button /div /template script setup import { ref, onMounted } from vue import ChildComponent from ./ChildComponent.vue const childRef ref(null) onMounted(() { console.log(childRef.value.content) // 访问子组件数据 childRef.value.increment() // 调用子组件方法 }) const callChildMethod () { const message childRef.value.getMessage() console.log(子组件消息, message) } /script7. 全局API变化7.1 createApp// Vue2constappnewVue({router,store,render:hh(App)})// Vue3constappcreateApp(App)app.use(router)app.use(store)app.mount(#app)7.2 全局属性// Vue2Vue.prototype.$httpaxios// Vue3constappcreateApp(App)app.config.globalProperties.$httpaxios!-- 组件内使用 -- script setup import { getCurrentInstance } from vue const { proxy } getCurrentInstance() // 访问全局属性 console.log(proxy.$http) /script7.3 配置选项constappcreateApp(App)// 全局配置app.config.errorHandler(err,vm,info){console.error(Global error:,err,info)}app.config.warnHandler(msg,vm,trace){console.warn(Global warning:,msg,trace)}app.config.globalProperties.customPropertyCustom Value8. 生命周期钩子更新8.1 新的钩子script setup import { onMounted, onUpdated, onUnmounted, onBeforeMount, onBeforeUpdate, onBeforeUnmount, onErrorCaptured, onActivated, onDeactivated, onRenderTracked, onRenderTriggered } from vue // 组件挂载前 onBeforeMount(() { console.log(Before Mount) }) // 组件挂载后 onMounted(() { console.log(Mounted) }) // 组件更新前 onBeforeUpdate(() { console.log(Before Update) }) // 组件更新后 onUpdated(() { console.log(Updated) }) // 组件卸载前 onBeforeUnmount(() { console.log(Before Unmount) }) // 组件卸载后 onUnmounted(() { console.log(Unmounted) }) // 捕获后代组件错误 onErrorCaptured((err, instance, info) { console.error(Error captured:, err, info) return false // 阻止错误传播 }) // 调试跟踪渲染 onRenderTracked(({ key, target, type }) { console.log(Render tracked:, key, type) }) // 调试触发渲染 onRenderTriggered(({ key, target, type }) { console.log(Render triggered:, key, type) }) /script9. 模板语法改进9.1 多v-model!-- 父组件 -- template UserForm v-model:nameuserName v-model:emailuserEmail v-model:ageuserAge / /template script setup import { ref } from vue import UserForm from ./UserForm.vue const userName ref(张三) const userEmail ref(zhangsanexample.com) const userAge ref(25) /script!-- UserForm.vue -- template div input typetext :valuename input$emit(update:name, $event.target.value) placeholder姓名 / input typeemail :valueemail input$emit(update:email, $event.target.value) placeholder邮箱 / input typenumber :valueage input$emit(update:age, $event.target.value) placeholder年龄 / /div /template script setup defineProps({ name: String, email: String, age: Number }) defineEmits([update:name, update:email, update:age]) /script9.2 v-memo指令template div v-foritem in items :keyitem.id v-memo[item.id, item.selected] pID: {{ item.id }}/p pName: {{ item.name }}/p pSelected: {{ item.selected }}/p /div /template script setup import { ref } from vue const items ref([ { id: 1, name: Item 1, selected: false }, { id: 2, name: Item 2, selected: true }, // ... ]) // 只有当 item.id 或 item.selected 改变时才会重新渲染 /script9.3 新的指令修饰符!-- 事件修饰符 -- button click.stophandleClick点击/button form submit.preventhandleSubmit提交/form input keyup.enterhandleEnter / button click.oncehandleClickOnce只执行一次/button !-- 鼠标修饰符 -- button click.lefthandleLeftClick左键/button button click.righthandleRightClick右键/button button click.middlehandleMiddleClick中键/button !-- 精确修饰符 -- button click.ctrl.exacthandleCtrlClick只有Ctrl/button10. 性能优化特性10.1 静态节点提升template div !-- 这个div只会在编译时创建一次 -- div classstatic静态内容/div !-- 这个div会在数据变化时重新创建 -- div{{ dynamicContent }}/div /div /template10.2 PatchFlags// Vue3编译时自动优化// 例如div classred{{ msg }}/div// 编译为h(div,{class:red,patchFlag:1// 文本内容会变化},msg)10.3 事件缓存template button clickhandleClick点击/button /template script setup // handleClick函数会被缓存不会每次渲染都重新创建 const handleClick () { console.log(Clicked) } /script11. 迁移指南11.1 主要变化对比Vue2Vue3说明new Vue()createApp()创建应用实例Vue.prototypeapp.config.globalProperties全局属性$childrenref访问子组件过滤器computed/methods过滤器被移除data必须为函数data必须为函数仍然是函数生命周期onXxx形式组合式API生命周期多根节点不支持多根节点支持Fragment支持mixinscomposables更好的逻辑复用只有一个v-model支持多个v-model灵活性更高11.2 迁移步骤升级依赖{dependencies:{vue:^3.0.0}}使用vue/compiler-sfc// vite.config.jsimport{defineConfig}fromviteimportvuefromvitejs/plugin-vueexportdefaultdefineConfig({plugins:[vue()]})逐步迁移组件从Options API迁移到Composition API使用新的生命周期钩子更新组件通信方式11.3 兼容性检查# 安装迁移辅助工具npminstallvue/compat# 配置兼容性// vite.config.jsexportdefault{plugins:[vue({template:{compilerOptions:{// 启用兼容性模式 isCompat:true}}})]}总结Vue3的新特性为我们带来了更强的逻辑复用能力- Composition API让代码组织更灵活更好的TypeScript支持- 类型推断更准确更灵活的开发方式- Fragment、Teleport等特性更好的性能- 编译时优化、响应式系统重构更现代的架构- 模块化设计、Tree-shaking支持