VUE复习笔记

VUE 复习笔记

Vue.js 四大文件关系

前端文件 / 角色 生活类比 核心定位
index.html 毛坯房(空房子) 最外层载体,只有框架,无实际装修
main.js 搬家工人 + 总负责人 执行搬运、组装、挂载,统筹整体
App.vue 硬装(墙体 / 吊顶 / 水电 / 全屋骨架) 项目根骨架,固定整体布局
自定义组件(xxx\.vue) 软装(家具 / 灯具 / 挂画 / 摆件) 可复用、可自由搭配的功能模块

一、逐个拆解讲解

1. index.html = 毛坯房

特点

房子本身存在,有墙体、门洞、空间框架,但空空如也,没有任何家具和装修

只预留了一个专属摆放区域 (对应 <div id="app">)。

对应代码逻辑:

index.html 是浏览器最先加载的静态页面,整个 Vue 项目最终都要放进它里面,它只提供容器,不写业务代码、不做页面渲染。

类比:毛坯房只是一个 "场地",所有装修、家具都要放在这个场地里。


2. main.js = 搬家工人(总调度)

特点

搬家工人负责:

  1. 硬装主体(App.vue) 搬进毛坯房;

  2. 把所有软装(自定义组件) 配套就位;

  3. 固定位置、完成整体 "安装";

  4. 额外统筹:全屋通用物件(全局组件、路由、工具)统一摆放。

对应代码逻辑:

  1. main.js 是项目启动入口;

  2. 导入根组件 App.vue,调用 createApp() 创建 Vue 应用;

  3. 通过 .mount('#app')把整套 Vue 项目 "搬进" index.html 的容器中

  4. 全局组件、路由、第三方库也在这里统一配置(相当于全屋共用物品统一安置)。

类比:没有搬家工人,硬装、软装都进不了毛坯房,房子永远是空的。


3. App.vue = 硬装(全屋基础骨架)

特点

硬装是房子的根基:墙面、地面、吊顶、门窗、水电、全屋分区布局。

  • 一旦完工,整体结构固定;

  • 所有家具、摆件(软装)都必须摆放在硬装划定的区域里;

  • 整间屋子只有一套主硬装 (对应项目只有一个根组件 App.vue)。

对应代码逻辑:

  1. App.vue 是 Vue 项目唯一根组件,搭建页面整体布局(导航、侧边栏、底部、路由出口等);

  2. 它是所有子组件的 "父容器",所有自定义组件都要嵌套在它内部使用;

  3. 结构稳定,是整个项目的核心骨架。

类比:硬装决定了房子长什么样、区域怎么划分,软装只能在硬装基础上搭配。


4. 自定义组件 = 软装(家具 / 装饰)

特点

软装:沙发、桌椅、灯具、挂画、窗帘、摆件......

  • 可复用:同款椅子可以放客厅、也可以放书房;

  • 可自由搭配:想换、想增删都很灵活,不改动房屋硬装;

  • 必须摆放在硬装划定的区域内,不能脱离房子单独存在。

对应代码逻辑:

  1. 按钮、卡片、列表、页面模块等自定义组件,都是可复用单元;

  2. 必须被 App.vue 或其他父组件引入使用,无法直接挂载到 index.html

  3. 增删、修改单个组件,不会影响项目整体骨架。

类比:换沙发、加挂画,不用砸墙改硬装;对应:修改子组件,不影响根组件整体结构。


二、完整流程串讲(从空房到入住)

结合加载顺序,走一遍完整场景:

  1. 拿到毛坯房(index.html)

    浏览器打开网址,加载空白 index.html,就像拿到一间空荡荡的房子,只留好了摆放位置。

  2. 搬家工人进场(执行 main.js)

    工具自动运行 main.js,工人开始干活:

    • 先把全屋硬装(App.vue) 搬进房子、固定到位;

    • 顺便把全屋通用物品(全局组件)提前布置好。

  3. 硬装成型(渲染 App.vue)

    硬装搭建完成,房子有了墙体、分区、基础布局(页面全局结构)。

  4. 摆放软装(渲染自定义组件)

    在硬装的各个区域里,依次摆放沙发、灯具、家具(渲染各类子组件)。

  5. 最终效果

    毛坯房 + 硬装 + 软装 组合成完整可入住的房子

    index.html + App.vue + 自定义组件 组合成完整可浏览的网页。


