您的位置:首页 > 文旅 > 美景 > 购物网站建设哪家好_广州荔湾发布公众号_网络营销的作用_网络宣传方式有哪些

购物网站建设哪家好_广州荔湾发布公众号_网络营销的作用_网络宣传方式有哪些

2025/4/19 15:10:01 来源:https://blog.csdn.net/weixin_37342647/article/details/147305826  浏览:    关键词:购物网站建设哪家好_广州荔湾发布公众号_网络营销的作用_网络宣传方式有哪些
购物网站建设哪家好_广州荔湾发布公众号_网络营销的作用_网络宣传方式有哪些

Vue 2中的emits声明与Vue 3的defineModel宏函数详解

1. Vue 2中的emits声明

在Vue 2中,代码是这样的:

export default {emits: ['page-back'],methods: {handlePageBack() {this.$emit('page-back');}}
}

1.1 为什么需要显式声明emits?

虽然Vue 2中不声明emits数组也可以直接使用this.$emit()触发事件,但显式声明有以下重要意义:

  1. 文档化组件接口:明确列出组件会触发的所有事件,使组件使用者清楚地知道可以监听哪些事件
  2. Vue DevTools支持:在Vue DevTools中可以正确显示组件可触发的事件
  3. 自动生成文档:许多文档生成工具会基于emits声明生成组件API文档
  4. 为Vue 3做准备:Vue 3中事件验证依赖于emits声明

在Vue 2.4后期版本中添加了这一特性,主要目的是提高组件接口的清晰度和为Vue 3迁移做准备。它属于一种良好的编程实践,即使在当时并非强制要求。

1.2 与Vue 3的区别

Vue 2中的emits是可选的,而在Vue 3中,未声明的事件会被视为原生事件,直接添加到组件根元素上,这是一个重要的行为变化。

2. Vue 3的defineModel宏函数

// Vue 3.4及以上版本
const model = defineModel<string>();// 读取值
console.log(model.value);// 更新值(自动触发更新事件)
model.value = 'new value';

2.1 defineModel的作用与背景

defineModel宏函数是Vue 3.4引入的,它解决了以下问题:

  1. 简化v-model实现:在Vue 3早期版本中,实现v-model需要同时定义prop和emit事件:
// Vue 3早期实现v-model的方式
const props = defineProps(['modelValue']);
const emit = defineEmits(['update:modelValue']);// 读取值
console.log(props.modelValue);// 更新值
function updateValue(newValue) {emit('update:modelValue', newValue);
}
  1. 减少模板代码:上述实现需要编写大量的模板代码,特别是在需要多个v-model的场景下

  2. 提高类型安全:通过泛型参数提供完整的类型推导

2.2 为什么需要defineModel?即使已有多个v-model支持

虽然Vue 3确实支持多个v-model,但实现方式依然复杂

<template><!-- 父组件 --><custom-inputv-model:first="firstName"v-model:last="lastName"/>
</template><!-- 子组件实现 -->
<script setup>
// 不使用defineModel时的实现
const props = defineProps({first: String,last: String
});const emit = defineEmits(['update:first', 'update:last']);function updateFirst(value) {emit('update:first', value);
}function updateLast(value) {emit('update:last', value);
}
</script>

而使用defineModel后:

// 使用defineModel简化多个v-model
const first = defineModel('first');
const last = defineModel('last');// 直接读取和修改
console.log(first.value);
first.value = 'new value'; // 自动触发update:first事件

2.3 defineModel的技术实现

defineModel在编译时会被展开为prop和emit的组合:

// 用户代码
const model = defineModel();// 编译后大致等价于
const props = defineProps(['modelValue']);
const emit = defineEmits(['update:modelValue']);
const model = computed({get: () => props.modelValue,set: (value) => emit('update:modelValue', value)
});

这实际上创建了一个具有getter和setter的计算属性,在内部处理了与父组件的数据同步。

2.4 为什么在add-modal.vue示例中没有使用defineModel

在提供的add-modal.vue示例中使用的是Vue 3早期的API模式,可能有几个原因:

  1. 版本原因:该代码可能在Vue 3.4发布前编写
  2. 迁移代码:可能是从Vue 2迁移而来,保留了原有模式
  3. 团队约定:团队可能约定使用显式的props/emits模式以保持一致性

