018、钩子函数 mounted和beforeDestroy、父组件向子组件传递参数 props 的使用

1、mounted 和 beforeDestroy

1.1、mounted

mounted() 钩子函数在组件被挂载到 DOM 后调用。代码 document.addEventListener(“click”, this.closeMenu) 在组件挂载后,为整个文档添加了一个点击事件监听器,当用户在文档任何地方点击时,都会触发 this.closeMenu 方法。

<script>
  export default {
 mounted() {
      //动作
    },

1.2、beforeDestroy

beforeDestroy() 钩子函数在组件被销毁之前调用。代码 document.removeEventListener(“click”, this.closeMenu) 在组件销毁之前,移除之前添加的点击事件监听器,避免组件销毁后仍然存在监听器,导致潜在的错误或内存泄漏。

 <script>
  export default {
 beforeDestroy() {
       //动作
    },

2、父组件向子组件传递参数 props

2.1、子组件定义

<script>
  export default {
    props: ["clientX", "clientY", "clickIndex","tagsLength"],
    //其余内容略
    }

2.2、父组件调用子组件并传参

<template>
//其余略
<TagsMenu v-show="isShowTagsMenu" :clientX="clientX" :clientY="clientY" :clickIndex="clickIndex"
      :tagsLength="tags.length" />
      //其余略
</template>
<script>
  import TagsMenu from './TagsMenu.vue';
  //其余略

3、完整例子

3.1、父组件 Tags.vue

<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" />
  </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: {
      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>

3.2、子组件 TagsMenu.vue

<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)">
        <i :class="item.icon"></i>
        {{item.text}}
      </li>
      <li>{{clientX+","+clickIndex}}</li>
    </ul>
  </div>
</template>

<script>
  export default {
    props: ["clientX", "clientY", "clickIndex","tagsLength"],
    methods: {
      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.3、效果图

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值