尚品汇-增删改查与ElementUI的技巧应用


添加表格数据

image-20230814224520994

为按钮添加修改状态的点击事件:

<el-button
     type="primary"
     icon="el-icon-plus"
     style="margin: 10px 0px"
     @click="showDialog"
     >添加</el-button
   >
   
   ...
    return {
     //代表的分页器第几页
     page: 1,
     //当前页数展示数据条数
     limit: 3,
     //总共数据条数
     total: 0,
     //列表展示的数据
     list: [],
     //对话框显示与隐藏控制的属性
     dialogFormVisible: false,
     //收集品牌信息:对象身上的属性,不能瞎写,需要看文档的
     tmForm: {
       tmName: "",
       logoUrl: "",
     },
     //表单验证规则
     rules: {
       //品牌名称的验证规则
       //require:必须要校验字段(前面五角星有关系)  message 提示信息    trigger:用户行为设置(事件的设置:blur、change)
       tmName: [
         { required: true, message: "请输入品牌名称", trigger: "blur" },
         //自定义校验规则
         { validator: validateTmName, trigger: "change" },
       ],
       //品牌的logo验证规则
       logoUrl: [{ required: true, message: "请选择品牌的图片" }],
     },
   };
   ...
    //点击添加品牌的按钮,确保用户在添加新品牌时开始于一个空白的状态。 
   showDialog() {
     //显示对话框
     this.dialogFormVisible = true;
     //清除数据
     this.tmForm = { tmName: "", logoUrl: "" };
   },

多级数据的添加

例如要添加三级分类的数据,按钮点击时除了三级分类id和等级外均为空数据:

//添加属性按钮的回调
    addAttr() {
      //切换table显示与隐藏
      this.isShowTable = false;
      //清除数据
      //收集三级分类的id
      this.attrInfo = {
        attrName: "", //属性名
        attrValueList: [
          //属性值,因为属性值可以有多个因此用数组,每一个属性值都是一个对象需要attrId,valueName
        ],
        categoryId: this.category3Id, //三级分类的id
        categoryLevel: 3, //因为服务器也需要区分几级id
      };
    },

通过标识符展示添加数据的页面:

<!-- 添加属性|修改属性的结构 -->
      <div v-show="!isShowTable">
        <el-form :inline="true" ref="form" label-width="80px" :model="attrInfo">
          <el-form-item label="属性名">
            <el-input
              placeholder="请输入属性名"
              v-model="attrInfo.attrName"
            ></el-input>
          </el-form-item>
        </el-form>
        <el-button
          type="primary"
          icon="el-icon-plus"
          @click="addAttrValue"
          :disabled="!attrInfo.attrName"
          >添加属性值</el-button
        >
        <el-button @click="isShowTable = true">取消</el-button>
        <el-table
          style="width: 100%; margin: 20px 0px"
          border
          :data="attrInfo.attrValueList"
        >
          <el-table-column align="center" type="index" label="序号" width="80">
          </el-table-column>
          <el-table-column width="width" prop="prop" label="属性值名称">
            <template slot-scope="{ row, $index }">
              <!-- 这里结构需要用到span与input进行来回的切换 -->
              <el-input
                v-model="row.valueName"
                placeholder="请输入属性值名称"
                size="mini"
                v-if="row.flag"
                @blur="toLook(row)"
                @keyup.native.enter="toLook(row)"
                :ref="$index"
              ></el-input>
              <span
                v-else
                @click="toEdit(row, $index)"
                style="display: block"
                >{{ row.valueName }}</span
              >
            </template>
          </el-table-column>
          <el-table-column width="width" prop="prop" label="操作">
            <template slot-scope="{ row, $index }">
              <!-- 气泡确认框 -->
              <el-popconfirm :title="`确定删除${row.valueName}?`" @onConfirm="deleteAttrValue($index)">
                <el-button
                  type="danger"
                  icon="el-icon-delete"
                  size="mini"
                  slot="reference"
                ></el-button>
              </el-popconfirm>
            </template>
          </el-table-column>
        </el-table>
        <el-button type="primary" @click="addOrUpdateAttr" :disabled="attrInfo.attrValueList.length<1">保存</el-button>
        <el-button @click="isShowTable = true">取消</el-button>
      </div>

