MrShi
2025-03-31 a96d905ebaca25c0d9738cb61fd52713f7104fd8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
<template>
  <div class="tags-view-style" style="display: flex; overflow-x: scroll">
    <i
      class="el-icon-arrow-left btn"
      v-if="leftStatus"
      :class="leftStatus ? 'nor-btn' : 'ban-btn'"
      @click="scrollToStart()"
    ></i>
    <div id="tags-box" ref="tags">
      <div
        v-for="(item, index) in tags"
        :key="index"
        :id="'tags-box-' + index"
        @contextmenu.prevent="openMenu(item, $event)"
        :class="isActive(item.url, item.index,index) ? 'active' : ''"
        class="tagsview"
        @click="tagsmenu(item, index)"
      >
        {{ item.label }}
        <!-- 这个地方一定要click加个stop阻止,不然会因为事件冒泡一直触发父元素的点击事件,无法跳转另一个路由 -->
        <span
          v-if="tags.length > 1"
          class="el-icon-close tagsicon"
          @click.stop="handleClose(item, index)"
        ></span>
        <!-- <ul v-show="visible" class="contextmenu" :style="{left:left+'px',top:top+'px'}">
          <li @click.stop="rightClose()">关闭</li>
          <li @click.stop="cleartags($route.path)">关闭其他</li>
        </ul> -->
      </div>
    </div>
    <i
      class="el-icon-arrow-right btn"
      v-if="rightStatus"
      :class="rightStatus ? 'nor-btn' : 'ban-btn'"
      @click="scrollToEnd()"
    ></i>
  </div>
</template>
 
