FullStack - 如何在 2021 年用纯 HTML、CSS 和 JS 创建一个可运行的博客网站 - 2
视频教程
代码
您可能觉得有用的文章
大家好,今天我们将对两周前创建的博客网站进行一些高级功能改进。我添加了一些高级功能,例如:
- Google 身份验证登录/注销
- 仪表板
- 用户在仪表板上撰写的博客
- 可以从仪表板阅读/编辑/删除博客。
- 从博客页面本身编辑博客。
- 存储/显示作者用户名。
由于这是上一个部分的延续,所以我使用了之前的代码和文件结构。
演示代码教程已在 Heroku 上架,并提供说明。您可以观看下方视频。
视频教程
教程观看目标 - 如果视频教程的观看次数达到 5K+,我将制作一个功能齐全的电子商务网站的教程,包括卖家页面、产品列表、下订单、贝宝网关、登录/注销等等。
因此,不要浪费更多时间,让我们看看如何编写代码。
代码
因此,开始之前请在public
文件夹中创建 4 个文件。
dashboard.html
css/dashboard.css
js/dashoboard.js
js/nav.js
我们也需要这四个文件。
因此让我们打开server.js
文件并制定/admin
路线。
app.get("/admin", (req, res) => {
res.sendFile(path.join(initial_path, "dashboard.html"));
})
这里需要注意的是,如果将此路由添加到/:blog
路由下方,它将无法正常工作。因为/:blog
单个“/”后面的内容表示任何字符,所以它会被视为/admin
博客。因此,请转到服务器仪表板。将路由添加到/:blog
路由上方。
路线完成后,我们来制作仪表板页面。
在仪表盘页面,添加这个 CSS 样式表。https://www.gstatic.com/firebasejs/ui/4.8.1/firebase-ui-auth.css
以及这个 JS 脚本https://www.gstatic.com/firebasejs/ui/4.8.1/firebase-ui-auth.js
,我从中获取了这些链接。这些链接是 Firebase 预构建的登录 UI。您可以在文档中轻松找到它们。
之后,链接我们上次使用的所有 Firebase CDN。并复制firestore
CDN。将 替换firestore
为auth
auth CDN。
以及链接home.css
和dashboard.css
文件。
<head>
<link type="text/css" rel="stylesheet" href="https://www.gstatic.com/firebasejs/ui/4.8.1/firebase-ui-auth.css" />
<link rel="stylesheet" href="css/home.css">
<link rel="stylesheet" href="css/dashboard.css">
</head>
<body>
<script src="https://www.gstatic.com/firebasejs/8.9.1/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.9.1/firebase-firestore.js"></script>
<script src="https://www.gstatic.com/firebasejs/ui/4.8.1/firebase-ui-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.10.0/firebase-auth.js"></script>
<script src="js/firebase.js"></script>
<script src="js/dashboard.js"></script>
<script src="js/nav.js"></script>
</body>
您可以观看教程以获得更好的理解。
现在让我们实现一个登录功能。为此
仪表板.html
<!-- login -->
<div class="login">
<div id="loginUI"></div>
</div>
仪表板.css
body{
background: #ececec;
}
.login{
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
z-index: 99;
background: #fff;
}
/* login hover effect */
.firebaseui-idp-button:hover{
background: #000 !important;
}
.firebaseui-idp-button:hover .firebaseui-idp-text{
color: #fff !important;
transition: .5s;
}
在dashboard.js
确保你这样做之前firebase.js
let auth = firebase.auth();
dashboard.js
let ui = new firebaseui.auth.AuthUI(auth);
let login = document.querySelector('.login');
auth.onAuthStateChanged((user) => {
if(user){
login.style.display = "none";
getUserWrittenBlogs();
} else{
setupLoginButton();
}
})
const setupLoginButton = () => {
ui.start("#loginUI", {
callbacks: {
signInSuccessWithAuthResult: function(authResult, redirectURL) {
location.reload();
return false;
}
},
signInFlow: "popup",
signInOptions: [firebase.auth.GoogleAuthProvider.PROVIDER_ID]
})
}
接下来,我们来为仪表盘和博客卡片创建一个导航栏。
这些元素和我们的主页一样。直接复制就行了。
<nav class="navbar">
<img src="img/logo.png" class="logo" alt="">
<ul class="links-container">
<li class="link-item"><a href="/" class="link">home</a></li>
<li class="link-item"><a href="/editor" class="link">editor</a></li>
</ul>
</nav><!-- dashboard -->
<h1 class="heading">your blogs</h1>
<!-- blog section -->
<section class="blogs-section">
<div class="blog-card">
<img src="img/header.png" class="blog-image" alt="">
<h1 class="blog-title">Lorem ipsum dolor sit amet consectetur.</h1>
<p class="blog-overview">Lorem ipsum dolor sit amet consectetur adipisicing elit. Sunt incidunt fugiat quos porro repellat harum. Adipisci tempora corporis rem cum.</p>
<a href="/" class="btn dark">read</a>
<a href="/" class="btn grey">edit</a>
<a href="/" class="btn danger">delete</a>
</div>
</section>
您可以看到一些我们在主页博客中没有的额外元素。为此,请提供以下样式。
.heading{
color: rgba(0, 0, 0, 0.5);
font-size: 60px;
text-align: center;
position: relative;
margin: 100px 0 20px;
}
.btn.grey{
background: #c5c5c5;
color: #000;
margin: 0 10px;
}
.btn.danger{
background: #f00;
color: #fff;
}
输出
现在您可以评论博客卡片了。
现在让我们创建导航栏动态链接。为此,请打开nav.js
并编写代码。
const ul = document.querySelector('.links-container');
auth.onAuthStateChanged((user) => {
if (user) {
ul.innerHTML += `
<li class="link-item"><a href="/admin" class="link">Dashboard</a></li>
<li class="link-item"><a href="#" onclick="logoutUser()" class="link">Logout</a></li>
`
} else {
ul.innerHTML += `
<li class="link-item"><a href="/admin" class="link">Login</a></li>
`
}
});
只需添加nav.js
CDN firebase-auth
。您的所有页面。
输出
如果你看到上面的代码,你会看到logout
函数。那么,让我们创建它。在里面创建这个firebase.js
const logoutUser = () => {
auth.signOut();
location.reload();
}
现在我们的登录/注销已经通过动态链接完成了。现在让我们将作者信息保存/检索到数据库中。
打开editor.js
并首先检查用户是否登录。
auth.onAuthStateChanged((user) => {
if (!user) {
location.replace('/admin');
}
});
然后像这样更改前面的代码。
db.collection("blogs").doc(docName).set({
title: blogTitleField.value,
article: articleFeild.value,
bannerImage: bannerPath,
publishedAt: `${date.getDate()} ${months[date.getMonth()]} ${date.getFullYear()}`, // till here we made in last blog
author: auth.currentUser.email.split('@')[0]
})
这样我们就可以将作者添加到数据库中了。现在,在博客页面上显示作者。
为此,请在设置元素后,打开blog.js
并在函数内部添加此代码。就像这样。setupBlog
publishedAt
publish.innerHTML += data.publishedAt;
publish.innerHTML += ` -- ${data.author}`;
输出
太棒了!我们已经完成了 50%。现在,让我们在仪表盘中获取/制作博客卡片。打开dashboard.js
// fetch user
const getUserWrittenBlogs = () => {
db.collection("blogs").where("author", "==", auth.currentUser.email.split('@')[0])
.get()
.then((blogs) => {
blogs.forEach((blog) => {
createBlog(blog);
});
})
.catch((error) => {
console.log("Error getting documents: ", error);
});
}
const createBlog = (blog) => {
let data = blog.data();
blogSection.innerHTML += `
<div class="blog-card">
<img src="${data.bannerImage}" class="blog-image" alt="">
<h1 class="blog-title">${data.title.substring(0, 100) + '...'}</h1>
<p class="blog-overview">${data.article.substring(0, 200) + '...'}</p>
<a href="/${blog.id}" class="btn dark">read</a>
<a href="/${blog.id}/editor" class="btn grey">edit</a>
<a href="#" onclick="deleteBlog('${blog.id}')" class="btn danger">delete</a>
</div>
`;
}
const deleteBlog = (id) => {
db.collection("blogs").doc(id).delete().then(() => {
location.reload();
}).catch((error) => {
console.error("Error removing document: ", error);
});
}
通过这种方式,我们现在可以获取用户撰写的博客,也可以删除它们。
输出
现在让我们编辑博客页面上的按钮。将此按钮添加到published
元素之后。
<a class="btn" id="edit-blog-btn" href="">edit blog</a>
并采用这样的风格。
博客.css
#edit-blog-btn{
background: rgba(0, 0, 0, 0.2);
display: none;
}
我在开发过程中发现了一些样式问题。因此,我建议你也为这些元素添加这些样式。
博客.css
.article *{
word-break: break-word;
}
主页.css
.blogs-section{
word-break: break-word;
}
现在,当作者访问该页面时,编辑按钮可见。
blog.js
try{
if(data.author == auth.currentUser.email.split('@')[0]){
let editBtn = document.getElementById('edit-blog-btn');
editBtn.style.display = 'inline';
editBtn.href = `${blogId}/editor`;
}
} catch{
// nothing
}
在函数中的publish.innerHTML +=
${data.author}后面添加这个。我们在这里使用它的原因是因为如果不使用它,当无人登录时会报错。;
setupBlog
try
现在一切都完成了。最后一步是编辑博客。打开server.js
并创建用于编辑现有博客的路径。
app.get("/:blog/editor", (req, res) => {
res.sendFile(path.join(initial_path, "editor.html"));
})
完成后,你打开了路由。你会看到编辑器页面,但它没有样式,也没有图片。这是为什么呢?我不太清楚,但我知道该怎么解决。如果你知道我们在 JS 中如何称呼这种情况,请在讨论中告诉我。
修复打开的editor.html
文件。在每个链接前添加../
。每个链接都添加。之后你的文件应该如下所示。
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Blog : Editor</title>
<link rel="stylesheet" href="../css/home.css">
<link rel="stylesheet" href="../css/editor.css">
</head>
<body>
<div class="banner">
<input type="file" accept="image/*" id="banner-upload" hidden>
<label for="banner-upload" class="banner-upload-btn"><img src="../img/upload.png" alt="upload banner"></label>
</div>
<div class="blog">
<textarea type="text" class="title" placeholder="Blog title..."></textarea>
<textarea type="text" class="article" placeholder="Start writing here..."></textarea>
</div>
<div class="blog-options">
<button class="btn dark publish-btn">publish</button>
<input type="file" accept="image/*" id="image-upload" hidden>
<label for="image-upload" class="btn grey upload-btn">Upload Image</label>
</div>
<script src="https://www.gstatic.com/firebasejs/8.9.1/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.9.1/firebase-firestore.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.10.0/firebase-auth.js"></script>
<script src="../js/firebase.js"></script>
<script src="../js/editor.js"></script>
</body>
现在它可以正常工作了。太棒了!现在让我们设置博客值并实现编辑功能。
编辑器.js
// already existing blog setup
let blogId = location.pathname.split("/");
blogId.shift(); // remove first item from the array because first item is empty
if(blogId[0] != 'editor'){
// means we are in existing blog route
let docRef = db.collection("blogs").doc(decodeURI(blogId[0]));
docRef.get().then((doc) => {
console.log(doc);
if(doc.exists){
let data = doc.data();
bannerPath = data.bannerImage;
banner.style.backgroundImage = `url(${bannerPath})`;
blogTitleField.value = data.title;
articleFeild.value = data.article;
} else{
location.replace("/");
}
})
}
这样就能设置文本字段的值了。 现在我们可以在点击事件中编辑它们了。像这样修改。publishBtn
if(articleFeild.value.length && blogTitleField.value.length){
// generating id
let docName;
if(blogId[0] == 'editor'){
let letters = 'abcdefghijklmnopqrstuvwxyz';
let blogTitle = blogTitleField.value.split(" ").join("-");
let id = '';
for(let i = 0; i < 4; i++){
id += letters[Math.floor(Math.random() * letters.length)];
}
docName = `${blogTitle}-${id}`;
} else{
docName = decodeURI(blogId[0]);
}
// setting up docName
let date = new Date(); // for published at info
//access firstore with db variable;
db.collection("blogs").doc(docName).set({
title: blogTitleField.value,
article: articleFeild.value,
bannerImage: bannerPath,
publishedAt: `${date.getDate()} ${months[date.getMonth()]} ${date.getFullYear()}`,
author: auth.currentUser.email.split('@')[0]
})
.then(() => {
location.href = `/${docName}`;
})
.catch((err) => {
console.error(err);
})
}
这与上一个相同。docName
这里仅值有所改变。
输出
好了,我们完成了。我们拥有所有高级功能。您可以点击这里,在线托管网站。
只需 5 美元即可在Patreon上获得我所有项目的源代码。支持我的工作,打造更多精彩绝伦的网站。这只是一个开始。源代码
希望你理解了所有内容。如果你有疑问或者我遗漏了什么,请在评论区告诉我。
您可能觉得有用的文章
如果您能订阅我的YouTube频道,我将不胜感激。我创作了非常棒的网络内容。
感谢您的阅读。
文章来源:https://dev.to/themodernweb/advance-features-how-to-create-a-working-blogging-website-with-pure-html-css-and-js-in-2021-50io