封装一个Element-ui生成一个可行内编辑的表格(vue2项目)

这个封装的是一个供整个项目使用的表格,可多次复用.放在一个全局使用的公共组件文件下.

大致功能介绍,封装自定义指令,点击获得焦点,显示输入框,失去焦点显示文本内容,类型是字典决定类型,图片可以显示图片名还是上传图片

子组件

javascript 复制代码
<script>
export default {
  props: {
    //生成表头
    fields: {
      type: Array,
      default: () => [],
    },
    //数据
    tableData: {
      type: Array,
      default: () => [],
    },
  },
  data() {
    return {};
  },
  created() {},
// 自定义指令
  directives: {
    focus: {
      inserted: function (el) {
        el.querySelector("input").focus();
      },
    },
  },
  methods: {
    // 点击框 获取焦点 column列,row 行
    cellClick(column, row) {
      column.iseditor = true;
      row.isnameSelected = true;
    },
    //输入框失去焦点触发,此处用提示框提示修改
    blurEvent(column, row) {
      //  console.log(column, row);
      column.iseditor = false;
      row.isnameSelected = false;
    },
   
  },
};
</script>
<template>
  <div>
    <el-table :data="tableData" border style="width: 100%">
      <el-table-column
        :prop="field.prop"
        :label="field.label"
        :min-width="field.minWidth || 140"
        v-for="(field, index) in fields"
        :key="index"
        show-overflow-tooltip
      >
        <template slot-scope="scope">
          <div v-if="field.slot">
            <slot :name="field.slot" :row="scope.row" />
          </div>
          <div v-else>
            <div>
              <el-input
                v-if="field.iseditor && scope.row.isnameSelected"
                v-model="scope.row[field.prop]"
                @focus="cellClick(field, scope.row)"
                @blur="blurEvent(field, scope.row)"
                v-focus
              >
              </el-input>
              <p @click="cellClick(field, scope.row)" v-else>
                {{ scope.row[field.prop] || "--" }}
              </p>
            </div>
          </div>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>
<style scoped>
</style>
<style>
.el-tooltip__popper {
  max-width: 1000px;
}
.disabled .el-upload--picture-card {
  display: none;
}
.avatar-uploader .el-upload {
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
}
.avatar-uploader .el-upload:hover {
  border-color: #409eff;
}
.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 178px;
  height: 178px;
  line-height: 178px;
  text-align: center;
}
.avatar {
  width: 178px;
  height: 178px;
  display: block;
}
</style>

父组件

这里还有封装了一个文件上传的组件嵌套在表格中,算是拓展

