vue3 setup语法糖
Holyzq 人气:0setup语法糖简介
直接在 script
标签中添加 setup
属性就可以直接使用 setup
语法糖了。
使用 setup
语法糖后,不用写 setup
函数,组件只需要引入不需要注册,属性和方法也不需要再返回,可以直接在 template
模板中使用。
setup语法糖中新增的api
- defineProps:子组件接收父组件中传来的
props
- defineEmits:子组件调用父组件中的方法
- defineExpose:子组件暴露属性,可以在父组件中拿到
模块简介
本次模块使用 vue3+element-plus
实现一个新闻站的后台分类管理模块,其中新增、编辑采用对话框方式公用一个表单。
分类模块路由
添加分类模块的路由
import { createRouter, createWebHistory } from "vue-router"; import Layout from "@/views/layout/IndexView"; const routes = [ { path: "/sign_in", component: () => import("@/views/auth/SignIn"), meta: { title: "登录" }, }, { path: "/", component: Layout, children: [ { path: "", component: () => import("@/views/HomeView"), meta: { title: "首页" }, }, // 分类管理 { path: "/categories", component: () => import("@/views/categories/ListView"), meta: { title: "分类列表" }, }, ], }, ]; const router = createRouter({ history: createWebHistory(process.env.BASE_URL), routes, }); export default router;
分类列表组件
在 views/categories/ListView.vue
中
<template> <div> <el-breadcrumb separator="/"> <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item> <el-breadcrumb-item>内容管理</el-breadcrumb-item> <el-breadcrumb-item>分类列表</el-breadcrumb-item> </el-breadcrumb> <el-divider /> <el-button type="primary">新增</el-button> <el-table :data="categories" style="width: 100%" class="set-top"> <el-table-column prop="id" label="编号" width="180" /> <el-table-column label="名称" width="180"> <template #default="scope"> <el-tag>{{ scope.row.name }}</el-tag> </template> </el-table-column> <el-table-column label="排序" width="180"> <template #default="scope"> {{ scope.row.sort }} </template> </el-table-column> <el-table-column label="创建日期" width="180"> <template #default="scope"> {{ formatter(scope.row.createdAt) }} </template> </el-table-column> <el-table-column label="操作"> <template #default="scope"> <el-button size="small" @click="handleEdit(scope.row)" >编辑 </el-button> <el-popconfirm title="确定要删除么?" confirm-button-text="确定" cancel-button-text="取消" @confirm="handleDelete(scope.row)" > <template #reference> <el-button size="small" type="danger">删除 </el-button> </template> </el-popconfirm> </template> </el-table-column> </el-table> </div> </template>
获取分类列表数据
<script setup> import { ref } from "vue"; // 5、导入 ref import { fetchCategoryList } from "@/api/categories"; // 6、导入接口 api import moment from "moment"; // 7、导入 moment 包 import { ElMessage, ElNotification } from "element-plus"; // 9、导入消息通知包 // 4、定义分类列表数组 const categories = ref([]); // 1、获取分类列表数据 const init = async () => { const res = await fetchCategoryList(); // 3、赋值 categories.value = res.data.categories; }; // 2、调用 init 方法 init(); // 8、时间格式化 const formatter = (date) => { if (!date) { return ""; } moment.locale("zh-cn"); return moment(date).format("LL"); }; const handleEdit = (row) => { console.log(row); }; // 10、点击删除按钮 const handleDelete = (row) => { try { const res = await deleteCategory(row.id); if (res.code === 20000) { init(); ElNotification({ title: "成功", message: res.message, type: "success", }); } } catch (e) { if (e.Error) { ElMessage.error(e.Error); } } }; </script>
分类表单组件
1、新建 src/views/categories/components/CategoryForm.vue
<template> <el-dialog v-model="dialogFormVisible" title="新增分类"> <el-form :model="form" :rules="rules" ref="ruleFormRef"> <el-form-item label="名称" :label-width="formLabelWidth" prop="name"> <el-input v-model="form.name" autocomplete="off" size="large" /> </el-form-item> <el-form-item label="排序" :label-width="formLabelWidth" prop="sort"> <el-input v-model.number="form.sort" autocomplete="off" size="large" /> </el-form-item> </el-form> <template #footer> <span class="dialog-footer"> <el-button @click="dialogFormVisible = false">取消</el-button> <el-button type="primary" @click="submitForm(ruleFormRef)">立即创建</el-button> </span> </template> </el-dialog> </template> <script setup> import { reactive, ref } from "vue"; // 1、定义对话框属性,默认值为 false const dialogFormVisible = ref(false); // 2、定义表单对象和属性 const form = ref({ name: "", sort: 0, }); const formLabelWidth = "140px"; // 3、表单验证 const ruleFormRef = ref(); const rules = reactive({ name: [ { required: true, message: "请输入分类名称", trigger: "blur" }, { min: 2, max: 20, message: "长度在 2 ~ 20 位", trigger: "blur" }, ], sort: [ { required: true, message: "请输入排序", trigger: "blur" }, { type: "number", message: "排序必须为数字值" }, ], }); // 4、表单提交 const submitForm = async (formEl) => { await formEl.validate(async (valid) => { if (valid) { console.log('submit'); } } } </script>
2、在 categories/ListView.vue
中引入上述表单组件
<template> <div> . . <!--表单对话框--> <CategoryForm ref="dialogShow" /> </div> </template> <script setup> import CategoryForm from "./components/CategoryForm"; // 导入对话框组件 </script>
ref=“dialogShow”:给表单对话框起别名
3、给新增、编辑按钮分别绑定事件,点击后弹出对话框
<el-button type="primary" @click="handleCreate">新增</el-button> <el-button size="small" @click="handleEdit(scope.row)">编辑</el-button>
// 点击新增按钮触发子组件的 showForm 方法,并传参 create,代表新增 const dialogShow = ref(null); const handleCreate = async () => { dialogShow.value.showForm("create"); }; // 点击编辑按钮钮触发子组件的 showForm 方法,并传参 edit 和编辑所需的 id 值,代表编辑 const handleEdit = async (row) => { dialogShow.value.showForm("edit", { id: row.id }); };
4、在表单组件中
<script setup> // 显示对话框 const showForm = async (type, data) => { console.log(type); console.log(data); } </script>
测试:此时点击新增或编辑按钮,发现无法触发 showForm 方法。原因在于我们要在父组件中调用子组件的方法,需导出子组件的方法后才能调用
<script setup> import { defineExpose } from "vue"; defineExpose({ showForm, }); </script>
此时再次点击新增或编辑按钮,发现已经拿到了 type 和 data 的值了。
5、完成新增和编辑的对话框正常显示
// 定义表单类型的默认值为 create const formType = ref("create"); // 完成新增和编辑正常对话框显示 const showForm = async (type, data) => { dialogFormVisible.value = true; formType.value = type; if (type == "create") { form.value = {}; } else { fetchCategory(data.id).then((res) => { form.value = res.data.category; }); } };
对话框字体显示
根据 formType
的值判断显示新增或编辑
<template> <el-dialog v-model="dialogFormVisible" :title="formType == 'create' ? '新增分类' : '编辑分类'" > <el-form :model="form" :rules="rules" ref="ruleFormRef"> <el-form-item label="名称" :label-width="formLabelWidth" prop="name"> <el-input v-model="form.name" autocomplete="off" size="large" /> </el-form-item> <el-form-item label="排序" :label-width="formLabelWidth" prop="sort"> <el-input v-model.number="form.sort" autocomplete="off" size="large" /> </el-form-item> </el-form> <template #footer> <span class="dialog-footer"> <el-button @click="dialogFormVisible = false">取消</el-button> <el-button type="primary" @click="submitForm(ruleFormRef)">{{ formType == "create" ? "立即创建" : "立即更新" }}</el-button> </span> </template> </el-dialog> </template>
完成新增和编辑功能
import { createCategory, fetchCategory, updateCategory, } from "@/api/categories"; import { ElMessage, ElNotification } from "element-plus"; // 表单提交 const submitForm = async (formEl) => { await formEl.validate(async (valid) => { if (valid) { let res; try { if (formType.value == "create") { res = await createCategory(form.value); } else { res = await updateCategory(form.value.id, form.value); } if (res.code === 20000) { ElNotification({ title: "成功", message: res.message, type: "success", }); dialogFormVisible.value = false; } } catch (e) { if (e.Error) { ElMessage.error(e.Error); } } } }); };
当新增或编辑表单提交后,新的数据要同步渲染到页面,根据思路,我们需要调用父组件的 init
方法即可,所以这里涉及到子组件调用父组件的方法
修改父组件引用子组件的代码,增加 @init
事件,绑定 init
方法
<!--表单对话框--> <CategoryForm ref="dialogShow" @init="init" />
在子组件中调用,注意注释中的代码
// eslint-disable-next-line no-undef const emit = defineEmits(["init"]); // 引入父组件的 init 方法 const submitForm = async (formEl) => { await formEl.validate(async (valid) => { if (valid) { let res; try { if (formType.value == "create") { res = await createCategory(form.value); } else { res = await updateCategory(form.value.id, form.value); } if (res.code === 20000) { ElNotification({ title: "成功", message: res.message, type: "success", }); dialogFormVisible.value = false; emit("init"); // 调用 init } } catch (e) { if (e.Error) { ElMessage.error(e.Error); } } } }); };
加载全部内容