组件拆分实战

我们以之前做的后台文章管理模块为例,实现组件拆分、组件之间互相传值、方法调用、代码封装等功能。

准备工作

src/componments 里面新建 articles 文件夹,用于存放我们拆分出来的子组件。

拆分面包屑

1、在 src/componments/articles 里面新建 BreadComponent.vue 组件

<template>
  <div>
    <el-breadcrumb separator="/">
      <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item><a href="/">新闻管理</a></el-breadcrumb-item>
      <el-breadcrumb-item>新闻列表</el-breadcrumb-item>
    </el-breadcrumb>

    <el-divider></el-divider>
  </div>
</template>

2、在 views/articles/ListView.vue

<template>
  <div>
    <!--面包屑-->
    <Bread />
    .
    .
  </div>
</template>
    
<script>
import Bread from "@/components/articles/BreadComponent";
.
.
export default {
  components: {
    Bread,
  },
  .
  .
}
</script>

拆分工具栏

1、在 src/componments/articles 里面新建 ToolsComponent.vue 组件

<template>
  <div class="controls">
    <!--通过 $parent 方法访问父组件的 showCreateForm 方法-->
    <el-button type="primary" @click="$parent.showCreateForm">新增</el-button>
    <!--通过 $parent 方法访问父组件的 handleMultipleDelete 方法-->
    <el-popconfirm
      title="确定要批量删除吗?"
      @confirm="$parent.handleMultipleDelete"
    >
      <el-button type="danger" slot="reference">批量删除</el-button>
    </el-popconfirm>
  </div>
</template>

2、在 views/articles/ListView.vue

<template>
  <div>
    .
    .
    <!--工具栏-->
    <Tools />
    .
    .
  </div>
</template>

<script>
.
.
import Tools from "@/components/articles/ToolsComponent";
.
.
export default {
  components: {
    .
    .
    Tools,
  },
  .
  .
  methods:{
    // 显示新增表单
    showCreateForm() {},
    // 批量删除
    handleMultipleDelete() {
      const length = this.multipleSelection.length;
      if (length == 0) {
        this.$message.error("你必须选择一条以上记录后,再做操作!");
        return;
      }

      const checkedId = this.multipleSelection.map((item) => {
        return item.id;
      });

      this.$confirm("此操作将删除到回收站, 是否继续?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      }).then(async () => {
        const res = await multipleDeleteArticle({ checkedId: checkedId });
        console.log(res);
      });
    },
  }
}
</script>

拆分搜索框

1、在 src/componments/articles 里面新建 SearchComponent.vue 组件

<template>
  <div>
    <!--通过 $parent 方法调用父组件的 searchData 属性和 init 方法-->
    <el-form
      :inline="true"
      :model="$parent.searchData"
      class="demo-form-inline"
    >
      <el-form-item label="标题">
        <el-input
          v-model="$parent.searchData.title"
          placeholder="请填写标题"
          clearable
          @clear="$parent.init"
        ></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="onSearch">查询</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
export default {
  methods: {
    // 绑定点击查询按钮执行搜索
    onSearch() {
      // 通过 $emit 方法 访问父组件自定义的 handleSearch 事件
      this.$emit("handleSearch");
    },
  },
};
</script>

2、在 views/articles/ListView.vue

<template>
  <div>
    .
    .
    <!--搜索:绑定子组件需要的自定义事件-->
    <Search @handleSearch="init" />
    .
    .
  </div>
</template>

<script>
.
.
import Search from "@/components/articles/SearchComponent";
.
.
export default {
  components: {
    .
    .
    Search,
  },
  .
  .
}
</script>

拆分表格

1、在 src/componments/articles 里面新建 TableComponent.vue 组件

<template>
  <div>
    <el-card>
      <el-table
        v-loading="loading"
        ref="multipleTable"
        :data="articles"
        tooltip-effect="dark"
        style="width: 100%"
        @selection-change="handleSelectionChange"
      >
        <el-table-column type="selection" width="55"> </el-table-column>
        <el-table-column label="编号" prop="id"></el-table-column>
        <el-table-column prop="title" label="标题"></el-table-column>
        <el-table-column label="创建时间">
          <template slot-scope="scope">{{
            scope.row.createdAt | dateFormat
          }}</template>
        </el-table-column>
        <el-table-column label="操作">
          <template slot-scope="scope">
            <el-button size="mini" @click="handleEdit(scope.row)"
              >编辑</el-button
            >
            <el-button
              size="mini"
              type="danger"
              @click="handleDelete(scope.$index, scope.row)"
              >删除</el-button
            >
          </template>
        </el-table-column>
      </el-table>

      <div class="block" style="margin-top: 20px">
        <el-pagination
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
          :current-page="pagination.currentPage"
          :page-sizes="[10, 20, 30, 40]"
          :page-size="pagination.pageSize"
          layout="total, sizes, prev, pager, next, jumper"
          :total="pagination.total"
        >
        </el-pagination>
      </div>
    </el-card>
  </div>
</template>

2、在 views/articles/ListView.vue

.
.
<!--表格:通过属性 articles 把获取到的 tableData 的数据传给子组件,pagination亦同。通过 tef 给表格起个名字叫 myTable-->
<Table ref="myTable" :articles="tableData" :pagination="pagination" />
.
.