如果采用最新的defineModel,代码可以简化为:

// 原代码
const props = withDefaults(defineProps<{type: viewType;visible: boolean;id: string;title: string;}>(),{type: viewType.ADD,visible: false,id: '',title: ''}
);
const emits = defineEmits(['page-back']);// 使用defineModel改写(部分)
const type = withDefaults(defineModel<'type', viewType>(), { default: viewType.ADD });
const visible = withDefaults(defineModel<'visible', boolean>(), { default: false });
const id = withDefaults(defineModel<'id', string>(), { default: '' });
const title = withDefaults(defineModel<'title', string>(), { default: '' });

3. Vue API设计演进的思考

3.1 从隐式到显式的转变

Vue API设计演进体现了从隐式到显式的转变:

  • Vue 2早期:很多行为是隐式的,如事件触发无需声明
  • Vue 2后期:引入emits声明,鼓励显式定义接口
  • Vue 3:通过defineProps/defineEmits强制显式声明
  • Vue 3.4:通过defineModel在保持显式性的同时提高开发效率

3.2 宏函数的多重角色

Vue 3的宏函数具有多重角色:

  1. 开发时角色:提供类型推导和IDE支持
  2. 编译时角色:转换为高效的运行时代码
  3. 文档化角色:明确组件的API界面

3.3 最佳实践的演进

Vue 2到Vue 3的API演进反映了最佳实践的变化:

  1. Vue 2最佳实践:虽然可以省略emits声明,但建议添加以提高代码清晰度
  2. Vue 3早期最佳实践:显式声明props和emits,使用组合式API组织逻辑
  3. Vue 3.4最佳实践:利用defineModel简化双向绑定实现,保持代码简洁

4. 实际应用案例分析

我们可以通过add-modal.vue示例看到不同API风格的混合:

// 使用宏函数定义组件名称
defineOptions({ name: 'energy-key-using-add-modal' });// 使用旧式API定义props和emits
const props = withDefaults(defineProps<{/*...*/}>(),{/*...*/}
);
const emits = defineEmits(['page-back']);// 使用组合式API组织功能模块
const {formRef,formData,/*...*/
} = useFormData({ defaultOptions, type: props.type });// 事件处理函数
const handlePageBack = () => {emits('page-back');
};

如果应用最新的API风格,可以重构为:

defineOptions({ name: 'energy-key-using-add-modal' });// 使用defineModel替代props+emits组合
const type = withDefaults(defineModel<'type', viewType>(), { default: viewType.ADD });
const visible = withDefaults(defineModel<'visible', boolean>(), { default: false });
const id = withDefaults(defineModel<'id', string>(), { default: '' });
const title = withDefaults(defineModel<'title', string>(), { default: '' });// 组合式API保持不变
const {/*...*/} = useFormData({ defaultOptions, type: type.value });// 页面返回简化
const handlePageBack = () => {// 不需要emits,直接使用内置的update事件visible.value = false;
};

5. 总结

5.1 Vue 2中emits的意义

  • 文档化组件接口:明确组件的事件API
  • 开发工具支持:提升DevTools显示
  • 向前兼容:为Vue 3迁移做准备
  • 代码自文档化:提高代码可读性

5.2 Vue 3 defineModel的价值

  • 简化代码:减少实现v-model的模板代码
  • 提高类型安全:提供完整的类型推导
  • 一致的心智模型:统一v-model处理方式
  • 性能优化:通过编译时转换优化运行时性能

5.3 API设计的整体思考

Vue API的演进反映了框架设计者在以下方面的平衡考量:

  1. 显式性 vs 简洁性:保持接口显式声明的同时,减少重复代码
  2. 类型安全 vs 开发便利:增强类型系统支持,同时保持代码直观
  3. 向后兼容 vs 创新改进:在保持核心概念的同时引入更现代的API

Vue 3的宏函数,尤其是defineModel的引入,代表了Vue团队在保持框架核心设计理念的同时,不断简化开发体验的努力。这种演进使Vue在保持易用性的同时,更好地满足了大型应用开发的类型安全和可维护性需求。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com