三、补充关键规则(结合生活场景理解)

  1. 硬装不能脱离毛坯房

    App.vue 必须通过 main.js 挂载到 index.html,不能单独运行。

  2. 软装不能脱离硬装

    自定义组件必须被父组件(优先 App.vue)引用,不能直接放到 index.html。

  3. 搬家工人只负责搬运安装,不改变房屋结构

    main.js 只做导入、创建、挂载、全局配置,不编写页面具体结构。

  4. 硬装改起来麻烦,软装灵活多变

    修改 App.vue 会影响全站布局;增删改自定义组件,影响范围小、维护简单。


Vue.js 基础入门

一、Vue.js 概述

1. 什么是 Vue.js

Vue是开源渐进式JavaScript框架 ,专注于视图层,用于开发交互式网页界面、单页应用。

  • 渐进式:可按需使用,从简单页面嵌入逐步扩展为大型项目,不用一次性接受全部功能。

  • 易上手:基于HTML、CSS、JavaScript,前端开发者可快速入门。

  • 轻量高效:压缩后仅20KB左右,加载速度快。

  • 灵活性:可嵌入现有项目,也可独立开发完整SPA。

2. Vue 核心特性
  1. 虚拟DOM:内存中虚拟节点树,减少真实DOM操作,提升性能。

  2. 数据绑定:通过指令绑定数据与DOM,数据变化自动更新页面。

  3. 组件化:封装可复用UI模块,解耦代码。

  4. 指令系统 :内置v-if/v-for/v-model等指令,简化DOM操作。

  5. 事件处理:简洁语法监听鼠标、键盘等DOM事件。

  6. 过渡&动画:内置过渡组件,轻松实现入场/出场动画。

  7. 计算属性:基于现有数据动态计算新值,缓存结果提升效率。

3. DOM 与 虚拟DOM(Virtual DOM)
(1)原生DOM 缺点

真实DOM是浏览器渲染页面的节点树,频繁修改DOM会触发页面重排/重绘,页面元素越多,性能损耗越大。

(2)Vue 虚拟DOM 工作原理(6步流程)

虚拟DOM是真实DOM的轻量级副本 ,存于内存中,Vue通过对比算法(Diff) 最小化DOM修改:

  1. 初始渲染:根据模板生成虚拟DOM,渲染为真实DOM展示页面。

  2. 数据变更 :页面数据发生修改,Vue生成全新虚拟DOM

  3. Diff对比 :对比新旧虚拟DOM,找出发生变化的节点

  4. 生成补丁:仅针对变化节点生成修改指令(Patch)。

  5. 应用补丁:只更新真实DOM中变化的部分,而非全量刷新。

  6. 同步完成:真实DOM与最新数据保持一致。

核心优势:只操作局部DOM,大幅提升页面渲染性能。

4. Vue 环境搭建(Vue 3 + Vue CLI)
前置条件

安装 Node.js(自带npm包管理工具),用于安装Vue CLI、管理项目依赖。

完整安装步骤
  1. 校验Node和npm是否安装成功(终端执行)
Bash 复制代码
node -v   # 查看Node版本
npm -v    # 查看npm版本
  1. 全局安装 Vue CLI(Vue官方脚手架)
Bash 复制代码
npm install -g @vue/cli
  1. 校验Vue CLI
Bash 复制代码
vue --version
  1. 创建Vue 3项目
Bash 复制代码
vue create my-vue-project  # my-vue-project 为项目名
  • 选择Manually select features(手动选择功能)

  • 勾选:Babel、Router、Vuex、Linter

  • 选择Vue 3.x版本

  1. 运行开发服务器
Bash 复制代码
cd my-vue-project  # 进入项目文件夹
npm run serve      # 启动本地开发服务,浏览器访问默认地址即可预览
补充:Vite(更快的构建工具)

Vite启动速度远快于Vue CLI,创建Vue项目命令:

Bash 复制代码
npm create vue@latest my-project
cd my-project
npm install
npm run dev
5. Vue CLI 项目目录结构
Plaintext 复制代码
my-vue-project/
├── node_modules/    # 项目所有依赖包(第三方库)
├── public/          # 静态资源(图片、静态html,不会被打包编译)
│   └── index.html  # 项目入口HTML文件
├── src/             # 源代码目录(核心开发文件夹)
│   ├── assets/      # 项目资源(图片、全局CSS,会被打包)
│   ├── components/  # 可复用小组件
│   ├── router/      # 路由配置(页面跳转)
│   ├── store/       # Vuex状态管理(全局数据)
│   ├── views/       # 页面级大组件
│   ├── App.vue      # 根组件(整个项目的根容器)
│   └── main.js      # 项目入口JS文件(创建Vue实例、挂载应用)
├── package.json     # 项目配置、脚本命令、依赖清单
└── README.md        # 项目说明文档
6. Vue 单文件组件(.vue 文件)结构

.vue是Vue专属单文件组件 ,一个文件封装模板、脚本、样式三部分,结构固定:

Plaintext 复制代码
<!-- 1. template:HTML模板区域,编写页面结构(必写) -->
<template>
  <div>页面HTML内容</div>
</template>

<!-- 2. script:JS逻辑区域,编写数据、方法、组件注册等 -->
<script>
export default {
  name: "组件名", // 组件名称
  data() {       // 组件数据
    return {}
  },
  methods: {}    // 组件方法
}
</script>

<!-- 3. style:样式区域,scoped表示样式仅作用于当前组件 -->
<style scoped>
/* CSS样式 */
</style>
  • scoped关键字:样式私有化,不会污染其他组件样式。
7. 常用Vue CLI 命令
Bash 复制代码
vue create 项目名   # 创建新项目
npm run serve       # 启动开发环境(热更新,开发使用)
npm run build       # 打包项目(生成dist文件夹,用于线上部署)

Vue 3 组件(核心:复用、通信、注册)

组件是Vue的核心单元,将页面拆分为独立、可复用的UI模块,每个组件拥有独立结构、数据、样式。

一、基础简单组件(可复用UI)

1. 代码示例

1)子组件:components/BasicComponent.vue(可复用组件)

Plaintext 复制代码
<template>
  <div class="my-component">
    <h1>来自可复用组件</h1>
    <p>我是独立可复用的Vue组件</p>
  </div>
</template>

<script>
export default {
  name: "BasicComponent" // 定义组件名称,一般和文件名一致
};
</script>

<!-- scoped:样式仅当前组件生效 -->
<style scoped>
.my-component {
  border: 2px solid green;
  padding: 20px;
  margin: 10px;
  background-color: #e8f5e9;
  border-radius: 10px;
}
</style>

2)根组件:App.vue(引入并使用子组件)

Plaintext 复制代码
<template>
  <div id="app">
    <h1>Vue 组件演示</h1>
    <!-- 多次使用组件:体现复用性 -->
    <BasicComponent />
    <BasicComponent />
    <BasicComponent />
  </div>
</template>

<script>
// 1. 导入子组件
import BasicComponent from "./components/BasicComponent.vue";

export default {
  name: "App",
  // 2. 局部注册组件
  components: { BasicComponent }
};
</script>
2. 代码详解
  1. 组件可以重复调用,实现UI复用;

  2. style scoped保证组件样式隔离,多个组件不会样式冲突;

  3. 组件拆分:复杂页面拆分为多个小组件,代码更易维护。

二、组件 data 必须是函数(数据隔离核心)

1. 核心规则(Vue 3 强制要求)
  • 正确写法data() { return {} }(函数形式)

  • 错误写法data: {}(对象形式,Vue会报错)

原因 :组件会被多次复用,若data是普通对象,所有组件实例共享同一份数据 ,修改一个会影响全部;

data写成函数,每次创建组件都会返回全新对象 ,每个实例拥有独立数据,实现数据隔离

2. 计数器案例(数据隔离演示)

子组件:ClickCounter.vue

Plaintext 复制代码
<template>
  <div class="counter-box">
    <h3>点击计数器</h3>
    <p>点击次数:<strong>{{ count }}</strong></p>
    <button @click="count++">点击我</button>
    <p>组件唯一ID:{{ componentId }}</p>
  </div>
</template>

<script>
export default {
  name: "ClickCounter",
  // data 必须是函数,返回新对象
  data() {
    return {
      count: 0, // 点击次数
      // 随机生成唯一ID,证明每个组件是独立实例
      componentId: Math.random().toString(36).substr(2, 4)
    };
  }
};
</script>

