前言
在现代前端开发中,模块化编程已经成为提升代码可维护性和可重用性的关键实践。JavaScript 模块的引入,使得开发者能够将代码分割成更小、更易于管理的部分,从而提高了开发效率和团队协作的能力。本文将深入探讨 JavaScript 模块的基本概念与语法,包括如何定义和导入模块、处理默认导出与按需导入等内容。此外,我们还将重点介绍在 Vue 组件中使用 props 和 emit 进行数据传递和事件触发的方法。通过具体的示例代码,我们将详细解释模块化编程的基本实现以及组件间通信的有效方式。无论您是 JavaScript 的新手还是希望提升开发技能的经验开发者,本指南都将为您提供清晰的理解和实用的技巧,帮助您在构建现代应用时更加得心应手。
module
意思
如果你有一个文件,现在没有任何 import 或者 export,但是你希望它被作为模块处理,添加这行代码:
export {};
语法
// @filename: hello.ts export default function helloWorld() { console.log("Hello, world!"); }
import hello from "./hello.js"; hello();
除了默认导出,你可以通过省略 default
的 export
语法导出不止一个变量和函数:
当没有default 的时候就 需要加上{} 按需导入
// @filename: maths.ts export var pi = 3.14; export let squareTwo = 1.41; export const phi = 1.61; export class RandomNumberGenerator {} export function absolute(num: number) { if (num < 0) return num * -1; return num; }
import { pi, phi, absolute } from "./maths.js"; console.log(pi); const absPhi = absolute(phi); // const absPhi: number
import { pi as π } from "./maths.js"; console.log(π); // (alias) var π: number // import π
你可以接受所有的导出对象,然后使用 * as name
把它们放入一个单独的命名空间:
// @filename: app.ts import * as math from "./maths.js"; console.log(math.pi); const positivePhi = math.absolute(math.phi); // const positivePhi: number
传输数据
props
<script setup lang="ts"> interface Props { msg?: string labels?: string[] } const props = withDefaults(defineProps < Props > (), { msg: 'hello', labels: () => ['one', 'two'] }) console.log(props) </script> <template> <h1>{{ msg }}</h1> <ul v-for="item in labels "> <li>{{ item }}</li> </ul> </template>
<template> <div> <A :labels="data"></A> </div> </template> <script setup lang="ts"> import { reactive } from 'vue'; import A from './views/A.vue'; let data = reactive(['first','second']) </script> <style scoped> </style>
emit
<script setup lang="ts"> const emit = defineEmits<{ (e: 'change', show: boolean): void }>() const show = () => { emit('change', false) } </script> <template> <el-button @click="show">显示/不显示</el-button> </template>
<template> <div> <A @change="change"></A> </div> </template> <script setup lang="ts"> import A from './views/A.vue'; const change = (data: boolean) => { console.log(data) } </script>
emit和props
<script setup lang="ts"> const emit = defineEmits<{ (e: 'update:visible', show: boolean): void }>() const handSubmit = () => { emit('update:visible', false) } interface Props{ showDialog?:boolean } withDefaults(defineProps<Props>(),{ showDialog:false }) </script> <template> <!-- 这里使用的是v-show --> <div class="box" v-show="showDialog"> <el-button @click="handSubmit" >显示/不显示</el-button> </div> </template> <style scoped > .box{ width: 200px; height: 200px; background-color: red; } .box button{ position: absolute; left: 8; top: 200px; z-index: 99; } </style>
<template> <div> <el-button @click="updateForm">显示/不显示</el-button> <A :showDialog="showDialog" @update:visible="handSubmit"></A> </div> </template> <script setup lang="ts"> import A from './views/A.vue'; import {ref} from 'vue' let showDialog = ref(false) const updateForm = ()=>{ showDialog.value= true } const handSubmit = (data: boolean) => { showDialog.value=data } </script>
FormModel
<template> <div> <el-dialog v-model="isShow" :title="props.dialogConfig?.dialogTitle" @close="handleCancel"> <el-form :model="form" style="max-width: 600px" ref="ruleFormRef" :rules="rules" status-icon> <el-form-item label="Name" prop="name"> <el-input v-model="form.name" /> </el-form-item> </el-form> <template #footer> <el-button type="default" @click="handleCancel">取消</el-button> <el-button type="primary" @click="handleSaveSubmit">保存提交</el-button> </template> </el-dialog> </div> </template> <script lang="ts" setup> import { reactive, computed, ref } from 'vue'; import type { FormInstance, FormRules } from 'element-plus'; // 定义 prop 类型 interface DialogProps { dialogVisible?: boolean; dialogConfig?: { dialogTitle: string; }; } interface FormValue { name: string; } // 使用 defineProps 声明 props const props = defineProps<DialogProps>(); const emits = defineEmits<{ (e: 'update:dialogVisible', isVisible: boolean): void; (e: 'save', formData: FormValue): void; (e: 'cancel', isVisible: boolean): void; }>(); // 校验 const ruleFormRef = ref<FormInstance>(); const form = reactive<FormValue>({ name: '' }); // 修改为 reactive const rules: FormRules<FormValue> = { name: [ { required: true, message: 'Please input Activity name', trigger: 'blur' }, { min: 3, max: 5, message: 'Length should be 3 to 5', trigger: 'blur' }, ], }; // 使用 computed 属性来同步 props.dialogVisible 的变化 const isShow = computed({ get() { return props.dialogVisible; }, set(value: boolean) { emits('update:dialogVisible', value); }, }); // 保存表单的回调函数 const handleSaveSubmit = async () => { const formEl = ruleFormRef.value; // 获取 ref 的值 if (!formEl) return; await formEl.validate((valid, fields) => { if (valid) { emits('save', { ...form }); // 发送表单数据到父组件 } else { console.log('error submit!', fields); } }); }; const handleCancel = () => { const formEl = ruleFormRef.value; // 获取 ref 的值 emits('cancel', false); // 发送数据到父组件 formEl?.resetFields(); // 使用可选链 }; </script>
<template> <div id="container"> <!-- 修改信息的按钮 --> <el-button @click="updateForm">修改信息</el-button> <!-- FormModel 组件,接收 props 并监听 save 事件 --> <!-- dialogVisible v-model 的 语法糖 进行 双向 绑定 绑定了 isVisible--> <FormModel v-model:dialog-visible="isVisible" :dialog-config="dialogConfig" @save="handleSave" @cancel="handleCancel"/> </div> </template> <script lang="ts" setup> import { ref, reactive } from 'vue'; import FormModel from '../src/views/A.vue'; // 确保路径正确 // 使用 ref 来创建响应式的布尔值,初始为 false(对话框默认关闭) const isVisible = ref(false); // 使用 reactive 来创建响应式的配置对象 const dialogConfig = reactive({ dialogTitle: "封装的第一个Dialog弹窗组件", }); // 更新表单(打开对话框)的方法 const updateForm = () => { // 每次点击修改信息按钮时,强制将isVisible设置为true,确保对话框能够正确显示 isVisible.value = true; }; interface FormValue { name: string } // 处理保存事件的方法 const handleSave = (data: FormValue) => { // 假设保存后需要关闭对话框,但也可以由子组件控制 isVisible.value = false; console.log(data) }; const handleCancel = (show:boolean)=>{ isVisible.value = show; }; </script>