注意细节:

  1. :disabled="!attrInfo.attrName"只有属性名有值的时候,才可以继续添加属性值。

  2. image-20230815171228733为达到spaninput进行来回的切换,使用row.flag属性进行控制。

  3. @blur@keyup.native.enter是事件监听器,分别在输入框失去焦点和按下回车键时触发toLook方法,并将row作为参数传递给toLook方法。:ref指令将当前输入框的索引值作为引用,可以在其他地方通过this.$refs[index]来获取该输入框的实例。

    //添加属性值回调
        addAttrValue() {
          //向属性值的数组里面添加元素
          //attrId:是你相应的属性的id,目前而言我们是添加属性的操作,还没有相应的属性的id,目前而言带给服务器的id为undefined
          //valueName:相应的属性值的名称
          this.attrInfo.attrValueList.push({
            attrId: this.attrInfo.id, //对于修改某一个属性的时候,可以在已有的属性值基础之上新增新的属性值(新增属性值的时候,需要把已有的属性的id带上)
            valueName: "",
            flag: true,
          });
          //flag属性:给每一个属性值添加一个标记flag,用户切换查看模式与编辑模式,好处,每一个属性值可以控制自己的模式切换
          //当前flag属性,响应式数据(数据变化视图跟着变化)这段代码的作用是在数据变化后,将焦点聚焦在最后一个元素上。
          this.$nextTick(() => {
        this.$refs[this.attrInfo.attrValueList.length - 1].focus();
          });
        },
        
    //失却焦点的事件---切换为查看模式,展示span
        toLook(row) {
          // 如果属性值为空不能作为新的属性值,需要给用户提示,让他输入一个其他的属性值
           if(row.valueName.trim()==''){
             this.$message('请你输入一个正常的属性值');
             return;
           }
           //新增的属性值不能与已有的属性值重复
          let isRepat  = this.attrInfo.attrValueList.some(item=>{
              //需要将row从数组里面判断的时候去除
              //row最新新增的属性值【数组的最后一项元素】
              //判断的时候,需要把已有的数组当中新增的这个属性值去除
              if(row!==item){
                return row.valueName==item.valueName;
              }
           });
    
           if(isRepat) return;
          // row:形参是当前用户添加的最新的属性值
          // 当前编辑模式变为查看模式【让input消失,显示span】
          row.flag = false;
        },

修改表格数据

<!-- 
         表格组件 
         data:表格组件将来需要展示的数据------数组类型
         border:是给表格添加边框
         column属性
         label:显示标题
         width:对应列的宽度
         align:标题的对齐方式
         prop:对应列内容的字段名
         注意1:elmentUI当中的table组件,展示的数据是以一列一列进行展示数据
       -->
    <el-table style="width: 100%" border :data="list">
      <el-table-column type="index" label="序号" width="80px" align="center">
      </el-table-column>
      <el-table-column prop="tmName" label="品牌名称" width="width">
      </el-table-column>
      <el-table-column prop="logoUrl" label="品牌LOGO" width="width">
        <template slot-scope="{ row, $index }">
          <img :src="row.logoUrl" alt="" style="width: 100px; height: 100px" />
        </template>
      </el-table-column>
      <el-table-column prop="prop" label="操作" width="width">
        <template slot-scope="{ row, $index }">
          <el-button
            type="warning"
            icon="el-icon-edit"
            size="mini"
            @click="updateTradeMark(row)"
            >修改</el-button
          >
          <el-button
            type="danger"
            icon="el-icon-delete"
            size="mini"
            @click="deleteTradeMark(row)"
            >删除</el-button
          >
        </template>
      </el-table-column>
    </el-table>
    
    ...
     //修改某一个品牌
    updateTradeMark(row) {
      //row:当前用户选中这个品牌信息
      //显示对话框
      this.dialogFormVisible = true;
      //将已有的品牌信息赋值给tmForm进行展示
      //将服务器返回品牌的信息,直接赋值给了tmForm进行展示。
      //也就是tmForm存储即为服务器返回品牌信息
      this.tmForm = { ...row };
    },

可以观察到,添加与修改使用了同一个弹出框,即实现这两个功能时都需要this.dialogFormVisible = true;

