Vue3 组件开发常用语法整理

1,407 阅读5分钟

🌱 搭建 Vue3 项目:一篇文章带你掌握实战演练

Vue3 + Vite + 组件化 + 响应式 + 表单绑定 + 计算属性 + Watch 全面上手!

🏗️ 创建项目脚手架

使用 vite 快速构建 Vue 项目:

npm create vite  # 根据提示选择 Vue 技术栈即可
cd your-project-name
npm install
npm run dev  # 启动项目

启动后,你的目录结构大致如下:

├─ .vscode/         # VSCode 配置
├─ public/          # 静态资源(如 favicon)
├─ src/             # 项目源码目录
├─ .gitignore       # Git 忽略配置
├─ index.html       # 入口 HTML 文件
├─ package.json     # 项目依赖与脚本配置(像 Maven 的 pom.xml)
├─ README.md        # 项目说明文档
└─ vite.config.js   # Vite 配置文件

🧱 组件化开发基础

Vue 以组件为中心:

  • 组件:独立、可复用的功能单元
  • 组合:多个组件组合形成完整应用

组件本质是一棵 组件树,每个界面都是组件组合的结果。

Vue 的组件文件叫做 SFC(Single File Component) ,结构如下:

image.png

<script setup>
  // JS逻辑区域
</script>

<template>
  <!-- HTML模板 -->
</template>

<style scoped>
  /* 样式,仅作用于当前组件 */
</style>

Vue工程

创建&运行

npm create vite  # 按照提示选择Vue
npm run dev #项目运行命令

运行原理

image.png

🧪 Vue 基础功能实战

🔁 数据插值(双大括号)

<script setup>
let name = "张三"
let age = 18
let car = {
  brand: "奔驰",
  price: 777
}
</script>

<template>
  <div>
    <p>姓名: {{ name }}</p>
    <p>年龄: {{ age }}</p>
    <div style="border: 2px dashed red">
      <p>品牌:{{ car.brand }}</p>
      <p>价格:{{ car.price }}</p>
    </div>
  </div>
</template>

📜 指令 v-text / v-html

<script setup>
let msg = "<p style='color: red'>你好</p>"
</script>

<template>
  <div v-html="msg"></div>  <!-- 渲染 HTML -->
  <div v-text="msg"></div>  <!-- 显示纯文本 -->
</template>

🎯 事件绑定 @click

<script setup>
function buy() {
  alert("购买成功")
}
</script>

<template>
  <button @click="buy">购买</button>
</template>

🔗 修饰符参考:事件修饰符文档

🔍 条件判断 v-if

<script setup>
let car = { brand: "奔驰", price: 777 }
</script>

<template>
  <span v-if="car.price < 1000">可以买</span>
  <span v-else>买不起</span>
</template>

🔁 列表渲染 v-for

<script setup>
let fruits = ["苹果", "香蕉", "橘子"]
</script>

<template>
  <li v-for="(f, i) in fruits" :key="i">{{ f }} ==> {{ i }}</li>
</template>

🔗 属性绑定 :href

<script setup>
let url = "https://www.baidu.com"
</script>

<template>
  <a :href="url">百度</a>
</template>

更多指令见:Vue 官方指令文档


⚡ 响应式数据管理

❌ 非响应式变量的问题

<script setup>
let url = "https://www.baidu.com"
function changeUrl() {
  url = "https://www.bilibili.com"
}
</script>

<template>
  <a :href="url">链接</a>
  <button @click="changeUrl">修改网址</button>
</template>

点击按钮后变量变了,页面却没变?因为这不是响应式变量!

✅ 使用 ref 创建响应式变量

<script setup>
import { ref } from 'vue'
const url = ref("https://www.baidu.com")
function changeUrl() {
  url.value = "https://www.bilibili.com"
}
</script>

<template>
  <a :href="url">链接:{{ url }}</a>
  <button @click="changeUrl">修改网址</button>
</template>

📌 注意:ref 中的值在 JS 中访问需要 .value,html中直接写变量名。

🧩 深层响应式:ref vs reactive

import { reactive } from 'vue'
const car = reactive({ brand: '小米', price: 999 })
car.price += 1000 // 直接修改即可
类型用法
基本类型使用 ref()
对象/数组使用 reactive()

总结:想偷懒也可以全用 ref,多写 .value 就完事。


📝 表单绑定 v-model

<script setup>
import { reactive } from 'vue'
const data = reactive({
  username: "",
  agree: true,
  hobby: [],
  sex: "",
  edu: "",
  course: []
})
</script>

绑定方式如下:

  • 文本框:v-model="data.username"
  • 复选框:v-model="data.agree"
  • 多选框:v-model="data.hobby"
  • 单选框:v-model="data.sex"
  • 下拉单选:v-model="data.edu"
  • 多选下拉:v-model="data.course"

使用 v-model 的输入控件值会自动同步到数据对象中。


🔢 计算属性 computed

<script setup>
import { reactive, ref, computed } from 'vue'
const car = reactive({ brand: "小米", price: 999 })
const num = ref(1)
const totalPrice = computed(() => num.value * car.price)
function addPrice() { car.price += 1000 }
</script>

<template>
  <div>
    <p>单价:{{ car.price }}</p>
    <p>数量:{{ num }}</p>
    <p>总价:{{ totalPrice }}</p>
    <button @click="addPrice">涨价</button>
    <button @click="num++">加数量</button>
  </div>
