前段时间有小伙伴问这个是怎么实现的,单独开一篇来说一下

首先说明一下Dream2.0Plus的主题文档中提供了访客侧边栏的源码方案(笔者也是自己写完了才发现原来主题作者其实有提供)
https://www.hcjike.com/docs/halo-theme-dream2.0/theme/sidebar-assembly
如果想直接采用主题作者方案的小伙伴,直接套用上述链接内的代码按照常规的自定义侧边栏配置即可,也可自行编写HTML嵌入
为了对得起自己造的轮子,下面笔者详细说明一下制作过程。
定位API服务
市面上有太多免费的API接口服务了,笔者测试了很多不同服务商的,当然也包括腾讯、高德、百度这些大厂,总结来说大厂的东西确实更好用,但作为个人开发者每天有限额,比如腾讯的地图服务大概是每天6000次的调用量,当然这个量级对于一个博客站来说已经完全够用了,但是配置过于复杂。经过三番比较,笔者最终选择了Nice猫,只能说这大概是笔者见过的最稳定最好用的API聚合站之一。
注册并获取API Key
打开Nice猫,注册并登录,随后在密钥管理中找您的API KEY 密钥同时根据需要配置安全校验方式 ,建议配置。

本站访客信息侧边栏源码
废话不多说,直接看代码
<style>
/* 居中对齐样式 */
.align-center {
text-align: center
}
/* 字体颜色样式 - 天蓝色 */
.font-color {
color: deepskyblue
}
/* IP地址遮罩样式 */
.ip-mask {
cursor: pointer;
/* 鼠标悬停时显示手型光标 */
user-select: none;
/* 禁止用户选择文本 */
transition: all .3s ease;
/* 添加过渡动画效果 */
filter: blur(4px)
/* 默认模糊效果 */
}
/* IP地址遮罩悬停效果 */
.ip-mask:hover {
filter: none
/* 悬停时取消模糊效果 */
}
</style>
<!-- 欢迎信息区域 -->
<div id="welcomeMessage" class="align-center" style="margin-top:13px">
<p>🌍 小伙伴你好呀! 🌍</p>
<p>正在寻找你的足迹...</p>
</div>
<hr />
<!-- 友情链接区域 -->
<div class="align-center"
style="margin-left:5px;margin-right:5px;margin-top:5px;border-bottom-width:unset;margin-bottom:5px">
<p>🚇 继续探索未知 👇️👇️ 发现更多精彩 🚇</p>
<!-- Travellings 友链接力链接 -->
<a href="https://www.travellings.cn/go.html" target="_blank" rel="noopener" title="开往-友链接力" aria-label="开往-友链接力">
<img src="https://www.travellings.cn/assets/logo.gif" alt="开往-友链接力" width="120" />
</a>
<!-- BlogsClub 空间穿梭链接 -->
<a href="https://blogs.quest" target="_blank" title="空间穿梭-随机访问 BlogsClub 成员博客"
aria-label="空间穿梭-随机访问 BlogsClub 成员博客">
<img src="https://www.blogsclub.org/images/shuttle_4.png" alt="空间穿梭" />
</a>
</div>
<script>
/**
* 根据当前时间获取问候语和建议
* @returns {Object} 包含问候语(greeting)和建议(advice)的对象
*/
function getGreetingAndAdvice() {
// 获取当前小时数
const hour = new Date().getHours();
// 根据不同时间段返回相应的问候语和建议
if (hour < 6) {
return {
greeting: "🌛 深夜好呀 👋",
advice: "🌙不要熬夜 早点休息啦🌙"
}
}
else if (hour < 11) {
return {
greeting: "🌞 早上好呀 👋",
advice: "💪新的一天 充满活力💪"
}
}
else if (hour < 13) {
return {
greeting: "🍽️ 中午好呀 👋",
advice: "🍔别忘了享受一顿美味的午餐🍔"
}
}
else if (hour < 18) {
return {
greeting: "☕ 下午好呀 👋",
advice: "🍵休息一下 喝杯咖啡吧🍵"
}
}
else if (hour < 22) {
return {
greeting: "🌜 晚上好呀 👋",
advice: "🌃放松心情 享受夜晚的宁静🌃"
}
}
else {
return {
greeting: "🌛 深夜好呀 👋",
advice: "🌙不要熬夜 早点休息啦🌙"
}
}
}
/**
* 角度转弧度函数
* @param {number} degrees - 角度值
* @returns {number} 弧度值
*/
function toRadians(degrees) {
return degrees * (Math.PI / 180)
}
/**
* 计算两点间距离(Haversine公式)
* @param {number} lat - 纬度
* @param {number} lng - 经度
* @returns {string} 格式化后的距离(公里)
*/
function calculateDistance(lat, lng) {
// 地球半径(公里)
const R = 6371;
// 自定义纬度(站点位置)
const customLat = 0.00;
// 自定义经度(站点位置)
const customLng = 0.00;
// 计算经纬度差值并转换为弧度
const dLat = toRadians(lat - customLat);
const dLon = toRadians(lng - customLng);
// Haversine公式计算距离
const a = Math.sin(dLat / 2) ** 2 +
Math.cos(toRadians(customLat)) *
Math.cos(toRadians(lat)) *
Math.sin(dLon / 2) ** 2;
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
// 返回格式化后的距离
return (R * c).toFixed(2)
}
/**
* 获取用户地理位置信息
* @returns {Promise<Object|null>} 用户位置信息对象或null
*/
async function fetchLocation() {
// API配置数组
const apis = [{
url: "https://api.nsmao.net/api/ip/query?key=XXXXXXXXXXXXX",
provinceField: "prov"
},
{
url: "https://api.nsmao.net/api/ipip/query?key=XXXXXXXXXXXXX",
provinceField: "province"
}
];
// 遍历API尝试获取位置信息
for (const api of apis) {
try {
// 发起请求
const res = await fetch(api.url);
// 解析响应
const { code, data } = await res.json();
// 请求成功
if (code === 200) {
return {
// IP地址
ip: data.ip,
// 国家
country: data.country,
// 省份
province: data[api.provinceField],
// 城市
city: data.city,
// 区县
district: data.district,
// 行政区划代码
adcode: data.adcode,
// 距离
length: calculateDistance(data.lat, data.lng)
}
}
}
catch (e) {
console.error(`获取地理位置失败 (${api.url}):`, e);
// 出错继续下一个API
continue
}
}
// 所有API都失败返回null
return null
}
/**
* 渲染欢迎信息
* @param {Object} location - 位置信息对象
*/
function renderWelcomeMessage(location) {
// 获取问候语
const { greeting, advice } = getGreetingAndAdvice();
// 构建位置HTML字符串
let locationHtml = "";
// 按优先级拼接位置信息
if (location.province) {
locationHtml += `<strong class="font-color">${location.province} </strong>`
}
if (location.city) {
locationHtml += `<strong class="font-color">${location.city} </strong>`
}
if (location.district) {
locationHtml += `<strong class="font-color">${location.district}</strong>`
}
// 更新欢迎信息内容
document.getElementById("welcomeMessage").innerHTML =
`<p class="align-center"><strong>${greeting}</strong></p>` +
`<p>欢迎来自 ${locationHtml} 的小伙伴!</p>` +
`<p class="align-center">${advice}</p>` +
`<p class="align-center">🌍 您当前的 IP 是<strong><span class="ip-mask font-color">${location.ip}</span></strong> 🌍</p>` +
`<p class="align-center">📍 距离 <strong class="font-color">本站</strong> 约<strong class="font-color">${location.length}</strong> 公里哦!📍</p>`
}
/**
* 初始化函数
*/
async function init() {
// 获取位置信息
const location = await fetchLocation();
if (location) {
// 渲染欢迎信息
renderWelcomeMessage(location);
}
else {
// 获取失败时显示错误信息
document.getElementById("welcomeMessage").innerHTML =
`<p>🌍 这位小伙伴,你似乎迷失了~🌍</p><p>获取位置信息失败,请稍后再试~😅<p>`
}
}
// 页面加载完成后执行初始化
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init)
}
else {
init()
}
</script>以上有几个需要进行配置的地方:
customLat(纬度)和customLng(经度)分别代表自定义的经纬度,默认是0.0,你可以设置成任何位置,同时也可以一并修改描述信息<strong class="font-color">本站</strong>,将本站改为你的目标地点名称。url: "https://api.nsmao.net/api/ip/query?key=XXXXXXXXXXXXX"和url: "https://api.nsmao.net/api/ipip/query?key=XXXXXXXXXXXXX"这里的key需要自行拼接上刚才在Nice猫生成的key
经纬度的获取也非常方便,直接使用百度坐标拾取器就行
https://lbs.baidu.com/maptool/getpoint
最后,把代码复制进自定义模块侧边栏的侧边栏内容里就大功告成了。

评论