diff --git a/src/layout/components/TagsView/ScrollPane.vue b/src/layout/components/TagsView/ScrollPane.vue
index 34a7e55f..655b6cce 100644
--- a/src/layout/components/TagsView/ScrollPane.vue
+++ b/src/layout/components/TagsView/ScrollPane.vue
@@ -34,11 +34,12 @@ export default {
     emitScroll() {
       this.$emit('scroll')
     },
-    moveToTarget(currentTag) {
+    moveToTarget(currentRoute) {
       const $container = this.$refs.scrollContainer.$el
       const $containerWidth = $container.offsetWidth
       const $scrollWrapper = this.scrollWrapper
-      const tagList = this.$parent.$refs.tag
+      const tagList = Array.from(window.document.querySelectorAll('#tags-view-container .tags-view-item'))
+      const currentTag = tagList.find(i => i.dataset.fullPath === currentRoute.fullPath)
 
       let firstTag = null
       let lastTag = null
@@ -60,10 +61,10 @@ export default {
         const nextTag = tagList[currentIndex + 1]
 
         // the tag's offsetLeft after of nextTag
-        const afterNextTagOffsetLeft = nextTag.$el.offsetLeft + nextTag.$el.offsetWidth + tagAndTagSpacing
+        const afterNextTagOffsetLeft = nextTag.offsetLeft + nextTag.offsetWidth + tagAndTagSpacing
 
         // the tag's offsetLeft before of prevTag
-        const beforePrevTagOffsetLeft = prevTag.$el.offsetLeft - tagAndTagSpacing
+        const beforePrevTagOffsetLeft = prevTag.offsetLeft - tagAndTagSpacing
 
         if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) {
           $scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth
diff --git a/src/layout/components/TagsView/index.vue b/src/layout/components/TagsView/index.vue
index d2a56e70..7a3d3067 100644
--- a/src/layout/components/TagsView/index.vue
+++ b/src/layout/components/TagsView/index.vue
@@ -1,20 +1,22 @@
 <template>
   <div id="tags-view-container" class="tags-view-container">
     <scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll">
-      <router-link
-        v-for="tag in visitedViews"
-        ref="tag"
-        :key="tag.path"
-        :class="isActive(tag)?'active':''"
-        :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
-        tag="span"
-        class="tags-view-item"
-        @click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''"
-        @contextmenu.prevent.native="openMenu(tag,$event)"
-      >
-        {{ tag.title }}
-        <span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
-      </router-link>
+      <div ref="sortable-wrap">
+        <router-link
+          v-for="tag in visitedViews"
+          :key="tag.path"
+          :class="{ active: isActive(tag), sortable: !isAffix(tag) }"
+          :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
+          tag="span"
+          class="tags-view-item"
+          :data-full-path="tag.fullPath"
+          @click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''"
+          @contextmenu.prevent.native="openMenu(tag,$event)"
+        >
+          {{ tag.title }}
+          <span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
+        </router-link>
+      </div>
     </scroll-pane>
     <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
       <li @click="refreshSelectedTag(selectedTag)">Refresh</li>
@@ -28,6 +30,7 @@
 <script>
 import ScrollPane from './ScrollPane'
 import path from 'path'
+import Sortable from 'sortablejs'
 
 export default {
   components: { ScrollPane },
@@ -64,6 +67,7 @@ export default {
   mounted() {
     this.initTags()
     this.addTags()
+    this.initSortableTags()
   },
   methods: {
     isActive(route) {
@@ -104,24 +108,32 @@ export default {
     },
     addTags() {
       const { name } = this.$route
-      if (name) {
+      if (!name) {
+        return
+      }
+      const res = this.visitedViews.find(v => v.path === this.$route.path)
+      if (res) {
+        // when query is different then update
+        if (res.fullPath !== this.$route.fullPath) {
+          this.$store.dispatch('tagsView/updateVisitedView', this.$route)
+        }
+      } else {
         this.$store.dispatch('tagsView/addView', this.$route)
       }
-      return false
+    },
+    initSortableTags() {
+      new Sortable(this.$refs['sortable-wrap'], {
+        draggable: '.sortable',
+        animation: 200,
+        onUpdate: event => {
+          const { oldIndex, newIndex } = event
+          this.$store.dispatch('tagsView/moveView', { oldIndex, newIndex })
+        }
+      })
     },
     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('tagsView/updateVisitedView', this.$route)
-            }
-            break
-          }
-        }
+        this.$refs.scrollPane.moveToTarget(this.$route)
       })
     },
     refreshSelectedTag(view) {
diff --git a/src/store/modules/tagsView.js b/src/store/modules/tagsView.js
index 57e72421..ab2ec298 100644
--- a/src/store/modules/tagsView.js
+++ b/src/store/modules/tagsView.js
@@ -63,6 +63,9 @@ const mutations = {
         break
       }
     }
+  },
+  MOVE_VIEW: (state, { oldIndex, newIndex }) => {
+    state.visitedViews.splice(newIndex, 0, state.visitedViews.splice(oldIndex, 1)[0])
   }
 }
 
@@ -149,6 +152,9 @@ const actions = {
 
   updateVisitedView({ commit }, view) {
     commit('UPDATE_VISITED_VIEW', view)
+  },
+  moveView({ commit }, arg) {
+    commit('MOVE_VIEW', arg)
   }
 }