<!--
     对话框
     标题动态切换:因为修改操作将row赋值给了tmForm,即id值被赋值
     :visible.sync:控制对话框显示与隐藏用的
     Form 组件提供了表单验证的功能,只需要通过 rules 属性传入约定的验证规则,并将 Form-Item 的 prop 属性设置为需校验的字段名即可
   -->
   <el-dialog
     :title="tmForm.id ? '修改品牌' : '添加品牌'"
     :visible.sync="dialogFormVisible"
   >
     <!-- form表单 :model属性,这个属性的作用是,把表单的数据收集到那个对象的身上 ,将来表单验证,也需要这个属性-->
     <el-form style="width: 80%" :model="tmForm" :rules="rules" ref="ruleForm">
       <el-form-item label="品牌名称" label-width="100px" prop="tmName">
         <el-input autocomplete="off" v-model="tmForm.tmName"></el-input>
       </el-form-item>
       <el-form-item label="品牌LOGO" label-width="100px" prop="logoUrl">
         <!--这里收集数据:不能使用v-model,因为不是表单元素
           action:设置图片上传的地址
           :on-success:可以检测到图片上传成功,当图片上传成功,会执行一次
           :before-upload:可以在上传图片之前,会执行一次

         -->
         <el-upload
           class="avatar-uploader"
           action="/dev-api/admin/product/fileUpload"
           :show-file-list="false"
           :on-success="handleAvatarSuccess"
           :before-upload="beforeAvatarUpload"
         >
           <img v-if="tmForm.logoUrl" :src="tmForm.logoUrl" class="avatar" />
           <i v-else class="el-icon-plus avatar-uploader-icon"></i>
           <div slot="tip" class="el-upload__tip">
             只能上传jpg/png文件,且不超过500kb
           </div>
         </el-upload>
       </el-form-item>
     </el-form>
     <div slot="footer" class="dialog-footer">
       <el-button @click="dialogFormVisible = false">取 消</el-button>
       <el-button type="primary" @click="addOrUpdateTradeMark"
         >确 定</el-button
       >
     </div>
   </el-dialog>
   ...
   
   //添加按钮(添加品牌|修改品牌)
   addOrUpdateTradeMark() {
     //当全部验证字段通过,再去书写业务逻辑
     this.$refs.ruleForm.validate(async (success) => {
       //如果全部字段符合条件
       if (success) {
         this.dialogFormVisible = false;
         //发请求(添加品牌|修改品牌)
         let result = await this.$API.trademark.reqAddOrUpdateTradeMark(
           this.tmForm
         );
         if (result.code == 200) {
           //弹出信息:添加品牌成功、修改品牌成功
           this.$message({
             type: "success",
             message: this.tmForm.id ? "修改品牌成功" : "添加品牌成功",
           });
           //添加或者修改品牌成功以后,需要再次获取品牌列表进行展示
           //如果添加品牌: 停留在第一页。如果修改品牌:修改品牌应该留在当前页面
           this.getPageList(this.tmForm.id ? this.page : 1);
         }
       } else {
         console.log("error submit!!");
         return false;
       }
     });
   },

图片上传

//图片上传之前 应用于:before-upload属性
   beforeAvatarUpload(file) {
     const isJPG = file.type === "image/jpeg";
     const isLt2M = file.size / 1024 / 1024 < 2;

     if (!isJPG) {
       this.$message.error("上传头像图片只能是 JPG 格式!");
     }
     if (!isLt2M) {
       this.$message.error("上传头像图片大小不能超过 2MB!");
     }
     return isJPG && isLt2M;
   },
    //图片上传成功,应用于on-success属性
   handleAvatarSuccess(res, file) {
     //res:上传成功之后返回前端数据
     //file:上传成功之后服务器返回前端数据
     //收集品牌图片数据,因为将来需要带给服务器,即添加|修改操作需要将表单数据作为参数
     this.tmForm.logoUrl = res.data;
   },

照片墙

<el-form-item label="SPU图片">
        <!-- 上传图片:action图片上传的地址  list-type: 文件列表的类型 
         file-list:照片墙需要展示的数据【数组:数组里面的元素务必要有name、url属性】
         on-preview:图片预览功能
         on-remove:删除图片的时候会触发
        -->
        <el-upload
          action="/dev-api/admin/product/fileUpload"
          list-type="picture-card"
          :on-preview="handlePictureCardPreview"
          :on-remove="handleRemove"
          :on-success="handlerSuccess"
          :file-list="spuImageList"
        >
          <i class="el-icon-plus"></i>
        </el-upload>
        <el-dialog :visible.sync="dialogVisible">
          <img width="100%" :src="dialogImageUrl" alt="" />
        </el-dialog>
      </el-form-item>

