普通视图

发现新文章,点击刷新页面。
今天 — 2025年4月3日懋和道人
  • ✇懋和道人
  • Z-BlogPHP 中自定义 Feed 输出功能的实现与应用
    在网站开发领域,为用户提供高效便捷的内容订阅途径,是提升用户体验、增强用户粘性的关键举措。在使用Z-BlogPHP搭建网站时,我们能够借助自定义PHP脚本,打造满足特定需求的Feed输出功能。接下来,本文将深入剖析feed_id.php和page_feed.php这两个脚本的功能、实现逻辑,以及基于它们所创建的 “订阅” 栏目。feed_id.php脚本主要用于依据Z-BlogPHP中的分类$categoryId,展示对应分类下的部分内容,生成分类的Feed输出。该脚本首先引入Z-BlogPHP系统核心文件并加载系统,为后续操作奠定基础。接着从URL参数获取分类ID,对其进行有效性验证,若分类ID无效或对应分类不存在,则输出错误信息并终止脚本运行。之后设置响应头为XML格式,生成XML声明及RSS 2.0文档的相关结构,并填充频道的标题(含分类名称和博客名称)、链接(分类链接)、描述(分类简介)和语言等信息。最后通过 $zbp->GetArticleList() 方法获取指定分类下正常发布的文章列表,按发布时间倒序排列,循环输出最多10篇文章的标题、链接、描述、发布日期和唯一标识
     

Z-BlogPHP 中自定义 Feed 输出功能的实现与应用

2025年4月2日 03:06

image.png

在网站开发领域,为用户提供高效便捷的内容订阅途径,是提升用户体验、增强用户粘性的关键举措。在使用Z-BlogPHP搭建网站时,我们能够借助自定义PHP脚本,打造满足特定需求的Feed输出功能。接下来,本文将深入剖析feed_id.php和page_feed.php这两个脚本的功能、实现逻辑,以及基于它们所创建的 “订阅” 栏目。

feed_id.php脚本主要用于依据Z-BlogPHP中的分类$categoryId,展示对应分类下的部分内容,生成分类的Feed输出。该脚本首先引入Z-BlogPHP系统核心文件并加载系统,为后续操作奠定基础。接着从URL参数获取分类ID,对其进行有效性验证,若分类ID无效或对应分类不存在,则输出错误信息并终止脚本运行。之后设置响应头为XML格式,生成XML声明及RSS 2.0文档的相关结构,并填充频道的标题(含分类名称和博客名称)、链接(分类链接)、描述(分类简介)和语言等信息。最后通过 $zbp->GetArticleList() 方法获取指定分类下正常发布的文章列表,按发布时间倒序排列,循环输出最多10篇文章的标题、链接、描述、发布日期和唯一标识符等内容,完成 Feed 的生成。比如,访问下方URL就能获取分类ID为2的分类内容的Feed输出。

https://www.dao.js.cn/feed_id.php?id=2

page_feed.php 脚本的核心功能是通过 GetPageList 方法获取网站内所有单页的信息,并生成相应的 Feed 输出。此脚本同样先引入并加载Z-BlogPHP系统,将当前操作类型设为feed并设置XML格式的响应头。然后执行相关钩子函数,生成XML声明和RSS 2.0文档的起始结构,填充频道的标题(含 “所有单页” 和博客名称)、链接(博客主页链接)、描述(所有单页的 RSS Feed)及语言等信息。再利用$zbp->GetPageList()方法获取所有单页列表,循环输出每个页面的标题、链接、描述(页面简介)、发布日期和唯一标识符等信息,最后结束XML结构并执行相应钩子函数。用户通过访问下方URL,便能获取所有的Feed输出。

https://www.dao.js.cn/page_feed.php

在完成feed_id.php和page_feed.php脚本的编写后,我们进一步创建了 “订阅” 栏目。用户访问 https://www.dao.js.cn/feed 即可进入该栏目,在此查看不同分类的内容Feed以及所有单页的Feed,及时掌握网站的最新动态。

