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>
相关推荐
Backstroke fish3 小时前
Token刷新机制
前端·javascript·vue.js·typescript·vue
小曲程序3 小时前
vue3 封装request请求
java·前端·typescript·vue
Lysun0014 小时前
[less] Operation on an invalid type
前端·vue·less·sass·scss
程序视点11 小时前
【Vue3新工具】Pinia.js:提升开发效率,更轻量、更高效的状态管理方案!
前端·javascript·vue.js·typescript·vue·ecmascript
刚刚好ā12 小时前
js作用域超全介绍--全局作用域、局部作用、块级作用域
前端·javascript·vue.js·vue
ZwaterZ15 小时前
vue el-table表格点击某行触发事件&&操作栏点击和row-click冲突问题
前端·vue.js·elementui·c#·vue
ZwaterZ18 小时前
el-table-column自动生成序号&&在序号前插入图标
前端·javascript·c#·vue
木子七20 小时前
vue2-vuex
前端·vue
小小黑00721 小时前
uniapp+vue3+ts H5端使用Quill富文本插件以及解决上传图片反显的问题
uni-app·vue
Ztiddler1 天前
【npm设置代理-解决npm网络连接error network失败问题】
前端·后端·npm·node.js·vue