<script>
// 这个就是导入vuex的数据,配合下面...map用
import { mapState, mapMutations } from 'vuex'
export default {
  data () {
    return {
      // 右键菜单隐藏对应布尔值
      visible: false,
      // 右键菜单对应位置
      top: 0,
      left: 0,
      leftStatus: false,
      rightStatus: false
    }
  },
  computed: {
    // 引入vuex中state中的tags数据,一样this调用就行
    ...mapState(['tags'])
  },
  watch: {
    // 监听右键菜单的值是否为true,如果是就创建全局监听点击事件,触发closeMenu事件隐藏菜单,如果是false就删除监听
    visible (value) {
      if (value) {
        document.body.addEventListener('click', this.closeMenu)
      } else {
        document.body.removeEventListener('click', this.closeMenu)
      }
    },
    $route (to, from) {
      this.tags.forEach((item, index) => {
        // if (item.url === to.path && item.index === to.query.index) {
        if (item.url === to.path && item.index === to.query.index) {
          const tagsDiv = document.getElementById('tags-box')
          if (index) {
            tagsDiv.scrollTo(index * 110, 0)
          } else {
            tagsDiv.scrollTo(0, 0)
          }
        }
      })
     /* var that =this
      this.$nextTick(() => {
        setTimeout(function(){ that.computeTableHeight()},1000)
      })*/
    }
  },
  mounted () {
    // window.addEventListener('resize', this.computeTableHeight)
    this.$refs.tags.addEventListener('scroll', e => {
      if (this.$refs.tags.scrollLeft > 0) {
        this.leftStatus = true
      } else {
        this.leftStatus = false
      }
      if (this.$refs.tags.scrollLeft + this.$refs.tags.clientWidth < this.$refs.tags.scrollWidth) {
        this.rightStatus = true
      } else {
        this.rightStatus = false
      }
    }, false)
  },
  methods: {
    // 引入vuex中mutation方法,可以直接this.xxx调用他
    ...mapMutations(['closeTab', 'cleartagsview']),
    // 点击叉叉删除的事件
    rightClose () {
      this.visible = false
      if (this.tags.length == 1) {
        return
      }
      const index = this.tags.indexOf(this.selectedTag)
      this.handleClose(this.selectedTag, index)
    },
    handleClose (item, index) {
      if (this.tags.length == 1) {
        return
      }
      // 先把长度保存下来后面用来比较做判断条件
      const length = this.tags.length - 1
      // vuex调方法,上面...map引入的vuex方法,不会这种方法的看vue官网文档
      this.closeTab(item)
      // 如果关闭的标签不是当前路由的话,就不跳转
      if (item.url !== this.$route.path) {
        return
      }
      // 判断:如果index和length是一样的,那就代表都是一样的长度,就是最后一位,那就往左跳转一个
      if (index === length) {
        // 再判断:如果length=0,也就是说你删完了所有标签
        if (length === 0) {
          // 那么再判断:如果当前路由不等于index,也就是我首页的路由
          if (this.$route.path !== '/index') {
            // 那么就跳转首页。这一步的意思是:如果删除的最后一个标签不是首页就统一跳转首页,如果你删除的最后一个标签是首页标签,已经在这个首页路由上了,你还跳个什么呢。这不重复操作了吗。
            this.$router.push({ path: '/index' })
          }
        } else {
          // 那么,如果上面的条件都不成立,没有length=0.也就是说你还有好几个标签,并且你删除的是最后一位标签,那么就往左边挪一位跳转路由
          this.$router.push({ path: this.tags[index - 1].url, query: { param: this.tags[index - 1].params } })
        }
      } else {
        // 如果你点击不是最后一位标签,点的前面的,那就往右边跳转
        this.$router.push({ path: this.tags[index].url, query: { param: this.tags[index].params } })
      }
    },
    // 点击跳转路由
    tagsmenu (item, index) {
      console.log('tagsmenu')
      // 判断:当前路由不等于当前选中项的url,也就代表你点击的不是现在选中的标签,是另一个标签就跳转过去,如果你点击的是现在已经选中的标签就不用跳转了,因为你已经在这个路由了还跳什么呢。
      if (this.$route.path !== item.url) {
        // 用path的跳转方法把当前项的url当作地址跳转。
        this.$router.push({ path: item.url, query: { index: this.tags[index].index, param: this.tags[index].params, time: (Math.random().toString())} })
        // this.$router.push( item.url)
        const tagsDiv = document.getElementById('tags-box')
        if (index) {
          tagsDiv.scrollTo(index * 110, 0)
        }
      }
      // this.computeTableHeight()
    },
    computeTableHeight () {
      this.$nextTick(() => {
        const height = window.innerHeight
        console.log('toolbar********************************', document.getElementsByClassName('toolbar').length)
        // console.log('main_app========================:' + height)
        const height13 = this.getEleHeghtByClassName('common-header', 0)
        const height5 = document.getElementsByTagName('thead') && document.getElementsByTagName('thead')[0] ? document.getElementsByTagName('thead')[0].clientHeight : 0
        if (document.getElementsByClassName('main_app') && document.getElementsByClassName('main_app')[0]) {
          // console.log('main_app========================')
          // alert(height)
          const height3 = this.getEleHeghtByClassName('main-header', 0)
          const height4 = this.getEleHeghtByClassName('table-pagination', 0)
          const height2 = this.getEleHeghtByClassName('toolbar', 0)
          const height6 = this.getEleHeghtByClassName('doumee-filter', 0, 16)
          const height7 = this.getEleHeghtByClassName('pt16', 0, 0)
          const height9 = this.getEleHeghtByClassName('static_wrap', 0)
          const height10 = this.getEleHeghtByClassName('query_btns', 0)
          const height11 = this.getEleHeghtByClassName('el-tabs-ele', 0)
          const height12 = this.getEleHeghtByClassName('platgroup_tabs', 0)
          this.$router.app.$store.commit('setTableHeightNew', height - height13 - height3 - height5 - height6 - height2 - height7 - height4 - height9 - height10 - height11 - height12)
          // console.log('gableHeightNew', this.$router.app.$store.state.tableHeightNew)
        } else {
          // console.log('tableLayout========================')
          const height1 = this.getEleHeghtByClassName('table-search-form', 40, 16)
          const height3 = this.getEleHeghtByClassName('main-header', 0)
          const height4 = this.getEleHeghtByClassName('table-pagination', 0)
          const height2 = this.getEleHeghtByClassName('toolbar', 0)
          // console.log('defualtlength', document.getElementsByClassName('table-search-form').length)
          this.$router.app.$store.commit('setTableHeightNew', height - height4 - height3 - height2 - height1 - height5 - height13)
          // console.log('gableHeightNew', this.$router.app.$store.state.tableHeightNew)
        }
      })
    },
    getEleHeghtByClassName (name, dv, margin) {
      if ((document.getElementsByClassName(name) && document.getElementsByClassName(name)[0])) {
        let t = 0
        document.getElementsByClassName(name).forEach(e => {
          // console.log(name + '========================' + t + ':' + e.clientHeight)
          t++
        })
        return document.getElementsByClassName(name)[document.getElementsByClassName(name).length - 1].clientHeight + (margin || 0)
      }
      return dv || 0
    },
    // 通过判断路由一致返回布尔值添加class,添加高亮效果
    isActive (route, params, index) {
      const res = (route === this.$route.path && params == this.$route.query.index)
      return res
    },
    scrollToStart () {
      const tagsDiv = document.getElementById('tags-box')
      tagsDiv.scrollTo(0, 0)
    },
    scrollToEnd () {
      const tagsDiv = document.getElementById('tags-box')
      tagsDiv.scrollTo(tagsDiv.scrollWidth, 0)
    },
    // 右键事件,显示右键菜单,并固定好位置。
    openMenu (tag, e) {
      this.visible = true
      this.selectedTag = tag
      const offsetLeft = this.$el.getBoundingClientRect().left
      console.log(tag, e)
      this.left = e.clientX - offsetLeft + 60 // 右键菜单距离左边的距离
      this.top = e.clientY + 20 // 右键菜单距离上面的距离           这两个可以更改,看看自己的右键菜单在什么位置,自己调
      // this.computeTableHeight()
    },
    // 隐藏右键菜单
    closeMenu () {
      this.visible = false
    },
    // 右键菜单关闭所有选项,触发vuex中的方法,把当前路由当参数传过去用于判断
    cleartags (val) {
      this.visible = false
      this.cleartagsview(val)
    }
  }
}
</script>
 