//收集SPU图片的信息
        spuImageList: [
          // {
          //   id: 0,
          //   imgName: "string",
          //   imgUrl: "string",
          //   spuId: 0,
          // },
        ],
//照片墙图片预览的回调
    handlePictureCardPreview(file) {
      //将图片地址赋值给这个属性
      this.dialogImageUrl = file.url;
      //对话框显示
      this.dialogVisible = true;
    },
    
    //照片墙删除某一个图片的时候会触发
    handleRemove(file, fileList) {
      //file参数:代表的是删除的那个张图片
      //fileList:照片墙删除某一张图片以后,剩余的其他的图片
      // console.log(file, fileList,22222);
      //收集照片墙图片的数据
      //对于已有的图片【照片墙中显示的图片:有name、url字段的】,因为照片墙显示数据务必要有这两个属性
      //对于服务器而言,不需要name、url字段,将来对于有的图片的数据在提交给服务器的时候,需要处理的
      this.spuImageList = fileList;
    },
    
     //照片墙图片上传成功的回调
    handlerSuccess(response, file, fileList) {
      //收集图片的信息
      this.spuImageList = fileList;
    },

多级数据的修改

<el-table-column prop="prop" label="操作" width="150">
            <template slot-scope="{ row, $index }">
              <el-button
                type="warning"
                icon="el-icon-edit"
                size="mini"
                @click="updateAttr(row)"
              ></el-button>
              <el-button
                type="danger"
                icon="el-icon-delete"
                size="mini"
              ></el-button>
            </template>
          </el-table-column>

...
 <span
                v-else
                @click="toEdit(row, $index)"
                style="display: block"
                >{{ row.valueName }}</span
              >
//修改某一个属性
    updateAttr(row) {
      //isShowTable变为false
      this.isShowTable = false;
      //将选中的属性赋值给attrInfo
      //由于数据结构当中存在对象里面套数组,数组里面有套对象,因此需要使用深拷贝解决这类问题
      //深拷贝,浅拷贝在面试的时候出现频率很高,切记达到手写深拷贝与浅拷贝
      this.attrInfo = cloneDeep(row);
      //在修改某一个属性的时候,将相应的属性值元素添加上flag这个标记
      this.attrInfo.attrValueList.forEach((item) => {
        //这样书写也可以给属性值添加flag自动,但是会发现视图不会跟着变化(因为flag不是响应式数据)
        //因为Vue无法探测普通的新增 property,这样书写的属性并非响应式属性(数据变化视图跟这边)
        //第一个参数:对象  第二个参数:添加新的响应式属性  第三参数:新的属性的属性值
        this.$set(item, "flag", false);
      });
    },
      ...  
   //点击span的回调,变为编辑模式
    toEdit(row, index) {
      row.flag = true;
      //获取input节点,实现自动聚焦
      //需要注意:点击span的时候,切换为input变为编辑模式,但是需要注意,对于浏览器而言,页面重绘与重拍耗时间的
      //点击span的时候,重绘重排一个input它是需要耗费事件,因此我们不可能一点击span立马获取到input
      //$nextTick,当节点渲染完毕了,会执行一次
      this.$nextTick(() => {
        //获取相应的input表单元素实现聚焦
        this.$refs[index].focus();
      });
    },
//保存按钮:进行添加属性或者修改属性的操作
    async addOrUpdateAttr(){
      //整理参数:1,如果用户添加很多属性值,且属性值为空的不应该提交给服务器
      //提交给服务器数据当中不应该出现flag字段
      this.attrInfo.attrValueList = this.attrInfo.attrValueList.filter(item=>{
          //过滤掉属性值不是空的
          if(item.valueName!=''){
            //删除掉flag属性
            delete item.flag;
            return true;
          }
      })
      try {
         //发请求
        await this.$API.attr.reqAddOrUpdateAttr(this.attrInfo);
        //展示平台属性的信号量进行切换
        this.isShowTable = true;
        //提示消失
        this.$message({type:'success',message:'保存成功'});
        //保存成功以后需要再次获取平台属性进行展示
        this.getAttrList();
      } catch (error) {
        // this.$message('保存失败')
      }

    }

注意细节:

  1. 对象与数组嵌套时,考虑深拷贝。
  2. 添加响应式数据需要用到this.$set()
  3. 元素切换时,重绘重排需要时间,所以需要考虑节点渲染完毕。

删除表格数据

