news 2026/9/28 15:12:53

Vue3入门:从组合式API到响应式原理,吃透核心少走弯路

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vue3入门:从组合式API到响应式原理,吃透核心少走弯路

直接上手Vue3,先别急着背文档,把这几个关键点吃透,你就能少走很多弯路。作为一个从Vue2一路用过来的老开发,我对Vue3的态度从最初的“不太适应”到现在的“真香”,中间踩过不少坑。这篇内容会把Vue3入门最核心的东西拆开讲清楚,包括环境搭建、组合式API、组件通信、常见业务场景的坑,以及面试和迁移中会碰到的问题。不管你是刚接触前端的新手,还是想从Vue2转过来的老开发,这篇文章都尽量用大白话和实操经验帮你建立完整的认知框架。

很多人入门Vue3的第一反应是“不就是换个写法吗?”但实际用起来会发现,Vue3的变化远不止写法,它对响应式底层、组件逻辑复用、类型推导都做了大改。如果还用Vue2的思维写Vue3,会写得很难受。这篇内容不只是讲API,更想把“为什么这么设计”“实战中要注意什么”说透。我们直接进入正题。

1. 为什么现在值得学Vue3:从Vue2迁移视角看差异

1.1 你真正需要知道的Vue2与Vue3核心差异

先抛一个常见问题:Vue2和Vue3到底有什么区别?面试里几乎必问,但很多回答都停留在“Vue3用组合式API、性能更好、Tree Shaking”这些套话上。真正落实到代码里,差异集中在四个层面。

第一是响应式原理。Vue2用的是Object.defineProperty,只能拦截对象属性的读取和修改,对新增属性、数组下标赋值、length变化都无能为力。Vue3用的是Proxy,直接代理整个对象,拦截所有操作,新增、删除、索引访问都能被监听到。这个底层变化带来的直接体验是:写代码时不用再小心翼翼地用Vue.set了,动态加属性就是自然响应式。

第二是组合式API。Vue2的逻辑组织是“按选项分”,data放一起、computed放一起、methods放一起。问题是,同一个功能的数据和逻辑会被拆散到各个选项里,一个复杂组件可能滚屏很久才能看全某个功能相关的代码。Vue3的setup函数让你可以“按功能聚合”,一个功能的ref、function、watch、computed写在一块,方便阅读和抽取复用。

第三是生命周期。Vue2的created、mounted、destroyed在Vue3里改名加前缀on,同时beforeCreate和created不再需要显式使用,因为setup本身就是创建阶段的执行点。对应关系建议直接记:beforeMount变成onBeforeMount,mounted变成onMounted,beforeDestroy变成onBeforeUnmount,destroyed变成onUnmounted。

第四是模板编译和虚拟DOM的优化。Vue3引入了静态标记、动态节点追踪、事件缓存,意味着更新时不再对整个组件树做diff,只精确更新动态部分。实测在列表渲染、频繁数据更新的场景下,性能提升非常明显。

1.2 组合式API到底解决了什么问题

用一句话概括组合式API的价值:把“和某个功能相关的代码”从“按选项分散”变成“按功能聚集”。

举个例子,一个列表页需要处理搜索条件、请求数据、分页、筛选排序。Vue2写法里,data里要有searchForm、tableData、pageNum,computed里要有筛选后的列表,methods里要有search、fetchData、resetSearch。看代码时你得在data、computed、methods之间来回跳,而且如果多个页面有类似功能,复制粘贴一份再改改,维护起来很痛苦。Vue3用组合式API可以这么写:一个useSearchTable函数,内部包含所有相关状态和方法,组件里直接调用,干净利落。

这个设计的意义在大型项目里更明显。比如有一个用户信息展示组件,里面既有登录用户的逻辑,又有权限判断,又有通知消息。把这些逻辑分别抽成useUser、usePermission、useNotification,组件代码会非常薄,逻辑复用靠函数组合就能实现,不依赖mixin那种容易命名冲突的机制。