</template>

🎯 响应式监听 watch / watchEffect

🔍 精准监听(watch)

import { watch, ref } from 'vue'
const num = ref(1)
watch(num, (newVal, oldVal, onCleanup) => {
  console.log("新值:", newVal, "旧值:", oldVal)
  if (newVal > 3) num.value = 3
  onCleanup(() => console.log("watch 清理了"))
})

👀 自动依赖收集(watchEffect)

import { watchEffect } from 'vue'
watchEffect(() => {
  console.log("响应式数据变了就触发")
})

🌀 生命周期钩子(Composition API)

在 Vue3 中,每个组件实例在创建时会经历一系列初始化步骤,如:

  • 设置响应式数据
  • 编译模板
  • 将组件挂载到 DOM
  • 监听数据变化并响应更新

Vue 在这些阶段会调用 生命周期钩子函数,让我们可以在合适的时机插入自定义逻辑。

image.png

🔄 生命周期四大阶段

阶段常用钩子函数
创建onBeforeMountonMounted
更新onBeforeUpdateonUpdated
卸载onBeforeUnmountonUnmounted
销毁

✅ 实战示例

<script setup>
import { ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated } from 'vue';

const count = ref(0);
const btn01 = ref();

onBeforeMount(() => {
  console.log('挂载之前', count.value, document.getElementById("btn01"));
});

onMounted(() => {
  console.log('挂载完毕', count.value, document.getElementById("btn01"));
});

onBeforeUpdate(() => {
  console.log('更新之前', count.value, btn01.value.innerHTML);
});

onUpdated(() => {
  console.log('更新完毕', count.value, btn01.value.innerHTML);
});
</script>

<template>
  <button ref="btn01" @click="count++">{{ count }}</button>
</template>

📦 组件传值通信

🔁 父传子(Props)

父组件通过绑定属性传递数据,子组件使用 defineProps 接收。

  • 数据是单向流动的:父 → 子
  • 子组件修改 props 并不会影响父组件的值
✅ 父组件传值
<Son :books="data.books" :money="data.money" />
✅ 子组件接收
const props = defineProps({
  money: {          //这里面是money的特殊定义,类型、是否为必须、当空时为200
    type: Number,
    required: true,
    default: 200
  },
  books: Array
});

📤 子传父(Emit)

子组件通过 emit 触发事件,父组件监听事件来接收数据或触发行为。

✅ 子组件定义并触发事件
<script setup>
const sonsum = defineProps(['sonsum']);
const emits = defineEmits(['buy']);

function buy() {
  emits('buy', -5);
}
</script>

<template>
  <div>
    <h3>Son</h3>
    <p>son sum: {{ sonsum }}</p>
    <button @click="buy">儿子购买了一根5块的棒棒糖</button>
  </div>
</template>
✅ 父组件监听子组件事件
<script setup>
import Son from './Son.vue';
import { ref } from 'vue';

const sum = ref(100);

function buy(num) {
  sum.value += num;
}
</script>

<template>
  <div>
    <h2>Father</h2>
    <Son :sonsum="sum" @buy="buy" />
  </div>
</template>

🪝 provide / inject 实现跨层通信

在祖先组件中使用 provide 提供变量或方法,在子孙组件中通过 inject 使用。

✅ 父组件 provide 示例

import { provide, ref, nextTick } from 'vue';

const hello = ref();
const reload = async () => {
  isRouterAlive.value = false;
  await nextTick();
  isRouterAlive.value = true;
};

provide("reload", reload);
provide("hello", hello);

✅ 子组件 inject 示例

import { inject } from 'vue';

const reload = inject("reload");
const hello = inject("hello");

🚨注意:方法需要用 箭头函数 形式定义,否则注入后 this 会丢失。


🧩 插槽(Slot)

父组件可以通过插槽向子组件注入内容,实现更灵活的组件布局。

✅ 子组件使用插槽

<script setup>
const sonsum = defineProps(['sonsum']);
const emits = defineEmits(['buy']);

function buy() {
  emits('buy', -5);
}
</script>

<template>
  <div>
    <h3>Son</h3>
    <p>son sum: {{ sonsum }}</p>

    <h2>按钮插槽</h2>
    <slot name="btn">没有按钮</slot>

    <h2>按钮文字插槽</h2>
    <button @click="buy">
      <slot name="买东西">初始值</slot>
    </button>
  </div>
</template>

✅ 父组件传入插槽内容

<script setup>
import Son from './Son.vue';
import { ref } from 'vue';

const sum = ref(100);

function buy(num) {
  sum.value += num;
}
</script>

<template>
  <div>
    <h2>Father</h2>
    <Son :sonsum="sum" @buy="buy">
      <!-- 命名插槽绑定  v-slot: -->
      <template v-slot:btn>
        <button>生成了按钮</button>
      </template>

      <!-- 简写语法 # -->
      <template #买东西>
        买棒棒糖
      </template>
    </Son>
  </div>
</template>

🧠 小结

功能点API/关键词特性说明
生命周期钩子onMounted提供组件各阶段插入钩子逻辑
父传子defineProps单向数据流,父到子
子传父defineEmits子触发事件,父来处理
跨层通信provide/inject跨层级传值传方法
插槽slot/v-slot/#插入结构内容,增强组件复用性

🛠️ 持续练习 + 阅读官方文档,是精通 Vue 的最佳方式!

📚 官方地址:cn.vuejs.org/