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

Posted 忆凡_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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>

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

列表增删改查

🌟Vue2父子组件传递参数

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

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

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

  • 在父组件内为子组件添加自定义属性,例如我上边的table-data,table-label,table-operation三个属性,并为其绑定数据;如果是动态绑定就需要加上 ,反则不用加。
  • 子组件内通过定义props来接受数据;并且有以下几个参数配置;
属性说明
type原生构造器参数的类型
defaultany参数的默认值,数组/对象的默认值应当由一个工厂函数返回
requiredtrue/false参数是否必传
validatorfunction自定义验证函数
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=“子组件里的通知方法”)

Vue 笔记11.24 使用Vue实现增删改查效果、Vue的生命周期

参考技术A  课堂学习:使用Vue实现增删改查    Vue的生命周期   Vue制作轮播图

不大好说 建议直接去敲 或者 看例子

以下写几个需要注意的地方:

这是一个把student对象添加到students对象数组中的方法(用了两种写法 就是先后展开的顺序不同而已 方法是同一种 一个先展开 一个后展开而已 后一种更好理解)

我们声明了 stu 接收this.student的各项属性和值 

然后再把stu添加到students的后面,这里注意要用 “...” 把stu展开

let stu = ...this.student  展开后的student 就是 no:''xxx,name:'xxx',age:0,sex:'xxx'   

这样就相当于声明了一个新的对象 let stu =  no:''xxx,name:'xxx',age:0,sex:'xxx' 

如果不展开 就是 stu = student 两个对象相等 对象相等就是储存地址相同 这样如果修改stu的值或者student的值 都会影响到另一方的属性值 

删除的方法是根据下标来截取 对象数组 students 把和 删除按钮 同一下标的对象从数组中截取掉

这个方法要传入下标 index 因为之前使用了列表渲染 v-for 所以绑定方法时可以直接传 index进去 即 @click=‘delStudent(index)’

这里的两个方法第一个是在点击 修改按钮 时 把列表里的值 赋值 给弹出的编辑框

因为列表中的数据都是通过列表渲染   v-for   从对象数组 students 中得到的 所以可以通过某一项属性把这一行列表所对应的对象 从 students 中找出来

这里要传入一个属性 我们使用的是 学号 no 属性 

声明了 stu 来接收 用数组的高阶函数   find   来把 students 中 no 属性值与列表中 no 属性值相同的对象找出来 赋值给 stu

然后把stu展开 再令 this.student = ...stu  重新定义了对象 student 

又因为 对象 student 的各个属性和编辑框的各个表单双向绑定 所以就完成了把列表里的值 赋值 给弹出的编辑框

第二个方法是在编辑框内点击修改按钮 使列表中的数据变化

同样是通过学号 no 来从students 中找到相对应的 对象

这边不用传入 no 作为参数 是因为 通过 修改按钮 打开编辑框后 student 对象各个属性已经有相应的值 可以直接拿来用 

用stu 来接收找到的相同 no 属性值的对象后 

用 student 中各个属性的值 重新定义 stu 接收的这个对象的各个属性的值

这样就影响到了 对象数组 students 中某一个相应的对象 也就是我们通过 no 找到的那个对象

(1).模板

el:'#app',指定挂载的容器

指定模板(如果有模板,vue会渲染整个模板;如果没有模板,vue会将el里面的所有内容当成模板使用)

template 就是模板  有的话Vue就会渲染这个模板 没有就渲染el里面所有内容

template:'<div><h2>name</h2><h2>age</h2></div>',

(2).手动挂载

通过vue实例的$mount方法,手动挂载容器 (这里需要 let vm = new Vue ())

公共el选项指定挂载容器,当模板渲染成功后,会立刻挂载页面

$mount方法的好处是,可以自行选择挂载的时机。

vm.$mount('#app')

比如可以把这放到定时器里面  

setTimeout(() => 

            vm.$mount('#app')

        , 1000);

beforeCreate(): 创建之前(数据初始化之前)

Vue实例已经创建完成,但是Vue实例未初始化完成(在这个函数里 打印 this 可以得到Vue 但是如果打印data里的属性就是undefined)

这个生命周期函数,基本上不用,除非要设置Vue实例的内容

created(): 创建之后(数据初始化完成)

在beforeCreate的基础上,Vue实例完成初始化(通俗来说就是Vue中data里的属性可以打印出来了)

这个生命周期函数,通常用于初始化Vue管理的数据,比如:发生ajax请求会放在这里。

beforeMount(): 挂载之前(模板已经成功渲染,但是还没有将内容挂载到页面中)

差值表达式还无法使用 name 显示出来还是name

个生命周期函数,基本上不用

mounted(): 挂载完成(模板已经成功渲染,并且已经将模板内容挂载到了页面)

name会显示在data中的值了

这个生命周期函数,通常用于对DOM的重新改动

beforeUpdata(): 修改之前(数据已经改了,只是还没有重新挂载页面)

Vue中的data里的值已经改变了 但是因为没有挂载所以页面中还是原来的数据

updated(): 修改完成(数据已经改了,页面也已经重新挂载)

这个就很好理解了 data中的数据和页面中的都改了

beforeDestroy(): 销毁之前

beforeDestroy() 

                console.log('-----------------beforeDestroy------------------');

                // 这个生命周期函数,会用的多一些

                console.log(this);

                // 对数据做任何的修改,都不会重新渲染到页面

                this.name = '王五'

            ,

destroyed(): 销毁完成

这个生命周期函数,几乎不用

// 通过vue实例的$mount方法,手动挂载容器

            // 公共el选项指定挂载容器,当模板渲染成功后,会立刻挂载页面

            // $mount方法的好处是,可以自行选择挂载的时机。

            vm.$mount('#app')

在destroyed和beforeDestroy中 修改数据无效。

以上是关于Vue实战封装一个简单的列表组件,实现增删改查的主要内容,如果未能解决你的问题,请参考以下文章

一起学Vue:CRUD(增删改查)

vue-实现对数组的增删改查

vue简单的增删查

vue的增删改查

vue实战:利用vue与ajax实现增删改查

VUE2.0增删改查附编辑添加model(弹框)组件共用