表格虽然拿过来了,但是我们要确认几个东西,这些变量或方法都是缺一不可的,如:

  • articles
  • handleSelectionChange
  • handleSizeChange
  • handleCurrentChange
  • pagination.currentPage
  • pagination.pageSize
  • pagination.total

所以 js 部分代码如下:

<script>
export default {
  // 接收父组件传过来的属性
  props: ["articles", "pagination"],
  data() {
    return {
      multipleSelection: [],
    };
  },
  methods: {
    handleSelectionChange(val) {
      this.multipleSelection = val;
    },
    handleSizeChange(val) {
      this.searchData.pageSize = val;
      this.init();
    },
    handleCurrentChange(val) {
      this.searchData.currentPage = val;
      this.init();
    },
  },
};
</script>

最终 TableComponent.vue 代码,如下

<template>
  <div>
    <el-card>
      <el-table
        v-loading="$parent.loading"
        ref="multipleTable"
        :data="articles"
        tooltip-effect="dark"
        style="width: 100%"
        @selection-change="handleSelectionChange"
      >
        <el-table-column type="selection" width="55"> </el-table-column>
        <el-table-column label="编号" prop="id"></el-table-column>
        <el-table-column prop="title" label="标题"></el-table-column>
        <el-table-column label="创建时间">
          <template slot-scope="scope">{{
            scope.row.createdAt | dateFormat
          }}</template>
        </el-table-column>
        <el-table-column label="操作">
          <template slot-scope="scope">
            <el-button size="mini" @click="handleEdit(scope.row)"
              >编辑</el-button
            >
            <el-button
              size="mini"
              type="danger"
              @click="handleDelete(scope.row)"
              >删除</el-button
            >
          </template>
        </el-table-column>
      </el-table>

      <div class="block" style="margin-top: 20px">
        <el-pagination
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
          :current-page="pagination.currentPage"
          :page-sizes="[10, 20, 30, 40]"
          :page-size="pagination.pageSize"
          layout="total, sizes, prev, pager, next, jumper"
          :total="pagination.total"
        >
        </el-pagination>
      </div>
    </el-card>
  </div>
</template>

<script>
import { deleteArticle, multipleDeleteArticle } from "@/api/articles";

export default {
  props: ["articles", "pagination"],
  data() {
    return {
      multipleSelection: [],
    };
  },
  methods: {
    handleSizeChange(val) {
      this.$parent.pagination.pageSize = val;
      this.$parent.init();
    },
    handleCurrentChange(val) {
      this.$parent.pagination.currentPage = val;
      this.$parent.init();
    },
    // 删除单条
    async handleDelete(row) {
      const res = await deleteArticle(row.id);
      this.$message.success(res.message);
      this.$parent.init();
    },
    handleSelectionChange(val) {
      this.multipleSelection = val;
    },
    async multipleDelete() {
      const length = this.multipleSelection.length;
      if (length == 0) {
        this.$message.error("你必须选择一条以上记录后,再做操作!");
        return;
      }

      const checkedId = this.multipleSelection.map((item) => {
        return item.id;
      });

      this.$confirm("此操作将删除到回收站, 是否继续?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      }).then(async () => {
        const res = await multipleDeleteArticle(checkedId);
        this.$message.success(res.message);
        this.$parent.init();
      });
    },
  },
};
</script>

首页增加如下方法

// 批量删除,调用子组件的方法
handleMultipleDelete() {
  this.$refs.myTable.multipleDelete();
},
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React 实战项目是指在开发中使用 React 框架来构建真实世界的应用程序。React 是一个流行的 JavaScript 库,用于构建用户界面,它提供了一种声明式的方式来编写组件,使得构建复杂的用户界面变得更加简单和高效。 React 实战项目通常包括以下几个步骤: 1. 需求分析:明确项目的需求和目标,确定应用程序的功能和用户体验。 2. 架构设计:基于需求分析结果,设计应用程序的整体架构,并拆分为独立的可复用的组件。 3. 组件开发:使用 React 组件模式,编写各个功能模块的组件,并实现组件之间的交互逻辑。 4. 状态管理:使用 React 的状态管理工具(如 Redux 或 MobX)管理应用程序的状态,并实现数据的传递和更新。 5. 路由配置:根据应用程序的需求,配置 React 路由,实现页面之间的切换和导航。 6. 接口对接:根据后端提供的接口文档,调用接口获取数据,并将数据展示在应用程序的各个组件中。 7. 样式设计:使用 CSS 或 CSS-in-JS 工具(如 styled-components)为组件添加样式,使应用程序具有良好的界面设计。 8. 测试和调试:编写单元测试和集成测试,确保应用程序的稳定性和准确性,并进行调试和优化。 9. 上线发布:将项目部署到服务器上,并进行线上环境的配置和优化,使应用程序能够正常运行。 通过实战项目,开发人员可以更深入地了解 React 的使用方式和工作原理,提高自己的开发技能,并丰富自己的项目经验。同时,实战项目也可以加深对软件开发流程和团队协作的理解,提高团队的开发效率和项目的质量。总之,React 实战项目是一种学习和提升 React 开发技能的有效方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值