对新手来说,组合式API的思维转变是:不要一上来就找data和methods,先想清楚这个组件有哪些“功能模块”,每个模块需要什么状态和动作。举个例子,一个购物车组件会有“购物车列表”“商品数量增减”“总价计算”这三个模块,每个模块用一组ref和function表达出来,最后组合在一起。

2. 环境搭建与第一个Vue3项目

2.1 官方推荐方式:Vite脚手架安装

Vue3的官方推荐是使用create-vue或者create-vite。相比Vue2常用的vue-cli,Vite的最大优势是开发服务器启动极快,因为它利用浏览器原生ESM,按需编译,而不是像Webpack那样先打包整个项目。

安装命令很简单:

npm create vue@latest

不过这个命令会创建一个create-vue项目,默认带入Router、Pinia、ESLint等选项。如果你只是想快速体验Vue3,可以直接用Vite官方脚手架:

npm create vite@latest my-vue3-app -- --template vue cd my-vue3-app npm install npm run dev

执行完后,浏览器打开http://localhost:5173就能看到初始页面。这里有个小坑:如果用npm create vue@latest创建项目,最新版本默认启用了TypeScript和JSX等选项,新手刚入门可能会被一堆配置文件吓到。建议第一次学习时,在交互提示里选择“No”跳过TypeScript和Vue Router,先把基础语法跑通。

等熟练之后,再重新创建带TS的项目。因为Vue3对TypeScript的支持非常友好,defineProps和defineEmits配合TS接口可以做到强类型约束,大型团队协作时非常有价值。

2.2 项目结构解读与关键配置

Vite创建的项目结构和Vue2的webpack项目很不一样。核心目录如下:

  • src/main.js:应用入口,创建Vue实例并挂载
  • src/App.vue:根组件
  • src/components/:存放组件
  • index.html:页面模板,注意它不在public里,而是项目根目录
  • vite.config.js:构建配置

Vite项目的index.html是真正的入口文件,浏览器先加载这个HTML,然后通过<script type="module" src="/src/main.js">加载你的应用脚本。这一点和Vue2 Webpack项目里的template入口思路不太一样,理解了这个才能明白为什么Vite启动那么快。

关键的vite.config.js可以配置别名、代理、插件。日常开发最常用的就是配置@指向src目录:

import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import path from 'path' export default defineConfig({ plugins: [vue()], resolve: { alias: { '@': path.resolve(__dirname, 'src') } }, server: { host: true, port: 5173, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } } })

这里要提醒一个开发时很常见的坑:在局域网中调试,手机或同事电脑访问你的开发地址时,如果页面空白,大概率是因为server.host没有设置为true。Vite默认只监听localhost,设置host: true后才会监听所有网卡地址,外部设备才能访问。

2.3 工程化细节:SCSS、JSX、环境变量

从热搜词里能看到很多人在问“vue3安装scss”“vue3使用jsx”,说明工程化配置是入门后马上会遇到的问题。

安装SCSS非常方便,Vite内置了对CSS预处理的依赖识别,只需要安装scss相关依赖,然后在<style>标签里加上lang="scss"即可:

npm install -D sass
<style lang="scss" scoped> $primary-color: #42b883; .button { background-color: $primary-color; &:hover { opacity: 0.8; } } </style>

不需要额外配置Vite插件,装着就能用。需要注意的是,如果使用dart-sass新版语法,/除法运算要写成math.div,老项目迁移时经常在编译时报错。

JSX在Vue3中也是支持的,但需要通过插件启用。使用create-vue创建项目时如果选择了JSX支持,会自动装@vitejs/plugin-vue-jsx。手写配置也很简单:

import vueJsx from '@vitejs/plugin-vue-jsx' export default defineConfig({ plugins: [vue(), vueJsx()] })

有了JSX支持,写render函数就不用心h函数了,可以通过类似React的方式写组件内容。不过大多数场景下,Vue模板已经够用,JSX更适合处理动态嵌套组件、高阶组件封装等场景,新手可以先不深究。

