谷粒商城实战笔记-71-商品服务-API-属性分组-前端组件抽取父子组件交互

news2024/9/20 19:26:57

文章目录

  • 一,一次性创建所有的菜单
  • 二,开发属性分组界面
    • 1,左侧三级分类树形组件
    • 2,右侧分组列表
    • 3,左右两部分通信
      • 3.1 子组件发送数据
      • 3.2,父组件接收数据
  • Vue的父子组件通信
    • 父组件向子组件传递数据
    • 子组件向父组件传递数据
  • category.vue组件完整代码
  • attrgroup.vue完整代码

一,一次性创建所有的菜单

创建菜单的工作非常简单,在页面上操作即可,是重复性的工作。为了避免重复的工作,使用脚本一次性创建所有的菜单。

在这里插入图片描述

二,开发属性分组界面

属性分组界面由左右两个部分构成,左侧是三级分类树,右侧是每个分类关联的分组列表,这种布局可以用Layout布局组件来实现。

  <el-row :gutter="20">
    <el-col :span="6">
      左侧三级分类树形布局
    </el-col>
    <el-col :span="18">
      右侧分组列表
    </el-col>
  </el-row>

1,左侧三级分类树形组件

将左侧三级分类的展示抽象为一个组件,名为category.vue,放在views/modules/common下。

在这里插入图片描述

2,右侧分组列表

这部分使用了el-formel-table组件。

3,左右两部分通信

现在的交互需求是左侧点击了某个分类,右侧要查询这个分类所属的所有分组,左右两边要联动。

难点是左侧是一个组件,定义在组件文件中。

这种情况下,就需要使用vue的父子组件通信机制。

子组件向父组件:通过触发自定义事件,并在父组件中监听这些事件来传递数据。

3.1 子组件发送数据

首先,在category.vue组件中注册结点点击事件。

在这里插入图片描述

在响应事件中使用$.emit向父组件发送数据。

在这里插入图片描述

this.$emit 方法被用来触发一个自定义事件,第一个参数是自定义事件的名称,这里是tree-node-click,父组件在使用子组件时,要通过给这个事件注册响应函数来获取子组件发送的数据。

理解这点非常重要。
理解这点非常重要。
理解这点非常重要。

3.2,父组件接收数据

父组件使用子组件时绑定一个接收数据的事件。

在这里插入图片描述

在这个事件响应函数中处理子组件传递的数据。

	treenodeclick(data, node, component) {
      if (node.level == 3) {
        this.catId = data.catId;
        this.getDataList(); //重新查询
      }
    },

Vue的父子组件通信

Vue.js 中的父子组件通信是构建复杂应用的基础之一。Vue 提供了多种方式来实现父子组件之间的数据传递。下面我将分别介绍父组件向子组件传递数据以及子组件向父组件传递数据的方法。

父组件向子组件传递数据

父组件向子组件传递数据最常用的方式是通过 props。这是 Vue 的单向数据流模型的一部分,确保了数据流动的方向明确且易于追踪。

  • 定义 Props:在子组件中定义接收父组件传递的数据的属性(props)。

    export default {
      props: ['message'],
    }
    
  • 传递 Props:在父组件中使用 <child-component> 标签,并通过属性绑定的方式传递数据。

    <template>
      <div>
        <child-component :message="parentMessage" />
      </div>
    </template>
    
    <script>
    import ChildComponent from './ChildComponent.vue';
    
    export default {
      components: {
        ChildComponent,
      },
      data() {
        return {
          parentMessage: 'Hello from parent',
        };
      },
    };
    </script>
    

子组件向父组件传递数据

子组件可以通过自定义事件的方式向父组件发送数据。这通常涉及到 v-on 或者 @ 指令以及 $emit 方法。

  • 触发事件:在子组件内部使用 $emit 方法触发自定义事件,并传递数据。

    methods: {
      sendMessageToParent() {
        this.$emit('send-message', 'Hello from child');
      },
    }
    
  • 监听事件:在父组件中监听子组件触发的事件,并处理传递过来的数据。

    <template>
      <div>
        <child-component @send-message="handleMessageFromChild" />
      </div>
    </template>
    
    <script>
    import ChildComponent from './ChildComponent.vue';
    
    export default {
      components: {
        ChildComponent,
      },
      methods: {
        handleMessageFromChild(message) {
          console.log('Received message:', message);
        },
      },
    };
    </script>
    
  • 父组件向子组件:通过 props 传递数据。

  • 子组件向父组件:通过触发自定义事件,并在父组件中监听这些事件来传递数据。

