FullStack - 如何在 2021 年用纯 HTML、CSS 和 JS 创建一个可运行的博客网站 - 2 个视频教程代码文章,你可能会觉得有用

2025-06-07

FullStack - 如何在 2021 年用纯 HTML、CSS 和 JS 创建一个可运行的博客网站 - 2

视频教程

代码

您可能觉得有用的文章

大家好,今天我们将对两周前创建的博客网站进行一些高级功能改进。我添加了一些高级功能,例如:

  1. Google 身份验证登录/注销
  2. 仪表板
  3. 用户在仪表板上撰写的博客
  4. 可以从仪表板阅读/编辑/删除博客。
  5. 从博客页面本身编辑博客。
  6. 存储/显示作者用户名。

由于这是上一个部分的延续,所以我使用了之前的代码和文件结构。

演示代码教程已在 Heroku 上架,并提供说明。您可以观看下方视频。

视频教程

教程观看目标 - 如果视频教程的观看次数达到 5K+,我将制作一个功能齐全的电子商务网站的教程,包括卖家页面、产品列表、下订单、贝宝网关、登录/注销等等。

因此,不要浪费更多时间,让我们看看如何编写代码。

代码

因此,开始之前请在public文件夹中创建 4 个文件。

  1. dashboard.html
  2. css/dashboard.css
  3. js/dashoboard.js
  4. js/nav.js

我们也需要这四个文件。

因此让我们打开server.js文件并制定/admin路线。

app.get("/admin", (req, res) => {
    res.sendFile(path.join(initial_path, "dashboard.html"));
})
Enter fullscreen mode Exit fullscreen mode

这里需要注意的是,如果将此路由添加到/: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。并复制firestoreCDN。将 替换firestoreauthauth CDN。

以及链接home.cssdashboard.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>
Enter fullscreen mode Exit fullscreen mode

您可以观看教程以获得更好的理解。

现在让我们实现一个登录功能。为此

仪表板.html
<!-- login -->
<div class="login">
    <div id="loginUI"></div>
</div>
Enter fullscreen mode Exit fullscreen mode
仪表板.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;
}
Enter fullscreen mode Exit fullscreen mode

dashboard.js确保你这样做之前firebase.js

let auth = firebase.auth();
Enter fullscreen mode Exit fullscreen mode
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]
    })
}
Enter fullscreen mode Exit fullscreen mode

我们的登录功能已经完成。
捕获

接下来,我们来为仪表盘和博客卡片创建一个导航栏。
这些元素和我们的主页一样。直接复制就行了。

<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>
Enter fullscreen mode Exit fullscreen mode

您可以看到一些我们在主页博客中没有的额外元素。为此,请提供以下样式。

.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;
}
Enter fullscreen mode Exit fullscreen mode
输出

捕获2
现在您可以评论博客卡片了。
现在让我们创建导航栏动态链接。为此,请打开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>
        `
    }
});
Enter fullscreen mode Exit fullscreen mode

只需添加nav.jsCDN firebase-auth。您的所有页面。

输出

捕获3

如果你看到上面的代码,你会看到logout函数。那么,让我们创建它。在里面创建这个firebase.js

const logoutUser = () => {
    auth.signOut();
    location.reload();
}
Enter fullscreen mode Exit fullscreen mode

现在我们的登录/注销已经通过动态链接完成了。现在让我们将作者信息保存/检索到数据库中。

打开editor.js并首先检查用户是否登录。

auth.onAuthStateChanged((user) => {
    if (!user) {
        location.replace('/admin');
    }
});
Enter fullscreen mode Exit fullscreen mode

然后像这样更改前面的代码。

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]
        })
Enter fullscreen mode Exit fullscreen mode

这样我们就可以将作者添加到数据库中了。现在,在博客页面上显示作者。
为此,请在设置元素后,打开blog.js并在函数内部添加此代码。就像这样。setupBlogpublishedAt

publish.innerHTML += data.publishedAt;
publish.innerHTML += ` -- ${data.author}`;
Enter fullscreen mode Exit fullscreen mode
输出

Capture4

太棒了!我们已经完成了 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);
    });
}
Enter fullscreen mode Exit fullscreen mode

通过这种方式,我们现在可以获取用户撰写的博客,也可以删除它们。

输出

Capture5

现在让我们编辑博客页面上的按钮。将此按钮添加到published元素之后。

<a class="btn" id="edit-blog-btn" href="">edit blog</a>
Enter fullscreen mode Exit fullscreen mode

并采用这样的风格。

博客.css
#edit-blog-btn{
    background: rgba(0, 0, 0, 0.2);
    display: none;
}
Enter fullscreen mode Exit fullscreen mode

我在开发过程中发现了一些样式问题。因此,我建议你也为这些元素添加这些样式。

博客.css
.article *{
    word-break: break-word;
}
Enter fullscreen mode Exit fullscreen mode
主页.css
.blogs-section{
    word-break: break-word;
}
Enter fullscreen mode Exit fullscreen mode

现在,当作者访问该页面时,编辑按钮可见。

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
}
Enter fullscreen mode Exit fullscreen mode

在函数中的publish.innerHTML +=${data.author}后面添加这个。我们在这里使用它的原因是因为如果不使用它,当无人登录时会报错。;setupBlogtry

现在一切都完成了。最后一步是编辑博客。打开server.js并创建用于编辑现有博客的路径。

app.get("/:blog/editor", (req, res) => {
    res.sendFile(path.join(initial_path, "editor.html"));
})
Enter fullscreen mode Exit fullscreen mode

完成后,你打开了路由。你会看到编辑器页面,但它没有样式,也没有图片。这是为什么呢?我不太清楚,但我知道该怎么解决。如果你知道我们在 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>
Enter fullscreen mode Exit fullscreen mode

现在它可以正常工作了。太棒了!现在让我们设置博客值并实现编辑功能。

编辑器.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("/");
        }
    })
}
Enter fullscreen mode Exit fullscreen mode

这样就能设置文本字段的值了。 现在我们可以在点击事件中编辑它们了。像这样修改。
Capture7
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);
    })
}
Enter fullscreen mode Exit fullscreen mode

这与上一个相同。docName这里仅值有所改变。

输出

Capture6

好了,我们完成了。我们拥有所有高级功能。您可以点击这里,在线托管网站。

只需 5 美元即可在Patreon上获得我所有项目的源代码。支持我的工作,打造更多精彩绝伦的网站。这只是一个开始。源代码

希望你理解了所有内容。如果你有疑问或者我遗漏了什么,请在评论区告诉我。

您可能觉得有用的文章

  1. 无限 CSS 加载器
  2. 最佳 CSS 效果
  3. 波浪按钮悬停效果
  4. Youtube API - Youtube 克隆
  5. TMDB - Netflix 克隆

如果您能订阅我的YouTube频道,我将不胜感激。我创作了非常棒的网络内容。

感谢您的阅读。

文章来源:https://dev.to/themodernweb/advance-features-how-to-create-a-working-blogging-website-with-pure-html-css-and-js-in-2021-50io
PREV
CSS 元素前后:关于 CSS 伪元素你需要知道的一切 什么是伪元素?:before 和 :after 让我们举个例子。内容属性 : 或 ::?你可能觉得有用的文章
NEXT
5 个让你惊叹的 CSS 卡片悬停效果🔥🤯 卡片悬停 - 01 卡片悬停 - 02 卡片悬停 - 03 卡片悬停 - 04 卡片悬停 - 05