通过对feed_id.php和page_feed.php脚本的精心开发与应用,我们在Z-BlogPHP网站中成功实现了自定义 Feed 输出功能,并搭建起 “订阅” 栏目。这不仅优化了网站的内容展示效果,还为用户提供了更为便捷的内容获取方式,有助于提升用户的留存率与活跃度。在今后的网站开发和维护中,我们还可依据实际需求,对这些脚本进行优化和拓展,以适应不断变化的业务场景。

需要feed_id.php和page_feed.php文件的,请通过“联系”栏目与我取得联系。feed页面模板如下:

    <h2>总体订阅</h2>                            
    <div class="category-wrapper">
        <a target="_blank" href="/feed.php" class="dingyue" title="南蛮子懋和博客默认订阅">
            <div class="dingyuetext">
                <div class="dingyuexl">默认订阅</div>
            </div>
            <i class="bi bi-rss"></i>
        </a>
        <a target="_blank" href="/page_feed.php" class="dingyue" title="南蛮子懋和博客单页订阅">
            <div class="dingyuetext">
                <div class="dingyuexl">单页订阅</div>
            </div>
            <i class="bi bi-rss"></i>
        </a>
    </div>
    <h2>分类订阅</h2>
    <div class="category-wrapper">
        {php}
        global $zbp;
        $categories = $zbp->GetCategoryList();
        foreach ($categories as $category) {
            if ($category->ID != 1) {
                $feed_url = 'feed_id.php?id='.$category->ID;
        {/php}
        <a target="_blank" href="{php}echo $feed_url;{/php}" class="dingyue" title="{php}echo $category->Intro;{/php}">
            <div class="dingyuetext">
                <div class="dingyuexl">{php}echo $category->Name;{/php}</div>
            </div>
            <i class="bi bi-rss"></i>
        </a>
        {php}
            }
        }
        {/php}
    </div>

依照Z-BlogPHP创建自定义页面方式,再合适的地方插入即可。需要feed样式的,可以自行f12复制,也可以向我索取,具体展示渲染效果如下:

https://www.dao.js.cn/feed

  • ✇懋和道人
  • 巧用张洪HeoMusic思路构建了我的“歌单”
    在音乐爱好者的世界里,拥有一个能自由听取的个性化歌单是许多人的梦想。为了实现这一目标,我借鉴了张洪 HeoMusic 的思路,成功搭建了属于自己的歌单页面。https://blog.zhheo.com/p/45699256.html张洪 HeoMusic 的思路为整个项目提供了关键的指引方向,其独特的架构理念和对音乐播放系统的理解,成为我搭建歌单页面的基石。在这个基础上,我对Meting.min.js进行了二次更改,这一举措极大地拓展了音乐获取的自由度。通过对代码的精细调整,我可以更灵活地从不同渠道获取心仪的音乐,让歌单内容更加丰富多样。值得注意的是因为跨域等问题,我们需要自己构建、或者反代一个API,因为版权原因,暂不提供思路,我是使用的injahow/meting-api使用cloudflare搭建的API。为了实现多id合并并打乱顺序输出json,我对Meting.min.js进行了下述修改(尊重著作权,console.log输出版权信息)class MetingJSElement extends HTMLElement {     constructor() {        
     

巧用张洪HeoMusic思路构建了我的“歌单”

2025年4月1日 02:51

image.png

在音乐爱好者的世界里,拥有一个能自由听取的个性化歌单是许多人的梦想。为了实现这一目标,我借鉴了张洪 HeoMusic 的思路,成功搭建了属于自己的歌单页面。

https://blog.zhheo.com/p/45699256.html

张洪 HeoMusic 的思路为整个项目提供了关键的指引方向,其独特的架构理念和对音乐播放系统的理解,成为我搭建歌单页面的基石。在这个基础上,我对Meting.min.js进行了二次更改,这一举措极大地拓展了音乐获取的自由度。通过对代码的精细调整,我可以更灵活地从不同渠道获取心仪的音乐,让歌单内容更加丰富多样。值得注意的是因为跨域等问题,我们需要自己构建、或者反代一个API,因为版权原因,暂不提供思路,我是使用的injahow/meting-api使用cloudflare搭建的API。

为了实现多id合并并打乱顺序输出json,我对Meting.min.js进行了下述修改(尊重著作权,console.log输出版权信息)

class MetingJSElement extends HTMLElement {
    constructor() {
        super();
        this._initialized = false;
    }

