Vue实战【封装一个简单的列表组件,实现增删改查】

简介: Vue实战【封装一个简单的列表组件,实现增删改查】

🌟前言

大家好,上一期的Vue实战都阅读了吗?上一期主要是对Vuex的一个基本操作,通过Vuex我们可以实现全局的状态(数据)共享,以便与我们更好的实现一些需求。

不知道大家在日常工作当中是否被频繁的列表增删改查困扰,功能很简单但确实是非常繁琐的一项工作;今天这一期呢我会从Vue2父子组件如何传值并结合Element来封装一个简单的列表组件;一次封装,多次复用。


🌟table组件封装

在你的component目录下创建一个Table.vue:

<template>
  <el-card class="box-card" style="width: 100%;height: 100%">
    <div class="btnBox">
      <el-button v-for="(item,index) in tableOperation" :key="index" :type="item.type" size="small" @[eventName]="handleClick(item.fun, multipleSelection)">{{ item.label }}</el-button>
    </div>
    <el-table
      style="margin-bottom: 20px"
      :data="tableData"
      size="small"
      row-class-name="row"
      cell-class-name="column"
      :highlight-current-row="true"
      fit
      @selection-change="handleSelectionChange"
    >
    <!--这是是为了将表格设置成带有选择框的表格-->
      <el-table-column
        type="selection"
        width="55"
      />
      <el-table-column
        v-for="(item, index) in tableLabel"
        :key="index"
        align="center"
        :prop="item.prop"
        :width="item.width"
        :label="item.label"
      />
    </el-table>
    <div class="block" style="text-align: end">
      <el-pagination
        background
        :current-page="1"
        :page-sizes="[10, 20, 30, 40]"
        :page-size="10"
        layout="total, sizes, prev, pager, next, jumper"
        :total="tableData.length"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
      />
    </div>
  </el-card>
</template>
<script>
export default {
  name: 'Table',
  // 因为是子组件,要接受父组件传递的数据,所以这里我们定义props
  props: {
    tableData: { // 父组件传递过来的表格数据
      type: Array,
      default: () => {
        return []
      }
    },
    tableLabel: { // 父组件传递过来的表头数据
      type: Array,
      default: () => {
        return []
      }
    },
    tableOperation: { // 父组件传递过来的操作按钮数据
      type: Array,
      default: () => {
        return []
      }
    }
  },
  data() {
    return {
      eventName: 'click',  // 点击按钮绑定的方法,这样写法也可以去绑定一些其他的比如change等方法
      multipleSelection: [] // 这个数组用来保存被选择行的数据,顺序是按照你勾选的顺序来排序的
    }
  },
  methods: {
    // @selection-change方法可以监听到表格里哪一行被选中,类型是数组;
    // 然后我们将它赋值给定义好的 multipleSelection 
    handleSelectionChange(val) {
      this.multipleSelection = val
    },
    // 动态绑定操作按钮的点击事件(按钮是父组件传递过来循环出来的,所以我们给按钮定义一个方法)
    // 接收两个参数,一个是fun(string类型),一个是row(array类型,也就是我们选中行的数据)
    // 这里的某个按钮时传递的参数
    // 比如我点击的是编辑,那这时的fun就是 'edit',执行的方法就是下边的this.edit(row)
    handleClick(fun,row) {
      this[fun](row)
    },
    edit(row) {
      if (!row.length) {
        this.$message.error('请勾选数据后操作')
        return false
      } else if (row.length > 2) {
        this.$message.error('当前仅支持单条数据操作')
        return false
      } else {
        console.log('子组件点击编辑,触发父组件方法;并传递数据', row)
        // 通过$meit通知父组件propClick方法,并传递两个参数:'edit'和row
        this.$emit('propClick', 'edit', row)
      }
    },
    look(row) {
      if (!row.length) {
        this.$message.error('请勾选数据后操作')
        return false
      } else if (row.length > 2) {
        this.$message.error('当前仅支持单条数据操作')
        return false
      } else {
        console.log('子组件点击查看,触发父组件方法;并传递数据', row)
        // 通过$meit通知父组件propClick方法,并传递两个参数:'edit'和row
        this.$emit('propClick', 'look', row)
      }
    },
    delete(row) {
      if (!row.length) {
        this.$message.error('请勾选数据后操作')
        return false
      } else if (row.length > 2) {
        this.$message.error('当前仅支持单条数据操作')
        return false
      } else {
        console.log('子组件点击删除,触发父组件方法;并传递数据', row)
        // 通过$meit通知父组件propClick方法,并传递两个参数:'edit'和row
        this.$emit('propClick', 'del', row)
      }
    },
    handleSizeChange(val) {
      console.log(`每页 ${val} 条`)
    },
    handleCurrentChange(val) {
      console.log(`当前页: ${val}`)
    }
  }
}
</script>
<style scoped>
</style>