category.vue组件完整代码

<template>
  <div>
    <el-input placeholder="输入关键字进行过滤" v-model="filterText"></el-input>
    <el-tree
      :data="menus"
      :props="defaultProps"
      node-key="catId"
      ref="menuTree"
      @node-click="nodeclick"
      :filter-node-method="filterNode"
      :highlight-current = "true"
    ></el-tree>
  </div>
</template>

<script>
//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
//例如:import 《组件名称》 from '《组件路径》';

export default {
  //import引入的组件需要注入到对象中才能使用
  components: {},
  props: {},
  data() {
    //这里存放数据
    return {
      filterText: "",
      menus: [],
      expandedKey: [],
      defaultProps: {
        children: "children",
        label: "name"
      }
    };
  },
  //计算属性 类似于data概念
  computed: {},
  //监控data中的数据变化
  watch: {
    filterText(val) {
      this.$refs.menuTree.filter(val);
    }
  },
  //方法集合
  methods: {
    //树节点过滤
    filterNode(value, data) {
      if (!value) return true;
      return data.name.indexOf(value) !== -1;
    },
    getMenus() {
      this.$http({
        url: this.$http.adornUrl("/product/category/list/tree"),
        method: "get"
      }).then(({ data }) => {
        this.menus = data.data;
      });
    },
    nodeclick(data, node, component) {
      console.log("子组件category的节点被点击", data, node, component);
      //向父组件发送事件;
      this.$emit("tree-node-click", data, node, component);
    }
  },
  //生命周期 - 创建完成(可以访问当前this实例)
  created() {
    this.getMenus();
  },
  //生命周期 - 挂载完成(可以访问DOM元素)
  mounted() {},
  beforeCreate() {}, //生命周期 - 创建之前
  beforeMount() {}, //生命周期 - 挂载之前
  beforeUpdate() {}, //生命周期 - 更新之前
  updated() {}, //生命周期 - 更新之后
  beforeDestroy() {}, //生命周期 - 销毁之前
  destroyed() {}, //生命周期 - 销毁完成
  activated() {} //如果页面有keep-alive缓存功能,这个函数会触发
};
</script>
<style scoped>

</style>

attrgroup.vue完整代码

<template>
  <el-row :gutter="20">
    <el-col :span="6">
      <category @tree-node-click="treenodeclick"></category>
    </el-col>
    <el-col :span="18">
      <div class="mod-config">
        <el-form :inline="true" :model="dataForm" @keyup.enter.native="getDataList()">
          <el-form-item>
            <el-input v-model="dataForm.key" placeholder="参数名" clearable></el-input>
          </el-form-item>
          <el-form-item>
            <el-button @click="getDataList()">查询</el-button>
            <el-button type="success" @click="getAllDataList()">查询全部</el-button>
            <el-button
              v-if="isAuth('product:attrgroup:save')"
              type="primary"
              @click="addOrUpdateHandle()"
            >新增</el-button>
            <el-button
              v-if="isAuth('product:attrgroup:delete')"
              type="danger"
              @click="deleteHandle()"
              :disabled="dataListSelections.length <= 0"
            >批量删除</el-button>
          </el-form-item>
        </el-form>
        <el-table
          :data="dataList"
          border
          v-loading="dataListLoading"
          @selection-change="selectionChangeHandle"
          style="width: 100%;"
        >
          <el-table-column type="selection" header-align="center" align="center" width="50"></el-table-column>
          <el-table-column prop="attrGroupId" header-align="center" align="center" label="分组id"></el-table-column>
          <el-table-column prop="attrGroupName" header-align="center" align="center" label="组名"></el-table-column>
          <el-table-column prop="sort" header-align="center" align="center" label="排序"></el-table-column>
          <el-table-column prop="descript" header-align="center" align="center" label="描述"></el-table-column>
          <el-table-column prop="icon" header-align="center" align="center" label="组图标"></el-table-column>
          <el-table-column prop="catelogId" header-align="center" align="center" label="所属分类id"></el-table-column>
          <el-table-column
            fixed="right"
            header-align="center"
            align="center"
            width="150"
            label="操作"
          >
            <template slot-scope="scope">
              <el-button type="text" size="small" @click="relationHandle(scope.row.attrGroupId)">关联</el-button>
              <el-button
                type="text"
                size="small"
                @click="addOrUpdateHandle(scope.row.attrGroupId)"
              >修改</el-button>
              <el-button type="text" size="small" @click="deleteHandle(scope.row.attrGroupId)">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
        <el-pagination
          @size-change="sizeChangeHandle"
          @current-change="currentChangeHandle"
          :current-page="pageIndex"
          :page-sizes="[10, 20, 50, 100]"
          :page-size="pageSize"
          :total="totalPage"
          layout="total, sizes, prev, pager, next, jumper"
        ></el-pagination>
        <!-- 弹窗, 新增 / 修改 -->
        <add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="getDataList"></add-or-update>

        <!-- 修改关联关系 -->
        <relation-update v-if="relationVisible" ref="relationUpdate" @refreshData="getDataList"></relation-update>
      </div>
    </el-col>
  </el-row>
