side-nav.vue 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. <style>
  2. .side-nav {
  3. width: 100%;
  4. box-sizing: border-box;
  5. padding-right: 30px;
  6. li {
  7. list-style: none;
  8. }
  9. ul {
  10. padding: 0;
  11. margin: 0;
  12. overflow: hidden;
  13. }
  14. .nav-dropdown {
  15. margin-bottom: 6px;
  16. width: 100%;
  17. span {
  18. display: block;
  19. width: 100%;
  20. font-size: 16px;
  21. color: #5e6d82;
  22. line-height: 40px;
  23. transition: .2s;
  24. border-bottom: 1px solid #eaeefb;
  25. &:hover {
  26. cursor: pointer;
  27. }
  28. }
  29. i {
  30. transition: .2s;
  31. font-size: 12px;
  32. color: #d3dce6;
  33. }
  34. @when active {
  35. span, i {
  36. color: #20a0ff;
  37. }
  38. i {
  39. transform: rotateZ(180deg) translateY(2px);
  40. }
  41. }
  42. &:hover {
  43. span, i {
  44. color: #20a0ff;
  45. }
  46. }
  47. }
  48. .nav-item {
  49. a {
  50. font-size: 16px;
  51. color: #5e6d82;
  52. line-height: 40px;
  53. height: 40px;
  54. margin: 0;
  55. padding: 0;
  56. text-decoration: none;
  57. display: block;
  58. position: relative;
  59. transition: all .3s;
  60. &.active {
  61. color: #20a0ff;
  62. }
  63. }
  64. .nav-item {
  65. a {
  66. display: block;
  67. height: 40px;
  68. line-height: 40px;
  69. font-size: 13px;
  70. padding-left: 24px;
  71. &:hover {
  72. color: #20a0ff;
  73. }
  74. }
  75. }
  76. }
  77. .nav-group__title {
  78. font-size: 12px;
  79. color: #99a9bf;
  80. padding-left: 8px;
  81. line-height: 26px;
  82. margin-top: 10px;
  83. }
  84. }
  85. .nav-dropdown-list {
  86. width: 120px;
  87. margin-top: -8px;
  88. li {
  89. font-size: 14px;
  90. }
  91. }
  92. </style>
  93. <template>
  94. <div class="side-nav" :style="navStyle">
  95. <el-dropdown
  96. v-show="isComponentPage"
  97. trigger="click"
  98. class="nav-dropdown"
  99. :class="{ 'is-active': dropdownVisible }">
  100. <span>
  101. {{ langConfig.dropdown }}{{ version }}
  102. <i class="el-icon-caret-bottom el-icon--right"></i>
  103. </span>
  104. <el-dropdown-menu
  105. slot="dropdown"
  106. :offset="-80"
  107. class="nav-dropdown-list"
  108. @input="handleDropdownToggle">
  109. <el-dropdown-item
  110. v-for="item in Object.keys(versions)"
  111. @click.native="switchVersion(item)">
  112. {{ item }}
  113. </el-dropdown-item>
  114. </el-dropdown-menu>
  115. </el-dropdown>
  116. <ul>
  117. <li class="nav-item" v-for="item in data">
  118. <a v-if="!item.path" @click="expandMenu">{{item.name}}</a>
  119. <router-link
  120. v-else
  121. active-class="active"
  122. :to="base + item.path"
  123. exact
  124. v-text="item.title || item.name">
  125. </router-link>
  126. <ul class="pure-menu-list sub-nav" v-if="item.children">
  127. <li class="nav-item" v-for="navItem in item.children">
  128. <router-link
  129. class=""
  130. active-class="active"
  131. :to="base + navItem.path"
  132. exact
  133. v-text="navItem.title || navItem.name">
  134. </router-link>
  135. </li>
  136. </ul>
  137. <template v-if="item.groups">
  138. <div class="nav-group" v-for="group in item.groups">
  139. <div class="nav-group__title" @click="expandMenu">{{group.groupName}}</div>
  140. <ul class="pure-menu-list">
  141. <li
  142. class="nav-item"
  143. v-for="navItem in group.list"
  144. v-if="!navItem.disabled">
  145. <router-link
  146. active-class="active"
  147. :to="base + navItem.path"
  148. exact
  149. v-text="navItem.title"></router-link>
  150. </li>
  151. </ul>
  152. </div>
  153. </template>
  154. </li>
  155. </ul>
  156. </div>
  157. </template>
  158. <script>
  159. import compoLang from '../i18n/component.json';
  160. export default {
  161. props: {
  162. data: Array,
  163. base: {
  164. type: String,
  165. default: ''
  166. }
  167. },
  168. data() {
  169. return {
  170. highlights: [],
  171. navState: [],
  172. isSmallScreen: false,
  173. versions: [],
  174. version: '',
  175. dropdownVisible: false
  176. };
  177. },
  178. watch: {
  179. '$route.path'() {
  180. this.handlePathChange();
  181. }
  182. },
  183. computed: {
  184. navStyle() {
  185. return this.isSmallScreen ? { 'padding-bottom': '60px' } : {};
  186. },
  187. isComponentPage() {
  188. return /^component-/.test(this.$route.name);
  189. },
  190. langConfig() {
  191. return compoLang.filter(config => config.lang === this.$route.meta.lang)[0]['nav'];
  192. }
  193. },
  194. methods: {
  195. switchVersion(version) {
  196. if (version === this.version) return;
  197. location.href = `${ location.origin }/${ this.versions[version] }/${ location.hash } `;
  198. },
  199. handleResize() {
  200. this.isSmallScreen = document.documentElement.clientWidth < 768;
  201. this.handlePathChange();
  202. },
  203. handlePathChange() {
  204. if (!this.isSmallScreen) {
  205. this.expandAllMenu();
  206. return;
  207. }
  208. this.$nextTick(() => {
  209. this.hideAllMenu();
  210. let activeAnchor = this.$el.querySelector('a.active');
  211. let ul = activeAnchor.parentNode;
  212. while (ul.tagName !== 'UL') {
  213. ul = ul.parentNode;
  214. }
  215. ul.style.height = 'auto';
  216. });
  217. },
  218. hideAllMenu() {
  219. [].forEach.call(this.$el.querySelectorAll('.pure-menu-list'), ul => {
  220. ul.style.height = '0';
  221. });
  222. },
  223. expandAllMenu() {
  224. [].forEach.call(this.$el.querySelectorAll('.pure-menu-list'), ul => {
  225. ul.style.height = 'auto';
  226. });
  227. },
  228. expandMenu(event) {
  229. if (!this.isSmallScreen) return;
  230. let target = event.currentTarget;
  231. if (!target.nextElementSibling || target.nextElementSibling.tagName !== 'UL') return;
  232. this.hideAllMenu();
  233. event.currentTarget.nextElementSibling.style.height = 'auto';
  234. },
  235. handleDropdownToggle(visible) {
  236. this.dropdownVisible = visible;
  237. }
  238. },
  239. created() {
  240. const xhr = new XMLHttpRequest();
  241. xhr.onreadystatechange = _ => {
  242. if (xhr.readyState === 4 && xhr.status === 200) {
  243. this.versions = JSON.parse(xhr.responseText);
  244. const pathname = location.pathname.replace(/\//, '');
  245. if (pathname.length > 0) {
  246. this.version = pathname;
  247. } else {
  248. const versionArr = Object.keys(this.versions);
  249. this.version = versionArr[versionArr.length - 1];
  250. }
  251. }
  252. };
  253. xhr.open('GET', '/versions.json');
  254. xhr.send();
  255. },
  256. mounted() {
  257. this.handleResize();
  258. window.addEventListener('resize', this.handleResize);
  259. },
  260. beforeDestroy() {
  261. window.removeEventListener('resize', this.handleResize);
  262. }
  263. };
  264. </script>