<style scoped>
.counter-box {
  border: 2px solid orange;
  padding: 15px;
  margin: 10px;
  display: inline-block;
  width: 200px;
  text-align: center;
}
</style>

App.vue 使用组件

Plaintext 复制代码
<template>
  <div>
    <h1>组件数据隔离演示</h1>
    <!-- 三个独立计数器,互不干扰 -->
    <ClickCounter />
    <ClickCounter />
    <ClickCounter />
  </div>
</template>

<script>
import ClickCounter from "./components/ClickCounter.vue";
export default {
  components: { ClickCounter }
};
</script>
3. 效果说明

点击任意一个计数器按钮,仅当前组件数字变化,其他组件不受影响,证明数据完全隔离。

三、组件注册方式(局部注册 + 全局注册)

1. 局部注册(推荐,主流用法)
特点
  • 组件仅在当前父组件内可用,外部无法使用;

  • 避免全局命名冲突,减少项目体积,大型项目首选。

代码示例

1)子组件:SpecialButton.vue

Plaintext 复制代码
<template>
  <button class="special-btn">局部组件按钮</button>
</template>
<script>
export default { name: "SpecialButton" };
</script>
<style scoped>
.special-btn { background: purple; color: white; padding: 10px; }
</style>

2)父组件:ParentBox.vue(局部注册)

Plaintext 复制代码
<template>
  <div class="parent-box">
    <h3>父组件</h3>
    <!-- 仅当前组件可使用 SpecialButton -->
    <SpecialButton />
  </div>
</template>

<script>
// 导入子组件
import SpecialButton from "./SpecialButton.vue";
export default {
  name: "ParentBox",
  // 局部注册:仅本组件生效
  components: { SpecialButton }
};
</script>

<style scoped>
.parent-box { border: 3px solid blue; padding: 20px; }
</style>

3)App.vue

Plaintext 复制代码
<template>
  <div>
    <ParentBox />
    <!-- 直接使用 SpecialButton 会报错:组件未注册 -->
    <!-- <SpecialButton /> -->
  </div>
</template>
<script>
import ParentBox from "./components/ParentBox.vue";
export default { components: { ParentBox } };
</script>
2. 全局注册(全局可用)
特点
  • main.js中一次性注册,整个项目所有组件都能直接使用,无需重复导入;

  • 适合高频通用组件(弹窗、全局按钮、通知提示)。

代码示例

1)全局组件:GlobalAlert.vue

Plaintext 复制代码
<template>
  <!-- v-if 控制组件显示/隐藏 -->
  <div class="alert-box" v-if="isVisible">
    <h3>{{ title }}</h3>
    <p>{{ message }}</p>
    <button @click="closeAlert">关闭</button>
  </div>
</template>

<script>
export default {
  name: "GlobalAlert",
  // 接收外部传入的参数
  props: {
    title: { type: String, default: "通知" },
    message: { type: String, default: "全局提示消息" }
  },
  data() {
    return { isVisible: true };
  },
  methods: {
    closeAlert() {
      this.isVisible = false; // 关闭提示
    }
  }
};
</script>

2)main.js(全局注册入口)

JavaScript 复制代码
import { createApp } from "vue";
import App from "./App.vue";
// 导入全局组件
import GlobalAlert from "./components/GlobalAlert.vue";

const app = createApp(App);
// 全局注册:所有组件均可使用 GlobalAlert
app.component("GlobalAlert", GlobalAlert);

app.mount("#app"); // 挂载Vue实例

3)App.vue(直接使用,无需导入)

Plaintext 复制代码
<template>
  <div>
    <!-- 全局组件,直接使用 -->
    <GlobalAlert title="欢迎" message="全局组件演示" />
    <GlobalAlert title="优惠活动" message="全场5折" />
  </div>
</template>

四、动态组件 <component :is>

1. 作用

运行时动态切换不同组件,常用于标签页、步骤向导、选项卡场景,无需路由即可切换UI。

2. 核心语法
Plaintext 复制代码
<!-- is 绑定组件名称/组件对象,动态渲染对应组件 -->
<component :is="当前组件变量"></component>
3. 完整代码示例

