refactor: 优化pinia setup store组合式函数写法

Former-commit-id: 27347ede51d0952d3422c3a6c3a86652f91e5639
This commit is contained in:
haoxr
2022-12-18 15:27:53 +08:00
parent fe49485563
commit 2a36afae16
27 changed files with 944 additions and 973 deletions

View File

@@ -1,8 +1,14 @@
<script setup lang="ts">
import { useTagsViewStore } from '@/store/modules/tagsView';
const tagsViewStore = useTagsViewStore();
</script>
<template>
<section class="app-main">
<router-view v-slot="{ Component, route }">
<transition name="router-fade" mode="out-in">
<keep-alive :include="cachedViews">
<keep-alive :include="tagsViewStore.cachedViews">
<component :is="Component" :key="route.fullPath" />
</keep-alive>
</transition>
@@ -10,15 +16,6 @@
</section>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import useStore from '@/store';
const { tagsView } = useStore();
const cachedViews = computed(() => tagsView.cachedViews);
</script>
<style lang="scss" scoped>
.app-main {
/* 50= navbar 50 */

View File

@@ -1,8 +1,55 @@
<script setup lang="ts">
import { computed } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { ElMessageBox } from 'element-plus';
import Breadcrumb from '@/components/Breadcrumb/index.vue';
import Hamburger from '@/components/Hamburger/index.vue';
import Screenfull from '@/components/Screenfull/index.vue';
import SizeSelect from '@/components/SizeSelect/index.vue';
import LangSelect from '@/components/LangSelect/index.vue';
import { CaretBottom } from '@element-plus/icons-vue';
import { useAppStore, DeviceType } from '@/store/modules/app';
import { useTagsViewStore } from '@/store/modules/tagsView';
import { useUserStore } from '@/store/modules/user';
const appStore = useAppStore();
const tagsViewStore = useTagsViewStore();
const userStore = useUserStore();
const route = useRoute();
const router = useRouter();
const device = computed(() => appStore.device);
function toggleSideBar() {
appStore.toggleSidebar(true);
}
function logout() {
ElMessageBox.confirm('确定注销并退出系统吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
userStore
.logout()
.then(() => {
tagsViewStore.delAllViews();
})
.then(() => {
router.push(`/login?redirect=${route.fullPath}`);
});
});
}
</script>
<template>
<div class="navbar">
<hamburger
id="hamburger-container"
:is-active="sidebar.opened"
:is-active="appStore.sidebar.opened"
class="hamburger-container"
@toggleClick="toggleSideBar"
/>
@@ -10,9 +57,7 @@
<breadcrumb id="breadcrumb-container" class="breadcrumb-container" />
<div class="right-menu">
<template v-if="device !== 'mobile'">
<!-- <search id="header-search" class="right-menu-item" />
<error-log class="errLog-container right-menu-item hover-effect" />-->
<template v-if="device !== DeviceType.mobile">
<screenfull id="screenfull" class="right-menu-item hover-effect" />
<el-tooltip content="布局大小" effect="dark" placement="bottom">
<size-select id="size-select" class="right-menu-item hover-effect" />
@@ -25,7 +70,7 @@
trigger="click"
>
<div class="avatar-wrapper">
<img :src="avatar + '?imageView2/1/w/80/h/80'" class="user-avatar" />
<img :src="userStore.avatar + '?imageView2/1/w/80/h/80'" />
<CaretBottom style="width: 0.6em; height: 0.6em; margin-left: 5px" />
</div>
@@ -52,53 +97,6 @@
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { ElMessageBox } from 'element-plus';
import useStore from '@/store';
// 组件依赖
import Breadcrumb from '@/components/Breadcrumb/index.vue';
import Hamburger from '@/components/Hamburger/index.vue';
import Screenfull from '@/components/Screenfull/index.vue';
import SizeSelect from '@/components/SizeSelect/index.vue';
import LangSelect from '@/components/LangSelect/index.vue';
// 图标依赖
import { CaretBottom } from '@element-plus/icons-vue';
const { app, user, tagsView } = useStore();
const route = useRoute();
const router = useRouter();
const sidebar = computed(() => app.sidebar);
const device = computed(() => app.device);
const avatar = computed(() => user.avatar);
function toggleSideBar() {
app.toggleSidebar();
}
function logout() {
ElMessageBox.confirm('确定注销并退出系统吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
user
.logout()
.then(() => {
tagsView.delAllViews();
})
.then(() => {
router.push(`/login?redirect=${route.fullPath}`);
});
});
}
</script>
<style lang="scss" scoped>
ul {
@@ -164,7 +162,7 @@ ul {
margin-top: 5px;
position: relative;
.user-avatar {
img {
cursor: pointer;
width: 40px;
height: 40px;

View File

@@ -1,3 +1,15 @@
<script setup lang="ts">
import { useSettingsStore } from '@/store/modules/settings';
import ThemePicker from '@/components/ThemePicker/index.vue';
const settingsStore = useSettingsStore();
function themeChange(val: string) {
settingsStore.changeSetting({ key: 'theme', value: val });
}
</script>
<template>
<div class="drawer-container">
<h3 class="drawer-title">系统布局配置</h3>
@@ -10,17 +22,17 @@
<div class="drawer-item">
<span>开启 Tags-View</span>
<el-switch v-model="tagsView" class="drawer-switch" />
<el-switch v-model="settingsStore.tagsView" class="drawer-switch" />
</div>
<div class="drawer-item">
<span>固定 Header</span>
<el-switch v-model="fixedHeader" class="drawer-switch" />
<el-switch v-model="settingsStore.fixedHeader" class="drawer-switch" />
</div>
<div class="drawer-item">
<span>侧边栏 Logo</span>
<el-switch v-model="sidebarLogo" class="drawer-switch" />
<el-switch v-model="settingsStore.sidebarLogo" class="drawer-switch" />
</div>
<el-divider>导航栏模式</el-divider>
@@ -48,49 +60,6 @@
</div>
</template>
<script setup lang="ts">
import { reactive, toRefs, watch } from 'vue';
import ThemePicker from '@/components/ThemePicker/index.vue';
import useStore from '@/store';
const { setting } = useStore();
const state = reactive({
fixedHeader: setting.fixedHeader,
tagsView: setting.tagsView,
sidebarLogo: setting.sidebarLogo
});
const { fixedHeader, tagsView, sidebarLogo } = toRefs(state);
function themeChange(val: any) {
setting.changeSetting({ key: 'theme', value: val });
}
watch(
() => state.fixedHeader,
value => {
setting.changeSetting({ key: 'fixedHeader', value: value });
}
);
watch(
() => state.tagsView,
value => {
setting.changeSetting({ key: 'tagsView', value: value });
}
);
watch(
() => state.sidebarLogo,
value => {
setting.changeSetting({ key: 'sidebarLogo', value: value });
}
);
</script>
<style lang="scss" scoped>
.drawer-container {
padding: 24px;

View File

@@ -1,3 +1,32 @@
<script lang="ts" setup>
import { computed } from 'vue';
import { isExternal } from '@/utils/validate';
import { useRouter } from 'vue-router';
import { DeviceType, useAppStore } from '@/store/modules/app';
const appStore = useAppStore();
const sidebar = computed(() => appStore.sidebar);
const device = computed(() => appStore.device);
const props = defineProps({
to: {
type: String,
required: true
}
});
const router = useRouter();
function push() {
if (device.value === DeviceType.mobile && sidebar.value.opened == true) {
appStore.closeSideBar(false);
}
router.push(props.to).catch(err => {
console.error(err);
});
}
</script>
<template>
<a v-if="isExternal(to)" :href="to" target="_blank" rel="noopener">
<slot />
@@ -6,40 +35,3 @@
<slot />
</div>
</template>
<script lang="ts">
import { computed, defineComponent } from 'vue';
import { isExternal } from '@/utils/validate';
import { useRouter } from 'vue-router';
import useStore from '@/store';
const { app } = useStore();
const sidebar = computed(() => app.sidebar);
const device = computed(() => app.device);
export default defineComponent({
props: {
to: {
type: String,
required: true
}
},
setup(props) {
const router = useRouter();
const push = () => {
if (device.value === 'mobile' && sidebar.value.opened == true) {
app.closeSideBar(false);
}
router.push(props.to).catch(err => {
console.log(err);
});
};
return {
push,
isExternal
};
}
});
</script>

View File

@@ -1,3 +1,18 @@
<script lang="ts" setup>
import { ref } from 'vue';
defineProps({
collapse: {
type: Boolean,
required: true
}
});
const logo = ref<string>(
new URL(`../../../assets/logo.png`, import.meta.url).href
);
</script>
<template>
<div class="sidebar-logo-container" :class="{ collapse: collapse }">
<transition name="sidebarLogoFade">
@@ -18,24 +33,6 @@
</div>
</template>
<script setup lang="ts">
import { reactive, toRefs } from 'vue';
const props = defineProps({
collapse: {
type: Boolean,
required: true
}
});
const state = reactive({
isCollapse: props.collapse,
logo: new URL(`../../../assets/logo.png`, import.meta.url).href
});
const { logo } = toRefs(state);
</script>
<style lang="scss" scoped>
.sidebarLogoFade-enter-active {
transition: opacity 1.5s;

View File

@@ -1,51 +1,3 @@
<template>
<div v-if="!item.meta || !item.meta.hidden">
<template
v-if="
hasOneShowingChild(item.children, item) &&
(!onlyOneChild.children || onlyOneChild.noShowingChildren) &&
(!item.meta || !item.meta.alwaysShow)
"
>
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
<el-menu-item
:index="resolvePath(onlyOneChild.path)"
:class="{ 'submenu-title-noDropdown': !isNest }"
>
<svg-icon
v-if="onlyOneChild.meta && onlyOneChild.meta.icon"
:icon-class="onlyOneChild.meta.icon"
/>
<template #title>
{{ generateTitle(onlyOneChild.meta.title) }}
</template>
</el-menu-item>
</app-link>
</template>
<el-sub-menu v-else :index="resolvePath(item.path)" popper-append-to-body>
<!-- popper-append-to-body -->
<template #title>
<svg-icon
v-if="item.meta && item.meta.icon"
:icon-class="item.meta.icon"
></svg-icon>
<span v-if="item.meta && item.meta.title">{{
generateTitle(item.meta.title)
}}</span>
</template>
<sidebar-item
v-for="child in item.children"
:key="child.path"
:item="child"
:is-nest="true"
:base-path="resolvePath(child.path)"
class="nest-menu"
/>
</el-sub-menu>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import path from 'path-browserify';
@@ -110,5 +62,52 @@ function resolvePath(routePath: string) {
return path.resolve(props.basePath, routePath);
}
</script>
<template>
<div v-if="!item.meta || !item.meta.hidden">
<template
v-if="
hasOneShowingChild(item.children, item) &&
(!onlyOneChild.children || onlyOneChild.noShowingChildren) &&
(!item.meta || !item.meta.alwaysShow)
"
>
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
<el-menu-item
:index="resolvePath(onlyOneChild.path)"
:class="{ 'submenu-title-noDropdown': !isNest }"
>
<svg-icon
v-if="onlyOneChild.meta && onlyOneChild.meta.icon"
:icon-class="onlyOneChild.meta.icon"
/>
<template #title>
{{ generateTitle(onlyOneChild.meta.title) }}
</template>
</el-menu-item>
</app-link>
</template>
<el-sub-menu v-else :index="resolvePath(item.path)" popper-append-to-body>
<!-- popper-append-to-body -->
<template #title>
<svg-icon
v-if="item.meta && item.meta.icon"
:icon-class="item.meta.icon"
></svg-icon>
<span v-if="item.meta && item.meta.title">{{
generateTitle(item.meta.title)
}}</span>
</template>
<sidebar-item
v-for="child in item.children"
:key="child.path"
:item="child"
:is-nest="true"
:base-path="resolvePath(child.path)"
class="nest-menu"
/>
</el-sub-menu>
</div>
</template>
<style lang="scss" scoped></style>

View File

@@ -1,6 +1,37 @@
<script setup lang="ts">
import { computed } from 'vue';
import { useRoute } from 'vue-router';
import SidebarItem from './SidebarItem.vue';
import Logo from './Logo.vue';
import variables from '@/styles/variables.module.scss';
import { useSettingsStore } from '@/store/modules/settings';
import { usePermissionStore } from '@/store/modules/permission';
import { useAppStore } from '@/store/modules/app';
import { storeToRefs } from 'pinia';
const settingsStore = useSettingsStore();
const permissionStore = usePermissionStore();
const appStore = useAppStore();
const { sidebarLogo } = storeToRefs(settingsStore);
const route = useRoute();
const isCollapse = computed(() => !appStore.sidebar.opened);
const activeMenu = computed<string>(() => {
const { meta, path } = route;
if (meta?.activeMenu) {
return meta.activeMenu as string;
}
return path;
});
</script>
<template>
<div :class="{ 'has-logo': showLogo }">
<logo v-if="showLogo" :collapse="isCollapse" />
<div :class="{ 'has-logo': sidebarLogo }">
<logo v-if="sidebarLogo" :collapse="isCollapse" />
<el-scrollbar>
<el-menu
:default-active="activeMenu"
@@ -13,7 +44,7 @@
mode="vertical"
>
<sidebar-item
v-for="route in routes"
v-for="route in permissionStore.routes"
:item="route"
:key="route.path"
:base-path="route.path"
@@ -23,29 +54,3 @@
</el-scrollbar>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { useRoute } from 'vue-router';
import SidebarItem from './SidebarItem.vue';
import Logo from './Logo.vue';
import variables from '@/styles/variables.module.scss';
import useStore from '@/store';
const { permission, setting, app } = useStore();
const route = useRoute();
const routes = computed(() => permission.routes);
const showLogo = computed(() => setting.sidebarLogo);
const isCollapse = computed(() => !app.sidebar.opened);
const activeMenu = computed(() => {
const { meta, path } = route;
// if set path, the sidebar will highlight the path you set
if (meta.activeMenu) {
return meta.activeMenu as string;
}
return path;
});
</script>

View File

@@ -1,14 +1,3 @@
<template>
<el-scrollbar
ref="scrollContainer"
:vertical="false"
class="scroll-container"
@wheel.prevent="handleScroll"
>
<slot />
</el-scrollbar>
</template>
<script setup lang="ts">
import {
ref,
@@ -17,8 +6,7 @@ import {
onBeforeUnmount,
getCurrentInstance
} from 'vue';
import useStore from '@/store';
import { TagView } from '@/store/modules/types';
import { useTagsViewStore, TagView } from '@/store/modules/tagsView';
const tagAndTagSpacing = ref(4);
const { proxy } = getCurrentInstance() as any;
@@ -28,9 +16,7 @@ const emitScroll = () => {
emits('scroll');
};
const { tagsView } = useStore();
const visitedViews = computed(() => tagsView.visitedViews);
const tagsViewStore = useTagsViewStore();
const scrollWrapper = computed(
() => proxy?.$refs.scrollContainer.$refs.wrapRef
@@ -58,9 +44,9 @@ function moveToTarget(currentTag: TagView) {
let lastTag = null;
// find first tag and last tag
if (visitedViews.value.length > 0) {
firstTag = visitedViews.value[0];
lastTag = visitedViews.value[visitedViews.value.length - 1];
if (tagsViewStore.visitedViews.length > 0) {
firstTag = tagsViewStore.visitedViews[0];
lastTag = tagsViewStore.visitedViews[tagsViewStore.visitedViews.length - 1];
}
if (firstTag === currentTag) {
@@ -69,7 +55,7 @@ function moveToTarget(currentTag: TagView) {
$scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth;
} else {
const tagListDom = document.getElementsByClassName('tags-view__item');
const currentIndex = visitedViews.value.findIndex(
const currentIndex = tagsViewStore.visitedViews.findIndex(
item => item === currentTag
);
let prevTag = null;
@@ -78,13 +64,13 @@ function moveToTarget(currentTag: TagView) {
if (k !== 'length' && Object.hasOwnProperty.call(tagListDom, k)) {
if (
(tagListDom[k] as any).dataset.path ===
visitedViews.value[currentIndex - 1].path
tagsViewStore.visitedViews[currentIndex - 1].path
) {
prevTag = tagListDom[k];
}
if (
(tagListDom[k] as any).dataset.path ===
visitedViews.value[currentIndex + 1].path
tagsViewStore.visitedViews[currentIndex + 1].path
) {
nextTag = tagListDom[k];
}
@@ -113,6 +99,17 @@ defineExpose({
});
</script>
<template>
<el-scrollbar
ref="scrollContainer"
:vertical="false"
class="scroll-container"
@wheel.prevent="handleScroll"
>
<slot />
</el-scrollbar>
</template>
<style lang="scss" scoped>
.scroll-container {
.el-scrollbar__bar {

View File

@@ -1,66 +1,5 @@
<template>
<div class="tags-view__container">
<scroll-pane
ref="scrollPaneRef"
class="tags-view__wrapper"
@scroll="handleScroll"
>
<router-link
v-for="tag in visitedViews"
:key="tag.path"
:data-path="tag.path"
:class="isActive(tag) ? 'active' : ''"
:to="{ path: tag.path, query: tag.query }"
class="tags-view__item"
@click.middle="!isAffix(tag) ? closeSelectedTag(tag) : ''"
@contextmenu.prevent="openMenu(tag, $event)"
>
{{ generateTitle(tag.meta.title) }}
<span
v-if="!isAffix(tag)"
class="icon-close"
@click.prevent.stop="closeSelectedTag(tag)"
>
<svg-icon icon-class="close" />
</span>
</router-link>
</scroll-pane>
<ul
v-show="visible"
:style="{ left: left + 'px', top: top + 'px' }"
class="tags-view__menu"
>
<li @click="refreshSelectedTag(selectedTag)">
<svg-icon icon-class="refresh" />
刷新
</li>
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">
<svg-icon icon-class="close" />
关闭
</li>
<li @click="closeOtherTags">
<svg-icon icon-class="close_other" />
关闭其它
</li>
<li v-if="!isFirstView()" @click="closeLeftTags">
<svg-icon icon-class="close_left" />
关闭左侧
</li>
<li v-if="!isLastView()" @click="closeRightTags">
<svg-icon icon-class="close_right" />
关闭右侧
</li>
<li @click="closeAllTags(selectedTag)">
<svg-icon icon-class="close_all" />
关闭所有
</li>
</ul>
</div>
</template>
<script setup lang="ts">
import {
computed,
getCurrentInstance,
nextTick,
ref,
@@ -71,29 +10,28 @@ import {
import path from 'path-browserify';
import { useRoute, useRouter } from 'vue-router';
import { useRoute, useRouter } from 'vue-router';
import ScrollPane from './ScrollPane.vue';
import SvgIcon from '@/components/SvgIcon/index.vue';
import { generateTitle } from '@/utils/i18n';
import useStore from '@/store';
import { TagView } from '@/store/modules/types';
const { tagsView, permission } = useStore();
import { usePermissionStore } from '@/store/modules/permission';
import { useTagsViewStore, TagView } from '@/store/modules/tagsView';
const permissionStore = usePermissionStore();
const tagsViewStore = useTagsViewStore();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const router = useRouter();
const route = useRoute();
const visitedViews = computed<any>(() => tagsView.visitedViews);
const routes = computed<any>(() => permission.routes);
const affixTags = ref([]);
const visible = ref(false);
const selectedTag = ref({});
const scrollPaneRef = ref();
const left = ref(0);
const top = ref(0);
const affixTags = ref<TagView[]>([]);
watch(
route,
@@ -140,30 +78,30 @@ function filterAffixTags(routes: any[], basePath = '/') {
}
function initTags() {
const res = filterAffixTags(routes.value) as [];
affixTags.value = res;
for (const tag of res) {
const tags = filterAffixTags(permissionStore.routes);
affixTags.value = tags;
for (const tag of tags) {
// Must have tag name
if ((tag as TagView).name) {
tagsView.addVisitedView(tag);
tagsViewStore.addVisitedView(tag);
}
}
}
function addTags() {
if (route.name) {
tagsView.addView(route);
tagsViewStore.addView(route);
}
}
function moveToCurrentTag() {
nextTick(() => {
for (const r of visitedViews.value) {
for (const r of tagsViewStore.visitedViews) {
if (r.path === route.path) {
scrollPaneRef.value.moveToTarget(r);
// when query is different then update
if (r.fullPath !== route.fullPath) {
tagsView.updateVisitedView(route);
tagsViewStore.updateVisitedView(route);
}
}
}
@@ -182,7 +120,7 @@ function isFirstView() {
try {
return (
(selectedTag.value as TagView).fullPath ===
visitedViews.value[1].fullPath ||
tagsViewStore.visitedViews[1].fullPath ||
(selectedTag.value as TagView).fullPath === '/index'
);
} catch (err) {
@@ -194,7 +132,7 @@ function isLastView() {
try {
return (
(selectedTag.value as TagView).fullPath ===
visitedViews.value[visitedViews.value.length - 1].fullPath
tagsViewStore.visitedViews[tagsViewStore.visitedViews.length - 1].fullPath
);
} catch (err) {
return false;
@@ -202,7 +140,7 @@ function isLastView() {
}
function refreshSelectedTag(view: TagView) {
tagsView.delCachedView(view);
tagsViewStore.delCachedView(view);
const { fullPath } = view;
nextTick(() => {
router.replace({ path: '/redirect' + fullPath }).catch(err => {
@@ -228,7 +166,7 @@ function toLastView(visitedViews: TagView[], view?: any) {
}
function closeSelectedTag(view: TagView) {
tagsView.delView(view).then((res: any) => {
tagsViewStore.delView(view).then((res: any) => {
if (isActive(view)) {
toLastView(res.visitedViews, view);
}
@@ -236,7 +174,7 @@ function closeSelectedTag(view: TagView) {
}
function closeLeftTags() {
tagsView.delLeftViews(selectedTag.value).then((res: any) => {
tagsViewStore.delLeftViews(selectedTag.value).then((res: any) => {
if (
!res.visitedViews.find((item: any) => item.fullPath === route.fullPath)
) {
@@ -245,7 +183,7 @@ function closeLeftTags() {
});
}
function closeRightTags() {
tagsView.delRightViews(selectedTag.value).then((res: any) => {
tagsViewStore.delRightViews(selectedTag.value).then((res: any) => {
if (
!res.visitedViews.find((item: any) => item.fullPath === route.fullPath)
) {
@@ -256,13 +194,13 @@ function closeRightTags() {
function closeOtherTags() {
router.push(selectedTag.value);
tagsView.delOtherViews(selectedTag.value).then(() => {
tagsViewStore.delOtherViews(selectedTag.value).then(() => {
moveToCurrentTag();
});
}
function closeAllTags(view: TagView) {
tagsView.delAllViews().then((res: any) => {
tagsViewStore.delAllViews().then((res: any) => {
toLastView(res.visitedViews, view);
});
}
@@ -298,6 +236,66 @@ onMounted(() => {
});
</script>
<template>
<div class="tags-view__container">
<scroll-pane
ref="scrollPaneRef"
class="tags-view__wrapper"
@scroll="handleScroll"
>
<router-link
v-for="tag in tagsViewStore.visitedViews"
:key="tag.path"
:data-path="tag.path"
:class="isActive(tag) ? 'active' : ''"
:to="{ path: tag.path, query: tag.query }"
class="tags-view__item"
@click.middle="!isAffix(tag) ? closeSelectedTag(tag) : ''"
@contextmenu.prevent="openMenu(tag, $event)"
>
{{ generateTitle(tag.meta?.title) }}
<span
v-if="!isAffix(tag)"
class="icon-close"
@click.prevent.stop="closeSelectedTag(tag)"
>
<svg-icon icon-class="close" />
</span>
</router-link>
</scroll-pane>
<ul
v-show="visible"
:style="{ left: left + 'px', top: top + 'px' }"
class="tags-view__menu"
>
<li @click="refreshSelectedTag(selectedTag)">
<svg-icon icon-class="refresh" />
刷新
</li>
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">
<svg-icon icon-class="close" />
关闭
</li>
<li @click="closeOtherTags">
<svg-icon icon-class="close_other" />
关闭其它
</li>
<li v-if="!isFirstView()" @click="closeLeftTags">
<svg-icon icon-class="close_left" />
关闭左侧
</li>
<li v-if="!isLastView()" @click="closeRightTags">
<svg-icon icon-class="close_right" />
关闭右侧
</li>
<li @click="closeAllTags(selectedTag)">
<svg-icon icon-class="close_all" />
关闭所有
</li>
</ul>
</div>
</template>
<style lang="scss" scoped>
.tags-view__container {
height: 34px;