|
1 | 1 | <template> |
2 | 2 | <div> |
3 | | - <div v-if="level===0" class="updateInfo not-print"> |
| 3 | + <div v-if="level === 0" class="updateInfo not-print"> |
4 | 4 | 标记显示出 |
5 | 5 | <select style="height: 23px;" v-model="updateDays"> |
6 | 6 | <option value="0" selected>当天</option> |
|
13 | 13 | 内更新的内容 |
14 | 14 | </div> |
15 | 15 | <ol> |
16 | | - <li v-for="page in information"> |
| 16 | + <li v-for="page in information" :key="page.links || page.title"> |
17 | 17 | <span v-if="page.links != null"> |
18 | 18 | <a :href="page.links"> |
19 | | - <span :class="'level'+level">{{page.title}}</span> |
| 19 | + <span :class="'level' + level">{{ page.title }}</span> |
20 | 20 | </a> |
21 | 21 | <div class="not-print" style="display: inline-block"> |
22 | 22 | <Badge type="error" v-if="checkUpdate(page)"> |
23 | | - {{page.update === 0 ? '当天更新': page.update+'天前更新'}} |
| 23 | + {{ page.update === 0 ? '当天更新' : page.update + '天前更新' }} |
24 | 24 | </Badge> |
25 | 25 | </div> |
26 | | - <span class="words">{{page.words}}</span> |
| 26 | + <span class="words">{{ page.words }}</span> |
27 | 27 | </span> |
28 | | - <span v-else :class="'level'+level"> |
29 | | - {{page.title}} |
30 | | - <span class="words">{{page.words}}</span> |
| 28 | + <span v-else :class="'level' + level"> |
| 29 | + {{ page.title }} |
| 30 | + <span class="words">{{ page.words }}</span> |
31 | 31 | </span> |
32 | | - <GlobalTOC v-if="showDays === undefined" :pages="page.children" :level="level + 1" :showDays="updateDays"/> |
33 | | - <GlobalTOC v-else :pages="page.children" :level="level + 1" :showDays="showDays"/> |
| 32 | + <GlobalTOC |
| 33 | + v-if="page.children && page.children.length" |
| 34 | + :pages="page.children" |
| 35 | + :level="level + 1" |
| 36 | + :showDays="showDays ?? updateDays" |
| 37 | + /> |
34 | 38 | </li> |
35 | 39 | </ol> |
36 | 40 | </div> |
37 | 41 | </template> |
38 | 42 |
|
39 | 43 | <script> |
40 | | - import Badge from '@vuepress/theme-default/global-components/Badge' |
41 | | - import moment from 'moment' |
42 | | -
|
43 | | - import {resolvePage} from '@parent-theme/util' |
44 | | -
|
45 | | - export default { |
46 | | - name: "GlobalTOC", |
47 | | - data() { |
48 | | - return { |
49 | | - updateDays: 0, |
50 | | - items: [], |
51 | | - information: [] |
52 | | - } |
| 44 | +import { computed, defineComponent, ref } from 'vue' |
| 45 | +import { usePagesData, useThemeData } from '@vuepress/client' |
| 46 | +import Badge from '@vuepress/theme-default/lib/client/components/Badge.vue' |
| 47 | +import moment from 'moment' |
| 48 | +
|
| 49 | +const normalizePath = (value = '') => value.replace(/\/$/, '') |
| 50 | +
|
| 51 | +const resolvePage = (pages, link) => { |
| 52 | + if (!link) return null |
| 53 | + const target = normalizePath(link) |
| 54 | + return pages.find((page) => normalizePath(page.path) === target) || null |
| 55 | +} |
| 56 | +
|
| 57 | +export default defineComponent({ |
| 58 | + name: 'GlobalTOC', |
| 59 | + components: { |
| 60 | + Badge |
| 61 | + }, |
| 62 | + props: { |
| 63 | + pages: { |
| 64 | + type: [Array, String], |
| 65 | + default: null |
53 | 66 | }, |
54 | | - props: ['pages', 'level', 'showDays'], |
55 | | - created: function () { |
56 | | - if (this.pages) { |
57 | | - let origin = (this.pages === '/' ? this.$themeConfig.sidebar : this.pages); |
58 | | - this.items = origin.map(item => { |
59 | | - let page |
60 | | - if (item.path) { |
61 | | - page = resolvePage(this.$site.pages, item.path, this.$route.path) |
62 | | - } else if (typeof (item) === 'string') { |
63 | | - page = resolvePage(this.$site.pages, item, this.$route.path) |
64 | | - } else { |
65 | | - page = item; |
66 | | - } |
67 | | - page.children = item.children |
68 | | - return page; |
69 | | - }) |
70 | | - this.information = this.items.map(item => { |
71 | | - return { |
72 | | - title: this.getTitle(item), |
73 | | - words: this.getWords(item), |
74 | | - links: this.getLinks(item), |
75 | | - update: this.getUpdate(item), |
76 | | - lastUpdated: item.lastUpdated, |
77 | | - children: item.children |
78 | | - } |
79 | | - }) |
80 | | - } |
| 67 | + level: { |
| 68 | + type: Number, |
| 69 | + default: 0 |
81 | 70 | }, |
82 | | - methods: { |
83 | | - checkUpdate: function (page) { |
84 | | - return page.update <= Math.max(this.updateDays, this.showDays); |
85 | | - }, |
86 | | - getTitle: function (page) { |
87 | | - try { |
88 | | - return page.title.replace('✔️ ', '') |
89 | | - } catch (e) { |
90 | | - return "标题错误" |
91 | | - } |
92 | | - }, |
93 | | - getWords: function (page) { |
94 | | - if (page && page.readingTime) { |
95 | | - return `${page.readingTime.words.toLocaleString()} 字 ` |
96 | | - } else { |
97 | | - return "" |
| 71 | + showDays: { |
| 72 | + type: Number, |
| 73 | + default: undefined |
| 74 | + } |
| 75 | + }, |
| 76 | + setup(props) { |
| 77 | + const updateDays = ref(0) |
| 78 | + const pagesData = usePagesData() |
| 79 | + const themeData = useThemeData() |
| 80 | +
|
| 81 | + const items = computed(() => { |
| 82 | + const origin = props.pages |
| 83 | + ? props.pages === '/' |
| 84 | + ? themeData.value.sidebar || [] |
| 85 | + : props.pages |
| 86 | + : themeData.value.sidebar || [] |
| 87 | +
|
| 88 | + return origin.map((item) => { |
| 89 | + const normalizedItem = typeof item === 'string' ? { link: item } : item |
| 90 | + const page = normalizedItem.link |
| 91 | + ? resolvePage(pagesData.value, normalizedItem.link) |
| 92 | + : normalizedItem |
| 93 | + return { |
| 94 | + ...(page || {}), |
| 95 | + children: normalizedItem.children || [] |
98 | 96 | } |
99 | | - }, |
100 | | - getLinks: function (page) { |
101 | | - //return (page.readingTime && page.readingTime.words > 100) ? "/TechShare" + page.path : null |
102 | | - return (page.readingTime && page.readingTime.words > 100) ? page.path : null |
103 | | - }, |
104 | | - getUpdate: function (page) { |
105 | | - let lastDay = new moment(page.lastUpdated, 'L'); |
106 | | - return Math.floor(-1 * moment.duration(lastDay.diff(new Date())).asDays()) |
| 97 | + }) |
| 98 | + }) |
| 99 | +
|
| 100 | + const getTitle = (page) => { |
| 101 | + try { |
| 102 | + return page.title?.replace('✔️ ', '') || '标题错误' |
| 103 | + } catch (error) { |
| 104 | + return '标题错误' |
107 | 105 | } |
108 | 106 | } |
| 107 | +
|
| 108 | + const getWords = (page) => { |
| 109 | + if (page?.readingTime?.words) { |
| 110 | + return `${page.readingTime.words.toLocaleString()} 字 ` |
| 111 | + } |
| 112 | + return '' |
| 113 | + } |
| 114 | +
|
| 115 | + const getLinks = (page) => (page?.readingTime?.words > 100 ? page.path : null) |
| 116 | +
|
| 117 | + const getUpdate = (page) => { |
| 118 | + if (!page?.lastUpdated) return Number.POSITIVE_INFINITY |
| 119 | + const lastDay = new moment(page.lastUpdated, 'L') |
| 120 | + return Math.floor(-1 * moment.duration(lastDay.diff(new Date())).asDays()) |
| 121 | + } |
| 122 | +
|
| 123 | + const information = computed(() => |
| 124 | + items.value.map((item) => ({ |
| 125 | + title: getTitle(item), |
| 126 | + words: getWords(item), |
| 127 | + links: getLinks(item), |
| 128 | + update: getUpdate(item), |
| 129 | + lastUpdated: item.lastUpdated, |
| 130 | + children: item.children || [] |
| 131 | + })) |
| 132 | + ) |
| 133 | +
|
| 134 | + const checkUpdate = (page) => page.update <= Math.max(updateDays.value, props.showDays ?? 0) |
| 135 | +
|
| 136 | + return { |
| 137 | + updateDays, |
| 138 | + information, |
| 139 | + checkUpdate |
| 140 | + } |
109 | 141 | } |
| 142 | +}) |
110 | 143 | </script> |
111 | 144 |
|
112 | 145 | <style scoped> |
|
0 commit comments