vue3+rust个人博客建站日记5-所有界面

news2024/11/16 11:25:10

没有数据的前端,是没有灵魂的。明明标题是vue3 + rust ,但日记撰写至今,似乎只有第一篇提及了Rust,这可不行。是时候一股作气,完成大部分页面绘制工作了!

最后再说一次,时间要加速了。 ——普奇神父

文章目录

      • 内容主页
      • 文章列表页
        • 列表组件封装
        • 用户文章列表页预览
      • 管理员列表页
      • 文章内容页
        • 封装文章内容组件
        • 编辑文章内容页
      • 管理员文章内容页
      • 管理员登陆页面
        • 封装登陆组件
        • 编写登陆界面
      • 文章编辑界面
        • 封装提交组件
        • 流转图

内容主页

src/views/BlogsView.vue
在这里插入图片描述

<script setup>
    import { NLayout,NMenu,NLayoutSider} from 'naive-ui';
    import { RouterView } from 'vue-router';
    import { ref } from 'vue';
import router from '../router';
    const menuSelect = ref("all")
    const menuOptions = ref(null)
    menuOptions.value = [
        {
            label:"全部",
            key:"all",
        },
        {
            label: "关于",
            key:"about-me"
        },
    ]

    function handleUpdateValue(key, item) {
        switch (key) {
            case "all":
                router.push("/articles/all")
                break
            case "about-me":
                router.push("about")
                break
        }
    }
</script>
<template>
    <n-layout has-sider style="height: 100%;">
        <n-layout-sider
            :bordered="true"
            show-trigger
            collapse-mode="width"
            :collapsed-width="64"
            :width="120"
            :native-scrollbar="false" 
        >
            <n-menu
            :collapsed-width="64"
            :collapsed-icon-size="22"
            :value="menuSelect"
            :options="menuOptions"
            @update:value="handleUpdateValue"
            />
        </n-layout-sider>

        <n-layout>
            <router-view />
        </n-layout>

    </n-layout>

</template>

文章列表页

文章列表页和管理员列表页类似的界面,所以我们封装一个列表组件以方便复用。

列表组件封装

列表组件要考虑普通用户和管理员两种情况。
src/components/BlogsList.vue

<script setup>
    import { NList,NListItem,NSpace,NButton } from 'naive-ui';
    import {ref} from 'vue'
    import router from '../router';
    const showModal = ref(false)

    const props = defineProps(['values',"isAdmin"])
    const emits = defineEmits(['jump-to-article'])
    function jumpToArticle(key){
        emits("jump-to-article",key)
    }
    function jumpToEdit(){
        router.push("/edit")
    }
</script>

<template>
    <n-list hoverable >
        <n-list-item v-for="item in props.values" >
            <n-thing 
                :title="item.title" 
                content-style="margin-top: 10px;pointer-events: none;"
                >
                <template #header-extra v-if="props.isAdmin">
                    <n-button 
                    style="margin-right: 3px;" 
                    strong 
                    secondary 
                    type="info"
                    size="small"
                    @click="jumpToArticle">预览</n-button>
                    <n-button 
                    style="margin-right: 3px;" 
                    strong 
                    secondary 
                    type="warning"
                    size="small"
                    @click="jumpToEdit">编辑</n-button>
                    <n-button 
                    strong 
                    secondary 
                    type="error"
                    size="small" 
                    @click="showModal = true">删除</n-button>
                    <n-modal
                        v-model:show="showModal"
                        preset="dialog"
                        title="确认"
                        content="确认删除文章?"
                        positive-text="确认"
                        negative-text="算了"
                        @positive-click="onPositiveClick"
                        @negative-click="onNegativeClick"
                    />
                </template>
                <template #description>
                <n-space size="small" style="margin-top: 4px">
                    <n-tag v-for="tag in item.tags" :bordered="false" type="info" size="small">
                    {{ tag }}
                    </n-tag>
                </n-space>
                </template>
                {{ item.details }}
            </n-thing>
        </n-list-item>
    </n-list>      
</template>

用户文章列表页预览

src/views/BlogsListView.vue

<script setup>
    import BlogsList from '../components/BlogsList.vue';
    import {ref} from 'vue'
    import router from '../router';
    const list = ref(null)
    list.value=[
        {
            title:"相见恨晚",
            tags:["暑夜","晚春"],
            details:"奋勇呀然后休息呀,完成你伟大的人生"
        },
        {
            title:"他在时间门外",
            tags:["环形公路","潜水艇司机"],
            details:"最新的打印机\n复制着彩色傀儡\n早上好我的罐头先生\n让他带你去被工厂敲击"
        }
    ]
    function jumpToArticle(key){
        router.push("1")
    }