</template>

<script>
/**
 * 父子组件传递数据
 * 1)、子组件给父组件传递数据,事件机制;
 *    子组件给父组件发送一个事件,携带上数据。
 * // this.$emit("事件名",携带的数据...)
 */
//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
//例如:import 《组件名称》 from '《组件路径》';
import Category from "../common/category";
import AddOrUpdate from "./attrgroup-add-or-update";
import RelationUpdate from "./attr-group-relation";
export default {
  //import引入的组件需要注入到对象中才能使用
  components: { Category, AddOrUpdate, RelationUpdate },
  props: {},
  data() {
    return {
      catId: 0,
      dataForm: {
        key: ""
      },
      dataList: [],
      pageIndex: 1,
      pageSize: 10,
      totalPage: 0,
      dataListLoading: false,
      dataListSelections: [],
      addOrUpdateVisible: false,
      relationVisible: false
    };
  },
  activated() {
    this.getDataList();
  },
  methods: {
    //处理分组与属性的关联
    relationHandle(groupId) {
      this.relationVisible = true;
      this.$nextTick(() => {
        this.$refs.relationUpdate.init(groupId);
      });
    },
    //感知树节点被点击
    treenodeclick(data, node, component) {
      if (node.level == 3) {
        this.catId = data.catId;
        this.getDataList(); //重新查询
      }
    },
    getAllDataList(){
      this.catId = 0;
      this.getDataList();
    },
    // 获取数据列表
    getDataList() {
      this.dataListLoading = true;
      this.$http({
        url: this.$http.adornUrl(`/product/attrgroup/list/${this.catId}`),
        method: "get",
        params: this.$http.adornParams({
          page: this.pageIndex,
          limit: this.pageSize,
          key: this.dataForm.key
        })
      }).then(({ data }) => {
        if (data && data.code === 0) {
          this.dataList = data.page.list;
          this.totalPage = data.page.totalCount;
        } else {
          this.dataList = [];
          this.totalPage = 0;
        }
        this.dataListLoading = false;
      });
    },
    // 每页数
    sizeChangeHandle(val) {
      this.pageSize = val;
      this.pageIndex = 1;
      this.getDataList();
    },
    // 当前页
    currentChangeHandle(val) {
      this.pageIndex = val;
      this.getDataList();
    },
    // 多选
    selectionChangeHandle(val) {
      this.dataListSelections = val;
    },
    // 新增 / 修改
    addOrUpdateHandle(id) {
      this.addOrUpdateVisible = true;
      this.$nextTick(() => {
        this.$refs.addOrUpdate.init(id);
      });
    },
    // 删除
    deleteHandle(id) {
      var ids = id
        ? [id]
        : this.dataListSelections.map(item => {
            return item.attrGroupId;
          });
      this.$confirm(
        `确定对[id=${ids.join(",")}]进行[${id ? "删除" : "批量删除"}]操作?`,
        "提示",
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        }
      ).then(() => {
        this.$http({
          url: this.$http.adornUrl("/product/attrgroup/delete"),
          method: "post",
          data: this.$http.adornData(ids, false)
        }).then(({ data }) => {
          if (data && data.code === 0) {
            this.$message({
              message: "操作成功",
              type: "success",
              duration: 1500,
              onClose: () => {
                this.getDataList();
              }
            });
          } else {
            this.$message.error(data.msg);
          }
        });
      });
    }
  }
};
</script>
<style scoped>
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1952034.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot添加密码安全配置以及Jwt配置