table组件封装好了,就可以在父组件里使用啦。

🌟父组件(展示表格的页面)

创建一个父组件(也就是你的页面),我这里起名index.vue大家可以随意;

<template>
  <div v-loading="tableLoading" class="dashboard-container">
  <!--子组件位置-->
  <!--自定义table-data,table-label,table-operation三个属性,分别传递我们需要的数据-->
  <!--自定义@propClick方法,用来接收子组件的通知并执行定义的btnClick方法-->
    <myTable
     :table-data="tableData" 
     :table-label="tableLabel"
     :table-operation="tableOperation"
      @propClick="btnClick" />
  </div>
</template>
<script>
import { mapGetters } from 'vuex'
// 根据你的table组件引入到父组件里
import myTable from '@/components/Table/table'
export default {
  name: 'Dashboard',
  // 并在父组件的compoments里边注册
  components: {
    myTable
  },
  computed: {
    ...mapGetters([
      'name'
    ])
  },
  // eslint-disable-next-line vue/order-in-components
  data() {
    return {
      tableLoading: true,
      // 子组件的表格数据
      tableData: [
        { id: 1, date: '2018-07-24', sales: 23.34, sale: 137597.76, const: 102203.71, profit: 35394.05 },
        { id: 2, date: '2018-07-24', sales: 23.34, sale: 137597.76, const: 102203.71, profit: 35394.05 },
        { id: 3, date: '2018-07-24', sales: 23.34, sale: 137597.76, const: 102203.71, profit: 35394.05 },
        { id: 4, date: '2018-07-24', sales: 23.34, sale: 137597.76, const: 102203.71, profit: 35394.05 },
        { id: 5, date: '2018-07-24', sales: 23.34, sale: 137597.76, const: 102203.71, profit: 35394.05 },
        { id: 6, date: '2018-07-24', sales: 23.34, sale: 137597.76, const: 102203.71, profit: 35394.05 },
        { id: 7, date: '2018-07-24', sales: 23.34, sale: 137597.76, const: 102203.71, profit: 35394.05 },
        { id: 8, date: '2018-07-24', sales: 23.34, sale: 137597.76, const: 102203.71, profit: 35394.05 },
        { id: 9, date: '2018-07-24', sales: 23.34, sale: 137597.76, const: 102203.71, profit: 35394.05 },
        { id: 10, date: '2018-07-24', sales: 23.34, sale: 137597.76, const: 102203.71, profit: 35394.05 },
        { id: 11, date: '2018-07-24', sales: 23.34, sale: 137597.76, const: 102203.71, profit: 35394.05 },
        { id: 12, date: '2018-07-24', sales: 23.34, sale: 137597.76, const: 102203.71, profit: 35394.05 }
      ],
      // 子组件的表头数据
      tableLabel: [
        { label: 'ID', width: '40', prop: 'id' },
        { label: '日期', width: '', prop: 'date' },
        { label: '销售量', width: '', prop: 'sales' },
        { label: '销售额', width: '', prop: 'sale' },
        { label: '成本', width: '', prop: 'const' },
        { label: '利润', width: '', prop: 'profit' }
      ],
      // 子组件的操作按钮
      tableOperation: [
        { label: '编辑', fun: 'edit', type: 'primary' },
        { label: '查看', fun: 'look', type: 'success' },
        { label: '删除', fun: 'delete', type: 'danger' }
      ]
    }
  },
  mounted() {
    setTimeout(() => {
      this.tableLoading = false
      this.$message.success('数据加载成功')
    }, 1000)
  },
  methods: {
    // 当父组件接收到了子组件this.$emit的通知后就会执行这个方法来接收子组件点击传递过来的数据
    btnClick(fun, row) {
      if (fun === 'edit') {
        console.log('子组件点击了编辑,父组件收到子组件传递的数据', row)
      } else if (fun === 'look') {
        console.log('子组件点击了查看,父组件收到子组件传递的数据', row)
      } else if (fun === 'del') {
        console.log('子组件点击了删除,父组件收到子组件传递的数据', row)
      }
    }
  }
}
</script>
<style lang="scss" scoped>
.dashboard {
  &-container {
    /*width: 100%;*/
    margin: 30px;
    height: 88vh;
  }
  &-text {
    font-size: 30px;
    line-height: 46px;
  }
}
</style>