<style lang="scss" scoped>
.btn {
  font-size: 20px;
  line-height: 48px;
  height: 48px;
}
.nor-btn {
  color: #666;
  cursor: pointer;
  &:hover {
    color: #2080f7;
  }
}
 
.ban-btn {
  color: #999;
  cursor: not-allowed;
}
 
#tags-box {
  overflow-x: hidden;
  white-space: nowrap;
  flex: 1;
  // width: 240px;
  scrollbar-width: none; /* firefox */
  -ms-overflow-style: none; /* IE 10+ */
  &::-webkit-scrollbar {
    display: none; /* Chrome Safari */
  }
}
#tags-box::-webkit-scrollbar {
  display: none; /* Chrome Safari */
}
//标签导航样式
.tagsview {
  cursor: pointer;
  // margin-left: 4px;
  height: 48px;
  line-height: 48px;
  padding: 0 8px 0 24px;
  // border: 1px solid #d8dce5;
  // border-radius: 5px;
  color: #000;
  font-size: 14px;
  display: inline-block;
}
//叉号鼠标经过样式
.tagsicon:hover {
  color: #f56c6c;
}
//标签高亮
.active {
  color: #2080f7;
  border-bottom: 2px solid #2080f7;
}
//右键菜单样式
.contextmenu {
  margin: 0;
  background: #fff;
  z-index: 100;
  position: absolute;
  list-style-type: none;
  padding: 5px 0;
  border-radius: 4px;
  font-size: 12px;
  font-weight: 400;
  color: #333;
  box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
  li {
    margin: 0;
    padding: 7px 16px;
    cursor: pointer;
    &:hover {
      background: #eee;
    }
  }
}
.tags-view-style {
  scrollbar-width: none; /* firefox */
  -ms-overflow-style: none; /* IE 10+ */
  &::-webkit-scrollbar {
    display: none; /* Chrome Safari */
  }
}
</style>