</script>

<template>
    <blogs-list :values="list" @jump-to-article="jumpToArticle"/>
</template>

在这里插入图片描述

管理员列表页

src/views/AdminBlogsListView.vue

<script setup>
    import BlogsList from '../components/BlogsList.vue';
    import {ref} from 'vue'
    import router from '../router';
    const list = ref(null)
    list.value=[
        {
            title:"相见恨晚",
            tags:["暑夜","晚春"],
            details:"奋勇呀然后休息呀,完成你伟大的人生"
        },
        {
            title:"他在时间门外",
            tags:["环形公路","潜水艇司机"],
            details:"最新的打印机\n复制着彩色傀儡\n早上好我的罐头先生\n让他带你去被工厂敲击"
        }
    ]
    function jumpToArticle(key){
        router.push("1")
    }
</script>


<template>
    <blogs-list :values="list" :is-admin="true" @jump-to-article="jumpToArticle"/>
</template>

在这里插入图片描述

文章内容页

封装文章内容组件

src>components>BlogContent.vue

<script setup>
    import MarkDownRead from './MarkDownRead.vue';
    import { NSpace,NCard,NTag,NIcon,NButton } from 'naive-ui';
    import { useThemeSwitch } from '../stores/themeSwitch';
    import {GitBranch,Eye} from "@vicons/ionicons5"
    const themeSwitcher = useThemeSwitch()
    const props = defineProps(["blogInfo","isAdmin"])

</script>
<template>
    <n-space         
        style="height: 100%;" 
        size="large"
        vertical="true"
        class="blog-read-preview"
        >
        <div class="title" style="margin-top: 20px;">{{ blogInfo.title }}</div>
        <n-card>
            <n-thing>
                <n-space align="center" justify="space-between">
                    <div class="flex-box">
                        <n-icon size="20" :component="GitBranch"/>
                        <div style="margin-right: 15px;">已于 {{ blogInfo.changeTime }} 修改 </div>
                        <n-icon size="20" :component="Eye"/>
                        {{ blogInfo.readCount }} 
                    </div>
                    <n-button 
                        v-if="isAdmin"
                        text 
                        type="info"> 编辑 </n-button>
                </n-space>

                <template  #action>
                <n-space align="center">
                    分类专栏:
                    <n-tag type="info">
                    {{ blogInfo.blogType }} 
                    </n-tag>
                    文章标签:
                    <n-tag
                        v-for="tag in blogInfo.tags" 
                        type="info"
                        >
                    {{ tag }}
                    </n-tag>
                </n-space>
                </template>
            </n-thing>
        </n-card>

        <mark-down-read  :key="themeSwitcher.active" :active="themeSwitcher.active"></mark-down-read>
    </n-space>
    
</template>

<style>
.flex-box{
    display: flex;
    align-items: center;
}
.blog-read-preview{
    margin-inline: 15vw;
    max-width: 900px;
}
.title{
    font-size: 28px;
    font-weight: 600;
    width: 100%;
}
</style>

编辑文章内容页

src>view>BlogReadView.vue

<script setup>
    import BlogContent from '../components/BlogContent.vue';
    import { useThemeSwitch } from '../stores/themeSwitch';
    const themeSwitcher = useThemeSwitch()
    const testData = {
        title:"预览就是帮其他人先看看",
        changeTime:"2023-02-27 09:43:26",
        readCount:"234",
        blogType:"1块钱",
        tags:["5块钱","10块钱","50块钱"],
        
    }
    
</script>
<template>
    <blog-content :blog-info="testData" />
</template>

<style>
.blog-read-preview{
    margin-inline: 15vw;
    max-width: 900px;
}
</style>

在这里插入图片描述

管理员文章内容页

管理员文章内容页就非常简单,只需要对组件isAdmin参数设置为true,即可。

<script setup>
    import BlogsList from '../components/BlogsList.vue';
    import {ref} from 'vue'
    import router from '../router';
    const list = ref(null)
    list.value=[
        {
            title:"相见恨晚",
            tags:["暑夜","晚春"],
            details:"奋勇呀然后休息呀,完成你伟大的人生"
        },
        {
            title:"他在时间门外",
            tags:["环形公路","潜水艇司机"],
            details:"最新的打印机\n复制着彩色傀儡\n早上好我的罐头先生\n让他带你去被工厂敲击"
        }
    ]
    function jumpToArticle(key){
        router.push("1")
    }
