019、子组件向父组件传递参数 this.$emit

文章目录

1、this.$emit

this.$emit 是 Vue.js 中一个非常重要的方法,它允许子组件向父组件发送自定义事件,并传递数据。

基本用法:

  • 子组件

    this.$emit('eventName', data);

  • 父组件
    注意 eventName 和 子组件声明的一致,父组件函数名的定义有一个入参,但是只需写一个函数名

    <TagsMenu @eventName="父组件函数名" />

    <script> import TagsMenu from './TagsMenu.vue'; export default { components: { TagsMenu }, methods: { 父组件函数名(data) { alert(data); },

eventName: 你要发送的自定义事件的名称。

data: 你要传递给父组件的数据,可以是任何类型,例如字符串、数字、对象、数组等。

2、简单举例

2.1、子组件

<ul>
      <li v-for="item,index in tmenu"
      :key="index"
      v-show="isShowLi(index)"
      @click="hdClick(index)"
      >
      </li>
    </ul>
  </div>
</template>

<script>
  export default {
    methods: {
      hdClick(index){
        this.$emit("fn",index)
      }

2.2、父组件

父组件需要使用一个函数接受子组件传递来的参数

  <TagsMenu  @fn="clickMenu" />
  </div>
</template>

<script>
  import TagsMenu from './TagsMenu.vue';
  export default {
    components: {
      TagsMenu
    },
    data() {
      return {
        tags: [{
          title: "layout",
          path: "/layout",
          isActive: true,
        }],
        isShowTagsMenu: false,
        clientX: 0,
        clientY: 0,
        clickIndex: 0,
      }
    },
    mounted() {
      document.addEventListener("click", this.closeMenu)
    },
    beforeDestroy() {
      document.removeEventListener("click", this.closeMenu)
    },
    methods: {
      clickMenu(i) {
        if (i == 5) {
          //关闭全部
          this.tags = [{
            "title": "layout",
            "path": "/layout"
          }]
          this.goTo("/layout")
        }
      },

3、完整例子

3.1、子组件

这里,调用子组件 hdClick 方法时,将 index 函数传递给父组件,自定义变量为 fn

<template>
  <div class="tags-menu" :style="{left:clientX+'px',top:clientY+'px'}">
    <ul>
      <li v-for="item,index in tmenu"
      :key="index"
      v-show="isShowLi(index)"
      @click="hdClick(index)"
      >
        <i :class="item.icon"></i>
        {{item.text}}
      </li>
      <li>{{clientX+","+clickIndex}}</li>
    </ul>
  </div>
</template>

<script>
  export default {
    props: ["clientX", "clientY", "clickIndex","tagsLength"],
    methods: {
      hdClick(index){
        this.$emit("fn",index)
      }
      ,
      isShowLi(i) {
        if(this.tagsLength===1){
          //只有首页
          return i===0;
        }
        if (this.clickIndex == 0) {
          return ![1, 3].includes(i)
        }
        if(this.clickIndex == 1 && this.clickIndex==this.tagsLength-1){
          return ![3,4].includes(i)
        }else if(this.clickIndex == 1 && this.clickIndex!=this.tagsLength-1){
          return ![3].includes(i)
        }else if(this.clickIndex==this.tagsLength-1){
          return ![4].includes(i)
        }
        return true;
      }
    },
    data() {
      return {
        tmenu: [{
            icon: "el-icon-refresh-right",
            text: "刷新页面"
          },
          {
            icon: "el-icon-close",
            text: "关闭当前"
          },
          {
            icon: "el-icon-circle-close",
            text: "关闭其他"
          },
          {
            icon: "el-icon-back",
            text: "关闭左侧"
          },
          {
            icon: "el-icon-right",
            text: "关闭右侧"
          },
          {
            icon: "el-icon-circle-close",
            text: "关闭全部"
          }
        ]
      }
    }
  }
</script>

<style>
  .tags-menu {
    position: absolute;
    z-index: 1000;
    /* 确保菜单在最上层 */
    background-color: white;
    /* 设置背景颜色为白色 */
    border: 1px solid #ddd;
    /* 添加边框 */
    border-radius: 4px;
    /* 圆角效果 */
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
    /* 添加阴影 */
    padding: 10px;
    /* 内边距 */
    min-width: 120px;
    /* 最小宽度 */
    /* 可选:添加过渡效果 */
    transition: opacity 0.2s ease;
  }

  .tags-menu ul {
    list-style: none;
    /* 去掉列表样式 */
    margin: 0;
    /* 去掉外边距 */
    padding: 0;
    /* 去掉内边距 */
  }

  .tags-menu li {
    padding: 8px 12px;
    /* 单个菜单项的内边距 */
    cursor: pointer;
    /* 鼠标悬停变成手指 */
    transition: background-color 0.2s;
    /* 添加过渡效果 */
  }

  .tags-menu li:hover {
    background-color: #f5f5f5;
    /* 悬停时的背景颜色 */
  }
</style>

3.2、父组件

这里父组件通过 @fn="clickMenu" 获得子组件的上传的参数,然后交给 clickMenu(i) 函数处理

<template>
  <div class="tags">
    <!-- .native 用法:在 Vue.js 中,.native 修饰符用于监听原生 DOM 事件,而不是 Vue 组件的自定义事件。
    例如,@contextmenu.native="rightClick($event)"
    .prevent 阻止浏览器默认行为
    表示你希望监听原生的 contextmenu 事件(通常是右键点击),
    而不是 Vue 组件中可能定义的 contextmenu 事件。这在你想要直接处理 DOM 事件时非常有用,
    尤其是当组件内部没有提供相应的事件时。 -->
    <el-tag size="medium" :closable="index>0" v-for="item,index in tags" :key="item.path"
      :effect="item.title==$route.name?'dark':'plain'" @click="goTo(item.path)" @close="close(index)"
      :disable-transitions="true" @contextmenu.native.prevent="rightClick($event,index)">
      <i class="cir" v-show="item.title==$route.name"></i>
      {{item.title}}</el-tag>

    <TagsMenu v-show="isShowTagsMenu" :clientX="clientX" :clientY="clientY" :clickIndex="clickIndex"
      :tagsLength="tags.length" @fn="clickMenu" />
  </div>
</template>

<script>
  import TagsMenu from './TagsMenu.vue';
  export default {
    components: {
      TagsMenu
    },
    data() {
      return {
        tags: [{
          title: "layout",
          path: "/layout",
          isActive: true,
        }],
        isShowTagsMenu: false,
        clientX: 0,
        clientY: 0,
        clickIndex: 0,
      }
    },
    mounted() {
      document.addEventListener("click", this.closeMenu)
    },
    beforeDestroy() {
      document.removeEventListener("click", this.closeMenu)
    },
    methods: {
      clickMenu(i) {
        if (i == 5) {
          //关闭全部
          this.tags = [{
            "title": "layout",
            "path": "/layout"
          }]
          this.goTo("/layout")
        }
      },
      closeMenu() {
        this.isShowTagsMenu = false
      },
      rightClick(e, i) {
        console.log("右键点击了", e.clientX, e.clientY, i);
        this.clientX = e.clientX;
        this.clientY = e.clientY;
        this.isShowTagsMenu = true;
        this.clickIndex = i;
        //关闭浏览器的默认行为
        window.event.returnValue = false;
        return false;
      },
      goTo(path) {
        this.$router.replace({
          path: (path == '/' || path == undefined ? '/Index' : path)
        });
      },
      close(index) {
        const name = this.tags[index].title;
        this.tags.splice(index, 1);
        if (this.tags.length == 0) return;
        //如果关闭当前页,则激活最后一个标签页
        const path = this.tags[this.tags.length - 1].path;
        if (name === this.$route.name && this.tags.length != 0) {
          this.$router.replace({
            path: (path == '/' || path == undefined ? '/Index' : path)
          });
        }

      }
    },
    watch: {
      $route: {
        immediate: true,
        handler(val, oldVal) {
          console.log(val);
          const bool = this.tags.find(item => {
            return item.path == val.path;
          });

          if (!bool) {
            this.tags.push({
              title: val.name,
              path: val.path
            });
          }

        }
      }
    }

  }
</script>

<style scoped>
  .tags {
    margin-top: 3px;
    /* 添加距离上边缘的距离 */
  }

  .tags .el-tag {
    padding-left: 10px;
    padding-top: 0px;
    margin-right: 5px;

    .cir {
      width: 8px;
      height: 8px;
      margin-right: 4px;
      background-color: #fff;
      border-radius: 50%;
      display: inline-block;
    }
  }
</style>
相关推荐
落魄实习生12 小时前
AI应用-本地模型实现AI生成PPT(简易版)
python·ai·vue·ppt
bpmf_fff14 小时前
二九(vue2-05)、父子通信v-model、sync、ref、¥nextTick、自定义指令、具名插槽、作用域插槽、综合案例 - 商品列表
vue
java_heartLake20 小时前
Vue3之状态管理Vuex
vue·vuex·前端状态管理
小马超会养兔子21 小时前
如何写一个数字老虎机滚轮
开发语言·前端·javascript·vue
小阳生煎1 天前
多个Echart遍历生成 / 词图云
vue
小马超会养兔子2 天前
如何写一个转盘
开发语言·前端·vue
bpmf_fff2 天前
二八(vue2-04)、scoped、data函数、父子通信、props校验、非父子通信(EventBus、provide&inject)、v-model进阶
vue
好开心333 天前
04、Vue与Ajax
前端·ajax·前端框架·vue·js
工业互联网专业3 天前
Python毕业设计选题:基于Python的社区爱心养老管理系统设计与实现_django
python·django·vue·毕业设计·源码·课程设计
平行线也会相交3 天前
云图库平台(一)后端项目初始化
spring boot·vue·云图库平台