setup语法糖简介

直接在 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);
        }
      }
    }
  });
};

到此这篇关于vue3 使用setup语法糖实现分类管理的文章就介绍到这了,更多相关vue3 setup语法糖内容请搜索阿兔在线工具以前的文章或继续浏览下面的相关文章希望大家以后多多支持阿兔在线工具!

点赞(0)

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部