Maven仓库&#xff08;依赖查找&#xff09; 1、SpringBoot安全访问配置 首先添加依赖 spring-boot-starter-security 然后之后每次启动项目之后&#xff0c;访问任何的请求都会要求输入密码才能请求。&#xff08;如下&#xff09; 在没有配置的情况下&#xff0c;默认用户…

LLM agentic模式之工具使用: Gorilla

Gorilla Gorilla出自2023年5月的论文《Gorilla: Large Language Model Connected with Massive APIs》&#xff0c;针对LLM无法准确地生成API调用时的参数&#xff0c;构建API使用数据集后基于Llama微调了一个模型。 数据集构建 API数据集APIBench的构建过程如下&#xff1…

《Programming from the Ground Up》阅读笔记:p75-p87

《Programming from the Ground Up》学习第4天&#xff0c;p75-p87总结&#xff0c;总计13页。 一、技术总结 1.persistent data p75, Data which is stored in files is called persistent data, because it persists in files that remain on disk even when the program …

C语言程序设计15

程序设计15 问题15_1代码15_1结果15_1 问题15_2代码15_2结果15_2 问题15_3代码15_3结果15_3 问题15_1 在 m a i n main main 函数中将多次调用 f u n fun fun 函数&#xff0c;每调用一次&#xff0c;输出链表尾部结点中的数据&#xff0c;并释放该结点&#xff0c;使链表缩短…

【SQL 新手教程 3/20】关系模型 -- 外键

&#x1f497; 关系数据库建立在关系模型上⭐ 关系模型本质上就是若干个存储数据的二维表 记录 (Record)&#xff1a; 表的每一行称为记录&#xff08;Record&#xff09;&#xff0c;记录是一个逻辑意义上的数据 字段 (Column)&#xff1a;表的每一列称为字段&#xff08;Colu…

Buildroot 构建 Linux 系统

Buildroot 是一个工具&#xff0c;以简化和自动化为嵌入式系统构建完整 Linux 系统的过程。使用交叉编译技术&#xff0c;Buildroot 能够生成交叉编译工具链、根文件系统、Linux 内核映像和针对目标设备的引导加载程序。可以独立地使用这些选项的任何组合&#xff0c;例如&…

Vitis AI 使用 VAI_Q_PYTORCH 工具

目录 1. 简介 2. 资料汇总 3. 示例解释 3.1 快速上手示例 4. 总结 1. 简介 vai_q_pytorch 是 Vitis AI Quantizer for Pytorch 的缩写&#xff0c;主要作用是优化神经网络模型。它是 Vitis AI 平台的一部分&#xff0c;专注于神经网络的深度压缩。 vai_q_pytorch 的作用…

大数据管理中心设计规划方案(可编辑的43页PPT)

引言&#xff1a;随着企业业务的快速发展&#xff0c;数据量急剧增长&#xff0c;传统数据管理方式已无法满足高效处理和分析大数据的需求。建立一个集数据存储、处理、分析、可视化于一体的大数据管理中心&#xff0c;提升数据处理能力&#xff0c;加速业务决策过程&#xff0…

Spring Boot:图书管理系统(一)

1.编写用户登录接口 代码&#xff1a; package com.example.demo;import jakarta.servlet.http.HttpSession; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotatio…

HarmonyOS和OpenHarmony区别联系

前言 相信我们在刚开始接触鸿蒙开发的时候经常看到HarmonyOS和OpenHarmony频繁的出现在文章和文档之中&#xff0c;那么这两个名词分别是什么意思&#xff0c;他们之间又有什么联系呢&#xff1f;本文将通过现有的文章和网站内容并与Google的AOSP和Android做对比&#xff0c;带…

