一、 开篇吐槽:谁还没被友情链接“坑”过?
兄弟们,不知道你们有没有这种经历:心血来潮建了个个人博客,或者好不容易搞了个小项目站。某天,好基友A跑来:“哥们儿,加个友情链接呗!”你爽快答应,打开模板文件,找到底部那坨HTML,吭哧吭哧加上一行 <a href="...">基友A的站</a>。
没过两天,好基友B也来了。你又重复一遍操作。后来,基友C的站打不开了,你得去手动删掉;基友A换域名了,你又得去手动修改……
此时的你,内心OS大概是: 我就想安安静静写个代码,怎么沦为了一个无情的“链接更新工人”?这玩意儿明明就是个简单的列表,为啥每次改动都像在给心脏做搭桥手术?
别慌!今天,咱们就要把这个“远古”流程彻底现代化。我们要实现的,是一个后台动态管理、前端自动渲染、还带点小酷炫效果的友情链接组件!从此,PM(或者就是你自个儿)在后台点点鼠标,前端就能优雅地展示出来,你再也不用碰那“脏兮兮”的模板代码了。
二、 后端基石:把链接“调教”成温顺的数据
前端再花哨,也得有坚实的数据支撑。咱们先花几分钟,用Django的模型(Model)给友情链接建个“户口本”。
1. 模型设计:咱们的链接得有“身份证”
我们不仅要存链接和名字,还得考虑点儿高级货,比如Logo、描述、是否展示等。打开你的 models.py,来这么一段:
from django.db import models
class FriendLink(models.Model):
# 链接名字,比如“老张的胡思乱想”
name = models.CharField(max_length=50, verbose_name="网站名称")
# 完整的网址,别忘了https://
url = models.URLField(verbose_name="网址")
# 不是必须的,但有个Logo会显得很专业
logo = models.ImageField(upload_to='friend_logo/', blank=True, null=True, verbose_name="网站Logo")
# 一段简短的描述,鼠标放上去能看到,提升逼格
description = models.CharField(max_length=200, blank=True, verbose_name="描述")
# 控制是否显示,不想展示某个链接时不用删除,勾掉就行
is_active = models.BooleanField(default=True, verbose_name="是否激活")
# 创建时间,可以用来排序
created_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
class Meta:
verbose_name = "友情链接"
verbose_name_plural = verbose_name
ordering = ['-created_time'] # 默认按创建时间倒序排列
def __str__(self):
return self.name # 在后台显示时,直接显示网站名,清晰明了
2. 视图函数:只吐出我们需要的“干货”
数据有了,怎么给前端呢?我们写一个超级简单的视图,只做一件事:把激活的友情链接,打包成JSON格式的数据扔给前端。在 views.py 里:
from django.http import JsonResponse
from .models import FriendLink
def friendlinks_json(request):
"""
专门用于提供友情链接JSON数据的视图
"""
# 从数据库里捞出所有“激活”的链接
links = FriendLink.objects.filter(is_active=True)
# 把QuerySet对象转换成字典列表,方便序列化成JSON
data = list(links.values('name', 'url', 'logo', 'description'))
return JsonResponse(data, safe=False) # safe=False允许我们返回列表而非字典
3. URL配置:给前端一个“接头地址”
光有视图不行,得告诉Django哪个网址能访问到这个数据。在 urls.py 里加一条:
from django.urls import path
from . import views
urlpatterns = [
# ... 你其他的url配置
path('api/friendlinks/', views.friendlinks_json, name='friendlinks_api'),
]
搞定!现在,任何人访问 /api/friendlinks/,就能拿到一份纯正的、热乎乎的友情链接JSON数据了。后端部分,宣告完工!是不是So easy?
三、 前端魔术:让链接列表“活”起来
重头戏来了!前方高能,我们将用纯原生JavaScript和CSS,打造一个低耦合、高颜值的友情链接组件。
1. HTML结构:搭好舞台
我们打算在页面某个地方(比如侧边栏或底部)留一个“坑”,这个坑将来会被我们的友情链接组件自动填充。
<!-- 在你想要展示友情链接的地方,比如sidebar或footer里,放上这个div -->
<aside class="friend-links-container">
<h3>🌟 小伙伴们</h3>
<!-- 这个ul就是为我们动态生成的链接列表准备的容器 -->
<ul id="friend-links-list"></ul>
<!-- 再来一个加载中的提示,很贴心有木有 -->
<p id="links-loading">友情链接加载中...</p>
</aside>
2. CSS样式:颜值即正义
光有骨架不行,得给它穿上好看的衣服。我们来写点现代感的CSS:
/* 友情链接容器样式 */
.friend-links-container {
background: #f9f9f9;
border-radius: 12px;
padding: 1.5rem;
margin-top: 2rem;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
}
.friend-links-container h3 {
margin-top: 0;
color: #333;
border-bottom: 2px solid #eee;
padding-bottom: 0.5rem;
}
/* 链接列表样式 */
#friend-links-list {
list-style: none;
padding: 0;
margin: 0;
display: grid; /* 使用Grid布局,自动适配,比Float不知道高到哪里去了 */
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 1rem;
}
/* 每个链接项的样式 */
.friend-link-item {
background: white;
border-radius: 8px;
padding: 1rem;
transition: all 0.3s ease; /* 过渡动画,让交互更丝滑 */
border: 1px solid #eaeaea;
}
.friend-link-item:hover {
transform: translateY(-3px); /* 悬停时微微上浮 */
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.1);
border-color: #4a90e2; /* 悬停时边框变蓝色 */
}
/* 链接本身的样式 */
.friend-link {
display: flex;
align-items: center;
text-decoration: none;
color: #555;
}
/* Logo的小图样式 */
.friend-logo {
width: 24px;
height: 24px;
border-radius: 4px;
margin-right: 0.75rem;
object-fit: cover; /* 防止图片被拉伸 */
}
/* 网站名字样式 */
.friend-name {
font-weight: 600;
font-size: 0.95rem;
}
/* 加载中的文字样式 */
#links-loading {
text-align: center;
color: #999;
font-style: italic;
}
3. JavaScript:注入灵魂的时刻
最后,就是让这一切动起来的魔法——JavaScript。我们会用 fetch API 去我们刚才定义的后端接口“取数据”。
// 等待整个页面的DOM内容加载完毕再执行我们的脚本
document.addEventListener('DOMContentLoaded', function() {
const listElement = document.getElementById('friend-links-list');
const loadingElement = document.getElementById('links-loading');
// 发起fetch请求,获取数据
fetch('/api/friendlinks/') // 这里就是我们在urls.py里配置的地址
.then(response => {
if (!response.ok) {
throw new Error('网络响应不正常');
}
return response.json(); // 解析JSON数据
})
.then(links => {
// 先隐藏加载中的提示
loadingElement.style.display = 'none';
// 如果拿到了数据且数据长度大于0
if (links && links.length > 0) {
// 遍历每一条链接数据
links.forEach(link => {
// 创建一个li元素
const li = document.createElement('li');
li.className = 'friend-link-item';
// 创建a标签
const a = document.createElement('a');
a.href = link.url;
a.className = 'friend-link';
a.target = '_blank'; // 在新窗口打开
a.rel = 'noopener noreferrer'; // 安全措施,防钓鱼
a.title = link.description || link.name; // 鼠标悬停显示描述
// 组装HTML内容
let htmlContent = '';
if (link.logo) {
// 如果有Logo,就加上图片
htmlContent += `<img src="${link.logo}" alt="${link.name}" class="friend-logo">`;
}
htmlContent += `<span class="friend-name">${link.name}</span>`;
a.innerHTML = htmlContent;
li.appendChild(a);
listElement.appendChild(li);
});
} else {
// 如果没有数据,显示一个友好的提示
listElement.innerHTML = '<li>暂无友情链接</li>';
}
})
.catch(error => {
// 如果请求失败,打印错误并提示用户
console.error('获取友情链接失败:', error);
loadingElement.textContent = '友情链接加载失败,请刷新试试~';
});
});
四、 完整示例:Copy/Paste就能跑
理论说再多,不如一个完整的例子来得实在。假设你有一个 base.html 模板,可以这样整合:
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>我的酷站</title>
<style>
/* 把上面那坨CSS代码原封不动地拷贝到这里 */
.friend-links-container { ... }
/* ... 省略其他CSS,为了篇幅,但你懂的,要全拷过来 */
</style>
</head>
<body>
<header>...</header>
<main>...</main>
<footer>
<!-- 这里是我们的友情链接组件 -->
<aside class="friend-links-container">
<h3>🌟 小伙伴们</h3>
<ul id="friend-links-list"></ul>
<p id="links-loading">友情链接加载中...</p>
</aside>
</footer>
<script>
// 把上面那坨JavaScript代码原封不动地拷贝到这里
document.addEventListener('DOMContentLoaded', function() { ... });
</script>
</body>
</html>
使用步骤:
- 将模型、视图、URL配置好,并运行
python manage.py makemigrations和migrate。 - 去Django自带的后台,创建几条
FriendLink数据,记得勾选is_active。 - 将上面的完整HTML示例放到你的模板中。
- 访问你的网站,刷新页面,就能看到动态加载、带悬停效果的友情链接了!
五、 总结与升华
你看,我们就这样,从一个令人烦躁的重复劳动中,解放了出来!
- 对站长/你: 以后增删改链接,只需要在Django后台动动手指,前端自动同步,维护成本几乎为零。
- 对用户: 看到了一个更具动态感和交互性的组件,体验Up!Up!
- 对SEO: 由于链接是JavaScript动态加载的,对于搜索引擎爬虫,可以考虑使用服务端渲染(SSR)或动态渲染技术来优化,这是后话,但我们的架构为这种进阶玩法留足了空间。
所以,别再傻乎乎地硬编码了!拥抱动态组件,让你的Django项目更智能、更优雅。这一个小小的组件,体现的是前端与后端分离的思想,是追求效率和体验的工匠精神。
快去你的项目里试试吧,保证你用过之后,再也不想回到“原始社会”了!
901

被折叠的 条评论
为什么被折叠?