1)三个页面组件(HomePage、AboutPage、ContactPage)

Plaintext 复制代码
<!-- HomePage.vue -->
<template><div class="page">首页</div></template>
<style scoped>.page{background:#e3f2fd;padding:20px;}</style>

<!-- AboutPage.vue -->
<template><div class="page">关于我们</div></template>
<style scoped>.page{background:#f3e5f5;padding:20px;}</style>

<!-- ContactPage.vue -->
<template><div class="page">联系我们</div></template>
<style scoped>.page{background:#e8f5e9;padding:20px;}</style>

2)动态标签页组件 DynamicTabs.vue

Plaintext 复制代码
<template>
  <div>
    <!-- 标签按钮:点击切换组件 -->
    <div class="tabs">
      <button 
        v-for="tab in tabs" 
        :key="tab.name"
        @click="currentTab = tab.component"
        :class="{ active: currentTab === tab.component }"
      >
        {{ tab.name }}
      </button>
    </div>
    <!-- 动态组件:根据 currentTab 渲染对应组件 -->
    <component :is="currentTab" />
  </div>
</template>

<script>
// 导入三个子组件
import HomePage from "./HomePage.vue";
import AboutPage from "./AboutPage.vue";
import ContactPage from "./ContactPage.vue";

export default {
  name: "DynamicTabs",
  data() {
    return {
      currentTab: HomePage, // 默认显示首页组件
      // 标签列表:名称 + 对应组件
      tabs: [
        { name: "首页", component: HomePage },
        { name: "关于", component: AboutPage },
        { name: "联系", component: ContactPage }
      ]
    };
  }
};
</script>

<style scoped>
.tabs button { padding: 10px 20px; margin-right: 10px; cursor: pointer; }
.tabs .active { background: #42b983; color: white; border: none; }
</style>

3)App.vue 使用

Plaintext 复制代码
<template>
  <div>
    <h1>动态组件-标签页</h1>
    <DynamicTabs />
  </div>
</template>
<script>
import DynamicTabs from "./components/DynamicTabs.vue";
export default { components: { DynamicTabs } };
</script>
4. 代码解析
  1. currentTab 存储当前激活的组件对象;

  2. 点击标签按钮,修改currentTab<component :is>自动切换渲染组件;

  3. 纯前端组件切换,不刷新页面,体验接近SPA。

五、组件鼠标事件(@mouseover / @mouseout)

实现鼠标悬浮、离开触发逻辑,结合组件数据隔离,每个组件独立响应。

完整代码(InteractiveCard.vue)
Plaintext 复制代码
<template>
  <!-- 绑定鼠标悬浮、离开事件 -->
  <div 
    class="interactive-card"
    @mouseover="handleMouseOver"
    @mouseout="handleMouseOut"
  >
    <h2>
      城市:
      <span :style="{ color: textColor }">{{ cityName }}</span>
    </h2>
    <!-- v-if 条件渲染提示文本 -->
    <p v-if="isHovered" class="message">鼠标已悬浮</p>
  </div>
</template>

<script>
export default {
  name: "InteractiveCard",
  // 每个组件独立数据
  data() {
    return {
      cityName: "上海",
      isHovered: false,
      textColor: "blue"
    };
  },
  methods: {
    // 鼠标悬浮事件
    handleMouseOver() {
      this.cityName = "贵州";
      this.isHovered = true;
      this.textColor = "red";
    },
    // 鼠标离开事件
    handleMouseOut() {
      this.cityName = "上海";
      this.isHovered = false;
      this.textColor = "blue";
    }
  }
};
</script>

<style scoped>
.interactive-card {
  border: 2px solid #42b983;
  padding: 20px;
  margin: 15px;
  display: inline-block;
  width: 280px;
  cursor: pointer;
  transition: all 0.3s;
}
.interactive-card:hover {
  transform: scale(1.02); /* 悬浮放大 */
  box-shadow: 0 5px 15px #ccc;
}
.message {
  background: #fff3cd;
  padding: 10px;
  border-radius: 5px;
}
</style>
使用与效果

在App.vue中多次引用组件,悬浮其中一个卡片,仅当前卡片变化,其他不受影响,验证组件数据隔离。


Vue 3 事件处理

Vue 使用 v-on 指令(简写 @)监听DOM事件,支持原生事件、事件修饰符、按键修饰符、自定义事件

一、基础点击事件 @click

1. 语法
  • 完整写法:v-on:click="方法名"

  • 简写(推荐):@click="方法名"

2. 代码示例(点击计算)
Plaintext 复制代码
<template>
  <div class="demo">
    <button @click="displayNumbers">点击计算 50 + 100</button>
    <h2>计算结果:{{ total }}</h2>
  </div>
</template>

<script>
export default {
  data() {
    return {
      num1: 50,
      num2: 100,
      total: ""
    };
  },
  methods: {
    // 点击触发的方法,可接收原生event对象
    displayNumbers(event) {
      console.log(event); // 打印原生点击事件对象
      this.total = this.num1 + this.num2;
    }
  }
};
</script>
解析
  1. 按钮被点击时,执行displayNumbers方法;

  2. 方法可接收event参数,获取原生DOM事件信息;

  3. 修改data中的total,页面自动更新(数据驱动视图)。

二、事件修饰符(.once / .prevent)

事件修饰符以.开头,用于简化原生JS的事件处理逻辑,Vue内置常用修饰符。

1. .once 只触发一次
作用

事件仅执行第一次,后续点击/触发无效。

代码示例
Plaintext 复制代码
<template>
  <div>
    <!-- 点击仅生效一次 -->
    <button @click.once="addOnce">只可点击一次</button>
    <p>计数:{{ num1 }}</p>

    <!-- 普通点击,无限触发 -->
    <button @click="addNormal">可重复点击</button>
    <p>计数:{{ num2 }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return { num1: 0, num2: 0 };
  },
  methods: {
    addOnce() { this.num1++; },
    addNormal() { this.num2++; }
  }
};
</script>
2. .prevent 阻止默认行为
作用

等价于原生 event.preventDefault(),阻止标签默认动作(如a标签跳转、表单提交)。

代码示例
Plaintext 复制代码
<template>
  <div>
    <!-- 加 .prevent:阻止a标签默认跳转 -->
    <a href="https://www.baidu.com" @click.prevent="clickA">阻止跳转</a>

    <!-- 无修饰符:点击后先弹窗,再跳转页面 -->
    <a href="https://www.baidu.com" @click="clickANormal">正常跳转</a>
  </div>
</template>

<script>
export default {
  methods: {
    clickA() { alert("已阻止跳转"); },
    clickANormal() { alert("即将跳转"); }
  }
};
</script>

三、按键修饰符(键盘事件)

监听键盘按键,基于@keyup/@keydown,Vue内置常用按键别名:

entertabdeleteescspaceup/down/left/right,支持组合键(ctrl/alt/shift)。

代码示例
Plaintext 复制代码
<template>
  <div>
    <p>输入内容后按 回车 提交</p>
    <input 
      type="text" 
      v-model="name"
      @keyup.enter="showName"
      placeholder="按Enter提交"
    >
    <p>结果:{{ resultName }}</p>

    <p>输入内容后按 Ctrl + 回车 提交</p>
    <input 
      type="text" 
      v-model="msg"
      @keyup.ctrl.enter="showMsg"
      placeholder="按Ctrl+Enter提交"
    >
    <p>结果:{{ resultMsg }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      name: "",
      resultName: "",
      msg: "",
      resultMsg: ""
    };
  },
  methods: {
    showName() {
      this.resultName = this.name;
    },
    showMsg() {
      this.resultMsg = this.msg;
    }
  }
};
</script>
解析
  1. @keyup.enter:按下回车键触发方法;

  2. @keyup.ctrl.enter组合键,必须同时按下Ctrl+回车才触发;

  3. v-model 双向绑定输入框内容。

