• 后台管理系统: 商品管理


     商品管理之三级联动静态组件

    先做俩个卡片组件,分开距离 

    三级联动很多地方都用到了它,我们可以封装成一个组件

    注册为一个全局组件

     

    1. <div>
    2. <el-form :inline="true" class="demo-form-inline">
    3. <el-form-item label="一级分类">
    4. <el-select placeholder="请选择" value="">
    5. <el-option label="区域一" value="shanghai"></el-option>
    6. <el-option label="区域二" value="beijing"></el-option>
    7. </el-select>
    8. </el-form-item>
    9. <el-form-item label="二级分类">
    10. <el-select placeholder="请选择" value="">
    11. <el-option label="区域一" value="shanghai"></el-option>
    12. <el-option label="区域二" value="beijing"></el-option>
    13. </el-select>
    14. </el-form-item>
    15. <el-form-item label="三级分类">
    16. <el-select placeholder="请选择" value="">
    17. <el-option label="区域一" value="shanghai"></el-option>
    18. <el-option label="区域二" value="beijing"></el-option>
    19. </el-select>
    20. </el-form-item>
    21. </el-form>
    22. </div>

    商品管理之三级联动动态组件

    书写相对于的api

      拿到数据,然后渲染到页面上

     一级分类完成

    我们需要在一级联动数据发生改变的时候,把id传给二级联动。这里有一个注意点,就是这个是在组件中,@change这个其实就是自定义事件 

    绑定事件,但是报错了

     接口测试没有问题,后面查询出来是接口的请求写错了

     

    三级联动完成

    一级分类数据发送变化的时候,二级,三级分类数据要变化。首先要清除原有的值,同时我们需要在子组件中给父组件传递参数

    1. <template>
    2. <div>
    3. <!-- inline:代表的是行内表单,代表一行可以放置多个表单元素 -->
    4. <el-form :inline="true" class="demo-form-inline" :model="cForm">
    5. <el-form-item label="一级分类">
    6. <el-select
    7. placeholder="请选择"
    8. v-model="cForm.category1Id"
    9. @change="handler1"
    10. :disabled="show"
    11. >
    12. <el-option
    13. :label="c1.name"
    14. :value="c1.id"
    15. v-for="(c1, index) in list1"
    16. :key="c1.id"
    17. ></el-option>
    18. </el-select>
    19. </el-form-item>
    20. <el-form-item label="二级分类">
    21. <el-select
    22. placeholder="请选择"
    23. v-model="cForm.category2Id"
    24. @change="handler2"
    25. :disabled="show"
    26. >
    27. <el-option
    28. :label="c2.name"
    29. :value="c2.id"
    30. v-for="(c2, index) in list2"
    31. :key="c2.id"
    32. ></el-option>
    33. </el-select>
    34. </el-form-item>
    35. <el-form-item label="三级分类">
    36. <el-select
    37. placeholder="请选择"
    38. v-model="cForm.category3Id"
    39. @change="handler3"
    40. :disabled="show"
    41. >
    42. <el-option
    43. :label="c3.name"
    44. :value="c3.id"
    45. v-for="(c3, index) in list3"
    46. :key="c3.id"
    47. ></el-option>
    48. </el-select>
    49. </el-form-item>
    50. </el-form>
    51. </div>
    52. </template>
    53. <script>
    54. export default {
    55. name: "CategorySelect",
    56. props: ["show"],
    57. data() {
    58. return {
    59. //一级分类的数据
    60. list1: [],
    61. //二级分类的数据
    62. list2: [],
    63. //三级分类的数据
    64. list3: [],
    65. //收集相应的一级二级三级分类的id
    66. cForm: {
    67. category1Id: "",
    68. category2Id: "",
    69. category3Id: "",
    70. },
    71. };
    72. },
    73. //组件挂载完毕:向服务器发请求,获取相应的一级分类的数据
    74. mounted() {
    75. //获取一级分类的数据的方法
    76. this.getCategory1List();
    77. },
    78. methods: {
    79. //获取一级分类数据的方法
    80. async getCategory1List() {
    81. //获取一级分类的请求:不需要携带参数
    82. let result = await this.$Api.attr.reqCategory1List();
    83. if (result.code == 200) {
    84. this.list1 = result.data;
    85. }
    86. },
    87. //一级分类的select事件回调(当一级分类的option发生变化的时候获取相应二级分类的数据)
    88. async handler1() {
    89. //清除数据
    90. this.list2 = [];
    91. this.list3 = [];
    92. this.cForm.category2Id = "";
    93. this.cForm.category3Id = "";
    94. //解构出一级分类的id
    95. const { category1Id } = this.cForm;
    96. this.$emit("getCategoryId", { categoryId: category1Id, level: 1 });
    97. //通过一级分类的id,获取二级分类的数据
    98. let result = await this.$Api.attr.reqCategory2List(category1Id);
    99. if (result.code == 200) {
    100. this.list2 = result.data;
    101. }
    102. },
    103. //二级分类的select事件回调(当二级分类的option发生变化的时候获取相应三级分类的数据)
    104. async handler2() {
    105. //清除数据
    106. this.list3 = [];
    107. this.cForm.category3Id = "";
    108. //结构出数据
    109. const { category2Id } = this.cForm;
    110. this.$emit("getCategoryId", { categoryId: category2Id, level: 2 });
    111. let result = await this.$Api.attr.reqCategory3List(category2Id);
    112. if (result.code == 200) {
    113. this.list3 = result.data;
    114. }
    115. },
    116. //三级分类的事件回调
    117. handler3() {
    118. //获取三级分类的id
    119. const { category3Id } = this.cForm;
    120. this.$emit("getCategoryId", { categoryId: category3Id, level: 3 });
    121. },
    122. },
    123. };
    124. </script>
    125. <style scoped>
    126. </style>

     父组件来接收数据

    平台属性管理动态展示属性

    就是三级联动数据确定那一刻,获取平台属性的内容

    先写接口 

    拿到数据 

    动态渲染 

    平台属性之添加属性与修改属性静态完成

    通过一个v-show来控制这个显示和隐藏

    这里有一个细节,那就是没有选一二三级。这个按钮就不能使用。这里我们用 :disabled="!category3Id" 如果有category3Id就是相当于可以使用

    我们还需要写添加属性修改属性的结构

    1. <div v-show="!isShowTable">
    2. <el-form :inline="true" ref="form" label-width="80px" >
    3. <el-form-item label="属性名">
    4. <el-input placeholder="请输入属性名"></el-input>
    5. </el-form-item>
    6. </el-form>
    7. <el-button type="primary" icon="el-icon-plus">添加属性值</el-button>
    8. <el-button @click="isShowTable = true">取消</el-button>
    9. <el-table style="width: 100%; margin: 20px 0px" border >
    10. <el-table-column align="center" type="index" label="序号" width="80"> </el-table-column>
    11. <el-table-column width="width" prop="prop" label="属性值名称">
    12. </el-table-column>
    13. <el-table-column width="width" prop="prop" label="操作">
    14. </el-table-column>
    15. </el-table>
    16. <el-button type="primary">保存</el-button>
    17. <el-button @click="isShowTable = true">取消</el-button>
    18. </div>
    19. </el-card>
    20. </div>

    收集属性名和属性值操作

    这里要说一下什么是属性和属性值

    这块写属性名称     属性列表

    属性:颜色

    属性值:粉色,红色等等

    调用这个接口

     携带参数有讲究的

    1. "attrName": "string",
    2. "attrValueList": [
    3. {
    4. "attrId": 0,
    5. "id": 0,
    6. "valueName": "string"
    7. }
    8. ],
    9. "categoryId": 0,
    10. "categoryLevel": 0,
    11. "id": 0

     注意:别在data当中收集三级分类的id

    因为对象存储数据是无序存储

    就是你不能确定对象中的属性谁先谁后,因此这个this.category3Id就是undefined

     通过这种方式就能获取到表单的属性 

    现在我们获取到了属性名,但是没有获取到属性值

    1. async getAttrList() {
    2. //获取分类的ID
    3. const { category1Id, category2Id, category3Id } = this;
    4. //获取属性列表的数据
    5. let result = await this.$Api.attr.reqAttrList(
    6. category1Id,
    7. category2Id,
    8. category3Id
    9. );
    10. if (result.code == 200) {
    11. this.attrList = result.data;
    12. }
    13. },
    14. addAttrValue() {
    15. //向属性值的数组里面添加元素
    16. //attrId:是你相应的属性的id,目前而言我们是添加属性的操作,还没有相应的属性的id,目前而言带给服务器的id为undefined
    17. //valueName:相应的属性值的名称
    18. this.attrInfo.attrValueList.push({
    19. attrId: this.attrInfo.id, //对于修改某一个属性的时候,可以在已有的属性值基础之上新增新的属性值(新增属性值的时候,需要把已有的属性的id带上)
    20. valueName: "",
    21. flag: true,
    22. });}

    解决返回按钮数据回显问题

    就是在每次按钮点击之前,把之前的数据清空。

    同时我们这里可以点击添加属性按钮,收集到3id

    1. addAttr() {
    2. //切换table显示与隐藏
    3. this.isShowTable = false;
    4. //清除数据
    5. //收集三级分类的id
    6. this.attrInfo = {
    7. attrName: "", //属性名
    8. attrValueList: [
    9. //属性值,因为属性值可以有多个因此用数组,每一个属性值都是一个对象需要attrId,valueName
    10. ],
    11. categoryId: this.category3Id, //三级分类的id
    12. categoryLevel: 3, //因为服务器也需要区分几级id
    13. };
    14. },

    修改属性操作

    这个row就是这一行的属性值

     这里有一个bug,就是我们点击取消按钮的时候他也会变化。这里我们不能使用浅拷贝,由于数据结构当中存在对象里面套数组,数组里面有套对象,因此需要使用深拷贝解决这类问题

    这里可以使用插件loadsh进行深拷贝,这就不能实现值不会随的v-model的修改,而修改了

    查看模式与修改模式切换

    当我们点击添加属性值按钮的时候就应该把属性的id传进去

    对于修改某一个属性的时候,可以在已有的属性值基础之上新增新的属性值(新增属性值的时候,需要把已有的属性的id带上)

    input跟span来回进行切换

    参看模式:显示span

    编辑模式:显示input

    注意:通过flag标记进行切换参看模式与编辑模式,但是需要注意的时候,一个属性flag是没有办法控制全部属性的切换

    解决方案就是在每个元素添加的时候给他添加一个属性flag

    flag属性:给每一个属性值添加一个标记flag,用户切换查看模式与编辑模式,好处,每一个属性值可以控制自己的模式切换

    当前flag属性,响应式数据(数据变化视图跟着变化) 

    然后通过v-if来控制 当失去焦点和回车的时候,我们需要进行模式的切换 

    查看模式与编辑模式注意事项

    1.如果属性值为空不能作为新的属性值,需要给用户提示,让他输入一个其他的属性值

    2.新增的属性值不能与已有的属性值重复

    row最新新增的属性值【数组的最后一项元素】 而item是指得这个数组的每一项

    修改查看模式和编辑模式的切换

    就是我们切换到编辑模式上,发现flag是没有的,因为它是后面添加上的,并不是响应式数据

    可以通过这种方式,但是视图并不会跟着变化(对象中后追加的属性,Vue默认不做响应式处理) 

    这里我们需要使用$set

    第一个参数:对象  第二个参数:添加新的响应式属性  第三参数:新的属性的属性值

    表单元素自动对焦实现

    点击span的时候,获取到input的节点,然后自动对焦

    这里我们给span绑定一个事件 同时给input 用ref获取到它的节点,但是这个input并不是一个而是多个。因此我们可以用索引值当做它的标记 用于区分它是第几个信息

    获取input节点,实现自动聚焦

            需要注意:点击span的时候,切换为input变为编辑模式,但是需要注意,对于浏览器而言,页面重绘与重拍耗时间的

           点击span的时候,重绘重拍一个input它是需要耗费事件,因此我们不可能一点击span立马获取到input

           $nextTick,当节点渲染完毕了,会执行一次

    除了切换span要获取聚焦外,点击添加属性值按钮也应该让获取到数组的最后一项聚焦

    删除属性值的操作

    这里我们需要用到这个组件

     复制到代码中,结构大概是这样的

    这里使用模板字符串的方式,告诉用户删除的是那个 confirm是气泡确定框确定事件

    但是我们会发现调用这个办法是没有效果的,因为我们这个项目的版本是老版本很旧

     所以用@onConfirm

    保存操作

    用这个接口

     这里提交给服务器的参数,有俩个讲究

    整理参数:1,如果用户添加很多属性值,且属性值为空的不应该提交给服务器

    2.提交给服务器数据当中不应该出现flag字段

    用filter这个方法实现那flag这个属性过滤掉 

    按钮与三级联动的可操作性 

    isShowTable给子传过去 

    子接收show属性 

    然后通过这个属性来控制 

  • 相关阅读:
    Python 实现Ridge Regression教程
    算法趣题-Q34
    SpringBoot结合SpringCache操作Redis实现数据缓存
    ant design vue树形表格默认展开所有行,并且去掉 + 号
    Linux | 进程间通信
    CSP-J初赛复习大题整理笔记
    转换张量形状:`nlc_to_nchw` 函数详解
    五大亮点探索互联网医院源码的创新应用方式
    k8s pod 无法启动一直ContainerCreating
    UGUI交互组件Toggle
  • 原文地址:https://blog.csdn.net/weixin_64612659/article/details/133417953