前言

Vuepress默认的图片浏览是点击放大,可以说是非常简洁,如果网站图片比较多,还是可以加载Fancybox来使它更加优雅。

因为我不喜欢把一大堆包都放在服务器,直接从CDN引入,自动加载其最新版本,这样省去很多后期维护成本。

这篇文章介绍一下这种最简单的方法让Vuepress网站使用Fancybox。

图片步骤(已验证)

  1. 创建fancybox插件

    docs/.vuepress/plugins 目录中创建一个名为vuepress-plugin-fancybox 的目录,如果没有 plugins 目录,先创建此目录;

    vuepress-plugin-fancybox 目录下,添加名为 index.js 的文件,将下面内容添加进去:

    // docs/.vuepress/plugins/vuepress-plugin-fancybox/index.js
    export default () => ({
    	name: 'vuepress-plugin-fancybox',
    	extendsMarkdown(md) {
    		md.renderer.rules.image = function (tokens, idx, options, env, self) {
    			const token = tokens[idx]
    			const srcIndex = token.attrIndex('src')
    			const src = token.attrs[srcIndex][1]
    			const alt = token.content || ''
    			// 使用页面路径作为 gallery 名称,避免跨页面冲突
    			const galleryName = (env.relativePath || 'gallery')
    			.replace(/\//g, '-')
    			.replace(/\.\w+$/, '')
    			return `<a href="${src}" data-fancybox="${galleryName}"><img src="${src}" alt="${alt}"></a>`
    		}
    	},
    })
  2. 修改 docs/.vuepress/config.js 配置文件

    对应栏目添加以下内容:

    // docs/.vuepress/config.js
    import { viteBundler } from '@vuepress/bundler-vite'
    import { defaultTheme } from '@vuepress/theme-default'
    //..省略..//
    import fancyboxPlugin from './plugins/vuepress-plugin-fancybox/index.js'
    
    export default defineUserConfig({
    
    //..省略..//
    
    	head: [
    		['link', { rel: 'stylesheet', href: 'https://unpkg.com/@fancyapps/ui/dist/fancybox/fancybox.css' }],
    		['script', { src: 'https://unpkg.com/@fancyapps/ui/dist/fancybox/fancybox.umd.js' }],
    	    ['script', {}, `
    	        document.addEventListener('DOMContentLoaded', () => {
    	            if (window.Fancybox) {
    	                window.Fancybox.bind('[data-fancybox]');
    	            }
    	        });
    	    `],
    		
    	//..省略..//
    	
    	],
    
    //..省略..//
    
    	plugins: [
    		fancyboxPlugin(),
    		
    		//..省略..//
    		
    	],
    })
  3. 构建网站

    最后使用 npm run docs:build 或者 npm run docs:dev 进行调试。

同时处理图片以及视频(未验证)

Fancybox给我最大的亮点是使用下面代码可以播放视频:

<a href="/sample.mp4" data-fancybox data-width="640" data-height="360">
  <img src="/poster.jpg" alt="Video poster" width="240" height="180" />
</a>

提供一个思路,修改 docs/.vuepress/plugins/vuepress-plugin-fancybox/index.js 的代码:

// docs/.vuepress/plugins/vuepress-plugin-fancybox/index.js
export default () => ({
  name: 'vuepress-plugin-fancybox',

  extendsMarkdown(md) {
    md.renderer.rules.image = function (tokens, idx, options, env, self) {
      const token = tokens[idx]
      const srcIndex = token.attrIndex('src')
      const src = token.attrs[srcIndex][1]
      const alt = token.content || ''

      const galleryName = (env.relativePath || 'gallery')
        .replace(/\//g, '-')
        .replace(/\.\w+$/, '')

      // 判断是否是视频
      const isVideo = /\.(mp4|webm|ogg)$/i.test(src)

      if (isVideo) {
        // 动态计算屏幕尺寸
        const width = window.innerWidth * 0.8  // 自适应 80% 屏幕宽度
        const height = window.innerHeight * 0.8  // 自适应 80% 屏幕高度

        return `<a href="${src}" data-fancybox="${galleryName}" data-width="${width}" data-height="${height}">
                  <img src="${token.attrs[srcIndex][1]}" alt="${alt}" />
                </a>`
      }

      // 默认渲染图片
      return `<a href="${src}" data-fancybox="${galleryName}"><img src="${src}" alt="${alt}"></a>`
    }
  },
})

不想弄视频的原因是需要给每个视频添加缩略图啥的,太麻烦,而且要考虑markdown的书写方式,图片和视频怎么写,怎么判断它是超链接还是图片,还是视频,缩略图怎么加,我这边也只是给个大致方向。不管出于什么原因,都不建议把视频加上。

最后

要说一个比较让我有点不习惯的地方:比如一个网页有很多图片,通过Fancybox浏览到其他一张图片,在这个位置关掉图片,那么页面会自动滚动到此时图片所在的位置。

不过这个也可以进行关闭:

// docs/.vuepress/config.js
['script', {}, `
	document.addEventListener('DOMContentLoaded', () => {
		if (window.Fancybox) {
			window.Fancybox.bind('[data-fancybox]', {
	            placeFocusBack: false    //添加这个
	          });
	    }
	});
`],

其他的完全没问题。