当前位置: 首页 > news >正文

Vue 3 掌握 script setup 语法,学会 props 和 emit

欢迎来到 Vue 3 学习第二天!🎉

昨天我们搞定了响应式基石,今天我们要进入组件化开发的核心:如何让组件之间“说话”

在 Vue 3 中,<script setup> 是官方推荐的语法糖。它让代码更简洁、性能更好(编译时优化),并且对 TypeScript 支持极佳。


1. <script setup>:现代 Vue 的默认写法

🆚 传统写法 vs <script setup>

特性 传统 <script> <script setup> (2026 标准)
组件注册 需手动 import 并写在 components: {} 自动注册 (导入即用)
暴露数据 return { ... } 自动暴露 (顶层变量直接用)
this 需要 this.count 无需 this (直接 count)
代码量 少 ~30%
TS 支持 一般 完美 (天然推导 Props/Emits 类型)

📝 基本用法

<script setup>
import { ref } from 'vue'
import ChildComponent from './ChildComponent.vue' // ✅ 自动注册,模板里直接用 <ChildComponent />const count = ref(0) // ✅ 自动暴露给模板,无需 returnconst increment = () => count.value++
</script><template><div><p>{{ count }}</p><button @click="increment">+1</button><!-- 直接使用组件,无需注册 --><ChildComponent :msg="'Hello from Parent'" /></div>
</template>

2. Props:父传子 (Parent → Child)

<script setup> 中,接收 props 需要使用 defineProps() 宏函数。

💡 核心规则

  1. 无需 importdefineProps 是编译时宏,直接在 <script setup> 中使用。
  2. 声明即接收:调用它返回的对象就是所有的 props。
  3. 2026 新特性 (Vue 3.5+)Props 解构不再丢失响应性! 以前需要用 toRefs,现在可以直接解构。

📝 代码示例 (子组件 Child.vue)

<script setup>
// 方式 A: 数组简写 (适合简单场景,无类型校验)
// const props = defineProps(['title', 'likes'])// 方式 B: 对象写法 (推荐,支持默认值和类型校验)
const props = defineProps({title: {type: String,required: true,default: '默认标题'},likes: {type: Number,default: 0},isActive: Boolean // 简写,等同于 { type: Boolean, default: false }
})// ✅ 2026 最佳实践:直接解构,依然保持响应式!
// 如果 title 变了,解构出来的 title 也会变 (Vue 3.5+ 特性)
const { title, likes } = props console.log(title) // 直接访问
</script><template><div class="card"><h3>{{ title }}</h3><p>点赞数: {{ likes }}</p><p v-if="isActive">当前激活</p></div>
</template>

⚠️ 注意:虽然可以直接修改 props.title = 'New' 不会报错,但严禁在子组件内直接修改 props(单向数据流原则)。如果需要改,请触发事件让父组件改,或使用计算属性副本。


3. Emits:子传父 (Child → Parent)

子组件通过 defineEmits() 声明它能触发的事件,父组件监听这些事件。

💡 核心规则

  1. 无需 importdefineEmits 也是编译时宏。
  2. 返回 emit 函数:调用它返回一个 emit 函数,用来触发事件。
  3. 类型安全:可以定义事件参数的类型。

📝 代码示例 (子组件 Child.vue 续)

<script setup>
// 1. 定义事件
// 数组写法
// const emit = defineEmits(['update', 'close'])// 对象写法 (推荐,可校验参数类型)
const emit = defineEmits({// 事件名: 验证函数 (返回 true 则合法,false 则控制台警告)update: (newVal) => typeof newVal === 'number',close: null // 不需要验证
})const handleLike = () => {// 2. 触发事件// 语法: emit('事件名', 参数1, 参数2...)emit('update', 100) emit('close')
}
</script><template><button @click="handleLike">点赞并通知父组件</button>
</template>

📝 父组件监听 (Parent.vue)

<script setup>
import Child from './Child.vue'
import { ref } from 'vue'const score = ref(0)// 处理更新事件
const onUpdate = (newScore) => {score.value = newScoreconsole.log('收到子组件消息:', newScore)
}
</script><template><div><p>当前分数: {{ score }}</p><!-- 3. 监听事件 --><!-- @update 是 @update:xxx 的简写 --><Child @update="onUpdate" @close="() => console.log('关闭了')" /><!-- 或者行内写法 --><Child @update="score = $event" /></div>
</template>

4. 进阶:双向绑定 (v-model) 的本质

在 Vue 3 中,v-model 只是 prop + emit 的语法糖。

  • Vue 2: value prop + input 事件
  • Vue 3: modelValue prop + update:modelValue 事件

🔄 如何在 <script setup> 中实现 v-model

子组件 (CustomInput.vue):

<script setup>
// 1. 定义 modelValue prop
const props = defineProps({modelValue: String
})// 2. 定义 update:modelValue 事件
const emit = defineEmits(['update:modelValue'])const onInput = (e) => {// 触发更新事件,把新值传给父组件emit('update:modelValue', e.target.value)
}
</script><template><input :value="modelValue" @input="onInput" />
</template>