四、自定义事件(子组件 → 父组件通信)

组件通信核心方案:子组件通过 $emit 触发自定义事件并传值,父组件通过 @自定义事件名 监听

完整案例
1)子组件 LanguageButton.vue(发送事件)
Plaintext 复制代码
<template>
  <!-- 点击按钮,触发自定义事件 -->
  <button @click="sendData">{{ item }}</button>
</template>

<script>
export default {
  // 接收父组件传递的数据
  props: ["item"],
  methods: {
    sendData() {
      // $emit("自定义事件名", 传递的数据)
      this.$emit("showLanguage", this.item);
    }
  }
};
</script>
2)父组件(监听自定义事件)
Plaintext 复制代码
<template>
  <div>
    <p>选中的语言:<b>{{ selectLang }}</b></p>
    <!-- 
      1. 循环渲染子组件,传递item数据
      2. @showLanguage 监听子组件触发的自定义事件
    -->
    <LanguageButton 
      v-for="lang in langList" 
      :key="lang"
      :item="lang"
      @showLanguage="getLang"
    />
  </div>
</template>

<script>
import LanguageButton from "./LanguageButton.vue";
export default {
  components: { LanguageButton },
  data() {
    return {
      selectLang: "",
      langList: ["Java", "Python", "JavaScript", "C++"]
    };
  },
  methods: {
    // 接收子组件传递的值
    getLang(val) {
      this.selectLang = val;
    }
  }
};
</script>
流程总结
  1. 父组件循环创建子组件,通过props给子组件传值;

  2. 子组件点击按钮,调用$emit("事件名", 数据)向外派发自定义事件;

  3. 父组件用@事件名监听,接收子组件传来的数据,更新页面。