环境变量则通过.env文件管理。Vite默认只暴露以VITE_开头的变量给前端代码:

# .env.development VITE_API_BASE_URL=/api VITE_APP_TITLE=开发环境

在代码里直接用import.meta.env.VITE_API_BASE_URL读取。这个细节和Vue2的process.env.VUE_APP_*不一样,如果你是从Vue2迁移过来,这里一定要记住。

3. 核心语法实战:组件、生命周期与Computed

3.1 组件通信的几种姿势

Vue3组件通信,最常用的是defineProps和defineEmits。在<script setup>语法下,这两个宏函数不需要导入就能使用,非常简洁。

父组件传值:

<Child :title="msg" @update="handleUpdate" />

子组件接收和触发:

<script setup> const props = defineProps({ title: { type: String, default: '' } }) const emit = defineEmits(['update']) const handleClick = () => { emit('update', 'new value') } </script>

这里有个细节:props是响应式对象,但你不能直接解构后拿去给模板用。直接解构会丢失响应式。如果确实需要解构并保持响应式,可以使用toRefs,比如const { title } = toRefs(props),模板里用title时自动带上.value。

除了父子通信,还有provide/inject可以跨层级传数据。封装一个全局主题、或者给多层子组件传递配置对象时,这种方案比层层传props清爽很多。使用时要注意,provide和inject本身不是响应式的,如果需要响应式,需要传入ref或reactive对象。

兄弟组件之间通信,简单场景可以用事件总线,但Vue3不再自带$on/$emit实例方法,需要自己实现一个事件总线或者使用mitt。更推荐的是全局状态管理库Pinia,尤其是涉及到跨组件共享用户信息、购物车状态时,Pinia的API设计比Vuex5(也就是Pinia的前身)更简单,没有mutations概念,直接改state就行。

3.2 ref、reactive与响应式原理

Vue3的响应式API有两个最基础的工具:ref和reactive。

ref用于包装基本类型值,也可以包装对象,但访问时都要带.value,模板中会自动解包所以省略.value。reactive只能用于对象,访问属性时直接object.xxx,不需要取value。

为什么有这两个API?因为Proxy只能代理对象,无法直接代理number、string这类基础数据类型。为了让基本类型也能有响应式能力,Vue3就把基本值包进一个对象里,再用Proxy代理这个对象。这就是ref内部做的事情。

在实际使用中,我的建议是:简单场景全部用ref,包括对象。因为ref写起来统一,语义更清晰,而且reactive对象如果直接赋值替换,响应式会丢失。比如:

let state = reactive({ list: [] }) // 请求回来之后这样写是错的,会丢失响应式 state = { list: res.data } // 应该用 push 或改写属性 state.list = res.data

用ref则没有这个顾虑,因为你可以直接state.value = res.data。从代码一致性来看,ref更适合大多数人作为主力响应式API。

需要提一下toRefs和computed的关系。computed返回的是一个只读的ref,你在模板里直接用,在函数里访问要.value。注意computed里如果依赖了props中的某个属性,直接用props.xxx写就可以了,计算属性会自动追踪依赖。但要注意不要在computed里修改props,这会警告甚至导致数据流混乱。

3.3 computed、watch与useSlots

computed的写法很简单:

const basePrice = ref(100) const discount = ref(0.8) const finalPrice = computed(() => basePrice.value * discount.value)

和Vue2的computed选项不同,这里finalPrice是一个ref对象,在模板里直接写{{ finalPrice }}没问题,在函数里要finalPrice.value。

watch在Vue3中支持多种用法。监听ref:

watch(basePrice, (newVal, oldVal) => { console.log('价格变化', newVal, oldVal) })

监听多个来源:

