Implementation of Vue top tags browsing history

Implementation of Vue top tags browsing history

nonsense

Demo preview

Functions implemented

There is a home page by default, which cannot be closed

Click the route menu to check if it exists. If not, add it. If it does, locate it above.

Click to jump, click X to close

Close the current page and automatically jump to the next tag page

If the current page is the last one, jump to the previous tag page by default

Right-click menu, refresh, close right, close all

When the tags are too long to fit, buttons on the left and right sides will appear and disappear automatically when the tags are reduced.

Dynamically determine whether the window is enlarged or reduced, and automatically determine whether there are buttons on the left and right sides

text

No need for any vuex, messy methods, all in one file, just paste and use

Just put it where you want (this demo is placed on the breadcrumbs)

Install first (a package that monitors the size of a DOM element)

npm install element-resize-detector

tags.vue

<template>
  <div>
    <div class="tags">
      <!-- Left Arrow -->
      <div
        class="arrow arrow_left"
        v-show="arrowVisible"
        @click="handleClickToLeft"
      >
        <i class="el-icon-arrow-left"></i>
      </div>
      <!-- Tag content -->
      <div class="tags_content" ref="box">
        <span ref="tags">
          <el-tag
            v-for="(tag, index) in tags"
            :key="tag.name"
            :class="[active == index ? 'active top_tags' : 'top_tags']"
            effect="dark"
            :closable="tag.name != 'Firstpage1'"
            @close="handleClose(index, tag)"
            @click="clickTag(index, tag)"
            @contextmenu.native.prevent="handleClickContextMenu(index, tag)"
          >
            {{ $t("router." + tag.name) }}
          </el-tag>
        </span>
      </div>
      <!-- Right Arrow -->
      <div
        class="arrow arrow_right"
        v-show="arrowVisible"
        @click="handleClickToRight"
      >
        <i class="el-icon-arrow-right"></i>
      </div>
    </div>
    <!-- Right-click menu-->
    <ul
      v-show="contextMenu.isShow"
      :style="{ left: contextMenu.menuLeft, top: '96px' }"
      class="el-dropdown-menu el-popper"
      x-placement="bottom-end"
    >
      <li
        v-if="this.active == this.contextMenu.index"
        class="el-dropdown-menu__item"
        @click="refresh"
      >
        Refresh
      <li class="el-dropdown-menu__item" @click="closeRightTag">
        Close right side</li>
      <li class="el-dropdown-menu__item" @click="closeOtherTag">
        Close Others</li>
      <div x-arrow="" class="popper__arrow" style="left: 44px;"></div>
    </ul>
  </div>
</template>

