作者 北风

tagview & sidebar 主题颜色与element ui(全局)同步

@@ -8,47 +8,50 @@ @@ -8,47 +8,50 @@
8 :background-color="variables.menuBg" 8 :background-color="variables.menuBg"
9 :text-color="variables.menuText" 9 :text-color="variables.menuText"
10 :unique-opened="true" 10 :unique-opened="true"
11 - :active-text-color="variables.menuActiveText" 11 + :active-text-color="settings.theme"
12 :collapse-transition="false" 12 :collapse-transition="false"
13 mode="vertical" 13 mode="vertical"
14 > 14 >
15 - <sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" /> 15 + <sidebar-item
  16 + v-for="route in permission_routes"
  17 + :key="route.path"
  18 + :item="route"
  19 + :base-path="route.path"
  20 + />
16 </el-menu> 21 </el-menu>
17 </el-scrollbar> 22 </el-scrollbar>
18 </div> 23 </div>
19 </template> 24 </template>
20 25
21 <script> 26 <script>
22 -import { mapGetters } from 'vuex'  
23 -import Logo from './Logo'  
24 -import SidebarItem from './SidebarItem'  
25 -import variables from '@/assets/styles/variables.scss' 27 +import { mapGetters, mapState } from "vuex";
  28 +import Logo from "./Logo";
  29 +import SidebarItem from "./SidebarItem";
  30 +import variables from "@/assets/styles/variables.scss";
26 31
27 export default { 32 export default {
28 components: { SidebarItem, Logo }, 33 components: { SidebarItem, Logo },
29 computed: { 34 computed: {
30 - ...mapGetters([  
31 - 'permission_routes',  
32 - 'sidebar'  
33 - ]), 35 + ...mapState(["settings"]),
  36 + ...mapGetters(["permission_routes", "sidebar"]),
34 activeMenu() { 37 activeMenu() {
35 - const route = this.$route  
36 - const { meta, path } = route 38 + const route = this.$route;
  39 + const { meta, path } = route;
37 // if set path, the sidebar will highlight the path you set 40 // if set path, the sidebar will highlight the path you set
38 if (meta.activeMenu) { 41 if (meta.activeMenu) {
39 - return meta.activeMenu 42 + return meta.activeMenu;
40 } 43 }
41 - return path 44 + return path;
42 }, 45 },
43 showLogo() { 46 showLogo() {
44 - return this.$store.state.settings.sidebarLogo 47 + return this.$store.state.settings.sidebarLogo;
45 }, 48 },
46 variables() { 49 variables() {
47 - return variables 50 + return variables;
48 }, 51 },
49 isCollapse() { 52 isCollapse() {
50 - return !this.sidebar.opened 53 + return !this.sidebar.opened;
51 } 54 }
52 } 55 }
53 -} 56 +};
54 </script> 57 </script>
@@ -9,11 +9,16 @@ @@ -9,11 +9,16 @@
9 :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }" 9 :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
10 tag="span" 10 tag="span"
11 class="tags-view-item" 11 class="tags-view-item"
  12 + :style="activeStyle(tag)"
12 @click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''" 13 @click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''"
13 @contextmenu.prevent.native="openMenu(tag,$event)" 14 @contextmenu.prevent.native="openMenu(tag,$event)"
14 > 15 >
15 {{ tag.title }} 16 {{ tag.title }}
16 - <span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" /> 17 + <span
  18 + v-if="!isAffix(tag)"
  19 + class="el-icon-close"
  20 + @click.prevent.stop="closeSelectedTag(tag)"
  21 + />
17 </router-link> 22 </router-link>
18 </scroll-pane> 23 </scroll-pane>
19 <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu"> 24 <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
@@ -26,8 +31,8 @@ @@ -26,8 +31,8 @@
26 </template> 31 </template>
27 32
28 <script> 33 <script>
29 -import ScrollPane from './ScrollPane'  
30 -import path from 'path' 34 +import ScrollPane from "./ScrollPane";
  35 +import path from "path";
