|
@@ -1,257 +1,254 @@
|
|
|
<template>
|
|
|
- <div class="l-main-tags">
|
|
|
- <!-- 标签页 -->
|
|
|
- <div class="l-main-tags__container">
|
|
|
- <scroll-pane ref="scrollPane" class="l-main-tags__list">
|
|
|
+ <div class="l-main-tags">
|
|
|
+ <!-- 标签页 -->
|
|
|
+ <div class="l-main-tags__container">
|
|
|
+ <scroll-pane ref="scrollPane" class="l-main-tags__list">
|
|
|
+ <router-link
|
|
|
+ v-for="tag in visitedViews"
|
|
|
+ ref="tag"
|
|
|
+ :class="isActive(tag) ? 'active' : ''"
|
|
|
+ :to="{
|
|
|
+ path: tag.path,
|
|
|
+ query: tag.query,
|
|
|
+ fullPath: tag.fullPath
|
|
|
+ }"
|
|
|
+ :key="tag.path"
|
|
|
+ tag="span"
|
|
|
+ class="l-main-tags__item"
|
|
|
+ @click.middle.native="closeSelectedTag(tag)"
|
|
|
+ @contextmenu.prevent.native="openMenu(tag, $event)"
|
|
|
+ >
|
|
|
+ <span class="l-main-tags__name" :title="generateTitle(tag.title)">{{ generateTitle(tag.title) }}</span>
|
|
|
+ <span class="el-icon-close" v-if="tag.title !== '我的主页'" @click.prevent.stop="closeSelectedTag(tag)" />
|
|
|
+ </router-link>
|
|
|
+ </scroll-pane>
|
|
|
+ <div class="l-main-tags__btn" v-show="showTagsList">
|
|
|
+ <!-- 悬浮提示 -->
|
|
|
+ <el-popover placement="top-start" popper-class="l-main-tags__popover" trigger="hover">
|
|
|
+ <div class="l-dropdown-tags" :style="dropdownStyleHeight">
|
|
|
+ <el-scrollbar wrap-class="l-dropdown-tags__wrapper">
|
|
|
+ <div class="l-main-tags__inner">
|
|
|
<router-link
|
|
|
- v-for="tag in visitedViews"
|
|
|
- ref="tag"
|
|
|
- :class="isActive(tag) ? 'active' : ''"
|
|
|
- :to="{
|
|
|
- path: tag.path,
|
|
|
- query: tag.query,
|
|
|
- fullPath: tag.fullPath
|
|
|
- }"
|
|
|
- :key="tag.path"
|
|
|
- tag="span"
|
|
|
- class="l-main-tags__item"
|
|
|
- @click.middle.native="closeSelectedTag(tag)"
|
|
|
- @contextmenu.prevent.native="openMenu(tag, $event)"
|
|
|
+ v-for="tag in visitedViews"
|
|
|
+ :class="isActive(tag) ? 'active' : ''"
|
|
|
+ :to="{
|
|
|
+ path: tag.path,
|
|
|
+ query: tag.query,
|
|
|
+ fullPath: tag.fullPath
|
|
|
+ }"
|
|
|
+ :key="tag.path"
|
|
|
+ tag="span"
|
|
|
+ class="l-main-tags__item l-dropdown-tags__item"
|
|
|
+ @click.middle.native="closeSelectedTag(tag)"
|
|
|
>
|
|
|
- <span class="l-main-tags__name" :title="generateTitle(tag.title)">{{
|
|
|
- generateTitle(tag.title)
|
|
|
- }}</span>
|
|
|
- <span class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
|
|
|
+ <span class="l-main-tags__name">{{ generateTitle(tag.title) }}</span>
|
|
|
+ <span class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
|
|
|
</router-link>
|
|
|
- </scroll-pane>
|
|
|
- <div class="l-main-tags__btn" v-show="showTagsList">
|
|
|
- <!-- 悬浮提示 -->
|
|
|
- <el-popover placement="top-start" popper-class="l-main-tags__popover" trigger="hover">
|
|
|
- <div class="l-dropdown-tags" :style="dropdownStyleHeight">
|
|
|
- <el-scrollbar wrap-class="l-dropdown-tags__wrapper">
|
|
|
- <div class="l-main-tags__inner">
|
|
|
- <router-link
|
|
|
- v-for="tag in visitedViews"
|
|
|
- :class="isActive(tag) ? 'active' : ''"
|
|
|
- :to="{
|
|
|
- path: tag.path,
|
|
|
- query: tag.query,
|
|
|
- fullPath: tag.fullPath
|
|
|
- }"
|
|
|
- :key="tag.path"
|
|
|
- tag="span"
|
|
|
- class="l-main-tags__item l-dropdown-tags__item"
|
|
|
- @click.middle.native="closeSelectedTag(tag)"
|
|
|
- >
|
|
|
- <span class="l-main-tags__name">{{ generateTitle(tag.title) }}</span>
|
|
|
- <span class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
|
|
|
- </router-link>
|
|
|
- </div>
|
|
|
- </el-scrollbar>
|
|
|
- </div>
|
|
|
- <div class="l-main-tags__btn-inner" slot="reference">
|
|
|
- <i class="icon icon-bottom"></i>
|
|
|
- <span class="l-main-tags__btn-name">全部</span>
|
|
|
- </div>
|
|
|
- </el-popover>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 右键操作区域 -->
|
|
|
- <ul v-show="visible" :style="{ left: left + 'px', top: top + 'px' }" class="l-main-tags__context">
|
|
|
- <li @click="refreshSelectedTag(selectedTag)">
|
|
|
- {{ $t("tagsView.refresh") }}
|
|
|
- </li>
|
|
|
- <li @click="closeSelectedTag(selectedTag)">
|
|
|
- {{ $t("tagsView.close") }}
|
|
|
- </li>
|
|
|
- <li @click="closeOthersTags">{{ $t("tagsView.closeOthers") }}</li>
|
|
|
- <li @click="closeAllTags">{{ $t("tagsView.closeAll") }}</li>
|
|
|
- </ul>
|
|
|
+ </div>
|
|
|
+ </el-scrollbar>
|
|
|
+ </div>
|
|
|
+ <div class="l-main-tags__btn-inner" slot="reference">
|
|
|
+ <i class="icon icon-bottom"></i>
|
|
|
+ <span class="l-main-tags__btn-name">全部</span>
|
|
|
+ </div>
|
|
|
+ </el-popover>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
+
|
|
|
+ <!-- 右键操作区域 -->
|
|
|
+ <ul v-show="visible" :style="{ left: left + 'px', top: top + 'px' }" class="l-main-tags__context">
|
|
|
+ <li @click="refreshSelectedTag(selectedTag)">
|
|
|
+ {{ $t('tagsView.refresh') }}
|
|
|
+ </li>
|
|
|
+ <li @click="closeSelectedTag(selectedTag)">
|
|
|
+ {{ $t('tagsView.close') }}
|
|
|
+ </li>
|
|
|
+ <li @click="closeOthersTags">{{ $t('tagsView.closeOthers') }}</li>
|
|
|
+ <li @click="closeAllTags">{{ $t('tagsView.closeAll') }}</li>
|
|
|
+ </ul>
|
|
|
+ </div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-import ScrollPane from "@/components/layout/scroll-pane";
|
|
|
-import common from "@/common";
|
|
|
+import ScrollPane from '@/components/layout/scroll-pane';
|
|
|
+import common from '@/common';
|
|
|
const { generateTitle } = common;
|
|
|
|
|
|
export default {
|
|
|
- components: { ScrollPane },
|
|
|
- data() {
|
|
|
- return {
|
|
|
- visible: false,
|
|
|
- top: 0,
|
|
|
- left: 0,
|
|
|
- selectedTag: {},
|
|
|
- showTagsList: false,
|
|
|
- dropdownListHeight: 100
|
|
|
- };
|
|
|
+ components: { ScrollPane },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ visible: false,
|
|
|
+ top: 0,
|
|
|
+ left: 0,
|
|
|
+ selectedTag: {},
|
|
|
+ showTagsList: false,
|
|
|
+ dropdownListHeight: 100
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ visitedViews() {
|
|
|
+ return this.$store.state.tagsView.visitedViews;
|
|
|
},
|
|
|
- computed: {
|
|
|
- visitedViews() {
|
|
|
- return this.$store.state.tagsView.visitedViews;
|
|
|
- },
|
|
|
- dropdownStyleHeight() {
|
|
|
- return "height: " + this.dropdownListHeight + "px;";
|
|
|
- }
|
|
|
+ dropdownStyleHeight() {
|
|
|
+ return 'height: ' + this.dropdownListHeight + 'px;';
|
|
|
+ }
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ $route() {
|
|
|
+ this.addViewTags();
|
|
|
+ this.moveToCurrentTag();
|
|
|
},
|
|
|
- watch: {
|
|
|
- $route() {
|
|
|
- this.addViewTags();
|
|
|
- this.moveToCurrentTag();
|
|
|
- },
|
|
|
- visible(value) {
|
|
|
- if (value) {
|
|
|
- document.body.addEventListener("click", this.closeMenu);
|
|
|
- } else {
|
|
|
- document.body.removeEventListener("click", this.closeMenu);
|
|
|
- }
|
|
|
- },
|
|
|
- /**
|
|
|
- * 检测标签页数目改变
|
|
|
- *
|
|
|
- */
|
|
|
- visitedViews() {
|
|
|
- this.iShowTagsBtn();
|
|
|
- this.dropdownTagsHeight();
|
|
|
- }
|
|
|
+ visible(value) {
|
|
|
+ if (value) {
|
|
|
+ document.body.addEventListener('click', this.closeMenu);
|
|
|
+ } else {
|
|
|
+ document.body.removeEventListener('click', this.closeMenu);
|
|
|
+ }
|
|
|
},
|
|
|
- methods: {
|
|
|
- generateTitle, // generateTitle by vue-i18n
|
|
|
- isActive(route) {
|
|
|
- return route.path === this.$route.path;
|
|
|
- },
|
|
|
- addViewTags() {
|
|
|
- const { name } = this.$route;
|
|
|
- if (name) {
|
|
|
- this.$store.dispatch("addView", this.$route);
|
|
|
- }
|
|
|
- return false;
|
|
|
- },
|
|
|
- moveToCurrentTag() {
|
|
|
- const tags = this.$refs.tag;
|
|
|
- this.$nextTick(() => {
|
|
|
- for (const tag of tags) {
|
|
|
- if (tag.to.path === this.$route.path) {
|
|
|
- this.$refs.scrollPane.moveToTarget(tag);
|
|
|
-
|
|
|
- // when query is different then update
|
|
|
- if (tag.to.fullPath !== this.$route.fullPath) {
|
|
|
- this.$store.dispatch("updateVisitedView", this.$route);
|
|
|
- }
|
|
|
-
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- },
|
|
|
- refreshSelectedTag(view) {
|
|
|
- this.$store.dispatch("delCachedView", view).then(() => {
|
|
|
- const { fullPath } = view;
|
|
|
- this.$nextTick(() => {
|
|
|
- this.$router.replace({
|
|
|
- path: "/redirect" + fullPath
|
|
|
- });
|
|
|
- });
|
|
|
- });
|
|
|
- },
|
|
|
- closeSelectedTag(view) {
|
|
|
- this.$store.dispatch("delView", view).then(({ visitedViews }) => {
|
|
|
- if (this.isActive(view)) {
|
|
|
- const latestView = visitedViews.slice(-1)[0];
|
|
|
- if (latestView) {
|
|
|
- this.$router.push(latestView);
|
|
|
- } else {
|
|
|
- this.$router.push("/");
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- },
|
|
|
- closeOthersTags() {
|
|
|
- this.$router.push(this.selectedTag);
|
|
|
- this.$store.dispatch("delOthersViews", this.selectedTag).then(() => {
|
|
|
- this.moveToCurrentTag();
|
|
|
- });
|
|
|
- },
|
|
|
- closeAllTags() {
|
|
|
- this.$store.dispatch("delAllViews");
|
|
|
- this.$router.push("/");
|
|
|
- },
|
|
|
- openMenu(tag, e) {
|
|
|
- const menuMinWidth = 105;
|
|
|
- const offsetLeft = this.$el.getBoundingClientRect().left; // container margin left
|
|
|
- const offsetWidth = this.$el.offsetWidth; // container width
|
|
|
- const maxLeft = offsetWidth - menuMinWidth; // left boundary
|
|
|
- const left = e.clientX - offsetLeft + 16; // 16: margin right
|
|
|
+ /**
|
|
|
+ * 检测标签页数目改变
|
|
|
+ *
|
|
|
+ */
|
|
|
+ visitedViews() {
|
|
|
+ this.iShowTagsBtn();
|
|
|
+ this.dropdownTagsHeight();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ generateTitle, // generateTitle by vue-i18n
|
|
|
+ isActive(route) {
|
|
|
+ return route.path === this.$route.path;
|
|
|
+ },
|
|
|
+ addViewTags() {
|
|
|
+ const { name } = this.$route;
|
|
|
+ if (name) {
|
|
|
+ this.$store.dispatch('addView', this.$route);
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ },
|
|
|
+ moveToCurrentTag() {
|
|
|
+ const tags = this.$refs.tag;
|
|
|
+ this.$nextTick(() => {
|
|
|
+ for (const tag of tags) {
|
|
|
+ if (tag.to.path === this.$route.path) {
|
|
|
+ this.$refs.scrollPane.moveToTarget(tag);
|
|
|
|
|
|
- if (left > maxLeft) {
|
|
|
- this.left = maxLeft;
|
|
|
- } else {
|
|
|
- this.left = left;
|
|
|
+ // when query is different then update
|
|
|
+ if (tag.to.fullPath !== this.$route.fullPath) {
|
|
|
+ this.$store.dispatch('updateVisitedView', this.$route);
|
|
|
}
|
|
|
- this.top = e.clientY - 32;
|
|
|
-
|
|
|
- this.visible = true;
|
|
|
- this.selectedTag = tag;
|
|
|
- },
|
|
|
- closeMenu() {
|
|
|
- this.visible = false;
|
|
|
- },
|
|
|
- /**
|
|
|
- * 检测是否显示 Tags 全部按钮
|
|
|
- *
|
|
|
- */
|
|
|
- iShowTagsBtn() {
|
|
|
- this.$nextTick(() => {
|
|
|
- // 容器的宽度
|
|
|
- const offsetWidth = this.$el.offsetWidth;
|
|
|
- // 标签列表
|
|
|
- const tagsArray = this.$refs.tag; // tags list
|
|
|
- // 预留的空间位置
|
|
|
- const leaveSpace = 160;
|
|
|
- // 计算标签列表所占的宽度
|
|
|
- let tagsWrapperWidth = 0;
|
|
|
|
|
|
- // 检测标签列是否存在
|
|
|
- if (tagsArray) {
|
|
|
- // 计算列表宽度总和
|
|
|
- tagsArray.forEach(item => {
|
|
|
- tagsWrapperWidth += item.$el.offsetWidth;
|
|
|
- });
|
|
|
- }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ refreshSelectedTag(view) {
|
|
|
+ this.$store.dispatch('delCachedView', view).then(() => {
|
|
|
+ const { fullPath } = view;
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.$router.replace({
|
|
|
+ path: '/redirect' + fullPath
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ closeSelectedTag(view) {
|
|
|
+ this.$store.dispatch('delView', view).then(({ visitedViews }) => {
|
|
|
+ if (this.isActive(view)) {
|
|
|
+ const latestView = visitedViews.slice(-1)[0];
|
|
|
+ if (latestView) {
|
|
|
+ this.$router.push(latestView);
|
|
|
+ } else {
|
|
|
+ this.$router.push('/');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ closeOthersTags() {
|
|
|
+ this.$router.push(this.selectedTag);
|
|
|
+ this.$store.dispatch('delOthersViews', this.selectedTag).then(() => {
|
|
|
+ this.moveToCurrentTag();
|
|
|
+ });
|
|
|
+ },
|
|
|
+ closeAllTags() {
|
|
|
+ this.$store.dispatch('delAllViews');
|
|
|
+ this.$router.push('/');
|
|
|
+ },
|
|
|
+ openMenu(tag, e) {
|
|
|
+ const menuMinWidth = 105;
|
|
|
+ const offsetLeft = this.$el.getBoundingClientRect().left; // container margin left
|
|
|
+ const offsetWidth = this.$el.offsetWidth; // container width
|
|
|
+ const maxLeft = offsetWidth - menuMinWidth; // left boundary
|
|
|
+ const left = e.clientX - offsetLeft + 16; // 16: margin right
|
|
|
|
|
|
- // 测试
|
|
|
- // console.log(tagsArray, tagsWrapperWidth, offsetWidth, tagsWrapperWidth + leaveSpace > offsetWidth);
|
|
|
+ if (left > maxLeft) {
|
|
|
+ this.left = maxLeft;
|
|
|
+ } else {
|
|
|
+ this.left = left;
|
|
|
+ }
|
|
|
+ this.top = e.clientY - 32;
|
|
|
|
|
|
- // 更改显示值
|
|
|
- this.showTagsList = tagsWrapperWidth + leaveSpace > offsetWidth;
|
|
|
- });
|
|
|
- },
|
|
|
- /**
|
|
|
- * 计算下拉框的高度值
|
|
|
- */
|
|
|
- dropdownTagsHeight() {
|
|
|
- let _height = this.visitedViews.length * 36 + 10;
|
|
|
- let _windowHeight =
|
|
|
- window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
|
|
|
+ this.visible = true;
|
|
|
+ this.selectedTag = tag;
|
|
|
+ },
|
|
|
+ closeMenu() {
|
|
|
+ this.visible = false;
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 检测是否显示 Tags 全部按钮
|
|
|
+ *
|
|
|
+ */
|
|
|
+ iShowTagsBtn() {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ // 容器的宽度
|
|
|
+ const offsetWidth = this.$el.offsetWidth;
|
|
|
+ // 标签列表
|
|
|
+ const tagsArray = this.$refs.tag; // tags list
|
|
|
+ // 预留的空间位置
|
|
|
+ const leaveSpace = 160;
|
|
|
+ // 计算标签列表所占的宽度
|
|
|
+ let tagsWrapperWidth = 0;
|
|
|
|
|
|
- // 自动计算高度值
|
|
|
- this.dropdownListHeight = _windowHeight - 180 < _height ? _windowHeight - 180 : _height;
|
|
|
+ // 检测标签列是否存在
|
|
|
+ if (tagsArray) {
|
|
|
+ // 计算列表宽度总和
|
|
|
+ tagsArray.forEach((item) => {
|
|
|
+ tagsWrapperWidth += item.$el.offsetWidth;
|
|
|
+ });
|
|
|
}
|
|
|
- },
|
|
|
- mounted() {
|
|
|
- // 添加标签页
|
|
|
- this.addViewTags();
|
|
|
|
|
|
- // 窗口 resize 监听事件
|
|
|
- window.addEventListener("resize", this.iShowTagsBtn);
|
|
|
- window.addEventListener("resize", this.dropdownTagsHeight);
|
|
|
+ // 测试
|
|
|
+ // console.log(tagsArray, tagsWrapperWidth, offsetWidth, tagsWrapperWidth + leaveSpace > offsetWidth);
|
|
|
+
|
|
|
+ // 更改显示值
|
|
|
+ this.showTagsList = tagsWrapperWidth + leaveSpace > offsetWidth;
|
|
|
+ });
|
|
|
},
|
|
|
- beforeDestroy() {
|
|
|
- // 移除窗口监听事件
|
|
|
- window.removeEventListener("resize", this.iShowTagsBtn);
|
|
|
- window.removeEventListener("resize", this.dropdownTagsHeight);
|
|
|
+ /**
|
|
|
+ * 计算下拉框的高度值
|
|
|
+ */
|
|
|
+ dropdownTagsHeight() {
|
|
|
+ let _height = this.visitedViews.length * 36 + 10;
|
|
|
+ let _windowHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
|
|
|
+
|
|
|
+ // 自动计算高度值
|
|
|
+ this.dropdownListHeight = _windowHeight - 180 < _height ? _windowHeight - 180 : _height;
|
|
|
}
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ // 添加标签页
|
|
|
+ this.addViewTags();
|
|
|
+
|
|
|
+ // 窗口 resize 监听事件
|
|
|
+ window.addEventListener('resize', this.iShowTagsBtn);
|
|
|
+ window.addEventListener('resize', this.dropdownTagsHeight);
|
|
|
+ },
|
|
|
+ beforeDestroy() {
|
|
|
+ // 移除窗口监听事件
|
|
|
+ window.removeEventListener('resize', this.iShowTagsBtn);
|
|
|
+ window.removeEventListener('resize', this.dropdownTagsHeight);
|
|
|
+ }
|
|
|
};
|
|
|
</script>
|