watch([basePrice, discount], ([newPrice, newDiscount], [oldPrice, oldDiscount]) => { // ... })

监听reactive对象的某个属性时,需要写函数返回:

watch(() => state.list.length, (len) => { console.log('列表长度变化', len) })

还有一个容易忽略的watchEffect,它会自动追踪内部用到的响应式数据,在数据变化时自动重新执行。比如动态计算总价时,无需手动声明要监听哪些依赖。

useSlots这个API是从热搜词里看到有人搜的。在<script setup>中,如果你想拿到插槽内容去做渲染控制,可以用useSlots:

import { useSlots } from 'vue' const slots = useSlots() console.log(slots.default?.())

这个API最常用在封装通用组件时判断某个插槽是否渲染,避免不必要的DOM节点。比如一个卡片组件的footer插槽没传内容时,就整个不渲染footer区域。

4. 常见业务场景中的踩坑实录

4.1 动态表单增删行

后台管理系统中,动态添加删除表单的一行数据是非常典型的需求。比如商品规格、联系方式列表。用Vue3实现时,坑点主要在“删除后表单校验状态残留”和“新增行的响应式丢失”。

先看基本做法:

<script setup> import { ref, reactive } from 'vue' const form = reactive({ list: [{ name: '', age: '' }] }) const addRow = () => { form.list.push({ name: '', age: '' }) } const removeRow = (index) => { form.list.splice(index, 1) } </script>

因为form.list本身是reactive数组,直接用push和splice操作是响应式的,没问题。但如果你写了form.list = [...form.list, newRow],就用到了数组替换,这时响应式会丢失,必须改成push或者对form整个重新赋值。

另一个常见坑是动态v-model绑定。在模板中遍历form.list,需要给每行绑定不同字段:

<div v-for="(item, index) in form.list" :key="index"> <input v-model="item.name" /> <button @click="removeRow(index)">删除</button> </div>

这里item是form.list里的对象引用,直接改item.name是响应式的,没问题。但如果你用v-model="form.list[index].name",虽然也可以,但表达式太长不推荐。

删除行之后,表单校验规则如果绑定了索引,可能会出现校验信息残留。解决方法是给每行加一个唯一key,不要用index作为key,最好用一个自增id。因为用index作为key,删除一行后,后面的组件会被复用,可能导致状态错乱。

4.2 日期校验rules写法

Element Plus的日期选择器配合表单校验,是后台高发问题。很多人搜“vue3 rules日期检验”,其实核心不是日期比较逻辑,而是校验规则里不知道如何判断空值和处理format格式。

基本写法是这样:

const rules = { dateRange: [ { required: true, message: '请选择日期范围', trigger: 'change' } ] }

但如果日期范围是数组,required的校验规则对数组长度为空的情况不会生效。需要用自定义校验函数:

const validateDateRange = (rule, value, callback) => { if (!value || value.length !== 2) { callback(new Error('请选择完整的日期范围')) } else { callback() } }

注意trigger用change而不是blur,因为日期选择器的失焦时机很奇怪,直接用change更稳妥。

还有一个容易踩的坑:如果你给日期选择器设置了format,比如value-format="YYYY-MM-DD",那么绑定值的类型是字符串。如果没设置value-format,值是Date对象,再转参给后端时就要自己格式化。Element Plus和Day.js配合,推荐后端接口日期统一用YYYY-MM-DD HH:mm:ss,所以建议显式加value-format。

4.3 登录跳转、搜索条件保留、首屏加载优化

“vue3 登录不跳转”这个问题,通常不是跳转代码的问题,而是路由守卫和时序问题。常见原因是:在登录页面调用router.push后,beforeEach守卫又拦截了,并且没有放行。排查思路是:先确认登录成功后的token已经存储,再检查路由守卫里对白名单的处理,最后确认router.push是否被回调包裹但回调里重复导航了。

另外,登录后如果router.push没反应,可以看下是不是在axios响应拦截器里做了全局错误处理,返回了401导致后续代码中断。我遇到过很多次这类问题,排查时优先看控制台有没有报错,而不是怀疑Vue3本身。

“搜索条件保留”这个问题分几种场景。一种是列表页跳详情页再返回,希望保留搜索条件和分页状态。简单的方案是用keep-alive缓存组件,但要注意Vue3中keep-alive只对动态组件或路由出口生效,并且配合onActivated来刷新数据。另一种是要保存到URL query里,刷新页面也不丢失。推荐把搜索条件序列化到location.hash或query中,进页面时解析参数初始化表单。这种方式对分享链接也友好,体验好于缓存。

“vxetable怎么避免vue3首屏加载”,这里说的是vxe-table这类大型表格组件。首屏加载慢的根源是组件库全量引入。解决方案是改为按需引入,和UI库的按需方案类似。具体到vxe-table,官方支持ESM按需导入,只引入用到的表格模块和样式,体积能减少一半以上。另一个经验是不要把所有异步组件都无脑分包,过度分包反而产生大量小请求,拖慢首屏。优先把路由组件用动态import,表格这类第三方库做手动分包(manualChunks),让主要框架代码和业务代码分开缓存。

5. 面试高频问题与源码层面的理解

5.1 经典面试题梳理

面试里Vue3最经典的6个问题,基本绕不开这些:

第一,Vue2和Vue3响应式原理的区别。回答要落到Object.defineProperty和Proxy的具体限制对比,最好说出数组变化的几个场景,以及Vue3如何通过Reflect和handler实现更全的拦截。

第二,ref和reactive的区别及使用场景。要解释为什么存在ref,基本类型无法被Proxy代理,所以包装成对象;对象可以用reactive直接代理,但赋值替换会丢响应式。

第三,computed和watch的区别。computed是声明式派生状态,有缓存,依赖变化时才重算;watch是命令式侦听器,适合执行异步操作或复杂逻辑。

第四,nextTick的作用原理。Vue3的DOM更新是异步批量的,nextTick在DOM更新完成后执行回调,源码里面通过Promise.resolve().then实现,如果环境不支持,会降级到MutationObserver。

第五,<script setup>相比Options API的优势。包括逻辑聚合、更好的TypeScript推导、不需要setup返回值、组件自动注册等。

第六,Vue3有哪些性能优化。虚拟DOM diff算法优化、静态节点提升、静态事件缓存、tree shaking、响应式代理更宽泛等。

这些题如果只背结论,面试官追问就露馅。建议每个问题都去读一下源码对应部分,理解背后的设计权衡。

5.2 从源码角度看响应式

简单说下Vue3响应式源码的结构。reactivity模块核心是reactive、ref、effect、track、trigger。

当你执行reactive(obj)时,会返回一个Proxy实例,handler中定义了get、set、deleteProperty等拦截。在get拦截里,会调用track函数,把当前正在运行的effect收集到依赖集合里。在set拦截里,会调用trigger函数,找出所有依赖这个属性的effect并重新执行。

effect是响应式的核心执行单位。computed和watchEffect底层都是effect。computed的effect有个lazy选项,只有读取值时才计算,并且有缓存和脏值判断;watchEffect则是立即执行一次,之后依赖变化重新执行。

ref的实现本质上也是代理,但它是一个包含value属性的对象。对于对象类型的ref,内部会用reactive去代理value。

理解了这套流程,你就明白为什么说“Vue3的响应式是运行时动态追踪依赖”,它和Vue2的依赖收集机制完全不同。Vue2在数据初始化时遍历属性并defineProperty,Vue3是在读取时动态建立依赖,这点对Map、Set等原生集合类型也能自然支持。

6. 从Vue2迁移到Vue3的注意事项

6.1 成熟项目的迁移策略

如果你手里有一个成熟Vue2项目要转Vue3,别想着一步到位全量重写,风险太大。推荐分三步走。

第一步,先梳理项目依赖。看现在用的第三方库是否有Vue3版本。像Element UI这种只支持Vue2的库,Vue3要对应用Element Plus;vxe-table、echarts这类库需要检查版本兼容性。特别注意全局组件的注册方式、插件机制的差异,比如Vue2的Vue.use,Vue3中变成了app.use;Vue2的Vue.prototype.$xxx,Vue3中变成了app.config.globalProperties.$xxx。

第二步,把Vue2项目先升级到Vue2.7。如果你还在Vue2.6以下,建议先升级到2.7,因为Vue2.7引入了<script setup>和composapi的兼容支持,同时保留Options API。升到2.7后先迁移代码风格,把一部分逻辑改用组合式API,再整体切换到Vue3,难度会降低很多。

第三步,使用官方迁移工具和兼容模式。Vue3提供了一个@vue/compat构建版本,可以让你在Vue3环境里跑Vue2代码,同时在控制台输出每个不兼容点的警告。这个方法适合大项目渐进式迁移,先把框架切到Vue3,再逐个模块修改警告。

迁移过程最常见的坑有几个:$listeners合并到$attrs里了;$children被移除了;filter被移除了;事件总线要自己换方案;v-model的组件用法改成modelValue和update:modelValue;异步组件的写法从() => import()保持一样,但同步组件变了;functional组件变成了普通函数组件。

6.2 生态兼容性排查

Vue3的生态如今已经相当完整,常用的组件库、UI库、图表库基本都有Vue3版本。但有几个特殊场景需要提前排查。

如果你的项目涉及到CefSharp(桌面客户端内嵌网页),热搜词里提到“cefsharp vue3 window.cefbridge 注册”。这个问题常见于桌面应用与前端通信,需要在window上挂桥接对象。在Vue3里,如果你在main.js中通过window.cefBridge = xxx注册,然后在组件里读取是没问题的,但如果你用了TypeScript,需要声明全局类型。另外要注意CefSharp旧版本的内核不支持现代浏览器特性,Vue3的Proxy在旧内核上可能无法工作,需要升级到新版CefSharp或Chromium内核。如果项目必须运行在低版本WebView中,建议先做兼容性测试。

OnlyOffice在线编辑、百度离线地图、three.js这类第三方集成,Vue3本身没有特别的坑,但要格外注意生命周期销毁。比如Three.js的场景、动画循环、renderer实例,必须在onBeforeUnmount中释放,否则切路由后GPU资源一直占用,页面会越来越卡。OnlyOffice和地图示例同样要在卸载时移除事件监听者。

如果项目还涉及微前端方案,Vue3配合Vite是主流选择。要注意Vite构建时的base路径配置、子应用的导出格式、CSS隔离问题。主应用用qiankun或wujie加载Vue3子应用时,子应用的Vite需要改成打包成UMD,或者使用vite-plugin-qiankun这类辅助插件,不然加载后会因为ESM跨域问题导致白屏。

7. 实操心得:从入门到写业务项目的几个关键建议

最后这部分算是我个人踩坑总结出的几条经验,不算什么高深道理,但确实能帮你少走很多弯路。

第一,不要一开始就追求“最新最全”。Vue3官方文档已经更新得很完善,但内容非常多。入门阶段只需要掌握<script setup>、ref、computed、watch、props、emit,就足以应付大多数后台管理页面的开发。像Suspense、TransitionGroup、自定义渲染器这些可以先放着,等你真正遇到需求再查。

第二,遇到问题先看控制台警告。Vue3的提示比Vue2友好得多,很多问题在编译阶段就会给出具体位置和建议。比如defineProps中声明了未使用的属性、reactive赋值导致的警告,控制台都会直接告诉你。养成看警告的习惯,比到处搜索答案高效得多。

第三,灵活运用v-model的多个参数。Vue3支持一个组件上写多个v-model,比如v-model:title和v-model:content,这在封装复杂的表单组件时非常顺手,也能让父组件的数据流更明确。这个能力是Vue2没做到的,实际业务里能减少很多冗余代码。

第四,项目配置一定要从需求出发。不需要一开始就封装一堆工具函数、配置好所有插件。开发过程中自然就会发现“我需要一个请求封装”“这里格式都是日期,应该统一格式化”,这时候再补,代码才是真正贴合业务的。全屋装修式的预配置,很容易引入用不到的东西,反而增加心智负担。

第五,关于“成熟项目vue2能转vue3”这件事,我的结论是:能转,但要控制范围。如果你只是一个人维护,且项目完整度很高,转Vue3的收益可能不如你在Vue2上继续迭代。Vue2官方已经停止维护,但从稳定性和团队熟悉度来看,大版本迁移的成本需要认真权衡。真正适合迁移的场景是项目还处于活跃迭代期、需要新特性、团队愿意花时间学习。迁移不是技术问题,而是工程管理问题。

如果你现在还在犹豫要不要学Vue3,我的建议是直接学。Vue2.7虽然还在维护,但前端新项目里Vue3已经是绝对主流。尽早建立组合式API的思维习惯,后面再过React的Hooks会顺畅很多。写这篇内容时,我把从安装到迁移、从响应式原理到业务坑点都过了一遍,就是希望你能站在前人的经验上去理解Vue3,而不是从零踩坑。上手过程中遇到具体报错,可以对照本文排查,能解决大部分入门阶段的问题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 15:10:45

原生PHP+MySQL服装商城源码拆解:木兮系统从架构到二次开发实战

做电商项目这些年&#xff0c;我越来越觉得"从零搭一套商城系统"是检验PHP基本功最好的方式。最近拿到一套名为"木兮"的服装购物系统源码&#xff0c;文件名后面带着编号38169&#xff0c;应该是打包发布时记录的版本号。这套系统用原生PHP加MySQL写成&…

作者头像 李华
网站建设 2026/9/28 15:09:42

用WorkBuddy搭建AI工作台:从对话到执行的自动化流程实战

用WorkBuddy搭建AI工作台这件事&#xff0c;我前前后后折腾了两周多&#xff0c;把一台平时只用来写文档的旧笔记本彻底改造成了个人自动化流水线。起因很简单&#xff1a;每天要处理的琐事实在太多&#xff0c;整理会议纪要、拆解需求、写周报、回消息、跑一些重复的数据处理&…

作者头像 李华
网站建设 2026/9/28 15:09:38

LeetCode 289 生命游戏:原地算法与状态标记法详解

1. 题目概览与核心思路1.1 从一道模拟题说开去LeetCode 289 生命游戏&#xff08;Game of Life&#xff09;是一道非常经典的二维数组模拟题&#xff0c;同时也是面试中出现频率很高的"原地算法"典型代表。我第一次刷这道题的时候&#xff0c;第一反应是"这不就…

作者头像 李华
网站建设 2026/9/28 15:09:03

GPS模块通信协议详解:NMEA 0183与UBX配置实战

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

作者头像 李华
网站建设 2026/9/28 15:09:00

CCKS 2019中文电子病历数据集:从解压到NER基线的完整实践

简介&#xff1a;CCKS 2019 中文电子病历数据集是一份面向自然语言处理与医疗信息抽取研究者的公开评测数据&#xff0c;可用于中文医学命名实体识别、关系抽取等任务的训练与验证。资源包含1379例真实病历样本&#xff0c;每个样本同时提供原始文本和实体标注&#xff0c;字段…

作者头像 李华
网站建设 2026/9/28 15:09:00

JEV模型实战:从申请密钥到接入Codex的完整指南

最近在开发者圈子里&#xff0c;JEV 这个词出现的频率明显变高了。从技术群里的讨论&#xff0c;到各种模型评测榜单的评论区&#xff0c;再到 Codex 这类 Agent 工具的配置教程里&#xff0c;到处都能看到有人在问“JEV 模型官网在哪”“JEV 怎么接入”“JEV 开源了吗”。我也…

作者头像 李华