🌟控制台查看父子组件通信是否成功

2023-04-14 (3).png

列表增删改查

🌟Vue2父子组件传递参数

接下来我们来复习一下父子组件传递参数的方法吧

父组件向子组件传递数据:

父组件通过 props 给子组件下发数据

  • 在父组件内为子组件添加自定义属性,例如我上边的table-data,table-label,table-operation三个属性,并为其绑定数据;如果是动态绑定就需要加上 ,反则不用加。
  • 子组件内通过定义props来接受数据;并且有以下几个参数配置;
属性 说明
type 原生构造器 参数的类型
default any 参数的默认值,数组/对象的默认值应当由一个工厂函数返回
required true/false 参数是否必传
validator function 自定义验证函数
Vue.component('example', {
  props: {
    // 基础类型检测 (`null` 指允许任何类型)
    propA: Number,
    // 可能是多种类型
    propB: [String, Number],
    // 必传且是字符串
    propC: {
      type: String,
      required: true
    },
    // 数值且有默认值
    propD: {
      type: Number,
      default: 100
    },
    // 数组/对象的默认值应当由一个工厂函数返回
    propE: {
      type: Object,
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定义验证函数
    propF: {
      validator: function (value) {
        return value > 10
      }
    },
    propG: {
      validator: function (value) {
        // 这个值必须匹配下列字符串中的一个
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
  }
})

子组件向父组件传递数据:

子组件通过事件给父组件发送消息

每个 Vue 实例都实现了事件接口,即:

  • 使用 $on(eventName) 监听事件


  • 使用 $emit(eventName, optionalPayload) 触发事件

1. 主要方法在父组件里。

2. 在父组件里添加自定义事件,自定义事件触发执行主要方法

3. 在子组件里写一个通知方法( this.$emit(‘自定义事件’,参数) )用来告诉父组件执行自定义事件。

4. 在需要触发这个事件的元素上添加触发事件(例:@click=“子组件里的通知方法”)

<!-- 子组件 -->
<template>
  <el-card class="box-card" style="width: 100%;height: 100%">
    <div class="btnBox">
      <el-button
         v-for="(item,index) in tableOperation"
        :key="index"
        :type="item.type"
         size="small"
         @click="handleClick(item.fun, multipleSelection)">{{ item.label }}
      </el-button>
    </div>
  </el-card>
</template>
<script>
export default {
  name: 'Table',
  methods: {
    add(row) {
      console.log('子组件点击新增,触发父组件里的自定义事件-propClick')
      this.$emit('propClick', 'add')
    }
  }
}
</script>
<style scoped>
</style>
<!-- 父组件 -->
<template>
  <div v-loading="tableLoading" class="dashboard-container">
    <myTable @propClick="btnClick" />
  </div>
</template>
<script>
import myTable from '@/components/Table/table'
export default {
  name: 'Dashboard',
  components: {
    myTable
  },
  methods: {
    //自定义事件-propClick触发该方法, 接收子组件点击按钮数据
    btnClick(fun, row) {
      if (fun === 'edit') {
        console.log('子组件点击了编辑,父组件收到子组件传递的数据', row)
        // 这里就可以去写我们需要调用的接口呀,数据处理逻辑呀等等
      } else if (fun === 'look') {
        console.log('子组件点击了查看,父组件收到子组件传递的数据', row)
        // 这里就可以去写我们需要调用的接口呀,数据处理逻辑呀等等
      } else if (fun === 'del') {
        console.log('子组件点击了删除,父组件收到子组件传递的数据', row)
        // 这里就可以去写我们需要调用的接口呀,数据处理逻辑呀等等
      }
    }
  }
}
</script>

🌟写在最后

这篇文章通过父子组件通信并结合Element封装了一个简单的增删改查列表组件,你是否学会了呢?很多复杂的功能都是通过基础知识举一反三得来的,小伙伴一定记的尝试哦。后续会为小伙伴们持续更新Vue的一些实战小魔法!各位小伙伴让我们 let’s be prepared at all times!


目录
相关文章
|
6天前
|
存储 JavaScript 开发者
Vue 组件间通信的最佳实践
本文总结了 Vue.js 中组件间通信的多种方法,包括 props、事件、Vuex 状态管理等,帮助开发者选择最适合项目需求的通信方式,提高开发效率和代码可维护性。
|
6天前
|
存储 JavaScript
Vue 组件间如何通信
Vue组件间通信是指在Vue应用中,不同组件之间传递数据和事件的方法。常用的方式有:props、自定义事件、$emit、$attrs、$refs、provide/inject、Vuex等。掌握这些方法可以实现父子组件、兄弟组件及跨级组件间的高效通信。
|
18天前
|
缓存 JavaScript UED
Vue 中实现组件的懒加载
【10月更文挑战第23天】组件的懒加载是 Vue 应用中提高性能的重要手段之一。通过合理运用动态导入、路由配置等方式,可以实现组件的按需加载,减少资源浪费,提高应用的响应速度和用户体验。在实际应用中,需要根据具体情况选择合适的懒加载方式,并结合性能优化的其他措施,以打造更高效、更优质的 Vue 应用。
|
21天前
|
JavaScript 前端开发 测试技术
组件化开发:创建可重用的Vue组件
【10月更文挑战第21天】组件化开发:创建可重用的Vue组件
24 1
|
JavaScript
Vue - 实战疑点总结
1.注册全局组件(是一个单vue页面组成的一个组件,而不是现拼的template结构) 结构: 代码:main.js import UserList from './components/UserList' Vue.
2196 0
|
5天前
|
JavaScript 前端开发
如何在 Vue 项目中配置 Tree Shaking?
通过以上针对 Webpack 或 Rollup 的配置方法,就可以在 Vue 项目中有效地启用 Tree Shaking,从而优化项目的打包体积,提高项目的性能和加载速度。在实际配置过程中,需要根据项目的具体情况和需求,对配置进行适当的调整和优化。
|
5天前
|
存储 缓存 JavaScript
在 Vue 中使用 computed 和 watch 时,性能问题探讨
本文探讨了在 Vue.js 中使用 computed 计算属性和 watch 监听器时可能遇到的性能问题,并提供了优化建议,帮助开发者提高应用性能。
|
5天前
|
存储 缓存 JavaScript
如何在大型 Vue 应用中有效地管理计算属性和侦听器
在大型 Vue 应用中,合理管理计算属性和侦听器是优化性能和维护性的关键。本文介绍了如何通过模块化、状态管理和避免冗余计算等方法,有效提升应用的响应性和可维护性。
|
5天前
|
存储 缓存 JavaScript
Vue 中 computed 和 watch 的差异
Vue 中的 `computed` 和 `watch` 都用于处理数据变化,但使用场景不同。`computed` 用于计算属性,依赖于其他数据自动更新;`watch` 用于监听数据变化,执行异步或复杂操作。
|
4天前
|
JavaScript 前端开发 UED
vue学习第二章
欢迎来到我的博客!我是一名自学了2年半前端的大一学生,熟悉JavaScript与Vue,目前正在向全栈方向发展。如果你从我的博客中有所收获,欢迎关注我,我将持续更新更多优质文章。你的支持是我最大的动力!🎉🎉🎉