Vue-ElementPlus 二次封装(可编辑模式)

目录

一、思路:

二、功能点:

三、封装组件:

1、代码 

1.1、capsulation-table  组件

1.2、capsulation-table 所要使用的数据

2、分析

2.1、cancelOtherOptions()方法

四、总结


 ElementPlus中的 el-table 中没有编辑模式,所以需要自己封装一下

一、思路:

        通过插槽(具名插槽、作用域插槽一起使用 )将 el-input 或 el-select 传递给封装的组件,其中 可编辑模式是利用 v-if 切换普通的 div 和 el-input/el-select 组件。

        具名插槽用于 插入位置,并按照名字来识别对应的插槽(插入多个el-input、el-select等)

        作用于插槽用于 让插槽内容能够访问或使用子组件中才有的数据


二、功能点:

  1. 根据某个属性去决定当前组件是否 可编辑
  2. 双击开启编辑模式(可编辑
  3. 开启编辑模式后点击其他位置(其他的el-input或dom),关闭编辑模式 (可编辑

三、封装组件:

1、代码 
1.1、capsulation-table  组件
<template>
  <div class="table-flex">
    <el-table
      ref="tableFlex"
      :data="tableData"
    >
      <template v-for="(col) in tableColumns" :key="col.prop">
        <el-table-column
          :prop="col.prop"
          :label="col.label"
          :show-overflow-tooltip="col.showTooltip"
        >
          <template #default="scope" v-if="col.edit">
            <div
              :class="col.edit + scope.$index + scope.cellIndex"
              @dblclick="
                () => {
                  cancelOtherOptions(scope,col.edit);
                }
              "
            >
              <div
                v-if="!scope.row[col.edit + scope.$index + scope.cellIndex]"
                style="
                  min-height: 23px;
                  white-space: nowrap;
                  overflow: hidden;
                  text-overflow: ellipsis;
                "
              >
                {{ scope.row[col.prop] }}
              </div>
              <slot
                v-else
                :name="col.edit"
                :scope="scope.row"
                :key="col.prop"
              ></slot>
            </div>
          </template>
        </el-table-column>
      </template>
    </el-table>
  </div>
</template>

<script setup lang="ts">
import { ref, watch } from "vue";
import { ElTable, ElTableColumn } from "element-plus";

defineOptions({
  name: "CapsulationTable",
});

const props = defineProps({
  tableData: {
    type: Array as any,
    default: () => [],
  },
  tableColumns: Array as any,
});
/**
 * 深度监听 tableDatle,数据发生变化后更新表格布局
 */
watch(
  () => props.tableData,
  () => {
    tableLayout();
  },
  { deep: true }
);

/**
 * 点击事件 用于完成功能点二
 */
const cancelOtherOptions = (scope: any,key:string) => {
  scope.row[key + scope.$index + scope.cellIndex] = true;
  const dom = document.querySelector(
    `.`+key + scope.$index + scope.cellIndex
  ) as HTMLDivElement;
  const monitorClick = (event: Event) => {
    let targetElement: any = event.target;

    if (!dom.contains(targetElement)) {
      document.removeEventListener("click", monitorClick);
      delete scope.row[key + scope.$index + scope.cellIndex];
    }
  };

  document.addEventListener("click", monitorClick);
};
const tableFlex = ref();

// 重新计算并更新表格的布局
const tableLayout = () => {
  tableFlex.value.doLayout();
};
</script>

<style lang="scss">
.table-flex {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  .el-table__inner-wrapper {
    .el-table__header-wrapper {
      .el-table__header {
        tr,
        th {
          background: #f5f5f5;
        }
      }
    }
  }
}
</style>
1.2、capsulation-table 所要使用的数据
<template>
    <capsulation-table
      :table-data="tableData"
      :table-columns="tableColumn"
    >
      <template #ddd="{ scope, key }">
        <el-input
          :autofocus="true"
          :autosize="{ minRows: 1, maxRows: 4 }"
          v-model="scope[key]"
        />
      </template>
      <template #abc="{ scope, key }">
        <el-select
          class="m-2"
          placeholder="Select"
          v-model="scope[key]"
        >
          <el-option
            v-for="item in options"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          />
        </el-select>
      </template>
    </capsulation-table>
</template>

<script setup lang="ts">

const tableData = reactive([
  {
    id: 1,
    name: "里斯",
    age: 18,
    studentID: 1231,
  },
  {
    id: 2,
    name: "里斯3",
    age: 18,
    studentID: 131,
  },
  {
    id: 3,
    name: "里斯",
    age: 18,
    studentID: 1231,
  },
  {
    id: 4,
    name: "里斯3",
    age: "",
    studentID: 131,
  },
  {
    id: 5,
    name: "里斯",
    age: 18,
    studentID: 1231,
  },
  {
    id: 6,
    name: "里斯3",
    age: 18,
    studentID: 131,
  },
  {
    id: 7,
    name: "里斯",
    age: 18,
    studentID: 1231,
  },
  {
    id: 313,
    name: "里斯3",
    age: 18,
    studentID: 131,
  },
  {
    id: 214,
    name: "里斯",
    age: 18,
    studentID: 1231,
  },
  {
    id: 1241,
    name: "里斯3",
    age: 18,
    studentID: 131,
  },
  {
    id: 1241,
    name: "里斯3",
    age: 18,
    studentID: 131,
  },
]);
const tableColumn = ref([
  {
    prop: "studentID",
    label: "学生ID",
  },
  {
    edit: "ddd",
    prop: "name",
    label: "名字",
    showTooltip: true
  },
  {
    edit: "abc",
    prop: "age",
    label: "年龄",
  },
]);
const options = [
  {
    value: 11,
    label: 11,
  },
  {
    value: 12,
    label: 12,
  },
  {
    value: 13,
    label: 13,
  },
  {
    value: 14,
    label: 14,
  },
  {
    value: 15,
    label: 15,
  },
];

</script>

 

2、分析
2.1、cancelOtherOptions()方法

        该方法用于用户点击 table 的时候,给点击的这个 table 添加一个属性,这个属性的键是由 {{传递过来的 edit的值}}+{{当前table所在的行}}+{{当前table所在的列}} 所组成的,是唯一的,值为 true or false。

        通过 :class="col.edit + scope.$index + scope.cellIndex" 给每一个div添加一个唯一的class

        因为一开始 tableData 中是没有这个属性的,所以 v-if="!scope.row[col.edit + scope.$index + scope.cellIndex]" 为true ,显示正常的div,当点击 table 后,给当前 table添加 scope.row[key + scope.$index + scope.cellIndex] 属性设置为 true ,显示通过插槽传递过来的 el-input 或 el-select组件,这样就可以对数据进行编辑。


        当组件处于可编辑状态的时候,点击组件内部不退出编辑状态,但是点击其他dom就需要退出编辑状态并显示原始 div

        要实现这个功能我的想法是在点击 table 的时候给 document 添加一个点击事件,用于监听接下来点击的dom是否为处于编辑状态的组件或或其子级div,如果不在则移除绑定在 document 上的点击事件并 删除 scope.row[key + scope.$index + scope.cellIndex] 属性,这样 !scope.row[key + scope.$index + scope.cellIndex] 为 true,退出编辑状态,显示常规 div。

    if (!dom.contains(targetElement)) {
      document.removeEventListener("click", monitorClick);
      delete scope.row[key + scope.$index + scope.cellIndex];
    }

        根据某个属性去决定当前组件是否 可编辑

        这个功能就很简单了,在 tableColumn 中的去添加一个edit属性,然后在  capsulation-table 组件中 <template #default="scope" v-if="col.edit"> 判断是否有这个属性,如果有 则对数据进行进一步处理,如果没有,则走el-table、el-table-column默认显示数据的路线。(这个edit一定要是唯一的,要不然会有问题

const tableColumn = ref([
  {
    prop: "studentID",
    label: "学生ID",
  },
  {
    edit: "ddd",
    prop: "name",
    label: "名字",
    showTooltip: true
  },
  {
    edit: "abc",
    prop: "age",
    label: "年龄",
  },
]);

四、总结

        封装的想法和思路主要是运用插槽的知识点,插槽在 vue 中还是蛮重要的,大家可以多看看插槽有关的知识点,灵活运用插槽。

        以上是我自己对于 ElementPlus el-table 二次封装的思路和想法,肯定是有更好的方法去实现这个功能,如果大家有不同的想法和思路 欢迎在评论区留言讨论。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Element Plus 的树形表格也可以使用类似的方式实现全选反选功能。以下是示例代码: ```html <template> <div> <el-checkbox v-model="allChecked" @change="selectAll">全选</el-checkbox> <el-table :data="tableData" style="width: 100%"> <el-table-column type="selection" v-model="checkedItems"></el-table-column> <el-table-column prop="name" label="名称"></el-table-column> <el-table-column prop="age" label="年龄"></el-table-column> </el-table> </div> </template> <script> import { ref, computed } from 'vue'; import { ElTable, ElTableColumn, ElCheckbox } from 'element-plus'; export default { components: { ElTable, ElTableColumn, ElCheckbox }, setup() { const tableData = ref([ { id: 1, name: 'John', age: 25, children: [ { id: 11, name: 'Mike', age: 22 }, { id: 12, name: 'Mary', age: 20 } ] }, { id: 2, name: 'Tom', age: 30, children: [ { id: 21, name: 'Jack', age: 28 }, { id: 22, name: 'Lucy', age: 26 } ] } ]); const checkedItems = ref([]); const checkAll = ref(false); const allChecked = computed({ get() { return checkedItems.value.length === tableData.value.length; }, set(val) { checkedItems.value = val ? tableData.value.slice() : []; } }); function selectAll() { checkedItems.value = allChecked.value ? [] : tableData.value.slice(); } return { tableData, checkedItems, checkAll, allChecked, selectAll }; } }; </script> ``` 在上面的代码中,我们使用 Element Plus 的 `ElTable` 和 `ElTableColumn` 组件来实现树形表格,用 `type="selection"` 的方式来添加选择列,将其与 `checkedItems` 变量绑定。在全选复选框中,我们使用 `ElCheckbox` 组件,并将其与 `allChecked` 变量绑定,使用 `@change` 事件监听全选复选框的状态变化,通过 `selectAll` 方法实现全选反选功能。 需要注意的是,在树形表格中,每一行数据可能还包含子节点,因此我们需要修改计算全选状态的逻辑,同时需要修改全选反选的实现方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值