    connectedCallback() {
        if (window.APlayer && window.fetch &&!this._initialized) {
            this._init();
            this._parse();
            this._initialized = true;
        }
    }

    disconnectedCallback() {
        if (!this.lock && this.aplayer) {
            this.aplayer.destroy();
        }
    }

    _camelize(str) {
        return str
          .replace(/^[_.\- ]+/, '')
          .toLowerCase()
          .replace(/[_.\- ]+(\w|$)/g, (m, p1) => p1.toUpperCase());
    }

    _init() {
        let config = {};
        for (let i = 0; i < this.attributes.length; i += 1) {
            config[this._camelize(this.attributes[i].name)] = this.attributes[i].value;
        }
        let keys = [
            'server', 'type', 'id', 'api', 'auth',
            'auto', 'lock',
            'name', 'title', 'artist', 'author', 'url', 'cover', 'pic', 'lyric', 'lrc',
        ];
        this.meta = {};
        for (let key of keys) {
            this.meta[key] = config[key];
            delete config[key];
        }
        this.config = config;

        this.api = this.meta.api || window.meting_api || 'https://xxx.xxx.xxx/?server=:server&type=:type&id=:id&r=:r';
        if (this.meta.auto) this._parse_link();

        // 支持多个 ID,将 id 属性按逗号分割成数组
        this.meta.ids = this.meta.id.split(',');
    }

    _parse_link() {
        let rules = [
            ['music.163.com.*song.*id=(\\d+)', 'netease', 'song'],
            ['music.163.com.*album.*id=(\\d+)', 'netease', 'album'],
            ['music.163.com.*artist.*id=(\\d+)', 'netease', 'artist'],
            ['music.163.com.*playlist.*id=(\\d+)', 'netease', 'playlist'],
            ['music.163.com.*discover/toplist.*id=(\\d+)', 'netease', 'playlist'],
            ['y.qq.com.*song/(\\w+).html', 'tencent', 'song'],
            ['y.qq.com.*album/(\\w+).html', 'tencent', 'album'],
            ['y.qq.com.*singer/(\\w+).html', 'tencent', 'artist'],
            ['y.qq.com.*playsquare/(\\w+).html', 'tencent', 'playlist'],
            ['y.qq.com.*playlist/(\\w+).html', 'tencent', 'playlist'],
            ['xiami.com.*song/(\\w+)', 'xiami', 'song'],
            ['xiami.com.*album/(\\w+)', 'xiami', 'album'],
            ['xiami.com.*artist/(\\w+)', 'xiami', 'artist'],
            ['xiami.com.*collect/(\\w+)', 'xiami', 'playlist'],
        ];

        for (let rule of rules) {
            let patt = new RegExp(rule[0]);
            let res = patt.exec(this.meta.auto);
            if (res!== null) {
                this.meta.server = rule[1];
                this.meta.type = rule[2];
                this.meta.id = res[1];
                return;
            }
        }
    }

    async _parse() {
        if (this.meta.url) {
            let result = {
                name: this.meta.name || this.meta.title || 'Audio name',
                artist: this.meta.artist || this.meta.author || 'Audio artist',
                url: this.meta.url,
                cover: this.meta.cover || this.meta.pic,
                lrc: this.meta.lrc || this.meta.lyric || '',
                type: this.meta.type || 'auto',
            };
            if (!result.lrc) {
                this.meta.lrcType = 0;
            }
            if (this.innerText) {
                result.lrc = this.innerText;
                this.meta.lrcType = 2;
            }
            this._loadPlayer([result]);
            return;
        }

        const allMusicData = [];
        for (const id of this.meta.ids) {
            let url = this.api
              .replace(':server', this.meta.server)
              .replace(':type', this.meta.type)
              .replace(':id', id)
              .replace(':auth', this.meta.auth)
              .replace(':r', Math.random());

            try {
                const res = await fetch(url);
                if (!res.ok) {
                    throw new Error(`HTTP error! status: ${res.status}`);
                }
                const text = await res.text();
                const result = JSON.parse(text);
                if (Array.isArray(result)) {
                    allMusicData.push(...result);
                } else {
                    console.error(`Data for ID ${id} is not an array:`, result);
                }
            } catch (error) {
                console.error(`Fetch error for ID ${id}:`, error);
            }
        }

        // 对获取到的所有音乐数据进行随机排序
        const shuffledMusicData = this._shuffleArray(allMusicData);

        this._loadPlayer(shuffledMusicData);
    }