javascript 复制代码
<script>
import editComponents from "../../components/editComponents";
export default {
  components: { editComponents },
  data() {
    return {
      fields: [
        {
          prop: "industryCode",
          label: "产品",
          iseditor: false,
        },
        {
          prop: "id",
          label: "id",
          iseditor: false,
        },
        {
          prop: "paragraphType",
          label: "产品类型",
          iseditor: false,
          slot: "paragraphType",
//根据这个slot来决定是否要使用插槽,让父组件可以更好地使用数据,不用传来传去,下面是一样的
        },
        {
          prop: "paragraphImage",
          label: "产品图片",
          slot: "paragraphImage",
          iseditor: false,
        },
        {
          prop: "action",
          label: "操作",
          slot: "action",
        },
      ],
      tableData: [
        {
          industryCode: "苹果",
          id: "15",
          paragraphType: "1",
          paragraphImage: "15.png",
        },
        {
          industryCode: "苹果",
          id: "16",
          paragraphType: "2",
          paragraphImage: "15.png",
        },
        {
          industryCode: "苹果",
          id: "17",
          paragraphType: "1",
          paragraphImage: "15.png",
        },
      ],
      fileList: [], //文件总数
      fileList1: [], //详情文件总数
      dialogImageUrl: "",
      dialogVisible: false,
      disabled: false,
    };
  },
  computed: {
    //文件上传地址
    upLoadUrl() {
      //process.env.VUE_APP_BASE_API 检测当前环境来决定接口路径
      //测试环境 VUE_APP_BASE_API = '/stage-api'
      if (process.env.VUE_APP_BASE_API == "/stage-api") {
        return "接口地址"; //   例如:'/minio/upload'
        // 生产
      } else if (process.env.VUE_APP_BASE_API == "生产接口") {
        return "接口地址";
      } else {
        // 本地
        return "接口地址";
      }
    },
  },
  created() {
    this.getlist();
  },
  methods: {
    //获取数据
    getlist() {
      // 发请求获取数据写在这里
      this.tableData = this.tableData.map((item) => {
        return { ...item, isnameSelected: false };
      });
    },
    // 添加
    hAdd() {
      const productObj1 = {
        industryCode: "",
        id: "",
        paragraphType: "",
        paragraphImage: "",
        iseditor: false,
        uuId: Math.random(),
      };

      this.tableData.push(productObj1);
    },
    // 删除
    del(row) {
      this.tableData = this.tableData.filter(
        (item) => item.uuId !== row.uuId || item.id !== row.id
      );
    },
    //图片上传===========================
    handleRemove(file) {
      console.log(file);
      console.log(this.$refs.upload);
      let uploadFiles = this.$refs.upload.uploadFiles;
      for (var i = 0; i < uploadFiles.length; i++) {
        if (uploadFiles[i]["url"] == file.url) {
          uploadFiles.splice(i, 1);
        }
      }
    },
    handlePictureCardPreview(file) {
      this.dialogImageUrl = file.url;
      this.dialogVisible = true;
    },
    handleDownload(file) {
      console.log(file);
    },
    // 文件上传成功-----------------
    async handleSuccess(response, row) {
      // 处理上传成功后的逻辑
      console.log("上传成功", response, row);
      this.fileName = response.data.fileName;
      row.paragraphImage = response.data.fileName;
    },
    handleError(err, file, fileList) {
      // 处理上传失败后的逻辑
      console.error("上传失败", err);
    },
    //  selectedLabel(selectedValue) {
    //   if (selectedValue === "1") {
    //     return "选择一";
    //   } else if (selectedValue === "2") {
    //     return "选择二";
    //   }
    // },
    async onSubmit() {
      // 删除不需要的属性
      this.tableData.forEach(function (obj) {
        if (obj.hasOwnProperty("iseditor")) {
          delete obj.iseditor;
        }
        if (obj.hasOwnProperty("uuId")) {
          delete obj.uuId;
        }
        if (obj.hasOwnProperty("isnameSelected")) {
          delete obj.isnameSelected;
        }
      });
      // 新增
      if (!this.industryCode) {
        //   新增请求写在这里
        console.log(res);
        if (res.message == "success") {
          this.$message({
            message: res.data,
            type: "success",
            duration: 1000,
          });
        } else {
          this.$message.error(res.data);
        }
      } else {
        // 修改请求写在这里
        console.log(res);
        if (res.message == "success") {
          this.$message({
            message: res.data,
            type: "success",
            duration: 1000,
          });
          this.goBack();
        } else {
          this.$message.error(res.data);
        }
      }
    },
  },
};
</script>
<template>
  <div>
    <el-button @click="hAdd" type="primary">添加</el-button>
    <editComponents :fields="fields" :tableData="tableData">
      <template #action="{ row }">
        <el-button type="text" size="small" @click="del(row)">删除</el-button>
      </template>
      <template #paragraphImage="{ row }">
        <div>
          <p>{{ row.paragraphImage || "--" }}</p>
          <el-upload
            ref="upload"
            :file-list="fileList1"
            :action="upLoadUrl"
            list-type="picture-card"
            :on-success="(e) => handleSuccess(e, row)"
            :on-error="handleError"
          >
            <i slot="default" class="el-icon-plus"></i>
            <div slot="file" slot-scope="{ file }">
              <img
                class="el-upload-list__item-thumbnail"
                :src="file.url"
                alt=""
              />
              <span class="el-upload-list__item-actions">
                <span
                  class="el-upload-list__item-preview"
                  @click="handlePictureCardPreview(file)"
                >
                  <i class="el-icon-zoom-in"></i>
                </span>

                <span
                  v-if="!disabled"
                  class="el-upload-list__item-delete"
                  @click="handleRemove(file)"
                >
                  <i class="el-icon-delete"></i>
                </span>
              </span>
            </div>
          </el-upload>
          <el-dialog :visible.sync="dialogVisible">
            <img width="100%" :src="dialogImageUrl" alt="" />
          </el-dialog>
        </div>
      </template>
      <template #paragraphType="{ row }">
        <div>
          <el-select v-model="row.paragraphType" placeholder="请选择">
            <el-option label="选择一" value="1"></el-option>
            <el-option label="选择二" value="2"></el-option>
          </el-select>
          <!-- <p @click="cellClick(row)">
              {{ selectedLabel(row.titleTypeSecond) || "--" }}
              {{row}}
            </p> -->
        </div>
      </template>
    </editComponents>
    <el-card>
      <div>
        <el-button type="primary" round @click="onSubmit">提交</el-button>
      </div>
    </el-card>
  </div>
</template>
<style scoped>
</style>
相关推荐
2401_857600952 小时前
SSM 与 Vue 共筑电脑测评系统:精准洞察电脑世界
前端·javascript·vue.js
2401_857600952 小时前
数字时代的医疗挂号变革:SSM+Vue 系统设计与实现之道
前端·javascript·vue.js
GDAL2 小时前
vue入门教程:组件透传 Attributes
前端·javascript·vue.js
轻口味2 小时前
Vue.js 核心概念:模板、指令、数据绑定
vue.js
2402_857583492 小时前
基于 SSM 框架的 Vue 电脑测评系统:照亮电脑品质之路
前端·javascript·vue.js
java_heartLake3 小时前
Vue3之性能优化
javascript·vue.js·性能优化
ddd君317744 小时前
组件的声明、创建、渲染
vue.js
前端没钱4 小时前
从 Vue 迈向 React:平滑过渡与关键注意点全解析
前端·vue.js·react.js
顽疲5 小时前
springboot vue 会员收银系统 含源码 开发流程
vue.js·spring boot·后端
羊小猪~~5 小时前
前端入门之VUE--ajax、vuex、router,最后的前端总结
前端·javascript·css·vue.js·vscode·ajax·html5