Typecho非插件实现文章相册功能

AI摘要:文章介绍了如何为Typecho 0.9默认主题添加图片排版和灯箱效果。作者通过修改`post.php`文件,使用DOMDocument处理HTML,为段落中的图片添加灯箱链接,并在`header.php`中引入Slimbox2插件。最后,作者分享了自定义CSS样式和Markdown图片插入方法,以实现图片的网格布局和单独排列。

最近在整理博客主题,我这个主题还是Typecho 0.9 系统默认的主题,比较老。

默认的主题

但是这个主题的好处就是比较简洁,代码很精简,在上面很方便改造,在追求内容方面很适合我这种不想太花哨的。

这次改造的就是给文章中增加图片排版,并且支持灯箱效果。

灯箱插件代码:https://wangdaodao.lanzn.com/ipNLk38sx3ij,下载了放在主题中,例如我主题所有的静态资源都在 assets 中,你也可以按照我这个方法,assets/plugin/slimbox2 方便后面维护。

我这个主题文章页面是 post.php,其他主题应该也是这个名字吧,毕竟官方文档里面主题结构是这样:

文件名作用必须
style.css主题样式文件
screenshot.png主题缩略图
index.php首页以及说明文件
404.php404页面文件
archive.php通用(分类、搜索、标签、作者)页面文件
category.php分类页面文件
search.php搜索页面文件
tag.php标签页面文件
author.php作者页面文件
comments.php评论页面文件
footer.php底部页面文件
functions.php主题函数文件
header.php头部页面文件
page.php独立页面文件
post.php日志页面文件
sidebar.php侧边栏页面文件

言归正传,重头戏来了,在 post.php 找到这段代码,这个就是输出内容的

<?php $this->content(); ?>

改造成:

<?php
    // 使用DOMDocument来精确处理p标签的直接子集img
    $doc = new DOMDocument();
    @$doc->loadHTML('<?xml encoding="UTF-8">' . $this->content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

    // 找到所有的p标签
    $paragraphs = $doc->getElementsByTagName('p');
    foreach ($paragraphs as $p) {
        // 先收集所有需要处理的直接子元素img
        $imgElements = array();
        foreach ($p->childNodes as $child) {
            if ($child->nodeType === XML_ELEMENT_NODE && $child->nodeName === 'img') {
                $imgElements[] = $child;
            }
        }

        // 统计当前p标签中的图片数量
        $imgCount = count($imgElements);
        if ($imgCount > 0) {
            // 如果p标签中有多个图片,添加相应的class
            if ($imgCount > 1) {
                $p->setAttribute('class', 'album-group multiple-images');
            } else {
                $p->setAttribute('class', 'album-group');
            }
        }

        // 处理收集到的img元素
        foreach ($imgElements as $img) {
            $src = $img->getAttribute('src');
            $alt = $img->getAttribute('alt');

            if ($src) {
                // 创建新的a标签
                $a = $doc->createElement('a');
                $a->setAttribute('href', $src);
                $a->setAttribute('rel', 'lightbox');
                $a->setAttribute('title', $alt);

                // 创建新的img标签
                $newImg = $doc->createElement('img');
                $newImg->setAttribute('loading', 'lazy');
                $newImg->setAttribute('src', $src);
                $newImg->setAttribute('alt', $alt);

                // 将新的img添加到a标签
                $a->appendChild($newImg);

                // 替换原来的img标签
                $p->replaceChild($a, $img);
            }
        }
    }

    // 获取处理后的HTML内容
    $content = $doc->saveHTML();
    echo $content;
?>

代码中有简单的注释,可以看看,看不懂的话,让AI解释一下也行。

然后在 header.php 中,在 <head></head> 标签中,增加以下代码:

<?php if ($this->is('single')): ?>
    <script src="<?php $this->options->themeUrl('/assets/plugin/slimbox2/js/slimbox2.js'); ?>"></script>
    <link rel="stylesheet" href="<?php $this->options->themeUrl('/assets/plugin/slimbox2/css/slimbox2.css'); ?>">
<?php endif; ?>

这里注意下引入的路径。

完成以上步骤,基本上算上完成了一大半了,剩下的就是改下样式,这里我提供我现在用的样式,动手能力强的可以自己再改造改造,让这个更符合自己的主题:

其中 post-content 是我自己博客内容的类名,需要根据自己的再调整一下

/* 图片灯箱效果 */
.post-content a[rel='lightbox'] img {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  transition: box-shadow 0.3s ease;
}

.post-content a[rel='lightbox']:hover {
  cursor: zoom-in;
}

.post-content a[rel='lightbox']:hover img {
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.25);
}

.post-content p.album-group img {
  border-radius: 10px;
  transition: all 0.2s ease;
}

.post-content p.album-group.multiple-images {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  grid-auto-rows: 250px;
  grid-gap: 0.5rem;
}

.post-content p.album-group.multiple-images a {
  display: block;
  min-width: calc(50% - 10px);
  margin: 0;
}

.post-content
  p.album-group.multiple-images
  a:nth-last-of-type(1):nth-of-type(odd) {
  grid-column: 1 / -1;
}

.post-content p.album-group.multiple-images img {
  object-fit: cover;
  display: block;
  width: 100%;
  height: 100%;
}

.post-content p.album-group.multiple-images br {
  display: none;
}

最后一步,就是发布文章时如何插入图片,由于我本人比较懒,一般都是用的typecho的默认编辑器,没有用其他的插件,所以这里也不准备弄什么标签啥的,懒……

如果每张图片想单独放一行,那就是这样:

<!--这里仅仅说明这里要空行-->
![图片1][1]
<!--这里仅仅说明这里要空行-->

注意啊,图片上下都要空一行,这样typecho的markdown的解析器,就会把这个转换成

<p>
  <img />
</p>

如果想做成一个一组,那就是这样,同样一组上下都要空一行:

<!--这里仅仅说明这里要空行-->
![图片1][1]
![图片2][2]
![图片3][3]
![图片4][4]
<!--这里仅仅说明这里要空行-->

这样就转换成

<p>
  <img />
  <img />
  <img />
  <img />
</p>

效果就是这样:

小院鱼池
晒太阳
魔鬼城1
魔鬼城2
溪流

目前针对移动端没有做效果,还是懒啊……

注意,如果用HTML压缩之类的,会破坏结构,这种情况会导致布局上的失效,所以如果发现没有生效,对比下HTML结构做调整吧。

已有 2 条评论

  1. 回复

    相比wordpress, typecho折腾起来比较费劲,我还没弄懂这个markdown的渲染逻辑,像自定义一些标签什么的还不会弄。

    1. 王叨叨 王叨叨 [作者]
      回复

      有个简单的办法,把代码和文档都喂给AI,让AI帮你分析,然后再让AI辅助编码。

添加新评论