|
42 | 42 | <a-anchor-link
|
43 | 43 | v-for="h in headers"
|
44 | 44 | :key="h.title"
|
45 |
| - :href="h.href || `#${h.title.replace(/^(\d)/, '_$1')}`" |
| 45 | + :href="h.href || `#${slugifyTitle(h.title)}`" |
46 | 46 | :title="h.title"
|
47 | 47 | ></a-anchor-link>
|
48 | 48 | </a-anchor>
|
@@ -88,6 +88,9 @@ import RightBottomAd from '../components/rice/right_bottom_rice.vue';
|
88 | 88 | import { CloseOutlined, MenuOutlined } from '@ant-design/icons-vue';
|
89 | 89 | import ThemeIcon from './ThemeIcon.vue';
|
90 | 90 |
|
| 91 | +const rControl = /[\u0000-\u001f]/g; |
| 92 | +const rSpecial = /[\s~`!@#$%^&*()\-_+=[\]{}|\\;:"'<>,.?/]+/g; |
| 93 | +
|
91 | 94 | export default defineComponent({
|
92 | 95 | name: 'Layout',
|
93 | 96 | components: {
|
@@ -162,6 +165,21 @@ export default defineComponent({
|
162 | 165 | visible.value = !visible.value;
|
163 | 166 | };
|
164 | 167 | return {
|
| 168 | + slugifyTitle: (str: string) => { |
| 169 | + return ( |
| 170 | + str |
| 171 | + // Remove control characters |
| 172 | + .replace(rControl, '') |
| 173 | + // Replace special characters |
| 174 | + .replace(rSpecial, '-') |
| 175 | + // Remove continuos separators |
| 176 | + .replace(/\-{2,}/g, '-') |
| 177 | + // Remove prefixing and trailing separtors |
| 178 | + .replace(/^\-+|\-+$/g, '') |
| 179 | + // ensure it doesn't start with a number (#121) |
| 180 | + .replace(/^(\d)/, '_$1') |
| 181 | + ); |
| 182 | + }, |
165 | 183 | themeMode,
|
166 | 184 | visible,
|
167 | 185 | isMobile: globalConfig.isMobile,
|
|
0 commit comments