JeecgBoot中的JEditableTable组件复杂自定义功能:修改其中一个字段时其他字段也同时做相应改变,级联选择器的使用

2023-10-31

参考官方技术文档:http://jeecg-boot.mydoc.io/?t=345687

初始需求:如下图,当我修改产品名称的选项时,产品编码和产品规格的字段会根据我给出的数组自动改变。
在这里插入图片描述
1.首先我们需要将column类型改为slot才能自定义产品名称的可选列表以及添加同时修改功能。需要注意的是在技术文档中我们可以看到,当 type=slot时所需的参数:

参数 类型 必填 说明
slotName string ✔️ slot的名称

所以最终代码如下:

columns: [
          {
            title: '产品名称',
            key: 'materialName',
            type: FormTypes.slot,
            slotName: 'materialName',
            width: '20%',
          },
          {
            title: '产品编码',
            key: 'materialCode',
            type: FormTypes.slot,
            slotName: 'materialCode',
            width: '20%',
          },
          {
            title: '产品规格',
            key: 'materialSpecs',
            type: FormTypes.slot,
            slotName: 'materialSpecs',
            width: '60%',
          },

2.然后再html代码中添加对应的插槽:

<j-editable-table
  :ref="tableName"
  :loading="loading"
  :columns="columns"
  :dataSource="dataSource"
  :maxHeight="300"
  :rowNumber="true"
  :rowSelection="true"
  :actionButton="true"
>
  <template v-slot:materialName="props">
    <a-select
      :default-value="props.text"
      placeholder="请选择产品名称"
      style="width: 100%"
      show-search
      @change="(value) => handleProChange(value, props.rowId)"
    >
      <a-select-option
        v-for="(item, i) in productsList"
        :key="i"
        :value="item.materialName"
      >
        {{ item.materialName }}
      </a-select-option>
    </a-select>
  </template>

  <template v-slot:materialCode="props">
    <a-input :value="props.text" disabled />
  </template>

  <template v-slot:materialSpecs="props">
    <a-input :value="props.text" disabled />
  </template>
  
</j-editable-table>

其中这个props参数,在技术文档中我们已经可以了解到它的基本用途:

  • props.index :当前行的下标
  • props.text :当前值,可能是defaultValue定义的值,也可能是从dataSource中取出的值
  • props.rowId :当前选中行的id,如果是新增行则是临时id
  • props.column :当前操作的列
  • props.getValue :这是一个function,执行后可以获取当前行的所有值(禁止在template中使用)例:const value = props.getValue()
  • props.target :触发当前事件的实例,可直接调用该实例内的方法(禁止在template中使用)例:target.add()

其中props.getValue()的返回值包含行id和conlums对应字段的值,如下图:
在这里插入图片描述
另外需要注意的是,选择器的@change只有value一个默认参数,如果我们需要传递额外的参数:

<a-select @change="(value) => handleProChange(value, props.rowId)">
//...
</a-select>

3.最后是响应修改的方法:

handleProChange(value, id) {
  let item = this.productsList.find((ele) => ele.materialName == value)
  let values = [
    {
      rowKey: id,
      values: {
        'materialName': value,
        'materialCode': item.materialCode,
        'materialSpecs': item.materialSpecs,
      },
    },
  ]
  this.$refs.tableName.setValues(values)
}

这里用到了实例封装的setValues方法,在技术文档中有功能介绍:
主动设置表格中某行某列的值

  • 参数:
参数名 类型 必填 说明
values array 传入一个数组,数组中的每项都是一行的新值,具体见下面的示例
  • 返回值:
  • 示例:
setValues([
    {
        rowKey: id1, // 行的id
        values: { // 在这里 values 中的 name 是你 columns 中配置的 key
            'name': 'zhangsan',
            'age': '20'
        }
    },
    {
        rowKey: id2,
        values: {
            'name': 'lisi',
            'age': '23'
        }
    }
])

方法的调用也很简单,我们已经为Table设定了一个 ref="tableName" 的属性,那么在vue中就可以使用this.$refs.tableName获取到该表格的实例,并调取其中的方法。在这里就是

this.$refs.tableName.setValues(values)

至此我们就实现了文章开头的需求。
开始接触这个组件遇到了很多麻烦,求助我的开发助手百度时,感觉这篇文章的入门也写得极为详细:JeecgBoot之自定义组件JEditableTable应用,费解的同学也可以多阅读~当然官方文档已然非常详尽。


需求更新2020/12/3:
今天发现同一个名称下存在不同的可选规格,然后对应唯一的编号,因此我们需要在选择产品名称后提供一个规格选择框,最后自动填上编码:
在这里插入图片描述

从后台传过来的数据格式大致如下:

data = [
	{
		materialName: '名字1',
		materialSpec: '规格1.1',
		materialCode: '编码1.1',
	},
	{
		materialName: '名字1',
		materialSpec: '规格1.2',
		materialCode: '编码1.2',
	},
	{
		materialName: '名字2',
		materialSpec: '规格2.1',
		materialCode: '编码2.2',
	},
	//.....
]

需求很明显可以看到,名称和规格是存在级联关系的,推荐使用antDesign中的Cascader组件,但在后端不做更改的情况下我们需要保留前端的基本格式,所以仍然使用Selector组件。
在开始之前,我们可以先参考官方文档中的省市联动例子,便于理解以下更复杂的运用。

data层需要绑定三个数据:

data() {
	return {
		//......
		nameList: [], //产品名称列表
		specList: [], //选定产品后对应的规格列表对象
		specCodeList: {}, //名称对应的编码和规格对象
	}
}

//其中specCodeList是所有数据的对应关系,类似于官方实例中的cityData,可以对比参考。在这里实例数据将转换为如下对象:
specCodeList = {
	'名字1' : {
				'规格1.1' : '编码1.1',
				'规格1.2' : '编码1.2', 
			},
	'名字2' : {
				'规格2.1' : '编码2.1',
			},
	//......
}

关于从dataspecCodeList的转化同时获取nameList:(这里面会涉及很多对对象的操作、运用、处理)

let specCodeList = {} 
for (let i =0; i < data.length; i++) {
  let name = data[i].materialName
  if (name in specCodeList) {
    specCodeList[name][data[i].materialSpecs] = data[i].materialCode
  } else {
    specCodeList[name] = {}
    specCodeList[name][data[i].materialSpecs] = data[i].materialCode
  }
}
this.nameList = Object.keys(specCodeList)
this.specCodeList = specCodeList
  1. 首先修改materialSepc的插槽:
    这其中的@focus@change方法稍后会作解释,先把组件填上。需要注意的是由于我们有可能需要通过setValues()方法来修改选择器显示的值,所以这里有:value="props.text"而不是default-value
<a-select
  :value="props.text"
  placeholder="请选择产品规格"
  style="width: 100%"
  show-search
  @focus="handleFocus(props)"
  @change="(value) => handleSpecChange(value, props)"
>
  <a-select-option v-for="(item, i) in specList" :key="i" :value="item">
    {{ item }}
  </a-select-option>
</a-select>
  1. 然后是materialName下的@change方法:
/**
*@param [value, id] 用户选择的产品名,对应行id
*这里要实现两个功能:
*1. 给出规格可选列表;
*2. 把所选值赋值给Table对应位置
*/
handleProChange(value, id) {
  //修改规格可选项:
  this.specList = Object.keys(this.specCodeList[value])
  //改变列表值:
  let values = [
    {
      rowKey: id,
      values: {
        'materialName': value,
        'materialCode': this.specCodeList[value][this.specList[0]], //编号跟随规格默认值
        'materialSpecs': this.specList[0], //规格默认可选值列表的第一个
      },
    },
  ]
  this.$refs.attrMaterialInfo.setValues(values)
}

  1. 选择好产品名称获得可选规格列表后,用户便会选择规格,对应的@change方法:
/**
*@param [value, props] 用户选择的规格,props
*功能:把新值赋给Table
*/
handleSpecChange(value, props) {
  let { materialName: name, id } = props.getValue()
  // console.log("对应编码是" + this.specCodeList[name][value])
  let values = [
    {
      rowKey: id,
      values: {
        'materialName': name,
        'materialCode': this.specCodeList[name][value],
        'materialSpecs': value,
      },
    },
  ]
  this.$refs.attrMaterialInfo.setValues(values)
}

要注意: 每次切换产品名称后,规格可选列表specList都会变化,所以我们需要在所有选择器上绑定@focus,以便当用户点击其他行的选择器时更新可选规格列表(否则会出现规格可选列表与产品名不对应的情况):

//specList需要根据聚焦行改变:
handleFocus(props) {
  let {materialName} = props.getValue()
  // console.log(props.getValue())
  if (materialName) {
    this.specList = Object.keys(this.specCodeList[materialName])
  } else {
  	//对于没有选择名称的空行,可选列表也对应为空
    this.specList = []
  }
}

至此便实现了我们的第二个需求。总结来说,需求总是不停变化的,还是要对组件熟悉,对ES6熟悉才能解决问题。刚开始我想将规格可选列表specList作为对象存储,key是行id,value是对应的可选列表。这样的话,在选择器访问时就需要写作specList[props.id],但是我发现选择器并接收对象内值得变化,始终是初始值,所以specList必须是字符串数组,于是乎只能通过@focus方法不断变幻specList对应的值。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JeecgBoot中的JEditableTable组件复杂自定义功能:修改其中一个字段时其他字段也同时做相应改变,级联选择器的使用 的相关文章

随机推荐