</script>

<template>
    <blogs-list :values="list" :is-admin="true" @jump-to-article="jumpToArticle"/>
</template>

在这里插入图片描述

管理员登陆页面

封装登陆组件

src/components/LoginCard.vue

<script setup>
import { NForm,NButton,NInput,NFormItem } from 'naive-ui';
</script>
<template>
    <n-card class="loginCard" title="登陆">   
        <n-form>
          <n-form-item label="用户名">
            <n-input placeholder="username"/>
          </n-form-item>
          <n-form-item label="密码">
            <n-input 
                type="password" 
                show-password-on="click" 
                placeholder="password"/>
          </n-form-item>
        </n-form>
        <n-button type="primary" block secondary strong>
          登录
        </n-button>
  </n-card>
</template>

<style>
.loginCard{
    margin-top: 12px;
    max-width: 350px;
    width: 50vw;
    min-width: 266px;
}
</style>

编写登陆界面

src/views/AdminLogin.vue

<script setup>
import LoginCard from '../components/LoginCard.vue';
import { NSpace } from 'naive-ui';
</script>
<template>
    <n-space 
    style="width: 100%;height: 100%;"
    align="center"
    justify="center"
    >
        <login-card></login-card>
    </n-space>
</template>

在这里插入图片描述

文章编辑界面

封装提交组件

<script setup>
    import { NButton,NSpace,NCard,NTag,NIcon,NScrollbar,NCheckboxGroup,NCheckbox } from 'naive-ui';
    import { ref } from 'vue';
    import { Close,Add } from '@vicons/ionicons5';
    const showModal = ref(false)
</script>
<template>
    <n-card
    style="width: 600px"
    title="发布文章"
    :bordered="false"
    size="huge"
    role="dialog"
    aria-modal="true"
    >
    <template #header-extra>
        <n-button 
            quaternary  
            size="15"
            @click="showModal=false">
            <template #icon>
                <n-icon><close /></n-icon>
            </template>
        </n-button>
    </template>
    <n-space >文章标签: 
        <n-tag 
            type="success" 
            closable  
            size="small"
            @close="handleClose">
            一个标签
        </n-tag>
        <n-button dashed size="tiny">
            <template #icon>
                <n-icon>
                    <add />
                </n-icon>
            </template>
            添加文章标签
        </n-button>
    </n-space>
    <n-card style="margin-top: 12px;">
        <n-scrollbar style="max-height: 120px">
            <n-checkbox-group v-model:value="value1">
                <n-space item-style="display: flex;">
                <n-checkbox size="small" value="a" label="擎天柱" />
                <n-checkbox value="b" label="大黄蜂" />
                <n-checkbox value="c" label="声波" />
                <n-checkbox value="d" label="红蜘蛛" />
            </n-space>
            </n-checkbox-group>
        </n-scrollbar>
    </n-card>

    <n-space style="margin-top: 12px;">分类专栏:
        <n-tag 
            type="success" 
            size="small"
            closable  
            @close="handleClose">
            一个专栏名
        </n-tag>
        <n-button dashed size="tiny">
            <template #icon>
                <n-icon>
                    <add />
                </n-icon>
            </template>
            新建分类专栏
        </n-button>
    </n-space>
    <n-card style="margin-top: 12px;">
        <n-scrollbar style="max-height: 120px">
            <n-checkbox-group v-model:value="value2">
                <n-space item-style="display: flex;">
                <n-checkbox value="a" label="a" />
                <n-checkbox value="b" label="b" />
                <n-checkbox value="c" label="c" />
                <n-checkbox value="d" label="d" />
                </n-space>
            </n-checkbox-group>
        </n-scrollbar>
    </n-card>
    <template #footer>
        <n-space justify="end">
            <n-button>取消</n-button>
            <n-button type="warning">发布</n-button>
        </n-space>
    </template>
    </n-card>
</template>

在这里插入图片描述#### 编辑界面

<script setup>
    import MarkDownEdit from '../components/MarkDownEdit.vue';
    import BlogEditConfirm from '../components/BlogEditConfirm.vue';
    import { useThemeSwitch } from '../stores/themeSwitch';
    import { NInput,NButton,NSpace,NModal,NCard,NTag,NIcon } from 'naive-ui';
    import { ref } from 'vue';
    const themeSwitcher = useThemeSwitch()
    const showModal = ref(false)
</script>