    _shuffleArray(array) {
        for (let i = array.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            [array[i], array[j]] = [array[j], array[i]];
        }
        return array;
    }

    _loadPlayer(data) {
        let defaultOption = {
            audio: data,
            mutex: true,
            lrcType: this.meta.lrcType || 3,
            storageName: 'metingjs'
        };

        if (!data.length) return;

        let options = {
            ...defaultOption,
            ...this.config,
        };
        for (let optkey in options) {
            if (options[optkey] === 'true' || options[optkey] === 'false') {
                options[optkey] = (options[optkey] === 'true');
            }
        }

        let div = document.createElement('div');
        options.container = div;
        this.appendChild(div);

        this.aplayer = new APlayer(options);
    }
}

console.log('\n %c MetingJS v2.0.1 %c https://github.com/metowolf/MetingJS \n', 'color: #fadfa3; background: #030307; padding:5px 0;', 'background: #fadfa3; padding:5px 0;');

if (window.customElements &&!window.customElements.get('meting-js')) {
    window.MetingJSElement = MetingJSElement;
    window.customElements.define('meting-js', MetingJSElement);
}

然而,在享受技术带来的便利时,我们绝不能忽视著作权的重要性。每一首音乐都是创作者的心血结晶,我们应当在合法合规的前提下使用这些作品,确保对知识产权的尊重。

在前端渲染方面,我选择了APlayer播放器。APlayer以其简洁美观的界面和强大的功能,为用户带来了优质的播放体验。它能够流畅地展示歌曲信息、控制播放进度,并且支持多种主题自定义,使歌单页面在功能性和美观性上达到了较好的平衡。

在前端仅需要随便往哪里插入下列代码即可(我是获取的“我收藏的歌单”下列的歌单,id是什么,需要自行理解,我尊重各站版权)

<link rel="stylesheet" href="/sucai/APlayer/APlayer.min.css">
<script src="/sucai/APlayer/APlayer.min.js"></script>
<script src="/sucai/APlayer/Meting.min.js"></script>
<meting-js server="netease" type="playlist" id="6948853317,326934130,446132364,978446985,2286543721,7235859079" autoplay="true" order="list" preload="auto" list-max-height="100vh"></meting-js>

通过这次实践,我不仅实现了歌单听取自由化的目标,还在技术运用和版权意识上有了更深的体会。希望我的经验能为其他音乐爱好者和开发者提供一些参考,共同打造更加优质、合法的音乐环境。

https://www.dao.js.cn/music

  • ✇懋和道人
  • 关于本站外链处理的思考与行动
    一、缘起在日常维护网站的过程中,一个细节问题引起了我的注意。一直以来,我都十分珍视与其他站点的友好合作关系,通过友情链接、联盟推广等方式,努力为用户拓展更多优质的信息渠道。然而,近期我在对网站进行深入检查时发现,博客中许多站外跳转链接,包括友链等,都没有正确设置 rel 标签。其实,由于一些不可控因素,之前我为所有站外跳转链接设置了中间跳转机制,本意是为了更好地管理和保障用户的浏览安全。但在这个过程中,却疏忽了 rel 标签的设置。https://www.dao.js.cn/new/2025030511627.shtml经过对友链的逐一排查,我发现目前共有 58 个友链站点。其中 41 个站点对出站链接(不限于友链)的 a 标签设置了 rel="noopener noreferrer nofollow",这体现了他们对网站 SEO 优化和链接管理的重视。有 5 个站点采用了转译的 golink 跳转方式处理出站链接,而 “爱写书” 站点则完全没有设置 target 和 rel 标签。其余站点虽设置了 target 跳转,但 rel 标签方面存在缺失。对于友情链接设置 rel 标签,我内
     

关于本站外链处理的思考与行动

2025年3月31日 01:49

一、缘起

