图片
样式(边框,加载)
config.mts
ts
export default defineConfig({
markdown: {
image: {
// 默认禁用图片懒加载
lazyLoading: true,
},
config: md => {
// 为图片添加 img-wrapper 类
md.renderer.rules.image = (tokens, idx, options, env, self) => {
const token = tokens[idx];
const src = token.attrGet('src');
const alt = token.content;
const wh = token.attrs && token.attrs[2] ? token.attrs[2][0] : 'auto';
const w = wh.split(',')[0];
const h = wh.split(',')[1] || w;
// 排除不显示img-wrapper样式的图片(指定ignoreClassArr数组内域名、alt含有ignore和src含有ignore)
let ignoreClassArr = ['https://img.shields.io'];
let imgParentClass = 'img-wrapper';
if (
ignoreClassArr.some(item => src?.indexOf(item) !== -1) ||
alt.indexOf('ignore') !== -1 ||
src?.indexOf('ignore') !== -1
) {
imgParentClass = 'img-wrapper-ignore';
}
// 返回自定义的 HTML 结构,给图片加上 onerror 事件
return `
<span class="${imgParentClass}">
<img
src="${src}"
alt="${alt}"
width="${w}"
height="${h}"
class="img-loading"
onload="this.classList.remove('img-loading')"
onerror="this.classList.remove('img-loading'); this.classList.add('img-error')"
/>
</span>
`;
};
},
},
});
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
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
custom.css
css
/**
* Component: Img图片
* -------------------------------------------------------------------------- */
.img-wrapper {
position: relative;
display: block;
width: fit-content;
margin: auto;
padding: 4px;
/* box-shadow: rgba(60, 61, 255, 0.1) 0px 1px 2px 0px, rgba(60, 61, 255, 0.1) 0px 2px 6px 2px; */
/* filter: drop-shadow(0px 1px 2px rgba(60, 61, 255, 0.2)) drop-shadow(0px 2px 6px rgba(60, 61, 255, 0.2)); */
/* box-shadow: rgb(85, 91, 255) 0px 0px 0px 2px, rgb(31, 193, 27) 0px 0px 0px 4px, rgb(255, 217, 19) 0px 0px 0px 6px,
rgb(255, 156, 85) 0px 0px 0px 8px, rgb(255, 85, 85) 0px 0px 0px 10px; */
/* filter: drop-shadow(0px 1px 0px rgba(85, 91, 255, 1)) drop-shadow(0px 2px 0px rgba(31, 193, 27, 1))
drop-shadow(0px 4px 0px rgba(255, 217, 19, 1)) drop-shadow(0px 6px 24px rgba(255, 156, 85, 1))
drop-shadow(0px 8px 0px rgba(255, 85, 85, 1)); */
/* box-shadow: #bd34fe 0px 0px 0px 2px, #47caff 0px 0px 0px 4px; */
}
.img-wrapper::before {
content: '';
width: 100%;
height: 100%;
border-radius: 4px;
background-image: linear-gradient(var(--rotate), #a805be, #3c67e3 43%, #4e00c2);
position: absolute;
z-index: -1;
top: 0%;
left: -0%;
animation: spin 3s linear infinite;
}
.img-wrapper .img-error {
background-color: var(--vp-c-neutral-inverse);
}
.img-wrapper .img-loading {
position: relative;
min-width: 160px;
min-height: 32px;
background-color: var(--vp-c-neutral-inverse);
}
.img-wrapper:has(.img-loading)::after {
content: '加载图片中...';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #999;
font-size: 14px;
z-index: 40;
}
@keyframes spin {
0% {
--rotate: 0deg;
}
100% {
--rotate: 360deg;
}
}
@property --rotate {
syntax: '<angle>';
initial-value: 132deg;
inherits: false;
}
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
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
指定图片不显示边框
提醒
- 默认图片地址包含
https://img.shields.io(徽标)
地址的图片不显示边框。可以往ignoreClassArr
数组中添加其他要排除边框的地址 - 图片 alt 属性中含有
ignore
关键字的图片不显示边框。例如![示例图ignore](/image.jpg)
- 图片 src 属性中含有
ignore
关键字的图片不显示边框。例如![示例图](/image.jpg?ignore)
点击放大和滚轮放大缩小
安装
地址:https://github.com/francoischalifour/medium-zoom
shell
pnpm add medium-zoom
1
配置
index.ts
ts
import { onMounted, watch, nextTick } from 'vue';
import { useRoute } from 'vitepress';
import mediumZoom from 'medium-zoom';
export default {
// ,,,
setup() {
const route = useRoute();
let initScale = 1;
// 初始化图片缩放
const initZoom = () => {
// mediumZoom('[data-zoomable]', { background: 'var(--vp-c-bg)' }); // 默认
const zoomInstance = mediumZoom('.main img', { background: 'var(--vp-c-bg)' });
// 监听点击放大图片
zoomInstance.on('open', () => {
document.body.style.overflow = 'hidden';
document.body.style.paddingRight = '17px';
nextTick(() => {
const image = document.querySelector('.medium-zoom-image--opened') as HTMLElement;
if (image) {
document.body.style.overflow = 'hidden';
// 获取初始的 transform 样式
let initTransform = image.style.transform || 'scale(1)';
const initScaleMatch = initTransform.match(/scale\(([^)]+)\)/);
initScale = initScaleMatch ? parseFloat(initScaleMatch[1]) : 1; // 获取初始缩放比例,默认为 1
// 添加滚轮缩放功能
image.addEventListener('wheel', (event: WheelEvent) => {
const currentTransform = image.style.transform || 'scale(1)'; // 默认值为 scale(1)
const scaleMatch = currentTransform.match(/scale\(([^)]+)\)/);
const currentScale = scaleMatch ? parseFloat(scaleMatch[1]) : 1; // 获取当前缩放比例,默认为 1
// 阻止浏览器的默认缩放行为
event.preventDefault();
// 根据滚轮方向进行放大或缩小
if (event.deltaY > 0) {
// 缩小图片
zoomOut(image, currentTransform, currentScale);
} else {
// 放大图片
zoomIn(image, currentTransform, currentScale);
}
});
}
});
});
// 还原图片
zoomInstance.on('close', () => {
document.body.style.overflow = 'auto';
document.body.style.paddingRight = '0px';
});
};
// 放大图片
const zoomIn = (image: HTMLElement, currentTransform: string, currentScale: number) => {
// 增加缩放值,并保持其他 transform 属性不变
const newScale = Math.min(currentScale + 0.1, initScale + 5); // 限制最大缩放为 5 倍
image.style.transform = currentTransform.replace(/scale\([^)]+\)/, `scale(${newScale})`);
};
// 缩小图片
const zoomOut = (image: HTMLElement, currentTransform: string, currentScale: number) => {
// 减小缩放值,并保持其他 transform 属性不变
const newScale = Math.max(currentScale - 0.1, 0.5); // 限制最小缩放为 0.5 倍
image.style.transform = currentTransform.replace(/scale\([^)]+\)/, `scale(${newScale})`);
};
onMounted(() => {
initZoom();
});
watch(
() => route.path,
() => {
nextTick(() => initZoom());
}
);
},
};
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
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
custom.css
css
/**
* Component: Img图片
* -------------------------------------------------------------------------- */
/* 图片放大查看 */
.medium-zoom-overlay {
z-index: 30;
}
.medium-zoom-image {
z-index: 31;
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
指定图片大小
配置
config.mts
ts
export default defineConfig({
markdown: {
image: {
// 默认禁用图片懒加载
lazyLoading: true,
},
config: md => {
// 为图片添加 img-wrapper 类
md.renderer.rules.image = (tokens, idx, options, env, self) => {
const token = tokens[idx];
const src = token.attrGet('src');
const alt = token.content;
const wh = token.attrs && token.attrs[2] ? token.attrs[2][0] : 'auto';
const w = wh.split(',')[0];
const h = wh.split(',')[1] || w;
// 排除不显示img-wrapper样式的图片(指定ignoreClassArr数组内域名、alt含有ignore和src含有ignore)
let ignoreClassArr = ['https://img.shields.io'];
let imgParentClass = 'img-wrapper';
if (
ignoreClassArr.some(item => src?.indexOf(item) !== -1) ||
alt.indexOf('ignore') !== -1 ||
src?.indexOf('ignore') !== -1
) {
imgParentClass = 'img-wrapper-ignore';
}
// 返回自定义的 HTML 结构,给图片加上 onerror 事件
return `
<span class="${imgParentClass}">
<img
src="${src}"
alt="${alt}"
width="${w}"
height="${h}"
class="img-loading"
onload="this.classList.remove('img-loading')"
onerror="this.classList.remove('img-loading'); this.classList.add('img-error')"
/>
</span>
`;
};
},
},
});
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
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
使用
提醒
在图片后添加{w,h}。例如![alt](src){200,300}
,中间不要有空格
其中 w(200)是指定的宽度,h(300)是指定图片的宽度;
只写一个值,代表宽高都是该值。例如![alt](src){200}
,宽高就都是 200px;
不写值默认 auto
markdown
![示例图](/image.jpg){200,100}
1
markdown
![示例图](/image.jpg){100}
1
完整预览插件 image-viewer
安装
地址:https://github.com/T-miracle/vitepress-plugin-image-viewer?tab=readme-ov-file
注意
如果用的是 npm 或者 yarn,就不用安装 viewerjs
shell
pnpm add vitepress-plugin-image-viewer
pnpm add viewerjs
1
2
2
配置
提醒
imageViewer()
接收三个参数:
route
路由(这是必需的)
el
CSS 选择器(默认
.vp-doc
,可以为空不填写,这不是必需的)option
配置选项(详细配置请看viewerjs option,已有默认配置,这不是必需的)
index.ts
ts
import 'viewerjs/dist/viewer.min.css';
import imageViewer from 'vitepress-plugin-image-viewer';
export default {
setup() {
const route = useRoute();
imageViewer(route);
// ...
},
};
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
扩展组件
vImageViewer
组件能编译成一个按钮,点击这个按钮能弹出图片,使用方式如下:
index.ts
ts
import vImageViewer from 'vitepress-plugin-image-viewer/lib/vImageViewer.vue';
export default {
// ...
enhanceApp(ctx: any) {
DefaultTheme.enhanceApp(ctx);
// 注册全局组件,如果你不想使用也可以不添加
ctx.app.component('vImageViewer', vImageViewer);
// ...
},
};
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
inline属性设置为
true,那么它会变成一个行内元素,他不是必需的,默认为
false
vue
<vImageViewer src="图片地址" alt="描述内容" :inline="false" />
1