<template>
    <n-space class="editTitleInput" justify="space-between">
        <n-input 
            style="width: 50vw"
            placeholder="请输入标题"
        ></n-input>

        <n-space>
            <n-button>保存草稿</n-button>
            <n-button @click="showModal = true">发布</n-button>
        </n-space>

    </n-space>

    <n-modal v-model:show="showModal">
        <blog-edit-confirm />
    </n-modal>

    <mark-down-edit :active="themeSwitcher.active"></mark-down-edit>
</template>

<style>
.editTitleInput{
    width: auto;
    margin-inline: 3.3vw;
    margin-top: 12px;
    margin-bottom: 12px;
}
</style>

在这里插入图片描述

流转图

接下来是前端和后端握手🤝的时刻,我们将完善前后端接口,实现建站日记2-确定需求中梳理的功能点。Rust部分也将在下一篇如闪电般归来。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/389713.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

EPICS S7nodave手册

第一章&#xff1a;介绍 本手册分为6章(不算次介绍部分)。第一章介绍s7nodave用于EPICS的设备支持的概念和特新。第二章描述启动一个使用s7nodave的IOC项目所需要的几步。第三章描述s7nodave支持的IOC shell命令。之后&#xff0c;第四章解释s7nodave支持的各种记录类型。最后…

【算法】期末复盘,酒店住宿问题——勿向思想僵化前进

文章目录前言题目描述卡在哪里代码&#xff08;C&#xff09;前言 省流&#xff1a;一个人也可以住双人间&#xff0c;如果便宜的话。 害&#xff01;尚正值青春年华&#xff0c;黄金岁月&#xff0c;小脑瓜子就已经不灵光咯。好在我在考试的最后一分钟还是成功通过了这题&am…

Jetpack Compose 中的 CompositionLocal

要在可组合函数之间共享数据时&#xff0c;可以通过参数传递显式地调用&#xff0c;这通常是最简单和最好的方式。 但随着参数越来越多&#xff0c;组件也越来越多&#xff0c;并且有些数据还需要保持私有性&#xff0c;这时这种方式就会显得很繁琐臃肿&#xff0c;难以维护。…

vscode插件推荐

文章目录前言一、vscode插件推荐&#xff1f;1、 Chinese (Simplified) (简体中文) Language Pack for Visual Studio Code2、Auto Close Tag3、Auto Import3、Error Lens4、vscode-icons5、ES7 React/Redux/React-Native snippets6、GitLens — Git supercharged7、JavaScript…

【FPGA】Verilog:时序电路应用 | 序列发生器 | 序列检测器

前言&#xff1a;本章内容主要是演示Vivado下利用Verilog语言进行电路设计、仿真、综合和下载 示例&#xff1a;序列发生器与序列检测器 ​ 功能特性&#xff1a; 采用 Xilinx Artix-7 XC7A35T芯片 配置方式&#xff1a;USB-JTAG/SPI Flash 高达100MHz 的内部时钟速度 存储器…

车道线检测CondLaneNet论文和源码解读

CondLaneNet: a Top-to-down Lane Detection Framework Based on Conditional Convolution Paper&#xff1a;https://arxiv.org/pdf/2105.05003.pdf code&#xff1a;GitHub - aliyun/conditional-lane-detection 论文解读&#xff1a; 一、摘要 这项工作作为车道线检测任…

js垃圾回收机制

内存的生命周期 ]S环境中分配的内存&#xff0c;一般有如下生命周期 1.内存分配:当我们声明变量、函数、对象的时候&#xff0c;系统会自动为他们分配内存 2.内存使用:即读写内存&#xff0c;也就是使用变量、函数等 3.内存回收: 使用完毕&#xff0c;由垃圾回收器自动回收不再…

MySQL实战解析底层---事务到底是隔离的还是不隔离的

目录 前言 “快照”在 MVCC 里是怎么工作的&#xff1f; 更新逻辑 前言 讲事务隔离级别的时候提到过&#xff0c;如果是可重复读隔离级别&#xff0c;事务 T 启动的时候会创建一个视图 read-view之后事务 T 执行期间&#xff0c;即使有其他事务修改了数据&#xff0c;事务 T…

​ ​​ ​IIS之FTP服务器 部署 (图文详细) 千锋

目录 概述 部署 步骤&#xff1a; 二重新配置FTP服务器 概述 1、File Transfor Protocol 文件传输协议 2、端口号&#xff1a; TCP 20/21 3、工作方式&#xff1a; 1)主动模式 2&#xff09;被动模式 部署 步骤&#xff1a; 配置静态IP 安装IIS-ftp软件 使用默认站…

