前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >vue组件化,emit还是don't emit,这的确是一个难题

vue组件化,emit还是don't emit,这的确是一个难题

原创
作者头像
brzhang
发布2023-09-10 13:34:16
1550
发布2023-09-10 13:34:16
举报
文章被收录于专栏:玩转全栈玩转全栈

案例背景:

我们来探讨前端组件方面的问题,假设有这么一个需求:

1、我有一个任务管理页面: task-mangerment.vue

2、然后这个页面中有一个 task-list.vue 组件, 用于展示任务列表,同时还有一些其他的交互

3、 task-list.vue 组件的每一项是一个 task-item 组件

4、我通过一个 store 来维护 tasks,task可能需要显示在其他的页面上,比如 index.vue 里面

现在有一个问题,我要对任务进行管理的话,如做 增加,删除,修改 操作时,我事件触发的起点是 task-item ,点击或者长按某个 task-item ;

基于上述案例的问题:

我应该在task-item内部就将这些事情搞定了,还是说,task-item 将事件emit 出来,交给上层task-list.vue 来处理呢?

我分别给出两种代码实现:

task-item自己处理业务逻辑的场景,这种有点让task-item成了一个业务组件的意思

task-item.vue

代码语言:javascript
复制
<template>
  <div>
    <span>{{ task.name }}</span>
    <button @click="deleteTask">删除</button>
  </div>
</template>

<script>
import { mapActions } from 'vuex';

export default {
  props: {
    task: {
      type: Object,
      required: true
    }
  },
  methods: {
    ...mapActions(['deleteTask'])
  }
}
</script>

task-list.vue:

代码语言:javascript
复制
<template>
  <div>
    <task-item
      v-for="task in tasks"
      :key="task.id"
      :task="task"
    ></task-item>
  </div>
</template>

<script>
import TaskItem from './task-item.vue';

export default {
  components: {
    TaskItem
  },
  computed: {
    tasks() {
      return this.$store.state.tasks;
    }
  }
}
</script>

task-item不处理业务逻辑,将之抛出emit 到外面

task-item.vue:

代码语言:javascript
复制
<template>
  <div>
    <span>{{ task.name }}</span>
    <button @click="emitDelete">删除</button>
  </div>
</template>

<script>
export default {
  props: {
    task: {
      type: Object,
      required: true
    }
  },
  methods: {
    emitDelete() {
      this.$emit('delete-task', this.task.id);
    }
  }
}
</script>

task-list.vue:

代码语言:javascript
复制
<template>
  <div>
    <task-item
      v-for="task in tasks"
      :key="task.id"
      :task="task"
      @delete-task="deleteTask"
    ></task-item>
  </div>
</template>

<script>
import { mapActions } from 'vuex';
import TaskItem from './task-item.vue';

export default {
  components: {
    TaskItem
  },
  computed: {
    tasks() {
      return this.$store.state.tasks;
    }
  },
  methods: {
    ...mapActions(['deleteTask'])
  }
}
</script>

相信很多做组件化的同学都遇到过这种类似的问题,那么究竟那种方式更加可取呢?就是今天这篇文章的主题了。

task-item最好是设计为纯展示组件

在这种情况下,我建议将事件处理放在上层组件(task-list.vue)中,并使用 emit 将事件从 task-item.vue 组件传递到上层组件。这样做的好处有以下几点:

  1. 代码解耦:将事件处理放在上层组件中,使得 task-item.vue 只负责展示任务项,不涉及任务的增删改操作,这样使得 task-item.vue 更加独立,便于复用和维护。
  2. 便于管理:将所有与任务相关的操作放在一个组件(task-list.vue)中处理,有利于统一管理和维护。当需要修改任务操作逻辑时,只需在 task-list.vue 中进行修改即可。

为什么就不建议在task-item做业务逻辑?

可能上面的方案,有很多人还是会觉得不服,说,我放在task-item里面怎么就不解耦了,也很高内聚呀,task-list的逻辑也很清晰呢?

这种说法也不能说完全不对,把所有的增删改操作放在 task-item 里面确实是可行的,但这样做可能会导致一些问题:

1. 职责不清晰:将所有的增删改操作都放在 task-item 组件中,会使得这个组件变得复杂,职责不明确。按照组件化的设计原则,每个组件应该只关注自己的职责,降低组件间的耦合度。task-item 组件的主要职责应该是展示任务项,而不是处理任务的增删改操作,你分别站在task-list的立场和task-item的立场来看看,谁更加适合做这个任务的管理角色

2. 难以复用:如果将所有操作都放在 task-item 组件中,当你需要在其他地方使用类似的任务项组件时,可能需要重新编写一个新的组件,或者对现有组件进行修改。而将事件抛出到外层,使得 task-item 组件更加独立,可以在其他地方直接复用,越是底层的组件,就越应该职责单一,能不干的就不干,干了就麻烦大了,一旦遇到其他组件引用你,但是不需要你的一些功能时,你就得改

3. 数据管理困难:如果将所有操作都放在 task-item 组件中,那么每个 task-item 都需要与 Vuex 进行交互,这会导致数据管理变得复杂。将事件抛出到外层,统一由 task-list 组件处理,可以更好地利用 Vuex 的功能,使得数据管理更加清晰。

在Vue 的组件化思想中,将一个复杂的应用程序分解为多个独立、可复用的组件,每个组件只关注自己的职责,降低组件间的耦合度。这种设计思想有助于提高代码的可维护性和可读性。将事件抛出到外层的原因也是为了遵循 Vue 的组件化思想,使得每个组件的职责更加明确。

因此,通过以上的分析,在这个例子中,task-item 组件的职责是展示任务项,而 task-list 组件的职责是管理任务列表。将事件抛出到外层,可以使得 task-item 组件更加独立,便于复用和维护。同时,将事件处理放在上层组件中,可以更好地利用 store 的功能,使得数据管理更加清晰。不知道你理解了没有,欢迎一起交流把,没有任何一种说法永远都是对的,连牛顿第一定律这种公理性的也只能放在宏观力学上才好使,更别提我说表达的观点,因此多思考,那种符合自己的项目,什么方式在大多数场景下是凑效的,而不是跟风。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 案例背景:
  • 基于上述案例的问题:
    • task-item自己处理业务逻辑的场景,这种有点让task-item成了一个业务组件的意思
      • task-item不处理业务逻辑,将之抛出emit 到外面
      • task-item最好是设计为纯展示组件
      • 为什么就不建议在task-item做业务逻辑?
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档