> 技术文档 > 全栈学习 —— 前端(三)Vue框架

全栈学习 —— 前端(三)Vue框架

目录

一、Vue 框架核心思想与优势

1. 核心设计理念

2. 与其他框架的对比

3. 为什么选择 Vue?

二、Vue 基础环境搭建

1. 快速入门:直接引入 Vue

2. 工程化开发:Vue CLI

(1)安装 Vue CLI

(2)创建项目

(3)运行项目

三、Vue 核心概念与基础语法

1. Vue 实例与数据绑定

2. 指令系统

(1)v-bind:绑定属性

(2)v-model:双向数据绑定

(3)v-for:列表渲染

(4)v-if与v-show:条件渲染

(5)v-on:事件绑定

3. 计算属性与侦听器

(1)计算属性(computed)

(2)侦听器(watch)

四、Vue 组件化开发

1. 组件的定义与注册

(1)全局组件

(2)局部组件

2. 组件通信

(1)父组件向子组件传值(props)

(2)子组件向父组件传值($emit)

3. 插槽(Slot)

五、Vue 底层原理

1. 响应式系统原理

2. 虚拟 DOM 与 Diff 算法

六、Vue Router 路由管理

1. 安装与配置

2. 路由使用

3. 动态路由与参数传递

七、实战项目:待办事项应用(Todo App)

1. 项目功能设计

2. 项目结构

3. 核心代码实现

(1)状态管理(stores/todoStore.js)

(2)输入组件(components/TodoInput.vue)

(3)列表项组件(components/TodoItem.vue)

(4)列表组件(components/TodoList.vue)

(5)筛选组件(components/TodoFilter.vue)

(6)主组件(App.vue)

4. 项目运行与测试


Vue.js(简称 Vue)是一套用于构建用户界面的渐进式 JavaScript 框架。自 2014 年由尤雨溪发布以来,凭借其简洁的 API、优秀的性能和灵活的集成能力,成为前端开发的主流框架之一。本文将从基础概念到实战开发,全面解析 Vue 的核心原理与应用。

一、Vue 框架核心思想与优势

1. 核心设计理念

Vue 的核心思想可以概括为两点:数据驱动组件化

  • 数据驱动(Data-Driven)
    传统 DOM 操作需要手动将数据同步到视图,而 Vue 通过数据绑定机制,使视图自动响应数据变化。当数据更新时,视图会自动重新渲染,无需开发者编写 DOM 操作代码。

  • 组件化(Component-Based)
    将页面拆分为独立、可复用的组件(Component),每个组件包含自身的结构(HTML)、样式(CSS)和逻辑(JavaScript)。组件化让代码更易维护、复用性更高。

2. 与其他框架的对比

框架 特点 适用场景 Vue 渐进式框架,API 简洁,学习曲线平缓 中小型应用、快速开发、与现有项目集成 React 基于 JSX,生态庞大,灵活性高 大型复杂应用、需要高度定制化的场景 Angular 全功能框架,TypeScript 友好,规范严格 企业级大型应用、团队协作开发

3. 为什么选择 Vue?

  • 易学易用:HTML、CSS、JavaScript 基础开发者可快速上手
  • 性能出色:采用虚拟 DOM 和响应式系统,渲染效率高
  • 灵活性强:可作为库引入现有项目,也可构建完整单页应用
  • 完善生态:配套工具(Vue CLI、Vue Router、Pinia)和社区支持丰富

二、Vue 基础环境搭建

1. 快速入门:直接引入 Vue

适合小型项目或学习测试:

{{ message }}
// 创建Vue实例 const { createApp } = Vue createApp({ data() { return { message: \'Hello Vue!\' } } }).mount(\'#app\')

2. 工程化开发:Vue CLI

适合中大型项目,提供完整的开发环境配置:

(1)安装 Vue CLI

# 全局安装Vue

CLI npm install -g @vue/cli

# 检查版本

vue --version

(2)创建项目
# 创建项目vue create my-vue-app# 选择预设(推荐手动选择特性)# 选择Vue 3、Babel、Router、Vuex等必要组件
(3)运行项目
cd my-vue-appnpm run serve

访问http://localhost:8080即可看到默认页面。

三、Vue 核心概念与基础语法

1. Vue 实例与数据绑定