//删除品牌的操作
    deleteTradeMark(row) {
      //弹框
      this.$confirm(`你确定删除${row.tmName}?`, "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(async () => {
          //当用户点击确定按钮的时候会出发
          //向服务器发请求,此处没有使用vuex发起请求,注意是异步函数
          let result = await this.$API.trademark.reqDeleteTradeMark(row.id);
          //如果删除成功
          if (result.code == 200) {
            this.$message({
              type: "success",
              message: "删除成功!",
            });
            //再次获取品牌列表数据
            this.getPageList(this.list.length>1?this.page:this.page-1);
          }
        })
        .catch(() => {
          //当用户点击取消按钮的时候会触发
          this.$message({
            type: "info",
            message: "已取消删除",
          });
        });
    },

注意细节:this.getPageList(this.list.length>1?this.page:this.page-1);这是因为getPageList函数参数默认为page=1,考虑以下情况:

  • 删除了当前页面非最后一条数据,此时page为当前页面的page,请求数据后仍然显示当前页面的所有数据。
  • 删除了当前页面最后一条数据,此时page为当前页面的page-1,请求数据后显示上一页的数据,即回到上一页。

分页器

<!-- 
     分页器 
     当前第几页、数据总条数、每一页展示条数、连续页码数
     @size-change="handleSizeChange"
     @current-change="handleCurrentChange"

     current-page:代表的是当前第几页
     total:代表分页器一共需要展示数据条数
     page-size:代表的是每一页需要展示多少条数据
     page-sizes:代表可以设置每一页展示多少条数据
     layout:可以实现分页器布局设置分页组件的布局,包括上一页按钮、页码、下一页按钮、跳转输入框、每页显示数量选择框和总记录数的显示。 
     pager-count:按钮的数量  如果 9  连续页码是7
	
   -->
   <el-pagination
     style="margin-top: 20px; text-align: center"
     :current-page="page"
     :total="total"
     :page-size="limit"
     :pager-count="7"
     :page-sizes="[3, 5, 10]"
     @current-change="getPageList"
     @size-change="handleSizeChange"
     layout="prev, pager, next, jumper,->,sizes,total"
   >
   </el-pagination>
   
   ...
   //获取品牌列表的数据
    async getPageList(pager = 1) {
    //pager默认值为1,每次点击页码都会根据页码而变化
     this.page = pager;
     //解构出参数
     const { page, limit } = this;
     //获取品牌列表的接口
     //当你向服务器发请求的时候,这个函数需要带参数,因此在data当中初始化两个字段,代表给服务器传递参数
     let result = await this.$API.trademark.reqTradeMarkList(page, limit);
     if (result.code == 200) {
       //分别是展示数据总条数与列表展示的数据
       this.total = result.data.total;
       this.list = result.data.records;
     }
   },
   
   //当分页器某一页需要展示数据条数发生变化的时候会触发
   handleSizeChange(limit) {
     //整理参数
     this.limit = limit;
     this.getPageList();
   },

三级分类联动

注册全局组件:

src\components\CategorySelect\index.vue

<template>
  <div>
    <!-- inline:代表的是行内表单,代表一行可以放置多个表单元素 -->
    <el-form :inline="true" class="demo-form-inline" :model="cForm">
      <el-form-item label="一级分类">
        <el-select
          placeholder="请选择"
          v-model="cForm.category1Id"
          @change="handler1"
          :disabled="show"
        >
          <el-option
            :label="c1.name"
            :value="c1.id"
            v-for="(c1, index) in list1"
            :key="c1.id"
          ></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="二级分类">
        <el-select
          placeholder="请选择"
          v-model="cForm.category2Id"
          @change="handler2"
          :disabled="show"
        >
          <el-option
            :label="c2.name"
            :value="c2.id"
            v-for="(c2, index) in list2"
            :key="c2.id"
          ></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="三级分类">
        <el-select
          placeholder="请选择"
          v-model="cForm.category3Id"
          @change="handler3"
          :disabled="show"
        >
          <el-option
            :label="c3.name"
            :value="c3.id"
            v-for="(c3, index) in list3"
            :key="c3.id"
          ></el-option>
        </el-select>
      </el-form-item>
    </el-form>
  </div>