Vue.js 2 项目实战(五):水果购物车

前言 Vue.js 是一个用于构建用户界面的渐进式 JavaScript 框架。它的设计目标是通过采用易于上手的结构和强大的功能&#xff0c;使前端开发变得更加简便和高效。以下是 Vue.js 的一些关键特性和优点&#xff1a; 核心特性 声明式渲染 Vue.js 使用声明式语法来描述用户界面&a…

AI周报(7.21-7.27)

AI应用-一款能提供情绪价值的智能鸟类喂食器&#xff08;Bird Buddy&#xff09; 图像识别技术&#xff1a;Bird Buddy装备了图像识别技术&#xff0c;能够识别超过1000种鸟类&#xff0c;涵盖了常见的鸟类品种。这种技术能够在鸟类经过时&#xff0c;通过内置麦克风捕捉的声音…

PID 控制实验 - 整定实验

Arduino PID Arduino-PID-LibraryArduino-PID-AutoTune-Library PID控制实验 – 制作测试台 PID Control Experiment – Making the Testing Rig PID (Proportional, Integral, Derivative) control is a classic control algorithm that I have used for a few projects,…

Debug-018-elementUI-el-tree中通过CSS隐藏任意一项的选择框checkbox

前情提要&#xff1a; 我们项目中使用的是elementUI&#xff0c;业务中经常需要使用到el-tree组件去实现一些有层级关系的功能。现在有一个需求描述一下&#xff1a;首先是这个el-tree是个有checkbox的树&#xff0c;每一子节点都可以被选择&#xff0c;用于去实现一些系统的权…

Shell编程之正则表达式与文本三剑客

目录 一、正则表达式 1.引言--什么是正则表达式 1.1正则表达式的功能 2.基础正则表达式&#xff08;BRE&#xff09; 2.1特殊字符 2.2定位符 2.3非打印字符 3.扩展正则表达式(ERE) 4.元字符操作的案列 二、命令小工具 1.cut&#xff1a;列截取工具 2.sort排序 …

vue3获取、设置元素高度

前言 在web端常见的需求场景中&#xff0c;会经常遇到table表格需要根据页面可视区域使高度自适应的情况。 傻喵(作者本人)昨天在尝试使用vue3实现这个需求时&#xff0c;看了几篇网上写的回答&#xff0c;都不太全面&#xff0c;所以干脆自己写个总结吧.(第一次写&#xff0c…

深入探讨 I/O 多路复用:提升系统 I/O 效率的关键技术

摘要 I/O&#xff08;输入/输出&#xff09;操作是计算机系统中不可或缺的一部分&#xff0c;而 I/O 多路复用技术则是提高系统 I/O 效率的重要手段。本文将浅谈 I/O 的基本概念&#xff0c;重点探讨 I/O 多路复用技术的原理、优势以及在现代系统中的应用。 引言 在现代计算…

php收银系统源码-收银员操作权限

收银系统是很多门店&#xff0c;尤其是连锁门店营业的必备工具&#xff0c;收银员每天需要通过收银系统记录商品的售卖数量&#xff0c;以及收款&#xff0c;会员开卡&#xff0c;核销订单等工作。但很多门店都不希望给收银员太高的权限&#xff0c;自然就离不开收银员的权限管…

flask开启调试模式,热部署

这里写自定义目录标题 功能快捷键 什么是热部署&#xff1f;简单说就是你程序改了&#xff0c;现在要重新启动服务器&#xff0c;嫌麻烦&#xff1f;不用重启&#xff0c;服务器会自己悄悄的把更新后的程序给重新加载一遍&#xff0c;这就是热部署&#xff08;抄的&#xff09;…

NameSilo域名注册和解析2024版教程(附优惠码)

上次给大家介绍了国外知名的域名注册商Dynadot&#xff0c;今天再给大家分享另一家国外知名的域名注册商NameSilo&#xff0c;同样性价比很高。使用本站提供的优惠码&#xff1a;ieearn.com&#xff0c;你还可以在首次注册购买域名时享受1美元的优惠&#xff1a; NameSilo简介…