在日常维护网站的过程中,一个细节问题引起了我的注意。一直以来,我都十分珍视与其他站点的友好合作关系,通过友情链接、联盟推广等方式,努力为用户拓展更多优质的信息渠道。然而,近期我在对网站进行深入检查时发现,博客中许多站外跳转链接,包括友链等,都没有正确设置 rel 标签。其实,由于一些不可控因素,之前我为所有站外跳转链接设置了中间跳转机制,本意是为了更好地管理和保障用户的浏览安全。但在这个过程中,却疏忽了 rel 标签的设置。

https://www.dao.js.cn/new/2025030511627.shtml

经过对友链的逐一排查,我发现目前共有 58 个友链站点。其中 41 个站点对出站链接(不限于友链)的 a 标签设置了 rel="noopener noreferrer nofollow",这体现了他们对网站 SEO 优化和链接管理的重视。有 5 个站点采用了转译的 golink 跳转方式处理出站链接,而 “爱写书” 站点则完全没有设置 target 和 rel 标签。其余站点虽设置了 target 跳转,但 rel 标签方面存在缺失。

对于友情链接设置 rel 标签,我内心一直有所顾虑。毕竟友情链接是网站之间友好交流的桥梁,设置 rel="noopener noreferrer nofollow" 可能会在一定程度上影响到友链站点的权益,感觉对友链朋友不够友好。尤其是 “爱写书” 站点,没有对我的站点链接做过多限制,这种信任让我很是感激。但从网站自身的 SEO 角度出发,缺失 rel 标签可能会导致 SEO 权重外流,影响网站在搜索引擎中的表现。

在这种纠结的心态下,我经过反复思考,最终决定还是要对网站的外链进行合理处理,以平衡网站自身发展和与友站的关系。

二、思考

从 SEO 的专业知识来讲,rel 标签的正确设置对于网站的权重分配和安全性至关重要。rel="noopener noreferrer nofollow" 这组属性,一方面可以有效防止搜索引擎将本站权重过多传递到外部链接,保障自身网站在搜索排名中的优势;另一方面,也能避免用户因误点恶意外链而带来的潜在风险。

然而,在实际操作中,要对全站的外链进行统一处理并非易事。网站的外链数量众多,来源复杂,涵盖了友链、广告链接、合作推广链接等多种类型。不同类型的外链,其功能和目的各异,处理方式也不能一概而论。而且,在处理外链时,还必须充分考虑用户体验。如果处理不当,可能会导致部分链接无法正常跳转,或者给用户的浏览过程带来不必要的困扰。经过慎重考虑,我认为对全站非 window.location.hostname 的 a 标签 url 施行强制 rel="noopener noreferrer nofollow" 处理是较为合适的方案。

这样既能最大程度地保障网站的 SEO 效果,又不会对用户的正常浏览造成严重影响。对于站内链接,用户可以自由访问;而对于站外链接,设置 rel 标签则是在保护网站自身利益的同时,也提醒用户谨慎对待外部链接。

三、实现

为了实现对全站外链的自动化处理,我借助了 JavaScript 技术。以下是具体的代码实现:

document.addEventListener('DOMContentLoaded', function () {
    const currentDomain = window.location.hostname;

    // 处理所有现有的 <a> 标签
    const allLinks = document.getElementsByTagName('a');
    for (let i = 0; i < allLinks.length; i++) {
        const link = allLinks[i];
        const href = link.href.trim();
        if (isValidExternalLink(href, currentDomain)) {
            link.setAttribute('rel', 'noopener noreferrer nofollow');
        }
    }

    // 创建一个 MutationObserver 实例来监听 DOM 变化
    const observer = new MutationObserver((mutationsList) => {
        for (const mutation of mutationsList) {
            if (mutation.type === 'childList') {
                // 遍历新增的节点
                for (const addedNode of mutation.addedNodes) {
                    if (addedNode.nodeName === 'A') {
                        const link = addedNode;
                        const href = link.href.trim();
                        if (isValidExternalLink(href, currentDomain)) {
                            link.setAttribute('rel', 'noopener noreferrer nofollow');
                        }
                    } else if (addedNode.querySelectorAll) {
                        // 检查新增节点的子节点中是否有 <a> 标签
                        const newLinks = addedNode.querySelectorAll('a');
                        for (const newLink of newLinks) {
                            const href = newLink.href.trim();
                            if (isValidExternalLink(href, currentDomain)) {
                                newLink.setAttribute('rel', 'noopener noreferrer nofollow');
                            }
                        }
                    }
                }
            } else if (mutation.type === 'attributes' && mutation.attributeName === 'href') {
                const link = mutation.target;
                const href = link.href.trim();
                if (isValidExternalLink(href, currentDomain)) {
                    link.setAttribute('rel', 'noopener noreferrer nofollow');
                }
            }
        }
    });

    // 配置 MutationObserver 监听的选项
    const config = { childList: true, subtree: true, attributes: true, attributeFilter: ['href'] };
    // 开始监听 document.body 及其子节点的变化
    observer.observe(document.body, config);

    function isValidExternalLink(href, currentDomain) {
        if (!href || href.startsWith('#') || href.startsWith('javascript:')) {
            return false;
        }
        try {
            const url = new URL(href);
            return url.hostname!== currentDomain;
        } catch (error) {
            return false;
        }
    }
});