31 36
32 export default { 37 export default {
33 components: { ScrollPane }, 38 components: { ScrollPane },
@@ -38,160 +43,174 @@ export default { @@ -38,160 +43,174 @@ export default {
38 left: 0, 43 left: 0,
39 selectedTag: {}, 44 selectedTag: {},
40 affixTags: [] 45 affixTags: []
41 - } 46 + };
42 }, 47 },
43 computed: { 48 computed: {
44 visitedViews() { 49 visitedViews() {
45 - return this.$store.state.tagsView.visitedViews 50 + return this.$store.state.tagsView.visitedViews;
46 }, 51 },
47 routes() { 52 routes() {
48 - return this.$store.state.permission.routes 53 + return this.$store.state.permission.routes;
  54 + },
  55 + theme() {
  56 + return this.$store.state.settings.theme;
49 } 57 }
50 }, 58 },
51 watch: { 59 watch: {
52 $route() { 60 $route() {
53 - this.addTags()  
54 - this.moveToCurrentTag() 61 + this.addTags();
  62 + this.moveToCurrentTag();
55 }, 63 },
56 visible(value) { 64 visible(value) {
57 if (value) { 65 if (value) {
58 - document.body.addEventListener('click', this.closeMenu) 66 + document.body.addEventListener("click", this.closeMenu);
59 } else { 67 } else {
60 - document.body.removeEventListener('click', this.closeMenu) 68 + document.body.removeEventListener("click", this.closeMenu);
61 } 69 }
62 } 70 }
63 }, 71 },
64 mounted() { 72 mounted() {
65 - this.initTags()  
66 - this.addTags() 73 + this.initTags();
  74 + this.addTags();
67 }, 75 },
68 methods: { 76 methods: {
69 isActive(route) { 77 isActive(route) {
70 - return route.path === this.$route.path 78 + return route.path === this.$route.path;
  79 + },
  80 + activeStyle(tag) {
  81 + if (!this.isActive(tag)) return {};
  82 + return {
  83 + "background-color": this.theme,
  84 + "border-color": this.theme
  85 + };
71 }, 86 },
72 isAffix(tag) { 87 isAffix(tag) {
73 - return tag.meta && tag.meta.affix 88 + return tag.meta && tag.meta.affix;
74 }, 89 },
75 - filterAffixTags(routes, basePath = '/') {  
76 - let tags = [] 90 + filterAffixTags(routes, basePath = "/") {
  91 + let tags = [];
77 routes.forEach(route => { 92 routes.forEach(route => {
78 if (route.meta && route.meta.affix) { 93 if (route.meta && route.meta.affix) {
79 - const tagPath = path.resolve(basePath, route.path) 94 + const tagPath = path.resolve(basePath, route.path);
80 tags.push({ 95 tags.push({
81 fullPath: tagPath, 96 fullPath: tagPath,
82 path: tagPath, 97 path: tagPath,
83 name: route.name, 98 name: route.name,
84 meta: { ...route.meta } 99 meta: { ...route.meta }
85 - }) 100 + });
86 } 101 }
87 if (route.children) { 102 if (route.children) {
88 - const tempTags = this.filterAffixTags(route.children, route.path) 103 + const tempTags = this.filterAffixTags(route.children, route.path);
89 if (tempTags.length >= 1) { 104 if (tempTags.length >= 1) {
90 - tags = [...tags, ...tempTags] 105 + tags = [...tags, ...tempTags];
91 } 106 }
92 } 107 }
93 - })  
94 - return tags 108 + });
  109 + return tags;
95 }, 110 },
96 initTags() { 111 initTags() {
97 - const affixTags = this.affixTags = this.filterAffixTags(this.routes) 112 + const affixTags = (this.affixTags = this.filterAffixTags(this.routes));
98 for (const tag of affixTags) { 113 for (const tag of affixTags) {
99 // Must have tag name 114 // Must have tag name
100 if (tag.name) { 115 if (tag.name) {
101 - this.$store.dispatch('tagsView/addVisitedView', tag) 116 + this.$store.dispatch("tagsView/addVisitedView", tag);
102 } 117 }
103 } 118 }
104 }, 119 },
105 addTags() { 120 addTags() {
106 - const { name } = this.$route 121 + const { name } = this.$route;
107 if (name) { 122 if (name) {
108 - this.$store.dispatch('tagsView/addView', this.$route) 123 + this.$store.dispatch("tagsView/addView", this.$route);
109 } 124 }
110 - return false 125 + return false;
111 }, 126 },
112 moveToCurrentTag() { 127 moveToCurrentTag() {
113 - const tags = this.$refs.tag 128 + const tags = this.$refs.tag;
114 this.$nextTick(() => { 129 this.$nextTick(() => {
115 for (const tag of tags) { 130 for (const tag of tags) {
116 if (tag.to.path === this.$route.path) { 131 if (tag.to.path === this.$route.path) {
117 - this.$refs.scrollPane.moveToTarget(tag) 132 + this.$refs.scrollPane.moveToTarget(tag);
118 // when query is different then update 133 // when query is different then update
119 if (tag.to.fullPath !== this.$route.fullPath) { 134 if (tag.to.fullPath !== this.$route.fullPath) {
120 - this.$store.dispatch('tagsView/updateVisitedView', this.$route) 135 + this.$store.dispatch("tagsView/updateVisitedView", this.$route);
121 } 136 }
122 - break 137 + break;
123 } 138 }
124 } 139 }
125 - }) 140 + });
126 }, 141 },
127 refreshSelectedTag(view) { 142 refreshSelectedTag(view) {
128 - this.$store.dispatch('tagsView/delCachedView', view).then(() => {  
129 - const { fullPath } = view 143 + this.$store.dispatch("tagsView/delCachedView", view).then(() => {
  144 + const { fullPath } = view;
130 this.$nextTick(() => { 145 this.$nextTick(() => {
131 this.$router.replace({ 146 this.$router.replace({
132 - path: '/redirect' + fullPath  
133 - })  
134 - })  
135 - }) 147 + path: "/redirect" + fullPath
  148 + });
  149 + });
  150 + });
136 }, 151 },
137 closeSelectedTag(view) { 152 closeSelectedTag(view) {
138 - this.$store.dispatch('tagsView/delView', view).then(({ visitedViews }) => {  
139 - if (this.isActive(view)) {  
140 - this.toLastView(visitedViews, view)  
141 - }  
142 - }) 153 + this.$store
  154 + .dispatch("tagsView/delView", view)
  155 + .then(({ visitedViews }) => {
  156 + if (this.isActive(view)) {
  157 + this.toLastView(visitedViews, view);
  158 + }
  159 + });
143 }, 160 },
144 closeOthersTags() { 161 closeOthersTags() {
145 - this.$router.push(this.selectedTag)  
146 - this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => {  
147 - this.moveToCurrentTag()  
148 - }) 162 + this.$router.push(this.selectedTag);
  163 + this.$store
  164 + .dispatch("tagsView/delOthersViews", this.selectedTag)
  165 + .then(() => {
  166 + this.moveToCurrentTag();
  167 + });
149 }, 168 },
150 closeAllTags(view) { 169 closeAllTags(view) {
151 - this.$store.dispatch('tagsView/delAllViews').then(({ visitedViews }) => { 170 + this.$store.dispatch("tagsView/delAllViews").then(({ visitedViews }) => {
152 if (this.affixTags.some(tag => tag.path === view.path)) { 171 if (this.affixTags.some(tag => tag.path === view.path)) {
153 - return 172 + return;
154 } 173 }
155 - this.toLastView(visitedViews, view)  
156 - }) 174 + this.toLastView(visitedViews, view);
  175 + });
157 }, 176 },
158 toLastView(visitedViews, view) { 177 toLastView(visitedViews, view) {
159 - const latestView = visitedViews.slice(-1)[0] 178 + const latestView = visitedViews.slice(-1)[0];
160 if (latestView) { 179 if (latestView) {
161 - this.$router.push(latestView.fullPath) 180 + this.$router.push(latestView.fullPath);
162 } else { 181 } else {
163 // now the default is to redirect to the home page if there is no tags-view, 182 // now the default is to redirect to the home page if there is no tags-view,
164 // you can adjust it according to your needs. 183 // you can adjust it according to your needs.
165 - if (view.name === 'Dashboard') { 184 + if (view.name === "Dashboard") {
166 // to reload home page 185 // to reload home page
167 - this.$router.replace({ path: '/redirect' + view.fullPath }) 186 + this.$router.replace({ path: "/redirect" + view.fullPath });
168 } else { 187 } else {
169 - this.$router.push('/') 188 + this.$router.push("/");
170 } 189 }
171 } 190 }
172 }, 191 },
173 openMenu(tag, e) { 192 openMenu(tag, e) {
174 - const menuMinWidth = 105  
175 - const offsetLeft = this.$el.getBoundingClientRect().left // container margin left  
176 - const offsetWidth = this.$el.offsetWidth // container width  
177 - const maxLeft = offsetWidth - menuMinWidth // left boundary  
178 - const left = e.clientX - offsetLeft + 15 // 15: margin right 193 + const menuMinWidth = 105;
  194 + const offsetLeft = this.$el.getBoundingClientRect().left; // container margin left
  195 + const offsetWidth = this.$el.offsetWidth; // container width
  196 + const maxLeft = offsetWidth - menuMinWidth; // left boundary
  197 + const left = e.clientX - offsetLeft + 15; // 15: margin right
179 198
180 if (left > maxLeft) { 199 if (left > maxLeft) {
181 - this.left = maxLeft 200 + this.left = maxLeft;
182 } else { 201 } else {
183 - this.left = left 202 + this.left = left;
184 } 203 }
185 204
186 - this.top = e.clientY  
187 - this.visible = true  
188 - this.selectedTag = tag 205 + this.top = e.clientY;
  206 + this.visible = true;
  207 + this.selectedTag = tag;
189 }, 208 },
190 closeMenu() { 209 closeMenu() {
191 - this.visible = false 210 + this.visible = false;
192 } 211 }
193 } 212 }
194 -} 213 +};
195 </script> 214 </script>
196 215
197 <style lang="scss" scoped> 216 <style lang="scss" scoped>
@@ -200,7 +219,7 @@ export default { @@ -200,7 +219,7 @@ export default {
200 width: 100%; 219 width: 100%;
201 background: #fff; 220 background: #fff;
202 border-bottom: 1px solid #d8dce5; 221 border-bottom: 1px solid #d8dce5;
203 - box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04); 222 + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04);
204 .tags-view-wrapper { 223 .tags-view-wrapper {
205 .tags-view-item { 224 .tags-view-item {
206 display: inline-block; 225 display: inline-block;
@@ -226,7 +245,7 @@ export default { @@ -226,7 +245,7 @@ export default {
226 color: #fff; 245 color: #fff;
227 border-color: #42b983; 246 border-color: #42b983;
228 &::before { 247 &::before {
229 - content: ''; 248 + content: "";
230 background: #fff; 249 background: #fff;
231 display: inline-block; 250 display: inline-block;
232 width: 8px; 251 width: 8px;
@@ -249,7 +268,7 @@ export default { @@ -249,7 +268,7 @@ export default {
249 font-size: 12px; 268 font-size: 12px;
250 font-weight: 400; 269 font-weight: 400;
251 color: #333; 270 color: #333;
252 - box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3); 271 + box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
253 li { 272 li {
254 margin: 0; 273 margin: 0;
255 padding: 7px 16px; 274 padding: 7px 16px;
@@ -272,10 +291,10 @@ export default { @@ -272,10 +291,10 @@ export default {
272 vertical-align: 2px; 291 vertical-align: 2px;
273 border-radius: 50%; 292 border-radius: 50%;
274 text-align: center; 293 text-align: center;
275 - transition: all .3s cubic-bezier(.645, .045, .355, 1); 294 + transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
276 transform-origin: 100% 50%; 295 transform-origin: 100% 50%;
277 &:before { 296 &:before {
278 - transform: scale(.6); 297 + transform: scale(0.6);
279 display: inline-block; 298 display: inline-block;
280 vertical-align: -3px; 299 vertical-align: -3px;
281 } 300 }