# el-popover 在 el-table 中使用问题记录

记录一下在使用 element UI 中 el-popover 组件在 el-table 中使用出现的问题

在使用 element UI 中 el-popover 遇到了下图的确定按钮点击时无法关闭 el-popover。对于这个问题如何解决实现下图点击取消时的关闭 el-popover 效果特定记录下。

表现效果

# 起因 & 原因

因为对前端 node,vue 并不精通,所以本章将用肤浅的表现来说明这个事件

官方的 el-popover 的使用例子。本质是通过 v-model 绑定一个 boolean 值。打开的时候值为 true,关闭的时候值为 false。但是在 el-table 中使用时却出现 boolean 值已经变成 false 了,可 el-popover 依旧未消失。

<el-popover
  placement="top"
  width="160"
  v-model="visible">
  <p>这是一段内容这是一段内容确定删除吗?</p>
  <div style="text-align: right; margin: 0">
    <el-button size="mini" type="text" @click="visible = false">取消</el-button>
    <el-button type="primary" size="mini" @click="visible = false">确定</el-button>
  </div>
  <el-button slot="reference">删除</el-button>
</el-popover>
<script>
  export default {
    data() {
      return {
        visible: false,
      };
    }
  }
</script>

# 解决办法

# 自己想的方法

在看到下图效果时,确定重复点击打开 el-popover 的按钮可以实现 el-popover 的展示和关闭,并符合模块的自身逻辑

重复点击开关效果

原理就是点击【下架】时打开 el-popover 同时将自身 Dom 节点元素放置到 scope 下。在点击【取消】或者【确定】时获取 Dom 节点通过 js 触发【下架】的点击事件。这个实现在 el-table-column 有 fixed 属性的时候依旧有效。

<!-- table 表格下的关键代码 -->
<el-table-column fixed="right" label="操作" width="130">
  <template slot-scope="scope">
    <div>
      <el-popover
        placement="top"
        width="160">
        <p>你确定要下架该接口吗?</p>
        <div style="text-align: right; margin: 0">
          <el-button size="mini" type="text" @click="test(scope.eventd)">取消</el-button>
          <el-button type="primary"size="mini"@click="test(scope.eventd)">确定</el-button>
        </div>
        <el-button slot="reference" type="text" size="small" @click="scope.eventd = $event">下架</el-button>
      </el-popover>
      <el-button type="text" size="small">上架</el-button>
      <el-button type="text" size="small">删除</el-button>
    </div>
  </template>
</el-table-column>
<!-- methods 下的 test 方法 -->
<script>
export default {
    methods: {
        test(a){
            // 除了 path 的第一个元素还有 a.srcElement.click (); 也是可以的,但这个方法面临废弃
            a.path[0].click();
        }
    }
}
</script>

问题解决后就看了看网上的一下实现方法。

# 通过 el-popover 的:ref 实现

实现原理:通过设置 ref 找到 el-popover 再调用关闭方法

实现代码如下

<!-- table 表格下的关键代码 -->
<el-table-column label="操作" width="130">
  <template slot-scope="scope">
    <div>
      <el-popover
        placement="top"
        width="160"
        :ref="'popover'+scope.$index">
        <p>你确定要下架该接口吗?</p>
        <div style="text-align: right; margin: 0">
          <el-button size="mini" type="text"  @click="test(scope.row,scope.$index)">取消</el-button>
          <el-button type="primary" size="mini" @click="scope._self.$refs[`popover${scope.$index}`].doClose()">确定</el-button>
        </div>
        <el-button slot="reference" type="text" size="small">下架</el-button>
      </el-popover>
      <el-button type="text" size="small">上架</el-button>
      <el-button type="text" size="small">删除</el-button>
    </div>
  </template>
</el-table-column>
<!-- methods 下的 test 方法 -->
<script>
export default {
    methods: {
        test(row, index) {
      		let s = 'popover' + index;
            console.log(this.$refs[s]); // 此处打印后续验证
      		this.$refs[s].doClose();
    	}
    }
}
</script>

因为并不是很懂 ref 这个元素属性的作用。但在测试中发现在 el-table-column 有 fixed 属性的时候无效。一下是对比图,第一个是不加 fixed,第二个是加了 fixed 的时候

不加fixed

加fixed

通过第二张图可以看出因为 el-table-column 有 fixed 属性,导致 table 表格中的操作这列有一个原本的列,和一个固定的列,而点击取消时获取到的【下架】并不是点击打开是的【下架】按钮。所以点击失效了。

# 通过 v-show 实现

实现原理:默认所有的 v-popover 全部加载,再通过 v-show 实现展示控制

实现代码如下

<!-- table 表格下的关键代码 -->
<el-table-column fixed="right" label="操作" width="130">
  <template slot-scope="scope">
    <div>
      <el-popover
        placement="top"
        width="160"
        v-model="popoverShow"
        v-show="popoverId == scope.$index">
        <p>你确定要下架该接口吗?</p>
        <div style="text-align: right; margin: 0">
          <el-button size="mini" type="text"  @click="popoverId = -1">取消</el-button>
          <el-button type="primary" size="mini" @click="popoverId = -1">确定</el-button>
        </div>
      </el-popover>
        <!-- 重点!! 下架按钮放置在 el-popover 之后 -->
      <el-button type="text" size="small" @click="popoverId = scope.$index;">下架</el-button>
      <el-button type="text" size="small">上架</el-button>
      <el-button type="text" size="small">删除</el-button>
    </div>
  </template>
</el-table-column>
<!-- data 下的 popoverShow 和 popoverId 值 -->
<script>
export default {
	data() {
        return {
          popoverId: -1,
          popoverShow: true,
        }
	}
}
</script>

经测试使用 v-show 实现在 el-table-column 有 fixed 属性时依旧有效,但 v-popover 弹窗所在的位置会有一定的偏移,因为 v-popover 窗口在加载时会调整位置,而通过 v-show 是不用重新加载的。 效果图如下

v-show控制

# 总结

因为时间不能对网上的所有实现都复现,这里只是检索了下,并对排在靠前的方式做了下尝试,学习下他们在遇到这个问题时的处理方式。开阔自己的思维。最重要的是希望官方能解决这个问题。