父组件:

<template><!-- 自动绑定 modelValue 和 update:modelValue --><CustomInput v-model="searchText" /><!-- 等价于 --><!-- <CustomInput :modelValue="searchText" @update:modelValue="searchText = $event" /> -->
</template>

💡 多个 v-model: Vue 3 支持多个 v-model。
<Comp v-model:title="t" v-model:count="c" />
对应 props: title, count 和 emits: update:title, update:count


🚫 Day 2 避坑指南

  1. 不要直接修改 Props

    props.count++ // ❌ 错误!违反了单向数据流,且在严格模式下会报警告
    

    正确做法emit('update:count', props.count + 1) 或者在本地创建一个 const localCount = ref(props.count)

  2. definePropsdefineEmits 不需要 import
    如果你写了 import { defineProps } from 'vue',那是多余的,甚至可能导致类型推导失效。它们是编译器宏

  3. 事件命名规范
    自定义事件通常使用 kebab-case (如 update-count),但在模板中监听时,Vue 会自动处理大小写,所以 @update-count@updateCount 通常都能工作,但建议统一用 kebab-case (@update-count) 以符合 HTML 标准。

  4. TypeScript 用户必看
    如果你用 TS,可以使用泛型来获得完美的类型提示:

    // TS 写法
    const props = defineProps<{ title: string; likes?: number }>()
    const emit = defineEmits<{ (e: 'update', val: number): void }>()
    

🎯 今日实战练习

任务:创建一个“计数器小组件”

  1. 子组件 (Counter.vue):
    • 接收一个 initialCount (数字) 作为 prop。
    • 内部维护一个当前的 count (初始值为 prop)。
    • 有两个按钮:+-
    • count 变化时,触发 change 事件,把新值发给父组件。
    • 如果 count 变为 0,触发 zero 事件。
  2. 父组件 (App.vue):
    • 引入 Counter
    • 设置初始值为 5。
    • 监听 change 事件,在父组件显示“当前子组件的值是:X”。
    • 监听 zero 事件,弹出一个 alert:“归零了!”。

思考题:如果我想让父组件直接控制子组件的 count (双向绑定),应该怎么修改 Counter.vue?(提示:使用 v-model 思路)

http://www.jsqmd.com/news/428793/

相关文章:

  • 2026年乙酰丙酮订制厂家推荐TOP排名榜:优质供应商精选 - 品牌推荐用户报道者
  • Java全栈开发面试实录:从基础到微服务的实战经验分享
  • 拨开迷雾看真相:德国MDQ卫浴客观评析,负面背后是假冒乱象 - 品牌评测官
  • PHP面向对象的庖丁解牛
  • shell引号用法
  • 英联翻译公司(INLION Translation)合作对接指南:2026年官方正规渠道全梳理 - 资讯焦点
  • 2026年矿用电缆夹板厂家推荐:保定创为金塑制品有限公司专业供应强磁/组合式/采煤机全系产品 - 品牌推荐官
  • 2026国内诚信的杭州花园设计施工企业推荐 - 品牌排行榜
  • ​中关村办公室写字楼哪家租赁中介好?深度解析远行地产的专业优势与服务体系 - 资讯焦点
  • PCB微孔加工 哪家技术好
  • 2026年国内热门的金属探测门厂商有哪些,安检设备/金属探测门/安检门/安检仪/安检机,金属探测门直销厂家口碑推荐榜 - 品牌推荐师
  • use PHPUnit\Framework\TestCase;的庖丁解牛
  • 2026年免熏蒸木托盘厂家推荐:定做/批发/物流/出口/租赁专业供应商选型指南 - 品牌推荐官
  • 2026年国内优质的隔油池疏通厂家联系电话,行业内可靠的隔油池清理厂家怎么选技术领航者深度解析 - 品牌推荐师
  • Linux uptime命令详解:系统运行时间的全能观测者
  • why i you love is better
  • 使用numpy实现复合系统AB纯态的施密特分解
  • 金手指电路板评测:谁是真正的插拔王者
  • 解锁天猫兑换码回收高效变现新方式,告别闲置损耗! - 京回收小程序
  • SiLU函数
  • 强烈安利 8个一键生成论文工具:继续教育毕业论文写作全攻略
  • PCB厚板评测:大电流高精度,谁才是载流之王?
  • 2026年重庆展厅设计公司五大权威推荐:格莱林领衔,数字展厅设计赋能品牌新高度 - 深度智识库
  • windows系统缺失DLL文件下载方法
  • 2026年钛酸正丁酯公司推荐榜:TOP排名榜权威发布 - 品牌推荐用户报道者
  • AI提示词(Prompt)从入门到精通,非常详细,收藏这一篇就够了!!!
  • 定稿前必看!AI论文网站 千笔 VS 笔捷Ai,专科生专属推荐!
  • 深入理解 lt; 和 gt;:HTML 实体转义的核心指南!!!
  • Jenkins部署与CICD流水线配置:自动构建发布到k8s集群
  • 横评后发现!人气爆表的降AI率软件 —— 千笔·降AIGC助手