这段代码的逻辑是:当页面加载完成(DOMContentLoaded 事件触发)时,获取当前页面的域名 currentDomain。然后遍历页面上所有的 <a> 标签,获取每个标签的 href 属性并进行修剪。通过 isValidExternalLink 函数判断该链接是否为有效的外部链接,如果是,则为其添加 rel="noopener noreferrer nofollow" 属性。同时,利用 MutationObserver 监听 DOM 的变化。当检测到有新节点添加(childList 类型变化)或 <a> 标签的 href 属性改变(attributes 类型变化且 attributeName 为 href)时,对新的或属性变化的 <a> 标签执行相同的检查和处理操作。

在代码编写完成后,我进行了严格的测试。先在本地开发环境中模拟各种页面情况和外链类型,确保代码能准确识别和处理外部链接。随后在生产环境中选取部分页面进行试点,观察实际运行效果并及时调整,最终保证代码能够稳定、有效地运行。

四、效果

image.png

经过对全站外链的处理,取得了较为显著的效果。从 SEO 方面来看,正确设置 rel 标签后,有效避免了 SEO 权重外流的问题。之前由于很多外链未设置 rel 标签,搜索引擎在抓取页面时可能会将部分权重传递到外部,影响网站自身排名。现在,搜索引擎能够更准确地处理外链,将权重更多地集中在站内页面,有助于提升网站在搜索结果中的整体排名。

在用户体验方面,虽然对外部链接设置了 rel 标签,但由于处理方式合理,并未对用户的正常浏览和跳转造成明显阻碍。用户依然可以自由点击外部链接,同时也在一定程度上提高了浏览的安全性,减少了恶意链接带来的潜在风险。此外,通过这次对外链的全面梳理和处理,我对网站的链接结构有了更清晰的认识。发现并清理了一些无效链接和重复链接,进一步优化了网站的性能和稳定性,为用户提供了更优质的浏览体验。

当然,SEO 优化是一个持续的过程,外链处理只是其中的一部分。未来,我会继续关注网站的 SEO 效果,不断优化和调整策略。同时,也会更加注重与友链站点的沟通与合作,在保障自身网站发展的前提下,维护好与友站的友好关系,共同促进互联网生态的健康发展。

思路来源于

https://blog.hslzz.cn/20250305191500.html

  • ✇懋和道人
  • 巧用泽泽社长NiceMapMarker思路构建我的“足迹”
    最近我被 “足迹” 功能深深吸引住了,起因是逛了好多博客,发现人家都有这么个有意思的功能,能在地图上标记去过的地方,分享自己的旅程。这可把我馋坏了,心心念念着自己的博客也得安排上。为这事儿,我晚上翻来覆去,脑子里全是怎么实现 “足迹” 功能,根本睡不着觉,辗转反侧、寤寐思服、夜不能寐,满心满眼就只有这一件事。今天总算是下定决心开始动手了,找来找去,发现泽泽社长的 NiceMapMarker 插件简直就是为我量身定制的!它能基于腾讯地图 API 和百度地图 API 实现地图多地点标记,这不就是我一直想要的嘛!https://store.typecho.work/archives/NiceMapMarker-typecho-plugin.html我赶紧打开插件介绍页面,仔仔细细研究起来。这一看,发现使用前准备工作还不少。首先得去腾讯地图开放平台和百度地图开放平台申请开发者账号。腾讯那边登录账号新建应用,选浏览器端,建好后能拿到应用 key;百度这边类似,新建应用拿到 AK,然后都填到插件设置里。这一步虽说有点繁琐,但难不倒我,按部就班地操作,很快就搞定了。https://lbs.qq.co
     