Vue 应用的入口是通过createApp创建的应用实例,所有功能都基于这个实例展开。

{{ title }}

{{ user.name }} - {{ user.age }}岁

{{ isActive ? \'在线\' : \'离线\' }}

{{ message.split(\'\').reverse().join(\'\') }}

const app = Vue.createApp({ // 数据对象,返回应用所需的响应式数据 data() { return { title: \'Vue基础示例\', user: { name: \'张三\', age: 25 }, isActive: true, message: \'Hello\' } } }) // 将应用挂载到DOM元素上 app.mount(\'#app\')
  • {{ }}:插值表达式,用于将数据渲染到视图中
  • 支持 JavaScript 表达式(如三元运算、字符串方法)
  • 数据是响应式的:当数据变化时,视图会自动更新

2. 指令系统

Vue 提供了一系列特殊属性(指令),用于在模板中实现逻辑控制。

(1)v-bind:绑定属性
data() { return { imageUrl: \'logo.png\', imageAlt: \'网站logo\' }}
(2)v-model:双向数据绑定

主要用于表单元素,实现数据与视图的双向同步:

你输入的是:{{ username }}

请选择 北京 上海
Vue.createApp({ data() { return { username: \'\', content: \'\', selectedCity: \'\' } } }).mount(\'#app\')
(3)v-for:列表渲染

用于循环渲染数组或对象:

  • {{ index + 1 }}. {{ item }}
姓名 年龄
{{ user.name }} {{ user.age }}
data() { return { fruits: [\'苹果\', \'香蕉\', \'橙子\'], users: [ { id: 1, name: \'张三\', age: 20 }, { id: 2, name: \'李四\', age: 22 } ] }}
  • :key:提高渲染性能,确保每个节点的唯一性
(4)v-ifv-show:条件渲染
欢迎回来,{{ username }}!
请先登录
= 90\">优秀
= 60\">及格
不及格
这是可以显示/隐藏的内容
data() { return { isLogin: true, username: \'张三\', score: 85, isActive: false }}
  • 区别v-if有更高的切换开销,v-show有更高的初始渲染开销
  • 频繁切换用v-show,条件很少改变用v-if
(5)v-on:事件绑定
data() { return { count: 0 }},methods: { handleClick() { this.count++ }, sayHello(name) { alert(`Hello ${name}!`) }, handleSubmit() { console.log(\'提交表单\') }}
  • 事件处理函数定义在methods选项中
  • this指向当前 Vue 实例
  • 事件修饰符:.stop(阻止冒泡)、.prevent(阻止默认行为)、.enter(按键修饰符)等

3. 计算属性与侦听器

(1)计算属性(computed)

用于处理复杂逻辑计算,具有缓存特性:

原始价格:{{ price }}

折扣价:{{ discountedPrice }}

总价:{{ totalPrice }}

Vue.createApp({ data() { return { price: 100, quantity: 3, discount: 0.8 } }, computed: { // 计算折扣价 discountedPrice() { return this.price * this.discount }, // 计算总价 totalPrice() { return this.discountedPrice * this.quantity } } }).mount(\'#app\')
  • 计算属性会基于依赖的数据自动更新
  • 相比方法(methods),计算属性有缓存,多次访问不会重复计算
(2)侦听器(watch)

用于监听数据变化并执行副作用操作:

{{ message }}

Vue.createApp({ data() { return { username: \'\', message: \'\' } }, watch: { // 监听username变化 username(newVal, oldVal) { if (newVal.length < 3) { this.message = \'用户名长度不能少于3个字符\' } else { this.message = \'用户名可用\' } } } }).mount(\'#app\')
  • 适合处理异步操作或复杂逻辑(如数据请求、定时器等)

四、Vue 组件化开发

组件是 Vue 的核心概念,将页面拆分为独立可复用的模块。

1. 组件的定义与注册

(1)全局组件

在整个应用中都可使用:

// 定义全局组件const app = Vue.createApp({})app.component(\'my-component\', { template: ` 

{{ title }}

{{ content }}

`, data() { return { title: \'我是全局组件\', content: \'这是全局组件的内容\' } }})app.mount(\'#app\')

使用组件:

(2)局部组件

仅在注册它的父组件中可用:

// 定义局部组件const MyComponent = { template: ` 

{{ message }}

`, data() { return { message: \'我是局部组件\' } }}// 在父组件中注册const app = Vue.createApp({ components: { \'my-component\': MyComponent }})app.mount(\'#app\')

2. 组件通信

(1)父组件向子组件传值(props)

javascript

// 子组件const ChildComponent = { // 声明接收的props props: [\'title\', \'userInfo\', \'isActive\'], template: ` 

{{ title }}

{{ userInfo.name }} - {{ userInfo.age }}岁

激活状态

`}// 父组件const app = Vue.createApp({ components: { \'child-component\': ChildComponent }, data() { return { parentTitle: \'来自父组件的标题\', user: { name: \'张三\', age: 25 }, active: true } }})

使用时传递数据:

  • props 命名:在组件中使用驼峰式(camelCase),在模板中使用短横线式(kebab-case)
  • 可以指定 props 类型和验证:
props: { // 基础类型检查 age: Number, // 多个可能的类型 id: [String, Number], // 必传且是字符串 name: { type: String, required: true }, // 带默认值的数字 count: { type: Number, default: 0 }}
(2)子组件向父组件传值($emit)
// 子组件const ChildComponent = { template: `  `, methods: { handleClick() { // 触发自定义事件,并传递数据 this.$emit(\'send-message\', \'来自子组件的消息\', 123) } }}// 父组件const app = Vue.createApp({ components: { \'child-component\': ChildComponent }, methods: { // 接收子组件传递的消息 receiveMessage(msg, num) { console.log(\'收到消息:\', msg, num) } }})

父组件监听事件:

3. 插槽(Slot)

用于组件内容分发,使组件更灵活:

// 子组件(MyButton)const MyButton = { template: `  `}// 父组件使用const app = Vue.createApp({ components: { \'my-button\': MyButton }})

使用带插槽的组件:

 点击我  提交

具名插槽(多个插槽区分):

// 子组件const Card = { template: ` 
`}

使用具名插槽:

  

卡片标题

这是卡片内容...

五、Vue 底层原理

1. 响应式系统原理

Vue 的响应式系统基于数据劫持依赖收集实现:

  1. 初始化阶段

    • Vue 会遍历 data 中的所有属性,使用Object.defineProperty(Vue 2)或Proxy(Vue 3)进行劫持
    • 为每个属性创建对应的Dep(依赖管理器),用于收集依赖
  2. 依赖收集

    • 当组件渲染时,会触发属性的 getter 方法
    • getter 方法会将当前组件的Watcher(观察者)添加到Dep
  3. 数据更新

    • 当属性被修改时,会触发 setter 方法
    • setter 方法会通知Dep中的所有Watcher
    • Watcher触发组件重新渲染

Vue 3 使用 Proxy 替代 Object.defineProperty 的优势:

  • 支持监听数组变化
  • 支持监听新增 / 删除属性
  • 性能更好,劫持整个对象而非单个属性

2. 虚拟 DOM 与 Diff 算法

Vue 通过虚拟 DOM 提高渲染性能:

  1. 虚拟 DOM

    • 用 JavaScript 对象模拟真实 DOM 结构
    • 例如:{ tag: \'div\', props: { id: \'app\' }, children: [] }
  2. Diff 算法

    • 当数据变化时,Vue 会生成新的虚拟 DOM
    • 通过 Diff 算法对比新旧虚拟 DOM 的差异
    • 只更新差异部分对应的真实 DOM,减少 DOM 操作
  3. key 的作用

    • 在列表渲染中,key 帮助 Vue 识别元素的唯一性
    • 提高 Diff 算法的效率,避免不必要的元素重绘

六、Vue Router 路由管理

Vue Router 是 Vue 官方的路由管理器,用于构建单页应用(SPA)。

1. 安装与配置

# 安装Vue Router(Vue 3对应版本)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(), // HTML5 history模式 routes})export default router

在 main.js 中引入:

import { createApp } from \'vue\'import App from \'./App.vue\'import router from \'./router\'createApp(App) .use(router) .mount(\'#app\')

2. 路由使用

在 App.vue 中添加路由出口和导航:

 

3. 动态路由与参数传递

// 路由配置{ path: \'/user/:id\', name: \'User\', component: User}

在组件中获取参数:

// User.vueexport default { mounted() { // 通过$route获取路由参数 console.log(this.$route.params.id) }}

编程式导航:

// 导航到用户页面this.$router.push({ name: \'User\', params: { id: 123 }})// 后退this.$router.go(-1)

七、实战项目:待办事项应用(Todo App)

1. 项目功能设计

  • 添加待办事项
  • 标记待办事项为已完成
  • 删除待办事项
  • 筛选待办事项(全部 / 已完成 / 未完成)
  • 统计待办事项数量

2. 项目结构

todo-app/├── public/├── src/│ ├── components/│ │ ├── TodoInput.vue // 输入组件│ │ ├── TodoList.vue // 列表组件│ │ ├── TodoItem.vue // 列表项组件│ │ └── TodoFilter.vue // 筛选组件│ ├── stores/│ │ └── todoStore.js // 状态管理│ ├── App.vue│ └── main.js└── package.json

3. 核心代码实现

(1)状态管理(stores/todoStore.js)
import { defineStore } from \'pinia\'export const useTodoStore = defineStore(\'todo\', { state: () => ({ todos: [ { id: 1, text: \'学习Vue\', completed: false }, { id: 2, text: \'完成项目\', completed: true } ], filter: \'all\' // all, active, completed }), getters: { // 筛选后的待办事项 filteredTodos(state) { switch (state.filter) { case \'active\': return state.todos.filter(todo => !todo.completed) case \'completed\': return state.todos.filter(todo => todo.completed) default: return state.todos } }, // 未完成数量 activeCount(state) { return state.todos.filter(todo => !todo.completed).length } }, actions: { // 添加待办 addTodo(text) { if (!text.trim()) return this.todos.push({ id: Date.now(), text, completed: false }) }, // 切换完成状态 toggleTodo(id) { const todo = this.todos.find(todo => todo.id === id) if (todo) { todo.completed = !todo.completed } }, // 删除待办 deleteTodo(id) { this.todos = this.todos.filter(todo => todo.id !== id) }, // 设置筛选条件 setFilter(filter) { this.filter = filter } }})
(2)输入组件(components/TodoInput.vue)
  import { useTodoStore } from \'../stores/todoStore\'export default { data() { return { newTodo: \'\' } }, methods: { handleAdd() { const todoStore = useTodoStore() todoStore.addTodo(this.newTodo) this.newTodo = \'\' // 清空输入框 } }}
(3)列表项组件(components/TodoItem.vue)
 
  • {{ todo.text }}
  • export default { props: { todo: { type: Object, required: true } }}.completed { text-decoration: line-through; color: #999;}
    (4)列表组件(components/TodoList.vue)
     

    没有待办事项

    import TodoItem from \'./TodoItem.vue\'import { useTodoStore } from \'../stores/todoStore\'export default { components: { TodoItem }, computed: { filteredTodos() { return useTodoStore().filteredTodos } }, methods: { toggleTodo(id) { useTodoStore().toggleTodo(id) }, deleteTodo(id) { useTodoStore().deleteTodo(id) } }}
    (5)筛选组件(components/TodoFilter.vue)
     
    筛选: 剩余:{{ activeCount }} 项
    import { useTodoStore } from \'../stores/todoStore\'export default { props: { currentFilter: { type: String, required: true } }, computed: { activeCount() { return useTodoStore().activeCount } }}.active { background-color: #42b983; color: white;}
    (6)主组件(App.vue)
     

    待办事项

    import TodoInput from \'./components/TodoInput.vue\'import TodoList from \'./components/TodoList.vue\'import TodoFilter from \'./components/TodoFilter.vue\'import { useTodoStore } from \'./stores/todoStore\'export default { components: { TodoInput, TodoList, TodoFilter }, computed: { filter() { return useTodoStore().filter } }, methods: { handleFilter(filter) { useTodoStore().setFilter(filter) } }}

    4. 项目运行与测试

    # 安装依赖npm install# 运行项目npm run serve

    访问http://localhost:8080即可使用待办事项应用,测试各功能是否正常工作:

    • 输入框中输入内容,按回车或点击添加按钮
    • 点击待办事项文本切换完成状态
    • 点击删除按钮移除待办事项
    • 切换筛选按钮查看不同状态的待办事项
    • 检查剩余数量统计是否正确