新闻详情

新闻详情

首页 / 资讯中心 / 详情

Vue3入门实战:Composition API、组合式函数与工程落地

发布时间:2026/9/28 18:46:02来源:尧图网络
Vue3入门实战:Composition API、组合式函数与工程落地
Vue3入门这件事网上教程一大把但很多都是照着官方文档念一遍看完还是不知道怎么落地到真实项目。我这两年从Vue2迁到Vue3又带过几个新人上手踩了不少坑也总结了一些经验。这篇东西不打算复述文档而是把Vue3入门最核心的几条路给你捋顺环境怎么搭、Composition API到底解决什么问题、组合式函数怎么写才不烂尾、从Vue2过来的人最容易被什么绊倒最后是刷面试题时常见的一些坑。看完你应该能直接开写而不是停留在“看懂了但不会用”。1. Vue3带来了什么以及为什么值得花时间学1.1 不只是换个写法是思维模式的变化很多人觉得Vue3就是把Vue2的options搬进setup里换个语法而已。真不是。Vue3最大的变化是把“按选项组织代码”变成了“按逻辑关注点组织代码”。Vue2时代一个组件里同步修改同一份数据的方法散落在data、computed、watch、methods四个选项里。读代码的时候要在整个文件里来回跳。比如一个购物车组件里面有商品列表、数量加减、总价计算、结算状态这些逻辑分别躺在四个选项里你需要自己在脑子里把它们“圈”出来才知道这个组件到底在干什么。Vue3的setup函数允许你把同一个业务关注点的状态、计算属性、事件处理、监听器写在一起。一个购物车模块几十行代码聚在一块儿读起来就像在读一个独立的函数——输入、处理、输出一目了然。这才是Composition API真正的价值不是炫技是把代码的可维护性拉高一个量级。再说响应式系统。Vue2用Object.defineProperty逐个劫持属性新增和删除属性检测不到数组索引和length变化也检测不到所以才有Vue.set和Vue.delete这种补丁式API。Vue3换成Proxy代理整个对象属性增删、数组下标修改全都原生响应式。这个改动是底层的直接影响你写业务代码时的自由度。1.2 入门Vue3之前建议先补的知识点如果你是从零开始直接上手Vue3也不是不行但有些前置知识建议先备好否则学习中会卡壳ES6模块语法import、export得会这是所有框架的基础。解构赋值和展开运算符组合式函数里返回对象、解构使用用到频率很高。尤其reactive对象被解构后会丢失响应性这个坑几乎所有Vue3新手都会踩一次。箭头函数和 this 的差异Composition API里基本不用this了但理解箭头函数能让你写watch和computed的回调时更顺畅。TypeScript基础可选但强烈推荐Vue3的源码和类型推导都是为TS设计的defineProps、ref 、computed 这些泛型标注能让编辑器提示强到离谱。哪怕你暂时不写TS也要知道这些泛型是干什么的。如果你是从Vue2迁移过来的重点不是学新语法而是忘掉this思维。Vue3的setup里this不再是组件实例你直接声明变量、直接定义函数、直接return出去给模板用。刚从前端那种到处this.xxx的习惯切换过来头两天确实有点别扭但撑过一周就好。2. 环境搭建与第一个Vue3项目2.1 最稳的起步方式create-vue现在官方推荐的是create-vue脚手架不是vue-cli。两者的区别create-vue是Vite驱动秒级冷启动热更新快到飞起vue-cli是Webpack驱动慢配置也重。新项目一律用create-vue别再开vue-cli的坑。注意之前网上大量教程还在用npm install -g vue/cli然后vue create xxx这条路径虽然还能跑但官方已经不再主推。2023年以后创建新项目请使用 npm create vuelatest。安装命令就一条npm create vuelatest执行后会问你要不要装TypeScript、JSX、Router、Pinia、Vitest、ESLint、Prettier。新手建议全部选No先把最小骨架跑起来后边按需再加。交互式选项看着多其实每个人都可以按自己的实际场景勾选比如做中后台管理系统你大概率需要Router和Pinia做基础组件库可能连Router都用不上。装完依赖、起服务cd your-project-name npm install npm run dev浏览器打开http://localhost:5173看到Vue的欢迎页就算成了。2.2 手动搭一个最精简的Vue3项目如果不想用脚手架或者想完全掌握底层的依赖关系手动搭一个也就三分钟的事。这种方式对理解Vite Vue3的运行机制特别有帮助建议入门阶段做一次。初始化目录装三个核心包npm init -y npm install vue npm install -D vite vitejs/plugin-vue新建index.html!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 titleVue3 最小项目/title /head body div idapp/div script typemodule src/src/main.js/script /body /html新建vite.config.jsimport { defineConfig } from vite import vue from vitejs/plugin-vue export default defineConfig({ plugins: [vue()] })新建src/main.jsimport { createApp } from vue import App from ./App.vue createApp(App).mount(#app)新建src/App.vue写一个最简单的响应式计数器script setup import { ref } from vue const count ref(0) function add() { count.value } /script template button clickadd当前数量: {{ count }}/button /template跑起来npx vite项目就通了。这套流程走一遍你会很清楚index.html是入口、main.js负责创建App、App.vue是根组件、Vite负责编译转换整个链路没有黑盒。2.3 关于Vite的几个坑Node版本不能太低Vite 5要求Node 18版本不够直接报错。装Node推荐用nvm别直接从官网下安装包后面切换版本会让你感谢这个决定。局域网访问空白开发时手机要调试启动命令加上npm run dev -- --host否则默认只绑定了localhost外部设备访问不到页面。首次启动慢第三方的依赖预构建需要一点时间会先显示几秒较短的等待别以为卡死了。node_modules里如果是新装的第一次启动可能需要个十几秒到几十秒之后冷启动基本秒开。scss安装Vite原生支持CSS预处理语言但不内置依赖。要写scss得手动装npm install -D sass装上就能直接用不用额外配置。注意别装成node-sass那个早就停止维护了。2.4 环境搭建常见问题速查表症状可能原因解决办法vite不是内部或外部命令依赖未安装npm installERR_OSSL_EVP_UNSUPPORTEDNode版本过新/过老切换Node 18 LTS端口被占用5173有别的进程npm run dev -- --port 5174页面白屏控制台报[plugin:vite:vue]vue文件语法错误看报错具体行号通常是template或script的括号不闭合CSS不生效忘记引入样式文件main.js里import ./assets/main.css3. Composition API核心操作拆解3.1 setup语法糖你现在99%的场景都用它Vue3.2之前setup得写成一个函数在script里导出模板用到的变量还得手动return写起来特别繁琐。3.2之后有了script setup语法糖所有在script顶层声明的东西模板里直接用不需要return了。这个改动极大降低了上手成本。script setup import { ref, computed } from vue const price ref(100) const quantity ref(2) const total computed(() price.value * quantity.value) /script template p单价{{ price }}/p p数量{{ quantity }}/p p总价{{ total }}/p /template注意事项script setup是不支持默认导出的一个.vue文件就是自包含的组件。组件引入后直接用不用注册script setup import ChildComponent from ./ChildComponent.vue /script template ChildComponent / /template你也可以在 script setup 中直接使用await组件会被自动包裹为异步组件这种“顶层await”在部分后台管理项目的路由懒加载场景中用得上。3.2 ref和reactive怎么选别纠结记住一条原则这两个API是Vue3响应式数据的基础新手最容易纠结的就是它们选谁。我的原则很简单基础类型用ref也就是String、Number、Boolean这些。对象类型常规用reactive数组、对象用reactive直观。如果对象的值会被替换、解构或者从函数返回就统一用ref。ref其实也可以包裹对象内部会自动帮你转成reactive。唯一的区别是访问方式ref要.valuereactive直接访问。但注意reactive对象一旦被解构属性就会失去响应性这是非常大的坑。import { reactive } from vue const state reactive({ count: 0 }) // 解构后就失去响应性了 const { count } state count // 页面不会更新 // 解法一转成ref const total ref(state.count) // 解法二使用toRefs import { toRefs } from vue const { count } toRefs(state) count.value为了少踩解构的坑我现在写业务代码习惯统一用ref。对象就写const user ref({ name: 张三, age: 18 })修改时user.value.name 李四。多写一个.value但换来的是心智负担小模板里自动解包完全不用管“谁的响应性丢了”。3.3 computed和watch常见的性能与正确性陷阱computed是带缓存的只有依赖项变化才重新计算。不适合有副作用的场景比如往localStorage写东西就不应该放computed里副作用用watch来做。watch是惰性监听有多个触发场景需要区分——watch一个ref就直接监听watch一个reactive对象时需要开启deep才能监听内部的深层属性变化监听多个数据源时用数组形式。import { watch, ref } from vue const keyword ref() const user reactive({ name: 张三, age: 18 }) // 单数据源 watch(keyword, (newVal, oldVal) { console.log(关键词变化:, newVal, oldVal) }) // 多数据源 watch([keyword, () user.name], ([newKeyword, newName], [oldKeyword, oldName]) { console.log(多个源变化了) }) // 开启deep监听reactive内部所有属性的变化 watch(user, (newVal, oldVal) { console.log(user任意属性变化都会触发) }, { deep: true }) // 立即执行一次的回调类似Vue2的immediate watch(keyword, () { // do something }, { immediate: true })两个高频踩坑点监听reactive对象的某个属性要传getter函数() user.name不能直接传user.name否则得到的是一个固定值永远监听不到变化。deep监听的是对象内部变化如果对象的引用整个被替换了要监听的对象也得换成新引用。比如你把user.value { name: 李四 }原来建立的watch还盯着旧对象需要手动重新监听。3.4 defineProps和defineEmits子组件通信的核心子组件里声明接收什么数据触发什么事件都用编译宏来完成不需要手动import。!-- ChildComponent.vue -- script setup const props defineProps({ title: { type: String, default: 默认标题 }, count: { type: Number, required: true } }) const emit defineEmits([update:count, delete]) function handleClick() { emit(update:count, props.count 1) } /script template div h3{{ title }}/h3 button clickhandleClick增加/button /div /template父组件那边script setup import { ref } from vue import ChildComponent from ./ChildComponent.vue const count ref(0) /script template ChildComponent title子组件标题 :countcount update:countcount $event / /template这里有个Vue2转Vue3特别需要注意的差异Vue2里子组件修改props会被警告需要commit事件再派发。Vue3里依然不推荐直接修改props但通过update:count这种约定事件写法配合v-model:count可以在父组件侧自动接住ChildComponent v-model:countcount /子组件改成emit(update:count, props.count 1)这时候父子之间的数据同步就特别顺畅。3.5 生命周期钩子setup里怎么用Vue2的生命周期钩子在Vue3的setup里全是函数形式Vue2写法Vue3 setup写法触发时机beforeCreate / created不需要直接在setup里写组件初始化beforeMountonBeforeMount挂载前mountedonMounted挂载完成beforeUpdateonBeforeUpdate数据变化DOM更新前updatedonUpdated数据变化DOM更新后beforeUnmountonBeforeUnmount卸载前unmountedonUnmounted卸载完成一个实际的use场景比如获取数据你可能会在onMounted里发请求。但注意如果你在setup顶层写异步请求和onMounted里写没有本质区别因为setup本身就是同步执行完才挂载。更推荐的做法是直接在setup顶层发请求逻辑上代码更紧凑也方便组合式函数复用。import { onMounted, onUnmounted } from vue function useMousePosition() { const x ref(0) const y ref(0) function update(e) { x.value e.clientX y.value e.clientY } onMounted(() { window.addEventListener(mousemove, update) }) onUnmounted(() { window.removeEventListener(mousemove, update) }) return { x, y } }4. 从Vue2到Vue3的迁移最容易被绊倒的5处4.1 v-model的变化不再是单向的value inputVue2中 v-model 默认绑定value属性和input事件。Vue3中改成了modelValue和update:modelValue。自定义组件上需要在子组件里显式声明!-- 子组件 -- script setup const props defineProps({ modelValue: { type: [String, Number], default: } }) const emit defineEmits([update:modelValue]) function onInput(e) { emit(update:modelValue, e.target.value) } /script template input :valuemodelValue inputonInput / /template另外Vue3支持v-model:xxx这种多v-model绑定一个组件可以同时绑定多个值这个在封装表单类组件时优势很大。比如搜索组件可以同时暴露v-model:keyword和v-model:category。4.2 全局API不再挂在构造函数上Vue2里你写Vue.use()、Vue.component()、Vue.prototype.$xxx。Vue3里这些全没了变成了从vue显式导入或者在app实例上调用import { createApp } from vue import MyComponent from ./MyComponent.vue const app createApp(App) app.component(my-component, MyComponent) // 全局组件 app.use(SomePlugin) // 插件 app.config.globalProperties.$fetch fetch // 替代 Vue.prototype.$fetch app.mount(#app)这个变化对项目影响最大的场景原来很多第三方库要求你Vue.use(Xxx)Vue3里统一走app.use(Xxx)没适配的就只能等升级或换方案。我在迁移项目时遇到一个老打印插件源码里有Vue.use直接迁移到Vue3白屏最后换成了封装过的新库。4.3 过滤器filter被移除了Vue2里可以定义filter做文本格式化Vue3彻底移除了。官方推荐用计算属性和方法替换。如果你之前项目里用了大量filter迁移成本不小要一个个改成computed或函数调用。比如Vue2里Vue.filter(formatMoney, (value) { return ¥ Number(value).toFixed(2) })Vue3里改成import { computed } from vue const formattedPrice computed(() ¥${Number(props.price).toFixed(2)})模板里直接{{ formattedPrice }}比filter更直观也是响应式的。4.4 v-for和v-if的优先级变了Vue2里v-for的优先级高于v-if同一元素上两者同时出现时v-for先循环再逐个v-if判断导致很多用户用这个特性配合做“当列表不为空时显示列表”。Vue3改成v-if优先同一元素上同时出现时v-if连循环的元素都拿不到直接报错。正确的写法是需要过滤列表时用计算属性新生成过滤后的数组再v-for。不要在模板里同时挂v-for和v-if。这既是性能优化也是代码规范。const visibleItems computed(() items.value.filter(item item.visible)) // 模板里 // li v-foritem in visibleItems :keyitem.id{{ item.name }}/li4.5 事件API$on、$off被移除Vue2里this.$on、this.$off可以作为事件总线用。Vue3不再支持组件实例的事件总线。要跨组件通信现在更推荐小项目直接父子props emit。跨多级组件用provide/inject。全局状态用Pinia。极少数广播场景可以自己实现一个轻量ublish/subscribe工具但不要用第三方库的全局事件寄生在组件实例上。5. 组合式函数让逻辑复用不再靠mixin5.1 为什么mixin不是好方案Vue2里想要复用逻辑最常见的做法就是mixin。但mixin有几个严重问题命名冲突不可控两个mixin都定义了同名的方法或数据合并时后一个覆盖前一个你根本不知道是谁覆盖了谁。数据来源隐式模板里看到一个变量你没法确定它在哪个mixin里嵌套多层mixin后代码像毛线团。传参困难mixin之间不能直接传递参数全靠命名约定。Vue3用组合式函数取代了mixin的位置。一个组合式函数就是一个普通的函数内部用ref、computed、watch等组合出逻辑最后返回状态和方法。组件里调用它拿到返回值直接使用。逻辑清晰、类型清晰、依赖清晰。5.2 写一个真实可用的组合式函数示例以一个常见场景为例——封装一个useTable组合式函数管理表格加载、分页、搜索和刷新// src/composables/useTable.js import { ref, reactive, onMounted } from vue export function useTable(fetcher, initialParams {}) { const loading ref(false) const list ref([]) const total ref(0) const queryParams reactive({ page: 1, pageSize: 20, ...initialParams }) async function loadData() { loading.value true try { const result await fetcher(queryParams) list.value result.list total.value result.total } catch (e) { console.error(表格数据加载失败:, e) } finally { loading.value false } } function search() { queryParams.page 1 loadData() } function reset() { Object.assign(queryParams, { page: 1, pageSize: 20, ...initialParams }) loadData() } onMounted(loadData) return { loading, list, total, queryParams, loadData, search, reset } }组件里用起来逻辑和模板紧密在一起script setup import { useTable } from /composables/useTable import { fetchUsers } from /api/user const { loading, list, total, queryParams, search, reset } useTable(fetchUsers, { status: 1 }) /script template el-table :datalist v-loadingloading !-- 列定义 -- /el-table el-pagination v-model:current-pagequeryParams.page :page-sizequeryParams.pageSize :totaltotal current-changesearch / /template这个组合式函数最大的优势任何组件需要同样的表格能力一行typed调用就拿到了所有状态和方法不用复制粘贴一堆data和methods下来。5.3 组合式函数的设计原则几个我总结的实践经验函数命名用use开头便于一眼识别。参数尽量传纯函数和纯数据不要在内部业务化保持通用。返回的reactive对象建议转成ref或者使用toRefs防止解构丢响应性。如果你直接返回reactive拿回来也只能整个对象操作。内部生命周期的使用要小心组合式函数里可以用onMounted、onUnmounted但只能在组件的setup阶段同步调用。如果你在异步回调里调用onMountedVue会警告。6. 常见报错和项目实战场景排查6.1 defineProps或defineEmits未定义很多人写defineProps([title])的时候IDE提示未定义。这是因为defineProps是一个编译宏只在script setup中生效不需要import。但IDE如果不识别往往是eslint或volar插件的版本不对。新版VolarVue Language Features已经能原生识别老版本需要把Vetur禁用掉否则两个插件互相打架。6.2 reactive对象被赋值后失去响应性这个错误几乎每个Vue3入门者都遇到const user reactive({ name: 张三 }) // 接口返回数据 user await fetchUserData() // 报错不能重新给reactive赋值正确做法是直接用ref然后整体赋值const user ref({ name: 张三 }) user.value await fetchUserData() // 可以页面自动更新这个区别背后的原理 reactive的代理对象在创建时就固定了如果要替换整个对象你实际是让代理对象指向新地址这是不可能的。ref则内部用了一个包裹对象替换时直接改ref内部的值所以可以。这也是我个人更偏ref的原因。6.3 v-for中的key使用index导致列表更新错乱Vue3对key的要求和Vue2一样但很多新手为了省事直接用index。这在纯展示列表时没问题一旦涉及列表项的增删、排序或者本地状态index作key就会出现张冠李戴。比如一个待办列表勾选完成后删除这一项用index做key会导致后续所有项的勾选状态错乱。正确的key应该用业务唯一ID哪怕后端没有也可以在前端生成一个自增的id。// 不要 li v-for(item, index) in list :keyindex // 推荐 li v-foritem in list :keyitem.id6.4 v-model更新不触发computed重算这个一般不是框架问题是你用了非响应式的方式修改数据。比如// 错误直接修改深层属性Vue3的ref深层自动响应还好 // 如果是reactive对象很多人会在异步回调里直接赋值却忘了用.value典型场景el-input绑定searchForm.value.keyword用户输入后computed没变。排查思路是打印一下searchForm.value看看输入的内容到底有没有写进去。通常不是响应式的问题而是绑定到了错误的字段名上。6.5 异步组件加载失败/白屏用defineAsyncComponent或者路由懒加载时如果组件内部报错Vue2会白屏或者弹错误框Vue3默认也是白屏难debug。建议开发阶段把自己的App.vue包一层错误处理组件script setup import { onErrorCaptured } from vue const error ref() onErrorCaptured((e) { error.value e.message return false // 阻止错误继续传播 }) /script template div v-iferror classerror-full-screen 组件渲染出错{{ error }} /div slot v-else / /template这样出错时你能看到错误信息而不是空白页。6.6 uniapp中使用echarts图片空白uniapp的app端canvas运行环境和浏览器有差异直接引入echarts后图表不渲染是常见问题。常规做法是改用renderjs配合echarts——renderjs运行在视图层可以直接操作canvas而且跟逻辑层通信是异步的。在vue3 uniapp的项目里还要注意renderjs只能在非编译小程序端使用小程序端得用ec-canvas等适配方案。我实测下来的配置要点canvas的id必须固定宽高必须显式指定不能在style里写百分比配置项变化后要通过renderjs的script暴露的接收方法重新渲染不能直接改echarts实例。如果图片不更新检查是否在正确的生命周期里调用了setOption。6.7 Edge浏览器右上角关闭按钮失效有个热搜词专门提到Vue3项目在Edge浏览器中偶尔无法关闭右上角的最小化按钮。这听起来奇怪其实大概率不是Vue3本身的问题而是项目中开启了全局的键盘事件监听或window尺寸变化监听导致Edge的原生标题栏响应被吞掉或者某个第三方组件在关闭时阻止了默认行为。我在一个后台管理项目里遇到过相似现象最后定位到是某个全局拖拽组件监听的mousemove没有在组件卸载时清理事件监听器堆积Edge的窗口按钮响应变得极其迟钝。排查思路全局搜索addEventListener和mousemove确认所有监听都有对应的移除。用Edge的开发者工具在console里执行getEventListeners(window)检测是否有异常数量的监听器。在beforeUnmount时清理定时器setInterval、setTimeout。如果你用了cefsharp这类内嵌壳还要检查壳层对Native窗口事件的中断情况。Vue3侧基本无解多半是宿主环境在事件循环上做了干扰。6.8 Vite Vue3项目本地正常局域网打开空白这个问题也上榜热搜了。本地localhost能跑换局域网IP访问白屏通常有三个原因Vite默认只绑定了127.0.0.1要设置server.host为true或具体IP。路由history模式在非首页刷新时后端服务器没有做history fallback返回404。Vite开发模式下自身会处理但如果你把打包产物放到了静态服务器上而没配rewrite规则非根路径刷新就白屏。打包时base配置写成了相对路径/绝对路径不匹配资源加载404也会白屏。生产环境有时要设base: ./让资源相对当前路径生效。7. 面试经典6连问背后的真正考点热搜里的“vue3面试最经典6个问题”虽然每年都在变但核心高价值问题一直围绕这些方向这里挑几个重点讲透不只是给答案更重要的是理解为什么考官会问这个。7.1 ref和reactive的区别以及各自的底层实现考点在响应式原理。ref内部调用的是reactive的包装对象返回的是个RefImpl实例有value属性模板里自动解包。reactive是直接对目标对象做Proxy代理。面试时会追着问为什么reactive不能解构因为解构出来的值是基本类型脱离了Proxy代理的get/set拦截自然失去响应性。想保住响应性就得用toRefs把每个属性转成ref。还有一层reactive的代理是懒代理嵌套对象只有真正访问时才继续代理好处是性能好。Vue2时代的defineProperty是在初始化时递归遍历所有属性多层嵌套对象一上来就全代理性能开销大这也是为什么Vue2里深层响应式对象初始化慢。7.2 Composition API和Options API对比面试官想听的是“什么时候用哪个”不是无脑夸new好。我的观点基础组件和模板简单的小组件Options API更直观中大型业务组件、跨组件复用逻辑Composition API优势明显。Vue3官方并没有说完全抛弃Options API而是给你选择。但作为面试你要能说清楚Composition API的三个核心优势逻辑复用能力组合式函数替代mixin干净无污染。代码组织方式按关注点聚合而不是按选项分散。类型推导友好TypeScript推断比Options API更顺特别是props和emits的类型标注。再补充一点Composition API的setup只执行一次所以你不需要担心重复执行的问题但也不要写在路由守卫里用options才有的api这种混搭玩法。7.3 Vue3的diff算法优化在哪Vue3的diff相比Vue2有以下几个优化点静态标记PatchFlags编译时对节点打标记动态绑定的部分才走diff纯静态节点直接跳过。静态提升不会变化的节点只创建一次重复render时直接复用。事件缓存对绑定的事件缓存避免每次render重新创建函数。最长递增子序列算法移动DOM时找到最少的移动次数不像Vue2的diff都从头到尾对比。解答问题时建议直接拿一个具体场景举例一个列表里只有一个文本框是动态变化的Vue3编译时会给这个文本框打上动态标记其他节点全部跳过。Vue2则是每次渲染都从头对比整个树结构。7.4 v-model v-model:xxx .sync的关系Vue2中 .sync 就是 v-model 的变体用于自定义组件同步多个prop。Vue3里 .sync 被彻底移除了统一合并为v-model:propName语法。所以现在你看到的就是ChildComponent v-model:titlepageTitle v-model:contentpageContent /子组件定义const props defineProps({ title: String, content: String }) const emit defineEmits([update:title, update:content])面试时这个问题考察的是你是否有vUe2迁移经验而不是背API。7.5 keep-alive和动态组件keep-alive在Vue3中多了几个新特性。它可以按include和exclude过滤缓存哪些组件还可以传入max限制最多缓存几个实例。Vue3里keep-alive的缓存机制改用Map存储支持动态的组件名这点比Vue2更强。企业中后台项目经常会用到keep-aliva按页面缓存列表页切换详情再返回列表数据、滚动位置要保持不刷新用include指定组件的name即可。注意在Vue3的setup语法下组件name的写法变成了额外一个script块定义nameVue3.3系列及以上支持了defineOptions更方便script export default { name: UserListPage } /script script setup // ... /script或者Vue 3.3script setup defineOptions({ name: UserListPage }) /script7.6 父组件访问子组件的实例Vue2里this.$refs.child.xxx。Vue3里子组件如果用script setup默认是关闭的父组件拿不到内部任何数据除非子组件主动通过defineExpose暴露出去!-- 子组件 -- script setup const count ref(0) const reset () { count.value 0 } defineExpose({ count, reset }) /script !-- 父组件 -- script setup import { ref, onMounted } from vue import Child from ./Child.vue const childRef ref(null) onMounted(() { childRef.value.reset() }) /script忘记defineExpose父组件拿到的是个空对象这是新手特容易撞上的“明明ref了为什么拿不到”问题。8. 后台管理系统常遇到的组件场景表单校验和tabs样式8.1 日期校验和白名单逻辑热搜里有“vue3 rules 日期检验”说明很多人在封装搜索表单时对范围日期选择器 rules的校验规则写法有疑问。使用Element Plus时留意日期选择器的绑定值本身是数组或Date对象rules校验时要对null、空数组分别处理const rules { dateRange: [ { validator: (rule, value, callback) { if (!value || !Array.isArray(value) || value.length ! 2) { callback(new Error(请选择开始和结束日期)) } else if (value[0] value[1] value[0] value[1]) { callback(new Error(开始日期不能晚于结束日期)) } else { callback() } }, trigger: change } ] }注意Element Plus的el-date-picker在清空时会传null而不是空数组所以校验里!value || value.length ! 2要同时覆盖。很多人的bug就是只在没有value时拦截清空数组却漏了。8.2 修改tabs标签页的样式热搜里“vue3修改tabs标签页样式”其实核心问题是如何对Element Plus的深层样式做定制。Element Plus的tab条、划线、内容区都有自己的类名直接写在scoped样式中是穿透不了的。以前Vue2的推荐做法是::v-deep或者/deep/Vue3有了新写法style scoped /* 这种写法Vue3.2推荐 */ :deep(.el-tabs__nav) { background: #f5f7fa; } :deep(.el-tabs__active-bar) { height: 3px; background: linear-gradient(90deg, #409eff, #67c23a); } :deep(.el-tabs__item) { color: #666; } :deep(.el-tabs__item.is-active) { color: #409eff; font-weight: 600; } /style有几个坑要提醒不要在全局样式中写这些覆盖否则影响全站所有tabs。如果改了active-bar却看不到变化多半是样式被更深的选择器覆盖检查Element Plus本身有没有!important。暗黑模式下深色背景的active-bar颜色需要额外写一套黑暗主题的样式。8.3 动态添加/删除表单行中后台配置页必有的场景用户点“加一行”就新增一条点删除就移除同时校验规则要跟着新行生效。用v-for 动态数组实现就行const formRows ref([ { id: 1, name: , price: null } ]) const addRow () { formRows.value.push({ id: Date.now(), name: , price: null }) } const removeRow (index) { if (formRows.value.length 1) { return // 至少保留一行 } formRows.value.splice(index, 1) }模板里要注意每一项的prop动态拼接el-form-item v-for(row, index) in formRows :keyrow.id :label项目 (index 1) :proprows. index .name :rulesrowRules.name el-input v-modelrow.name / /el-form-itemrules的注脚写法rows. index .name是在el-form上绑定:modelform时生效的关键。很多人就是漏了这步导致规则永远校验不上新增的行。9. 完整可落地的Vue3入门学习路径建议收藏如果你真要从零开始别东一榔头西一棒子。我建议按这个顺序来每一步都有明确目标理解核心概念读完Vue3官方文档的“基础”章节从创建应用开始到模板语法、组件、props、事件、插槽尽量不看Composition API先把模板这部分吃透。目标是能做出静态页面和简单组件。上手Composition API把官方文档的响应式核心、Composition API这两章精读动手改写一个你之前用Options写的小组件。目标是理解setup里ref、reactive、computed、watch的配合。做三个小项目待办清单增加、删除、筛选、本地存储搜索列表页防抖、分页、loading态表单校验组件validate、reset、动态添删行学习Vue Router和Pinia做一个小型后台登录首页用户列表把路由守卫、动态路由权限、状态管理都过一遍。目标是理解SPA应用的项目结构。读源码可选当你能不看文档写出一个复杂组件时再去看Vue3源码中ref、effect、computed的实现。那时你会发现很多面试题背后的原理不攻自破。这个路径大概需要2到4周取决于你每天能投入的时间。重点是第三、四步一定要动手敲不能只看。我自己带新人的体会是学Vue3最大的门槛不是语法是对响应式模型的理解。只要想明白“数据变了视图自动更新”底层是Proxy 依赖收集 触发更新这一条链路后面所有API都是围绕这条链路的工具。不是你用了工具才聪明是理解了模型才会用对工具。最后分享一个小技巧入门阶段不要追求“优雅”不要一上来就封装组合式函数、抽象通用组件。先老老实实把业务代码写出来跑通一版再看哪里重复多。等你在两三个页面感受到了“这段逻辑我复制了两遍”自然就知道该抽什么、怎么抽了。抽象过早反而是新手最容易憋出来的一堆没人看得懂的“高级代码”的来源。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

