子传父

@defineEmits()
Introduction
子组件除了定义属性参数为方法和父组件通信外,还可以通过编译宏 defineEmits() 发布自定义事件给父组件
过程
在 <script setup> 的顶级作用域下,子组件使用 defineEmits() 宏,以 数组 的形式,声明向父组件传递的自定义事件;同样建议使用某个变量接收以便进一步处理,如 emit
父组件响应子组件传递的自定义事件
为了和普通事件区分,建议加上 emit 前缀
逻辑中推荐使用 camelCase,如:greetingMessage;结构中推荐使用 kebab-case,如:greeting-message
可以直接在子组件结构中,使用专有变量 $emit 发送事件 - 仅限 Vue 环境
自定义事件可以携带参数
也可以使用 - 对象 - 声明校验自定义事件,可以方便的指定参数的类型
子组件
可以在传统的单击事件中触发;也可以在非事件中触发,如使用生命周期函数
<button @click="handleSuper">click me</button>
// 声明自定义事件
const emit = defineEmits(['emitSuper', 'emitHi'])

// 使用1:上来就传递自定义事件;或在onmounted() 中传递
emit('emitHi', 'hi,there.')
onMounted(() => {
  emit('emitHi', 'hi,there.')
})

// 使用2:在单击事件中传递自定义事件
// 使用具名函数
const handleSuper = () => {
    emit('emitSuper', 'hi,there.')
}

// 使用3:具名函数中触发声明的自定义事件
function handleSuper() {
    emit('emitSuper')
}
子组件也可以使用内置方法 $emit 传递事件 - built-in $emit method
<button @click="$emit('emitSuper')">click me, no param</button>
<button @click="$emit('emitSuper', 'hi,there.')">click me with param</button>
父组件
监听事件 emitSuper,并在回调函数中接收并处理参数
<MyComponent @emit-super="callback" />
const callback = (e) => {
    console.log('hihihi', e);
}
emits vs props
props:父组件向子组件的通信,子组件调用父组件声明的方法,并根据需要使用参数
emits:子组件向父组件的通信,使用自己的数据,由父组件定义的方法触发
Drill
[] 模态框 - 自定义事件版
详情页 DetailsView.vue → 权益保护模态框组件 Modal.vue;使用自定义事件 defineEmits() 实现
围绕一个数据 isShowModal 展开
1. 权益保护组件 Guarantee.vue
单击"详情"显示对应的权益模态框
这里使用内联事件触发自定义事件showGuarantee;也可以显示的使用 defineEmits()
<div class="guarantee">
  <h3 class="em">小程序交易保障</h3>
  <span class="ellipsis">先行赔付 · 消费者权益保护</span>
  <button class="btn" @click.stop="$emit('showGuarantee')">详情</button>
</div>
2. 父组件 DetailsView.vue
引入并使用 权益保护组件 Guarantee.vue
指定响应自定义事件,设置 isShowModal 为真,显示模态框
<Guarantee @show-guarantee="switchModal" />
const switchModal = () => {
  isShowModal.value = true
}
简单逻辑,可以使用内联事件,直接赋值
<Guarantee @show-guarantee="isShowModal = true" />
3. 模态框组件 Modal.vue
定义函数属性;同样可以使用自定义事件
单击关闭按钮和背景都应该触发事件 switchModal
<div class="modal" @click.self="props.closeGuarantee">
  <button class="btn" @click.stop="props.closeGuarantee">详情</button>
  // ...
</div>
const props = defineProps({
  closeGuarantee: {
    type: Function,
    default: () => { }
  }
})
4. 父组件 DetailsView.vue
引入并使用模态框组件 Modal.vue
分配方法/函数属性
指定条件渲染
<Modal :close-guarantee="switchModal" v-show="isShowModal" />
同样可以使用内联事件
<Modal :close-guarantee="isShowModal = false" v-show="isShowModal" />
数据流
[] 标题组件 Title.vue - 自定义时间版
Homework
[] 改造封装的产品列表组件 GoodsItem.vue,单击某个产品,跳转到详情页
数据流
子组件 - 定义事件并传递产品 id;结构其它内容略
<button class="btn" @click="toDetail(item.id)">详情</button>
const emits = defineEmits(['emitToDetail'])

const toDetail = (id) => {
  emits('emitToDetail', id)
}
父组件 - 接收并响应事件;数据略
<GoodsItem :lists="lists" @emit-to-detail="doDetail"></GoodsItem>
const doDetail = (e) => {
    console.log('hi outer', e);
}
[] 点赞组件
封装点赞组件 → 接收父组件拉取的点赞数 → 单击时,点赞数量加1
数据流
子组件 - 定义并接收父组件传递的参数,+1后,通过事件回传给父组件
const props = defineProps({
    propLike: Number
})
const emits = defineEmits(['emitInc'])
const incLike = () => {
    emits('emitInc', props.propLike + 1)
}
<div @click="incLike"><span class="fa fa-heart"></span> {{ propLike }}</div>
父组件 - 传递参数并响应事件
<Like :propLike="like" @emit-inc="incLike" />
//传递给子组件的数据
let like = ref(0)

//处理子组件传递的事件
const incLike = (e) => {
  console.log(e);
  like.value = e
}
[] 搜索组件 - 表单
子组件 - Sql.vue
const emits = defineEmits(['emitIpt'])
<input type="text" @input="$emit('emitIpt', $event.target.value)">
<input type="text" @input="(e) => $emit('emitIpt', e.target.value)">
父组件
<Sql @emit-inc="(e) => console.log(e)" />
<Sql @emit-inc="console.log($event)" />