巧用泽泽社长NiceMapMarker思路构建我的“足迹”

2025年3月30日 05:21

image.png

最近我被 “足迹” 功能深深吸引住了,起因是逛了好多博客,发现人家都有这么个有意思的功能,能在地图上标记去过的地方,分享自己的旅程。这可把我馋坏了,心心念念着自己的博客也得安排上。为这事儿,我晚上翻来覆去,脑子里全是怎么实现 “足迹” 功能,根本睡不着觉,辗转反侧、寤寐思服、夜不能寐,满心满眼就只有这一件事。

今天总算是下定决心开始动手了,找来找去,发现泽泽社长的 NiceMapMarker 插件简直就是为我量身定制的!它能基于腾讯地图 API 和百度地图 API 实现地图多地点标记,这不就是我一直想要的嘛!

https://store.typecho.work/archives/NiceMapMarker-typecho-plugin.html

我赶紧打开插件介绍页面,仔仔细细研究起来。这一看,发现使用前准备工作还不少。首先得去腾讯地图开放平台和百度地图开放平台申请开发者账号。腾讯那边登录账号新建应用,选浏览器端,建好后能拿到应用 key;百度这边类似,新建应用拿到 AK,然后都填到插件设置里。这一步虽说有点繁琐,但难不倒我,按部就班地操作,很快就搞定了。

https://lbs.qq.com/getPoint/

接着就是查经纬度,用哪个平台就在哪个平台查。腾讯地图在指定的网址查,百度地图也有对应的查询页面。我一边查,一边感慨这细节还挺多,不过每完成一步,离实现 “足迹” 功能就更近一步,心里那叫一个兴奋。

设置参数的时候也有点小挑战。它可以用zoom参数设置地图缩放,默认是 5,还能用height参数设置地图组件在文章里显示的高度。一开始,我设置的参数没达到预期效果,地图不是缩放得不合适,就是显示高度不对。好在我多试了几次,不断调整,总算是让地图显示得像模像样了。

在文章里按照格式书写标记信息的时候,我又遇到了点小麻烦。超链接和图片链接的填写得格外注意,有一次因为少写了个符号,怎么都显示不对。不过,经过反复检查和修改,最终还是成功实现了!看着地图上一个个标记着我 “足迹” 的点,心里别提多有成就感了。

https://www.dao.js.cn/zuji

现在,我的博客 “足迹” 功能算是初步完成了。虽然过程中遇到了不少问题,但好在都一一解决了。接下来,我打算再优化优化,比如多找些好看的图片当标记,让 “足迹” 页面更美观。今天的成果让我对后续的开发充满了信心,期待能给博客带来更多有趣的功能!