条件渲染、列表渲染、过渡与动画

一、条件渲染指令:v-if / v-else / v-else-if

1. v-if 基础(移除/创建DOM)

v-if 根据表达式真假,彻底创建或销毁DOM元素(元素不存在于页面中)。

Plaintext 复制代码
<template>
  <div>
    <button @click="show = !show">切换显示</button>
    <!-- 条件渲染:show为true则显示,false则销毁DOM -->
    <h1 v-if="show">v-if 测试文本</h1>
    <h2>永久显示的文本</h2>
  </div>
</template>

<script>
export default {
  data() {
    return { show: true };
  }
};
</script>
2. v-if + v-else 互斥渲染

v-else 必须紧跟v-if,二者互斥,二选一渲染。

Plaintext 复制代码
<template>
  <div>
    <button @click="show = !show">切换</button>
    <h1 v-if="show">标签1 显示</h1>
    <h2 v-else>标签2 显示</h2>
  </div>
</template>

<script>
export default {
  data() { return { show: true }; }
};
</script>

二、v-show(CSS 隐藏/显示)

1. 与 v-if 核心区别
指令 原理 适用场景
v-if 动态创建/销毁DOM,切换开销大 元素很少切换,一次性显示/隐藏
v-show 仅切换CSS display: none,DOM始终存在 元素频繁切换(弹窗、选项卡)
代码示例
Plaintext 复制代码
<template>
  <div>
    <button @click="show = !show">切换</button>
    <!-- v-show:DOM始终存在,仅隐藏 -->
    <div v-show="show">
      <img src="图片地址" alt="图片">
    </div>
  </div>
</template>

<script>
export default {
  data() { return { show: true }; }
};
</script>

三、列表渲染 v-for

1. 作用

遍历数组/对象,批量渲染列表,Vue 3 强制添加 :key(用于DOM节点标识,提升渲染效率)。

2. 基础语法
Plaintext 复制代码
<!-- 遍历数组:item 为当前项,index 为索引 -->
<li v-for="(item, index) in 数组" :key="index">{{ item }}</li>
3. 完整案例(动态添加列表)
Plaintext 复制代码
<template>
  <div>
    <!-- 输入框:回车添加内容到列表 -->
    <input 
      type="text"
      v-model="inputVal"
      @keyup.enter="addItem"
      placeholder="输入水果,按回车添加"
    >
    <!-- 数组有内容才显示标题 -->
    <h1 v-if="fruitList.length > 0">水果列表</h1>
    <!-- 列表渲染 -->
    <ul>
      <li v-for="(fruit, idx) in fruitList" :key="idx">
        {{ fruit }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      inputVal: "",
      fruitList: [] // 水果数组
    };
  },
  methods: {
    addItem() {
      // 去除首尾空格,非空才添加
      if(this.inputVal.trim()){
        this.fruitList.push(this.inputVal.trim());
        this.inputVal = ""; // 清空输入框
      }
    }
  }
};
</script>

四、Vue 过渡 & 动画 <transition>

Vue 内置 <transition> 组件,为元素入场、出场添加过渡动画,无需复杂原生动画代码。