学python的第三天---基础(1)

一、圆的面积print("A{:.4f}".format(s))二、两点间的距离![在这里插入图片描述](https://img-blog.csdnimg.cn/0d07c41d856d470796c79067b78c41b6.png)写法一&#xff1a;写法二&#xff1a;三、钞票和硬币写法一&#xff1a;写法二&#xff1a;四、倍数在python中实…

Spring Aware总结

概述 Spring中Aware到底是什么意思&#xff1f; 我们在看Spring源码的时候&#xff0c;经常可以看到xxxAwarexxx的身影&#xff0c;通常我会很疑惑&#xff0c;Aware到底是什么意思呢&#xff1f; 比如图片中这些包含Aware关键字的类或者接口。 我对下面3个类或接口进行了解…

【FMCW 02】测距

承接上篇博文 中频IF信号 &#xff0c;我们已经知道得到的中频IF信号的形式为&#xff1a; xIF(t)A′′cos⁡(2πKτt2πfoτ)x_{\tiny{IF}}(t) A^{\prime \prime} \cos(2\pi K\tau t2\pi f_o \tau ) xIF​(t)A′′cos(2πKτt2πfo​τ) 其中时延τ2dc\tau \frac{2d}{c}τc2…

【数据库】15分钟了解TiDB

由于目前的项目把mysql换成了TiDb&#xff0c;所以特意来了解下tidb。其实也不能说换&#xff0c;由于tidb和mysql几乎完全兼容&#xff0c;所以我们的程序没有任何改动就完成了数据库从mysql到TiDb的转换&#xff0c;TiDB 是一个分布式 NewSQL (SQL 、 NoSQL 和 NewSQL 的优缺…

C++之空间配置器

目录 一、C语言中的类型转换 二、C的类型转换 三、C强制类型转换 static_cast reinterpret_cast const_cast volatile关键字 dynamic_cast 什么情况下需要将父转成子呢&#xff1f; static_cast与dynamic_cast转换对比 四、空间配置器 什么是空间配置器 为什么需要…

raspberry pi播放音视频

文章目录目的QMediaPlayerGStreamerwhat is GStreamer体系框架优势omxplayerwhat is omxplayercommand Linekey bindings运行过程中错误ALSA目的 实现在树莓派下外接扬声器&#xff0c; 播放某段音频&#xff0c; 进行回音测试。 QMediaPlayer 首先我的安装是5.11版本。 优先…

【并发编程二十一:终章】c++20协程( co_yield、co_return、co_await )

【并发编程二十一】c20协程(co_yield、co_return、co_await &#xff09;一、协程分类1、控制机制划分2、有栈&#xff08;stackfull)/无栈&#xff08;stackless)划分二、c20协程三、co_yield1、demo2、相关知识点介绍四、co_return五、co_await一、协程分类 上一篇我们讲解了…

如何让AI帮你干活-娱乐(2)

背景&#xff1a;好容易完成朋友的任务&#xff0c;帮忙给小朋友绘画比赛生成一些创意参考图片。他给我个挑战更高的问题&#xff0c;是否可以帮他用AI生成一些视频。这个乍一听以现在AI技术根本不太可能完成。奈何他各种坚持&#xff0c;无奈被迫营业。苦脸接受了这个不可能完…

Java线程知识点总结

文章目录Java 线程基础线程简介什么是进程什么是线程进程和线程的区别创建线程ThreadRunnableCallable、Future、FutureTaskCallableFutureFutureTaskCallable Future FutureTask 示例线程基本用法线程休眠线程礼让终止线程守护线程线程通信wait/notify/notifyAlljoin管道线程…

MATLAB——数据及其运算

MATLAB数值数据数值数据类型的分类1&#xff0e;整型整型数据是不带小数的数&#xff0c;有带符号整数和无符号整数之分。表中列出了各种整型数据的取值范围和对应的转换函数。2&#xff0e;浮点型浮点型数据有单精度(single&#xff09;和双精度&#xff08;(double)之分&…

精粤X99M-PLUS D3+ E5-2696 v3电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。硬件型号驱动情况主板精粤X99M-PLUS D3处理器E5-2696 v3已驱动内存64GB ECC DDR3 1866MHz (16GB*4)已驱动硬盘TOPMORE CAPRICORNUS NVMe 1TB已驱动显卡AMD Radeon™ RX 570 series (4GB/MSI)已驱动声卡Realtek ALC897 英特…