ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

JavaScript 开发者快速上手 Vue 3 教程

2026/8/16 21:30:18 拓冰建站 浏览量
JavaScript 开发者快速上手 Vue 3 教程 JavaScript 开发者快速上手 Vue 3 教程基于 Vue 官方当前文档Vue 3 推荐使用单文件组件 SFC、script setup和Composition API。项目脚手架推荐使用create-vue它基于 Vite。参考文档Vue Quick StartVue Single-File ComponentsVue Composition API FAQ1. 你应该怎么理解 Vue如果你熟悉 JavaScript可以把 Vue 理解成HTML 模板 响应式状态 组件化 自动 DOM 更新你不再手动写document.querySelector(#count).textContentcount而是写script setup import { ref } from vue const count ref(0) /script template button clickcount Count: {{ count }} /button /template当count变化时Vue 自动更新页面。2. 创建 Vue 项目官方推荐脚手架npmcreate vuelatest然后按提示选择Project name: my-vue-app Add TypeScript? 建议先选 No熟悉后再用 Add JSX? No Add Vue Router? Yes做 SPA 建议选 Add Pinia? Yes做中大型项目建议选 Add Vitest? 可选 Add ESLint? Yes Add Prettier? Yes进入项目cdmy-vue-appnpminstallnpmrun dev典型目录src/ main.js App.vue components/ views/ router/ stores/3. Vue 单文件组件.vueVue 最常见的组件格式是 SFCSingle-File Componentscript setup const title Hello Vue /script template h1{{ title }}/h1 /template style scoped h1 { color: #42b883; } /style一个.vue文件通常分三块script setup 写 JS 逻辑 template 写 HTML 结构 style scoped 写当前组件样式scoped表示样式只影响当前组件。4.ref最常用的响应式状态script setup import { ref } from vue const count ref(0) function increment() { count.value } /script template button clickincrement {{ count }} /button /template注意count.value在script setup里访问ref要用.value。但在模板里不用{{ count }}Vue 会自动解包。5.reactive对象响应式script setup import { reactive } from vue const user reactive({ name: Alice, age: 18 }) function grow() { user.age } /script template p{{ user.name }} - {{ user.age }}/p button clickgrowGrow/button /template简单选择基本类型ref 对象/嵌套对象reactive 或 ref({ ... })实际项目里ref更通用很多团队会优先用ref。6. 模板语法文本插值p{{ message }}/p动态属性img :srcimageUrl :alttitle /:src是v-bind:src的简写。条件渲染p v-ifisLoggedIn欢迎回来/p p v-else请登录/p列表渲染ul li v-fortodo in todos :keytodo.id {{ todo.text }} /li /ul一定要写:key。事件绑定button clicksave保存/buttonclick是v-on:click的简写。7. 表单绑定v-modelscript setup import { ref } from vue const username ref() /script template input v-modelusername / p你输入的是{{ username }}/p /template相当于自动处理value input 事件常见用法input v-modeltext / textarea v-modelcontent / input typecheckbox v-modelchecked / select v-modelselected.../select8.computed派生状态如果一个值可以从现有状态计算出来用computed。script setup import { ref, computed } from vue const firstName ref(Ada) const lastName ref(Lovelace) const fullName computed(() { return ${firstName.value} ${lastName.value} }) /script template p{{ fullName }}/p /template不要这样写p{{ firstName lastName }}/p简单可以但复杂逻辑应该放进computed。9.watch监听变化执行副作用computed用于算值watch用于做事。例如搜索框防抖、请求接口、本地存储同步。script setup import { ref, watch } from vue const keyword ref() watch(keyword, (newValue, oldValue) { console.log(搜索关键词变化, oldValue, , newValue) }) /script template input v-modelkeyword / /template监听多个值watch([page,keyword],([newPage,newKeyword]){fetchData(newPage,newKeyword)})10. 生命周期最常用的是onMounted。script setup import { ref, onMounted } from vue const users ref([]) onMounted(async () { const res await fetch(/api/users) users.value await res.json() }) /script常见生命周期onMounted 组件挂载后 onUpdated DOM 更新后 onUnmounted 组件卸载后如果你熟悉 ReactonMounted ≈ useEffect(() {}, []) onUnmounted ≈ useEffect 的 cleanup computed ≈ useMemo 的一部分场景 ref/reactive ≈ useState 但自动响应式11. 组件拆分父组件script setup import UserCard from ./components/UserCard.vue const user { id: 1, name: Alice, role: Admin } /script template UserCard :useruser / /template子组件UserCard.vuescript setup defineProps({ user: { type: Object, required: true } }) /script template article h2{{ user.name }}/h2 p{{ user.role }}/p /article /templatedefineProps在script setup中不需要 import。12. 子组件向父组件通信emit子组件script setup const emit defineEmits([delete]) function handleDelete() { emit(delete) } /script template button clickhandleDelete删除/button /template父组件UserCard deleteremoveUser /带参数emit(delete,user.id)父组件接收UserCard deleteremoveUser /functionremoveUser(id){console.log(id)}13. 一个完整小例子Todo ListApp.vuescript setup import { ref, computed } from vue const newTodo ref() const todos ref([ { id: 1, text: 学习 Vue 模板语法, done: true }, { id: 2, text: 学习组件通信, done: false } ]) const unfinishedCount computed(() { return todos.value.filter(todo !todo.done).length }) function addTodo() { const text newTodo.value.trim() if (!text) return todos.value.push({ id: Date.now(), text, done: false }) newTodo.value } function removeTodo(id) { todos.value todos.value.filter(todo todo.id ! id) } /script template main h1Todo List/h1 form submit.preventaddTodo input v-modelnewTodo placeholder输入任务 / button typesubmit添加/button /form p未完成{{ unfinishedCount }}/p ul li v-fortodo in todos :keytodo.id label input typecheckbox v-modeltodo.done / span :class{ done: todo.done } {{ todo.text }} /span /label button clickremoveTodo(todo.id) 删除 /button /li /ul /main /template style scoped .done { text-decoration: line-through; color: #888; } /style这里覆盖了ref computed v-model v-for :key click submit.prevent 动态 class 数组更新14. Vue Router页面路由如果创建项目时选择了 Router会有src/router/index.js src/views/基本配置import{createRouter,createWebHistory}fromvue-routerimportHomeViewfrom../views/HomeView.vueimportAboutViewfrom../views/AboutView.vueconstroutercreateRouter({history:createWebHistory(import.meta.env.BASE_URL),routes:[{path:/,name:home,component:HomeView},{path:/about,name:about,component:AboutView}]})exportdefaultrouter入口main.jsimport{createApp}fromvueimportAppfrom./App.vueimportrouterfrom./routercreateApp(App).use(router).mount(#app)页面出口RouterView /导航RouterLink to/首页/RouterLink RouterLink to/about关于/RouterLink编程式跳转script setup import { useRouter } from vue-router const router useRouter() function goHome() { router.push(/) } /script15. Pinia状态管理如果多个组件共享状态用 Pinia。src/stores/counter.jsimport{defineStore}frompiniaimport{ref,computed}fromvueexportconstuseCounterStoredefineStore(counter,(){constcountref(0)constdoubleCountcomputed(()count.value*2)functionincrement(){count.value}return{count,doubleCount,increment}})组件里使用script setup import { useCounterStore } from /stores/counter const counter useCounterStore() /script template p{{ counter.count }}/p p{{ counter.doubleCount }}/p button clickcounter.increment 1 /button /template什么时候用 Pinia多个页面共享用户信息 购物车 权限信息 主题设置 复杂筛选条件 需要跨组件复用的业务状态什么时候不用只在一个组件内部使用的状态 父子组件之间简单传值16. Vue 和 React / 原生 JS 的思维差异你不要再频繁操作 DOM少写document.querySelector(.modal).classList.add(open)多写script setup import { ref } from vue const isOpen ref(false) /script template Modal v-ifisOpen / /template状态决定 UI。模板不是字符串拼接不要这样list.innerHTMLtodos.map(...).join()Vue 里这样li v-fortodo in todos :keytodo.id {{ todo.text }} /li数据流一般是单向的父组件 - props - 子组件 子组件 - emit - 父组件 共享状态 - Pinia不要让子组件直接修改父组件对象除非你明确知道这样做的影响。17. 常用指令速查p v-ifvisible显示/p p v-else否则显示/p li v-foritem in list :keyitem.id {{ item.name }} /li input v-modelname / button clicksubmit提交/button img :srcurl / div :class{ active: isActive }/div form submit.preventsubmit/form常见缩写v-bind:src - :src v-on:click - click18. 常见修饰符事件修饰符form submit.preventsubmit阻止默认提交。button click.stophandleClick阻止事件冒泡。键盘修饰符input keyup.entersubmit /v-model 修饰符input v-model.trimname / input v-model.numberage /19. 推荐学习路径第 1 天基础语法掌握create-vue .vue 文件结构 ref 模板插值 click v-if v-for v-model练习做一个 Todo List。第 2 天组件化掌握props emit slot 组件拆分 父子通信练习把 Todo List 拆成App.vue TodoInput.vue TodoList.vue TodoItem.vue第 3 天副作用和请求掌握onMounted watch computed fetch/axios loading/error 状态练习做一个用户列表页面支持搜索和加载状态。第 4 天路由掌握Vue Router RouterLink RouterView 动态路由 编程式跳转练习做一个三页应用首页 用户列表 用户详情第 5 天状态管理掌握Pinia store 共享状态 持久化练习做登录状态或购物车状态。20. 一个小型项目结构建议src/ assets/ components/ AppHeader.vue AppButton.vue views/ HomeView.vue UserListView.vue UserDetailView.vue router/ index.js stores/ user.js services/ userService.js App.vue main.jsservices/userService.jsexportasyncfunctionfetchUsers(){constresawaitfetch(/api/users)if(!res.ok){thrownewError(Failed to fetch users)}returnres.json()}组件中script setup import { ref, onMounted } from vue import { fetchUsers } from /services/userService const users ref([]) const loading ref(false) const error ref(null) onMounted(async () { loading.value true try { users.value await fetchUsers() } catch (err) { error.value err } finally { loading.value false } }) /script21. 最容易踩的坑1. 在 JS 里忘记.value错误count正确count.value2.v-for不写key错误li v-foritem in list正确li v-foritem in list :keyitem.id3. 过度使用watch如果你只是要计算一个值用computed。consttotalcomputed(()price.value*count.value)不要用watch手动同步。4. 子组件直接改 props不推荐props.user.nameBob推荐emit(update-user,newUser)或者把共享状态放到 Pinia。5. 把所有状态都放 PiniaPinia 不是全局变量垃圾桶。局部状态放组件里共享状态才放 store。22. 你可以按这个顺序写第一个 Vue 项目目标用户管理小应用。功能用户列表 新增用户 删除用户 搜索用户 用户详情页 全局登录用户状态涉及知识点组件 props emit ref computed watch Router Pinia API 请求推荐文件src/ views/ UserListView.vue UserDetailView.vue components/ UserForm.vue UserTable.vue stores/ auth.js services/ userService.js23. 总结你熟悉 JavaScript上手 Vue 的关键不是语法难度而是转变思路用状态描述 UI 用组件拆分页面 用 props/emit 处理父子通信 用 computed 表达派生数据 用 watch 处理副作用 用 Router 管页面 用 Pinia 管共享状态最快路线npmcreate vuelatest然后从一个 Todo List 开始把它逐步拆成组件再加路由和 Pinia。这样学 Vue 会比单纯看语法快很多。