过渡类名规则(name="xxx")

Vue 自动生成6个过渡类名,前缀为name值:

  1. xxx-enter:入场起始状态

  2. xxx-enter-active:入场动画过程(设置过渡时长、动画曲线)

  3. xxx-enter-to:入场结束状态

  4. xxx-leave:出场起始状态

  5. xxx-leave-active:出场动画过程

  6. xxx-leave-to:出场结束状态

1. 淡入淡出过渡(Fade)
Plaintext 复制代码
<template>
  <div>
    <button @click="show = !show">淡入淡出</button>
    <!-- 过渡组件,name="fade" 定义类名前缀 -->
    <transition name="fade">
      <p v-show="show">淡入淡出动画文本</p>
    </transition>
  </div>
</template>

<script>
export default {
  data() { return { show: true }; }
};
</script>

<style scoped>
/* 入场/出场 动画过程:过渡时长3秒 */
.fade-enter-active,
.fade-leave-active {
  transition: opacity 3s;
}
/* 入场起始、出场结束:透明度0(隐藏) */
.fade-enter,
.fade-leave-to {
  opacity: 0;
}
</style>
2. 位移动画(ShiftX 横向滑动)
Plaintext 复制代码
<template>
  <div>
    <button @click="show = !show">滑动动画</button>
    <transition name="shiftx">
      <div v-show="show">
        <img src="图片地址" width="100">
      </div>
    </transition>
  </div>
</template>

<script>
export default {
  data() { return { show: true }; }
};
</script>

<style scoped>
.shiftx-enter-active,
.shiftx-leave-active {
  transition: all 2s ease-in-out;
}
/* 入场从右侧100px开始,透明度0 */
.shiftx-enter,
.shiftx-leave-to {
  transform: translateX(100px);
  opacity: 0;
}
</style>
3. 帧动画(Rotate 旋转)

结合CSS @keyframes 实现复杂帧动画:

Plaintext 复制代码
<template>
  <div>
    <button @click="show = !show">旋转动画</button>
    <transition name="rotate">
      <img v-show="show" src="图片地址" width="100">
    </transition>
  </div>
</template>

<script>
export default {
  data() { return { show: true }; }
};
</script>

<style scoped>
/* 入场动画 */
.rotate-enter-active {
  animation: rotateIn 2s;
}
/* 出场动画(反向执行) */
.rotate-leave-active {
  animation: rotateIn 2s reverse;
}
/* 定义旋转帧动画 */
@keyframes rotateIn {
  0% { transform: rotateX(0deg); opacity: 0; }
  100% { transform: rotateX(360deg); opacity: 1; }
}
</style>
4. 自定义过渡类(集成 Animate.css)

使用enter-active-class/leave-active-class 引入第三方动画库(如Animate.css),无需手写动画:

Plaintext 复制代码
<template>
  <div>
    <button @click="show = !show">第三方动画</button>
    <!-- 自定义过渡类,绑定Animate.css动画类名 -->
    <transition
      enter-active-class="animate__animated animate__swing"
      leave-active-class="animate__animated animate__bounceOut"
    >
      <p v-if="show">第三方动画效果</p>
    </transition>
  </div>
</template>

<script>
export default {
  data() { return { show: true }; }
};
</script>
相关推荐
大家的林语冰1 小时前
npm 不忍了,正式上线“阶段式发布“的新功能,进一步对抗频繁的供应链攻击!
前端·javascript·node.js
by————组态2 小时前
Ricon组态技术架构 - 企业级Web组态解决方案
运维·服务器·前端·物联网·架构·组态·组态软件
llz_1122 小时前
web-第六次课后作业
前端·spring boot·后端
爱勇宝2 小时前
CEO通知5100名员工:今年不涨薪了,钱要投给AI!
前端·后端·程序员
乘风gg2 小时前
前端死到第几轮了?得物前端部门解散有感!
前端·ai编程·claude
艾伦野鸽ggg2 小时前
web 组大一下第二次考核
前端·css·html
水煮白菜王2 小时前
高德地图"未获得商用授权"水印临时移除方案
前端·javascript
库拉AI小李2 小时前
# 数据清洗与分析:Gemini 3.5 处理 Excel 数据的实操体验
前端·人工智能·后端