Siricee / hexo-theme-Chic

An elegant, powerful, easy-to-read Hexo theme.
https://siricee.github.io/hexo-theme-Chic/
Other
872 stars 175 forks source link

实现标签墙功能 #144

Open greendolphindance opened 6 months ago

greendolphindance commented 6 months ago

这里是原文

尝试实现了标签墙效果,供参考。声明:我其实不会写任何Javascript代码,所有代码都由ChatGPT生成,我也不会debug。如果出现bug,我爱莫能助,请自行加油吧。

1. 准备数据

首先,我创建了source/_data目录,并在其下创建了一个tag_groups.yml文件,用来定义标签及其分类。

标签1: 分类A
标签2: 分类B
标签3: 分类C
……

2. 修改tag.ejs

在我的主题模板文件 tag.ejs 中,我添加了以下代码来展示标签,并为每个标签添加了一个数据属性来存储其分类。

<div class="tag-cloud-tags">
    <% sortedTags.forEach(function(tag) { %>
        <% var tagName=tag.name; %>
            <% var tagGroup=tagGroups[tagName] ? tagGroups[tagName] : '未分类' ; %>
                <a class="tag" href="<%- url_for(tag.path) %>"
                    data-tag-group="<%- tagGroup %>">
                    <%- tagName %><small>(<%- tag.length %>)</small>
                </a>
                <% }); %>
</div>

<% } else { %>
    <p>未找到标签分组数据。</p>
    <% } %>

        <div id="tag-background"></div>
        <div id="tag-group-name"></div>

3. CSS样式

为了使标签墙看起来更美观,我添加了一些基本的 CSS 样式,并为夜间模式定义了不同的颜色。

<style>
    :root {
        --tag-border-color: #ddd;
        /* 标签文本颜色 */
    }

    body.dark-theme {
        --tag-border-color: #a9a9b3;
        /* 夜间模式下的边框颜色 */
    }

    .tag {
        display: inline-block;
        margin: 0 10px;
        padding: 5px 10px;
        border: 1px solid var(--tag-border-color);
        transition: opacity 0.3s;
    }

    .tag:hover {
        cursor: pointer;
        opacity: 1;
        /* 鼠标悬停时,标签不会减淡 */
    }

    .dimmed {
        opacity: 0.3;
        /* 减淡显示的样式 */
    }

    #tag-group-name {
        display: none;
        /* 默认不显示 */
        position: fixed;
        left: 50%;
        bottom: 10%;
        /* 或根据需要调整 */
        transform: translateX(-50%);
        font-size: 3em;
        /* 大字号,根据需要调整 */
        z-index: 9999;
        /* 确保它在页面内容之上 */
        color: var(--tag-border-color);
        /* 使用同样的颜色 */
        padding: 0.5em 1em;
        /* 内边距,根据需要调整 */
        border-radius: 10px;
        /* 圆角边框 */
        transition: opacity 0.3s, bottom 0.3s;
        /* 平滑过渡效果 */
        opacity: 0;
        pointer-events: none;
        /* 确保鼠标事件可以透过它传递 */
    }

    @media (prefers-color-scheme: dark),
    .dark-theme {
        #tag-group-name {
            color: var(--tag-text-color);
            /* 夜间模式的文本颜色 */
        }
    }
</style>

4. JavaScript交互

最后,我通过 JavaScript 添加了交互效果,当鼠标悬停在标签上时,显示标签的分类,并减淡其他分类的标签。

<script>
    document.addEventListener('DOMContentLoaded', function () {
        var tags = document.querySelectorAll('.tag-cloud-tags a');
        var groupNameDisplay = document.getElementById('tag-group-name');

        tags.forEach(function (tag) {
            tag.addEventListener('mouseover', function () {
                var group = this.getAttribute('data-tag-group');
                groupNameDisplay.textContent = group; // 设置分类名称文本
                groupNameDisplay.style.display = 'block'; // 显示分类名称
                groupNameDisplay.style.opacity = 1; // 使其可见
                groupNameDisplay.style.bottom = '20%'; // 提高位置使其更可见

                tags.forEach(function (otherTag) {
                    if (otherTag.getAttribute('data-tag-group') !== group) {
                        otherTag.classList.add('dimmed');
                    }
                });
            });

            tag.addEventListener('mouseout', function () {
                groupNameDisplay.style.opacity = 0; // 使其透明
                groupNameDisplay.style.bottom = '10%'; // 降低位置
                groupNameDisplay.style.display = 'none'; // 再次隐藏

                tags.forEach(function (otherTag) {
                    otherTag.classList.remove('dimmed');
                });
            });
        });
    });
</script>

5. 小修改:移动端的点击效果

如果仅做此前的修改,会导致在移动端时,点击标签直接跳转了子页面,没有显示标签墙的突出选中分类的效果。因此,我希望实现移动端点击一次时突出显示选中分类、点击两次时才跳转至子页面。添加如下Javascript代码:

<script>
    document.addEventListener('DOMContentLoaded', function () {
        var tags = document.querySelectorAll('.tag-cloud-tags a');
        var groupNameDisplay = document.getElementById('tag-group-name');

        function handleTagInteraction(currentTag, isMouseOver) {
            var group = currentTag.getAttribute('data-tag-group');
            groupNameDisplay.textContent = group;
            groupNameDisplay.style.display = isMouseOver ? 'block' : 'none';

            tags.forEach(function (tag) {
                if (isMouseOver && tag.getAttribute('data-tag-group') !== group) {
                    tag.classList.add('dimmed');
                } else {
                    tag.classList.remove('dimmed');
                }
            });
        }

        tags.forEach(function (tag) {
            // 鼠标悬停效果
            tag.addEventListener('mouseover', function () {
                handleTagInteraction(this, true);
            });

            tag.addEventListener('mouseout', function () {
                handleTagInteraction(this, false);
            });

            // 移动端点击效果
            tag.addEventListener('touchend', function (event) {
                // 阻止默认的链接跳转
                event.preventDefault();

                // 切换激活状态
                if (!this.classList.contains('active')) {
                    // 移除之前激活的标签的激活状态
                    document.querySelector('.tag-cloud-tags a.active')?.classList.remove('active');

                    // 激活当前标签并应用效果
                    this.classList.add('active');
                    handleTagInteraction(this, true);
                } else {
                    // 如果已经激活,则允许链接跳转
                    window.location.href = this.href;
                }
            });
        });
    });
</script>