RK3588软实时化实战:LubanCat 5与RKDevTool协同调优指南 2026/9/28 19:44:29

RK3588软实时化实战:LubanCat 5与RKDevTool协同调优指南

1. 项目概述:软实时化不是“打补丁”,而是重构系统响应的底层逻辑软实时化LubanCat 5和RKDevTool的使用,这个标题背后藏着一个被很多嵌入式开发者低估的现实问题:我们总在用硬实时的标准去要求一个原本设计为通用Linux的系统&…

阅读更多 →
ASP.NET Core 实战:为 MCP Streamable HTTP 配置 TaoToken 统一 API 通道 2026/9/28 19:44:29

ASP.NET Core 实战:为 MCP Streamable HTTP 配置 TaoToken 统一 API 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
Claude Opus 4.7 曝光、实名制风暴与国产大模型崛起:GLM-5.1 对比分析 2026/9/28 19:44:29

Claude Opus 4.7 曝光、实名制风暴与国产大模型崛起:GLM-5.1 对比分析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
车规级Hypervisor功能安全设计与认证实践 2026/9/28 19:44:29

车规级Hypervisor功能安全设计与认证实践

1. 项目概述:为什么功能安全系统开始认真对待Hypervisor?你有没有遇到过这样的场景:一辆智能汽车的仪表盘要实时显示车速、油量、导航信息,同时车载信息娱乐系统(IVI)还要播放高清视频、运行语音助手、处理…

阅读更多 →
影刀RPA实操指南:Excel批量处理万行数据的性能优化方案 2026/9/28 19:44:29

影刀RPA实操指南:Excel批量处理万行数据的性能优化方案

影刀RPA实操指南:Excel批量处理万行数据的性能优化方案 同样是处理一万行数据,有人用影刀RPA跑十分钟就完事,有人跑一个小时还中途内存爆掉——差距不在电脑配置,而在流程写法上。我接手过一个同事写的库存汇总流程,逐…

阅读更多 →
Win/Mac 双端通用 OpenClaw 2.7.9 可视化落地完整实操流程:TaoToken 统一 Key 配置与验证 2026/9/28 19:44:14

Win/Mac 双端通用 OpenClaw 2.7.9 可视化落地完整实操流程:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