x-extends / vxe-table

Vxe table 的表格组件
https://vxetable.cn
MIT License
7.66k stars 1.06k forks source link

新版vxe-table在使用自定义渲染器时,怎么把渲染器的事件发送到vxe-grid? #2573

Open chenchifeng opened 1 month ago

chenchifeng commented 1 month ago

可复现的链接(包含复现链接与示例代码):

https://codesandbox.io/p/sandbox/thirsty-thunder-5hnw23

问题描述与截图:

下面是vxe-table旧版的时候我做的一个自定义渲染器(编辑时是一个input输入框,而且右侧可以点击,之后使用this.$emit发送editClick事件给vxe-grid用@editClick的方式接收,然后因为二次封装成my-table了,再发这个事件发送到my-table,在my-table里面执行打开弹窗,弹窗的配置是接口返回的,每个表格配置不一样)

VXETable.renderer.add('MySelector', {
  // 可编辑激活模板
  renderEdit(h, editRender, { row, column }) {
    if (!editRender.props || editRender.props.disabled === undefined) {
      editRender.props = Object.assign(editRender, { disabled: true })
    }
    const mySelector = [
      <a-input
        {...{ props: editRender.props, attrs: editRender.attrs }}
        size="small"
        type="text"
        value={row[column.property]}
        onInput={(event) => {
          row[column.property] = event.target.value
        }}
        onchange={() => {
          this.$emit('editChange', row, column)
        }}
        onFocus={(e) => {
          selectInputText(e.target)
        }}
        allowClear={true}
        defaultValue={editRender.defaultValue}
      >
        <a-icon
          slot={'addonAfter'}
          style="cursor: pointer;"
          type="ellipsis"
          onClick={() => {
            this.$emit('editClick', row, column)
          }}
        />
      </a-input>,
    ]
    return mySelector
  },
  // 可编辑显示模板
  renderCell(h, editRender, { row, column }) {
    if (editRender.options) {
      const idx = editRender.options.findIndex((item) => item.value === row[column.property])
      if (idx < 0) {
        return [<span>{row[column.property]}</span>]
      } else {
        return <span>{editRender.options[idx].label}</span>
      }
    }
    return [<span>{row[column.property]}</span>]
  },
})

但是到了vue3+vxe-table4.7之后,发现这种方法走不通了,已经多次查阅最新问答了,也没有在文档找到什么api,方法或者示例去解决这个需求问题.

因为这个columns也是接口返回的或者单独写在一个json文件或者js文件里面的,所以也不适合使用events.xxx的方法把方法发送到columns的events里面.

因为在main.ts里面引入自定义渲染器配置,所以也很难找到渲染器和vxe-grid之间的联系.

如果在二次封装vxe-grid的组件里面引入自定义渲染器配置的话,通过把自定义渲染器逻辑写成hooks,然后把要响应事件调用的方法作为函数传入hooks里面也是可以实现,但是浏览器也会提示: "Renderer.MySelector" 的参数 "renderEdit" 重复定义,这可能会出现错误; "Renderer.MySelector" 的参数 "renderCell" 重复定义,也就是最终调用的方法就是最后一个渲染这个模板的vxe-grid实例方法,所以也是有问题的.

目前只能暂时用事件总线,发送"事件名+实例.xID"的事件去解决(但是这样,事件名不加实例.xID的话又会导致同一条事件页面上多个表格同时响应事件,而不是只响应自己的渲染器发出的事件. 事件名加了实例.xID的话,页面多了的时候好像就创建了好多事件,不知道有没有什么影响).

现在大概复刻这个需求的demo也在上面放上来了. 在这里寻求更好的解决方法.希望作者或其他大佬帮忙看看,谢谢

期望的结果:

希望可以像之前旧版+vue2一样可以在使用vxe-grid的时候处理到渲染器发出的事件或者说有方法能让自定义渲染器发送事件给vxe-grid

操作系统:

window 10

浏览器版本:

chrome 95.0.4638.69

vue 版本:

3.5.4

vxe-pc-ui 版本:

4.1.25

vxe-table 版本:

4.7.78

是否使用当前最新版本?

xlz26296 commented 1 month ago

截至目前 vxe-table 不管哪个版本都没有种用法的

chenchifeng commented 1 month ago

截至目前 vxe-table 不管哪个版本都没有种用法的

但是我在使用vxe-table@2.10.10+vue@2.6.14的就是这样用的,虽然我也忘记是哪里找到的示例参考的了.

VXETable.renderer.add('MySelector', {
  // 可编辑激活模板
  renderEdit(h, editRender, { row, column }) {
    if (!editRender.props || editRender.props.disabled === undefined) {
      editRender.props = Object.assign(editRender, { disabled: true })
    }
    const mySelector = [
      <a-input
        {...{ props: editRender.props, attrs: editRender.attrs }}
        size="small"
        type="text"
        value={row[column.property]}
        onInput={(event) => {
          row[column.property] = event.target.value
        }}
        onchange={() => {
          this.$emit('editChange', row, column)
        }}
        onFocus={(e) => {
          selectInputText(e.target)
        }}
        allowClear={true}
        defaultValue={editRender.defaultValue}
      >
        <a-icon
          slot={'addonAfter'}
          style="cursor: pointer;"
          type="ellipsis"
          onClick={() => {
            this.$emit('editClick', row, column)
          }}
        />
      </a-input>,
    ]
    return mySelector
  },
  // 可编辑显示模板
  renderCell(h, editRender, { row, column }) {
    if (editRender.options) {
      const idx = editRender.options.findIndex((item) => item.value === row[column.property])
      if (idx < 0) {
        return [<span>{row[column.property]}</span>]
      } else {
        return <span>{editRender.options[idx].label}</span>
      }
    }
    return [<span>{row[column.property]}</span>]
  },
})

然后这样

    <vxe-grid
      ref="xTable"
      @editClick="handleEditClick"
    ></vxe-grid>
xywc-s commented 1 week ago

这两个版本的区别很明显就在this的指向, v2的版本里面可行, 说明this.$emit的this指向了vxe-grid这个组件实例, v3不行, 说明this并没有指向vxe-grid组件, 打个断点调试看看就知道了. 另外, 渲染器里面的第二个参数params是可以解构出组件实例$table的, 尝试直接用$table替代this