昨天以前懋和道人
  • ✇懋和道人
  • 纯净主题的几个东西的备份
    一,关于新增分页模板的include.php修改,纯净主题每加个自定义模板如haowu,则改之function tpure_DefaultTemplate(&$template) {     global $zbp;     if($template->GETTags('type') == 'index' && $template->GETTags('page') != '1'){         switch($zbp->Config('tpure')->PostINDEXSTYLE){             case "1":                 $template->SetTemplate('forum');                 break;             case "2":                 $template->SetTemplate('album');                 break;             case "3":             
     

纯净主题的几个东西的备份

2025年3月28日 22:41

一,关于新增分页模板的include.php修改,纯净主题每加个自定义模板如haowu,则改之

function tpure_DefaultTemplate(&$template)
{
    global $zbp;
    if($template->GETTags('type') == 'index' && $template->GETTags('page') != '1'){
        switch($zbp->Config('tpure')->PostINDEXSTYLE){
            case "1":
                $template->SetTemplate('forum');
                break;
            case "2":
                $template->SetTemplate('album');
                break;
            case "3":
                $template->SetTemplate('sticker');
                break;
            case "4":
                $template->SetTemplate('hotspot');
                break;
            case "5":
                $template->SetTemplate('haowu');
                break;
            case "6":
                $template->SetTemplate('zuji');
                break;
            default:
                $template->SetTemplate('catalog');
        }
    }
    if(($template->GetTags('type') == 'category' && $template->GetTags('category')->Template != 'forum' && $template->GetTags('category')->Template != 'album' && $template->GetTags('category')->Template != 'sticker' && $template->GetTags('category')->Template != 'hotspot' && $template->GetTags('category')->Template != 'haowu' && $template->GetTags('category')->Template != 'zuji') ||
       ($template->GetTags('type') == 'tag' && $template->GetTags('tag')->Template != 'forum' && $template->GetTags('tag')->Template != 'album' && $template->GetTags('tag')->Template != 'sticker' && $template->GetTags('tag')->Template != 'hotspot' && $template->GetTags('tag')->Template != 'haowu' && $template->GetTags('tag')->Template != 'zuji') || $template->GetTags('type') == 'date'){
        $template->SetTemplate('catalog');
    }
    if($template->GetTags('type') == 'author' && $template->GetTags('author')->Template != 'catalog' && $template->GetTags('author')->Template != 'forum' && $template->GetTags('author')->Template != 'album' && $template->GetTags('author')->Template != 'sticker' && $template->GetTags('author')->Template != 'hotspot' && $template->GetTags('author')->Template != 'haowu' && $template->GetTags('author')->Template != 'zuji'){
        $template->SetTemplate('author');
    }
}

第二部分

function tpure_JudgeListTemplate($listtype)
{
    global $zbp;
    $listtype = $zbp->Config('tpure')->PostSEARCHSTYLE;
    switch($listtype)
    {
        case 1:
            $template = 'forum';
            break;
        case 2:
            $template = 'album';
            break;
        case 3:
            $template = 'sticker';
            break;
        case 4:
            $template = 'hotspot';
            break;
        case 5:
            $template = 'haowu';
            break;
        case 6:
            $template = 'zuji';
            break;    
        default:
            $template = '';
    }
    return $template;
}

二,由于纯净主题的IP归属地数据库不太理想,所以用的插件替代,如

<div class="cmtsname">{if $comment.Author.HomePage}<a href="{$comment.Author.HomePage}" rel="nofollow" target="_blank">{$comment.Author.StaticName}</a>{else}{$comment.Author.StaticName}{/if}{if $comment.Author.ID >= 59 && $comment.Author.ID <= 95}&nbsp;<i class="bi bi-robot"></i>&nbsp;{/if}{if $zbp->Config('tpure')->PostCMTIPON == '1'}<em>IP:{tpure_ipLocation($comment.IP)}</em>{/if}&nbsp;<em>{$comment.CommentUA['browser']['title']}</em>
            &nbsp;<em>{$comment.CommentUA['platform']['title']}</em></div>

三,评论处添加自定义提示,如commentpost.php,comment.php等

<textarea name="txaArticle" id="txaArticle" rows="3" tabindex="1" placeholder="请输入您的评论。点击“评论”按钮后,如果信息无误会自动刷新页面,即评论成功。因为缓存、CDN等因素,新评论将延时展示,并不能第一时间看到自己的评论。"></textarea>

四,纯净主题的文章页面在新版本的略缩图不可用,上传自定义略缩图无效,保存文章直接500;

五,纯净主题的文章页面的音乐播放与修改后的模板某些地方js冲突,只能优先使用拓源的mp3插件;

六,纯净主题暂不支持PHP8.*,故每次更新需要覆盖plugin/phpmailer;

七,每次更新要注意footer.php内版权信息的更新。

其他需要注意的地方

右侧的作者统计,数字展示已经更改

https://www.dao.js.cn/new/2025020511594.shtml

暂时没有任何办法强制评论邮箱、网址、用户名均为必填,故如下

https://www.dao.js.cn/new/2024092011436.shtml

文章页面新增的ai摘要,每次升级需注意添加

https://www.dao.js.cn/new/2024121611540.shtml

文章页面新增的时间因子,每次升级需要注意添加

https://www.dao.js.cn/new/2024090311412.shtml

❌
❌