</template>
  1. 获取一级分类数据:不需要携带参数

    //获取一级分类数据的方法
        async getCategory1List() {
          //获取一级分类的请求:不需要携带参数
          let result = await this.$API.attr.reqCategory1List();
          if (result.code == 200) {
            this.list1 = result.data;
          }
        },     
  2. 获取一级分类数据后,再根据一级分类的id获取二级分类。

    注意在发起请求前要清空数据,否则二级分类和一级分类的对应关系会发生混乱。

    并触发一个自定义事件,传递参数为分类id以及分类的级别。同理三级分类的获取也是如此。

    //一级分类的select事件回调(当一级分类的option发生变化的时候获取相应二级分类的数据)
        async handler1() {
          //清除数据
          this.list2 = [];
          this.list3 = [];
          this.cForm.category2Id = "";
          this.cForm.category3Id = "";
          //解构出一级分类的id
          const { category1Id } = this.cForm;
          this.$emit("getCategoryId", { categoryId: category1Id, level: 1 });
          //通过一级分类的id,获取二级分类的数据
          let result = await this.$API.attr.reqCategory2List(category1Id);
          if (result.code == 200) {
            this.list2 = result.data;
          }
        },
          //二级分类的select事件回调(当二级分类的option发生变化的时候获取相应三级分类的数据)
        async handler2() {
          //清除数据
          this.list3 = [];
          this.cForm.category3Id = "";
          //结构出数据
          const { category2Id } = this.cForm;
          this.$emit("getCategoryId", { categoryId: category2Id, level: 2 });
          let result = await this.$API.attr.reqCategory3List(category2Id);
          if (result.code == 200) {
            this.list3 = result.data;
          }
        },
          //三级分类的事件回调
        handler3() {
          //获取三级分类的id
          const { category3Id } = this.cForm;
          this.$emit("getCategoryId", { categoryId: category3Id, level: 3 });
        },

src\views\product\Attr\index.vue

<el-card style="margin: 20px 0px">
     <CategorySelect @getCategoryId="getCategoryId" :show="!isShowTable"></CategorySelect>
   </el-card>
   ...
    //自定义事件的回调
   getCategoryId({ categoryId, level }) {
     //区分三级分类相应的id,以及父组件进行存储
     if (level == 1) {
       this.category1Id = categoryId;
       this.category2Id = "";
       this.category3Id = "";
     } else if (level == 2) {
       this.category2Id = categoryId;
       this.category3Id = "";
     } else {
       //代表三级分类的id有了
       this.category3Id = categoryId;
       //发请求获取平台的属性数据
       this.getAttrList();
     }
   },
//获取平台属性的数据
    //当用户确定三级分类的数据时候,可以向服务器发请求获取平台属性进行展示
    async getAttrList() {
      //获取分类的ID
      const { category1Id, category2Id, category3Id } = this;
      //获取属性列表的数据
      let result = await this.$API.attr.reqAttrList(
        category1Id,
        category2Id,
        category3Id
      );
      if (result.code == 200) {
        this.attrList = result.data;
      }
    },

表格展示

<div v-show="isShowTable">
       <el-button
         type="primary"
         icon="el-icon-plus"
         :disabled="!category3Id"
         @click="addAttr"
         >添加属性</el-button
       >
       <!-- 表格:展示平台属性 -->
       <el-table style="width: 100%" border :data="attrList">
         <el-table-column type="index" label="序号" width="80" align="center">
         </el-table-column>
         <el-table-column prop="attrName" label="属性名称" width="150">
         </el-table-column>
         <el-table-column prop="prop" label="属性值列表" width="width">
           <template slot-scope="{ row, $index }">
             <el-tag
               type="success"
               v-for="(attrValue, index) in row.attrValueList"
               :key="attrValue.id"
               style="margin: 0px 20px"
               >{{ attrValue.valueName }}</el-tag
             >
           </template>
         </el-table-column>
         <el-table-column prop="prop" label="操作" width="150">
           <template slot-scope="{ row, $index }">
             <el-button
               type="warning"
               icon="el-icon-edit"
               size="mini"
               @click="updateAttr(row)"
             ></el-button>
             <el-button
               type="danger"
               icon="el-icon-delete"
               size="mini"
             ></el-button>
           </template>
         </el-table-column>
       </el-table>
     </div>
  • isShowTable属性控制表格的显示与否,即在添加|修改属性时需要隐藏,此时三种级别的分类也进入不可修改的状态。
  • 每条属性可能有多条属性值,即在el-tag标签中再次循环。

上架下架状态切换

抽屉效果


文章作者: QT-7274
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 QT-7274 !
评论
  目录