<script>
import elementResizeDetectorMaker from "element-resize-detector";
export default {
  data() {
    return {
      // Is there an arrow arrowVisible: true,
      //Number of clicks: 0,
      active: 0,
      tags: [],
      // Right-click element contextMenu: {
        index: 0,
        tag: {},
        menuLeft: 0,
        isShow: false
      }
    };
  },
  watch:
    $route() {
      this.getThisPage();
    },
    tags() {
      this.listenFun(this.$refs.tags, "tags");
    }
  },
  mounted() {
    this.listenFun(this.$refs.box, "box");
    var that = this;
    document.addEventListener("click", function(e) {
      that.contextMenu.isShow = false;
    });
  },
  methods: {
    // Monitor the width of the visible area, and execute listenFun(monitor, dom) when the browser window size changes {
      let boxWidth = this.$refs.box.offsetWidth,
        tagsWidth = this.$refs.tags.offsetWidth,
        erd = elementResizeDetectorMaker();
      erd.listenTo(monitor, ele => {
        this.$nextTick(() => {
          if (
            (dom == "box" && ele.offsetWidth >= tagsWidth) ||
            (dom == "tags" && ele.offsetWidth <= boxWidth)
          ) {
            this.arrowVisible = false;
            this.$refs.box.style.paddingLeft = "16px";
            this.$refs.box.style.paddingRight = "16px";
            this.$refs.box.style.transform = "TranslateX(0px)";
            this.num = 0;
          } else {
            this.arrowVisible = true;
            this.$refs.box.style.paddingLeft = "56px";
            this.$refs.box.style.paddingRight = "56px";
          }
        });
      });
    },
    // Determine the current page getThisPage() {
      let currentPgae = this.$route;
      // Determine whether there is the current page in tags var index = this.tags.findIndex(tag => tag.name == currentPgae.name);
      if (index == -1) {
        this.tags.push({
          name: currentPgae.name,
          path: currentPgae.path
        });
      }
      //Currently selected page this.active = this.tags.findIndex(tag => tag.name == currentPgae.name);
    },
    // Close tag handleClose(index, tag) {
      this.tags.splice(this.tags.indexOf(tag), 1);
      if (index == this.tags.length) {
        this.active = index - 1;
        this.$router.push(this.tags[index - 1].path);
      } else {
        this.$router.push(this.tags[index].path);
      }
    },
    // Click the tag clickTag(index, tag) {
      this.active = index;
      this.$router.push(tag.path);
    },
    // Left button handleClickToLeft() {
      if (this.num > 0) {
        this.num--;
        this.$refs.box.style.transform = `TranslateX(-${this.num * 200}px)`;
      }
    },
    // Right button handleClickToRight() {
      // The last tag is measured from the left side of the browser let lastChild = document
        .querySelectorAll(".top_tags")
        [this.tags.length - 1].getBoundingClientRect().right;
      // Width of the visible window let bodyWidth = document.body.offsetWidth;
      // Right arrow 48 + right margin 16
      if (bodyWidth - lastChild <= 64) {
        this.num++;
        this.$refs.box.style.transform = `TranslateX(-${this.num * 200}px)`;
      }
    },
    // right click handleClickContextMenu(index, tag) {
      this.contextMenu.isShow = true;
      this.contextMenu.index = index;
      this.contextMenu.tag = tag;
      let isTag = document
        .querySelectorAll(".top_tags")
        [index].getBoundingClientRect();
      this.contextMenu.menuLeft = isTag.left - 48 + isTag.width / 2 + "px";
    },
    // Refresh refresh() {
      this.$router.go(0);
    },
    // Close other closeOtherTag() {
      let tagsLin = this.tags.length,
        { index, tag, menuLeft } = this.contextMenu;
      if (index != 0) {
        this.tags = [
          {
            name: "Firstpage1",
            path: "/First/page1"
          },
          {
            name: tag.name,
            path: tag.path
          }
        ];
      } else {
        this.tags = [
          {
            name: "Firstpage1",
            path: "/First/page1"
          }
        ];
      }
      this.active = index;
      this.$router.push(tag.path);
    },
    // Close the right side closeRightTag() {
      let tagsLin = this.tags.length,
        { index, tag, menuLeft } = this.contextMenu;
      this.tags.splice(index + 1, tagsLin - index);
      this.active = index;
      this.$router.push(tag.path);
    }
  },
  created() {
    // Listen for page refresh window.addEventListener("beforeunload", e => {
      localStorage.setItem(
        "tagInfo",
        JSON.stringify({
          active: this.active,
          tags: this.tags
        })
      );
    });
    let tagInfo = localStorage.getItem("tagInfo")
      ? JSON.parse(localStorage.getItem("tagInfo"))
      : {
          active: 0,
          tags: [
            {
              name: "Firstpage1",
              path: "/First/page1"
            }
          ]
        };
    this.active = tagInfo.active;
    this.tags = tagInfo.tags;
  }
};
</script>
<style lang="less" scoped>
/deep/.el-tag--dark {
  border-color: transparent;
}
/deep/.el-tag--dark .el-tag__close {
  color: #86909c;
  font-size: 16px;
}
/deep/.el-tag--dark .el-tag__close:hover {
  background: #e7eaf0;
}
.tags {
  position: relative;
  overflow: hidden;
  .arrow {
    width: 48px;
    text-align: center;
    cursor: pointer;
    background: #fff;
    position: absolute;
    z-index: 1;
    &_left {
      left: 0;
      top: 0;
    }
    &_right {
      right: 0;
      top: 0;
    }
  }
  &_content {
    transition: 0.3s;
    white-space: nowrap;
    // padding: 0 16px;
  }
  .top_tags {
    margin-right: 8px;
    cursor: pointer;
    background: #fff;
    font-size: 12px;
    font-weight: 400;
    color: #1d2129;
  }
  .top_tags:hover,
  .active,
  .arrow:hover {
    background: #e7eaf0;
  }
}
</style>

Key Points

What needs to be modified

currentPgae.name is the name of the routing structure. Check if it exists. If not, add it. If yes, locate it above. Modify it according to the project

When monitoring refresh, go to local storage tags and the active of the current page, and change Ftistpage1 to your own homepage

This is the end of this article about the implementation of Vue top tags browsing history. For more relevant Vue top tags browsing history content, please search 123WORDPRESS.COM's previous articles or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Several ways to encapsulate breadcrumb function components in Vue3
  • Encapsulation method of Vue breadcrumbs component
  • Vue encapsulated breadcrumbs component tutorial
  • vue+element-ui table encapsulation tag label using slot
  • Practical vue tags to create cache navigation process
  • Vue basics breadcrumbs and tag detailed explanation

<<:  Example of compiling LNMP in Docker container

>>:  CSS3 simple cutting carousel picture implementation code

Recommend

Detailed discussion of the character order of mysql order by in (recommended)

//MySQL statement SELECT * FROM `MyTable` WHERE `...

MySQL 8.0.12 installation configuration method and password change

This article records the installation and configu...

...

Solution to mysql error when modifying sql_mode

Table of contents A murder caused by ERR 1067 The...

Install tomcat and deploy the website under Linux (recommended)

Install jdk: Oracle official download https://www...

Tomcat class loader implementation method and example code

Tomcat defines multiple ClassLoaders internally s...

How to develop uniapp using vscode

Because I have always used vscode to develop fron...

How to use sed command to efficiently delete specific lines of a file

Preface Normally, if we want to delete certain li...

Implementing a simple Christmas game with JavaScript

Table of contents Preface Achieve results Code CS...

Detailed explanation of Docker Volume permission management

Volume data volume is an important concept of Doc...

Detailed tutorial on running selenium+chromedriver on the server

1. Introduction I want to use selenium to scrape ...

JavaScript function call classic example code

Table of contents JavaScript function call classi...

Ubuntu 16.04 installation tutorial under VMware 12

This article shares with you the installation tut...

Analysis of the difference between Mysql InnoDB and MyISAM

MySQL supports many types of tables (i.e. storage...