Vue3——简易版个人空间(上半部分)

news2024/11/25 7:33:47

创建项目

使用vue 的图形化界面创建一个新的vue3项目如下图所示

装两个新的插件——router和vuex插件

该过程的可能有点久,需要耐心等待。

 再装一些需要的依赖

 需要用到的依赖: boostrap和poperjs/core(bootstrap是提供给不会做美工的程序员的一个新的好选择)第二个依赖是使用bootstrap时需要用到的一个依赖。

 到此为止,该项目需要用到的东西已经装完。

项目结构

如上图所示的项目

main.js是这一整个项目的入口文件,在里面可以看见如下的一些语句,  上面的一句话意思是根据App.vue这个组件创建一个虚拟dom元素挂载到了id=app的区域里面,对应public文件夹下面的index.html里面的如下图所示的div区域的id就是app。

至于新装的两个依赖router和vuex在上面也有体现出来,上面的store对应的就是vuex插件。 

基本概念 

后端渲染模型:

每一次打开一个新的页面,都会由客户端client向服务器发送一次请求,服务器将请求的页面返回给客户端。

前端渲染模型:

只有在最开始的时候会请求一次服务器,服务器一次性将所有页面都返回给客户端,后面每一次切换页面都是从本地加载。

需求分析

需要完成的一个项目最后效果图如下所示

 需求实现

要使用bootstrap要先在App.vue里面进行引入,这里要连带js,css文件一起引入,不然就无法使用

bootstrap里面的一些交互样式

1.导航栏部分实现

在components文件夹下面新建一个NavBar.vue组件,并加上固定模板语句

随后去bootstrap官网里面去找一些喜欢的导航栏样式

 为了能够让别的组件能够引入,这里NavBar组件需要将自己暴露出去并给定一个name属性。

此处的name属性必须有两个大写的字母,否则语法检查过不了。

下面的style scoped可以让这个组件的样式不会影响别的组件里面的样式。

 因为每一个页面都需要导航栏,因此可以直接将NavBar组件引入到根组件App.vue里面,为了能使用NavBar,还需要在components区域标注出来,然后就可以直接在template区域里面使用它了。

 达成效果

代码实现:

<template>
    <nav class="navbar navbar-expand-lg bg-body-tertiary">
        <div class="container">
            <a class="navbar-brand" href="#">鼠鼠空间</a>
            <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarText"
                aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarText">
                <ul class="navbar-nav me-auto mb-2 mb-lg-0">
                    <li class="nav-item">
                        <a class="nav-link active" aria-current="page" href="#">首页</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#">鼠友列表</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#">鼠友动态</a>
                    </li>
                </ul>
                <ul class="navbar-nav">
                    <li class="nav-item">
                        <a class="nav-link" href="#">登录</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#">注册</a>
                    </li>
                </ul>

            </div>
        </div>
    </nav>
</template>

<script >
export default {
    name: "NavBar",
}
</script>

<style scoped></style>

为了实现网站美化,可以用一个框将网页内容都包裹起来的。为此使用到一个bootstrap里的一个模块——Card卡片 

2.首页页面实现

代码:

实现效果 

这里再加上一个container将里面内容括起来使得页面布局更对称,container也是bootstrap里面定义好的一个class,可以响应式的调整中间内容区域的大小。

代码:

实现效果:

可以看见card区域已经和上面导航栏区域对齐。这是因为上面的导航栏区域也是有一个container

 导航栏部分代码:

3.公共ContentBase部分实现 

由上面的这个图可以看出,所有的页面都会有一个content区域,如果每一个页面都要修改外边距就要全部修改,但是利用一个单独的ContentBase.vue组件就可以实现一次修改在所有页面都生效。

在components文件夹下新建一个ContentBase.vue组件 

内容如下,将公共部分抽取出来

<template>
    <div class="home">
        <div class="container">
            <div class="card">
                <div class="card-body">
                    <slot></slot>
                </div>
            </div>
        </div>
    </div>
</template>


<script>
export default {
    name: "ContentBase"
}
</script>

<style scoped></style>

随后在首页的组件HomeView.vue当中改成如下,将ContentBase.vue引入并在ContentBase标签里面填充当前页面的信息。

在<ContenBase></ContenBase>里面可以渲染任意的内容,如上面的效果图就是

 

 这里container被定义在了ContentBase里面,所以要将样式也移动到ContentBase.vue下面

知识点 

这里要想在Content.vue里面展示不同页面插入的信息,需要用到一个<slot></slot>标签,

可以将子组件的元素都渲染到slot里面。这个也叫做插槽

Vue3——路由的query参数和命名路由以及默认插槽slot的使用_vue3 路由query_北岭山脚鼠鼠的博客-CSDN博客

4.剩下的页面一起实现(登录、注册、404、鼠友列表,鼠友动态五个页面)

先将剩下的所有需要的页面组件都建好,然后将home页面的内容都复制粘贴进去,每一个都要改name属性。

注意点:所有的name属性都一定要有两个大写字母,否则语法检查过不去。

模板页面代码: 

<template>
  <ContentBase>

  </ContentBase>
</template>

<script>
import ContentBase from '@/components/ContentBase.vue';
export default {
  name: 'XXXX',
  components: {
    ContentBase
  }
}
</script>
<style scope></style>

 配置不同页面的路由信息:

现在所有的页面都准备好了,要能够根据不同的url后缀跳转不同的页面组件需要到Router里面配置

配置信息如下图所示

import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import UserListView from '../views/UserListView.vue'
import UserProfileView from '../views/UserProfileView.vue'
import LoginView from '../views/LoginView.vue'
import NotFoundView from '../views/NotFoundView.vue'
import RegisterView from '../views/RegisterView.vue'


const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    path: '/userlist',
    name: 'UserList',
    component: UserListView
  },
  {
    path: '/userprofile',
    name: 'userprofile',
    component: UserProfileView
  },
  {
    path: '/login',
    name: 'login',
    component: LoginView
  },
  {
    path: '/register',
    name: 'register',
    component: RegisterView
  },
  {
    path: '/404',
    name: '404',
    component: NotFoundView
  }
]

const router = createRouter({
  history: createWebHistory(),
  routes
})

export default router

配置完之后能够跳转相应页面就算成功

 配置导航栏的跳转标签

这里设置到的router-link标签的使用可以到一下文章去学习一下,这里的router-link有两种配置方式。

这里直接放结果代码:Navbar.vue代码如下所示

<template>
    <nav class="navbar navbar-expand-lg bg-body-tertiary">
        <div class="container">
            <router-link class="navbar-brand" :to="{ name: 'home',params:{} }">
                鼠鼠空间
            </router-link>
            <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarText"
                aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarText">
                <ul class="navbar-nav me-auto mb-2 mb-lg-0">
                    <li class="nav-item">
                        <router-link class="nav-link active" to="/">首页</router-link>
                    </li>
                    <li class="nav-item">
                        <router-link class="nav-link" :to="{ name: 'userlist',params:{} }">鼠友列表</router-link>
                    </li>
                    <li class="nav-item">
                        <router-link class="nav-link" :to="{ name: 'userprofile',params:{} }">鼠友动态</router-link>
                    </li>
                </ul>
                <ul class="navbar-nav">
                    <li class="nav-item">
                        <router-link class="nav-link" :to="{ name: 'login',params:{} }">登录</router-link>
                    </li>
                    <li class="nav-item">
                        <router-link class="nav-link" :to="{ name: 'register' ,params:{}}">注册</router-link>
                    </li>
                </ul>

            </div>
        </div>
    </nav>
</template>

<script >
export default {
    name: "NavBar",
}
</script>

<style scoped></style>

到此为止,总体的布局已经完成了。

下面都是单独的页面的实现。

鼠友动态页面:

需求说明:

此处的三个模块使用三个不同的组件进行实现:

在Compontents文件夹下面新建三个组件如图

页面布局,这里使用到bootstrap的grid系统 这玩意是将一个单独的块划分为12份,可以支持调整多个块和每一块的大小。

此处需要grid外部是有container的才可以,因为这个是对container进行划分,在contentbase里面已经有了,说错了,这里不是对container进行划分,而是对一个新的块进行划分,就是上图中<div class="row">这个块。

这个row和container还有row之间的关系如下图所示 

效果图:

下面这个是进行了3-9分的,在class处使用了col-3和col-9

代码部分:

 用户信息组件实现

区域也要分成两个部分,左边区域显示头像,右边区域显示名字 

这里同样使用了39分的grid布局,在头像显示那里使用到了一个bootstrap提供的类属性可以让头像自适应布局的大小。

 效果演示 

此处再将头像变成圆形,设置CSS样式如下可以将图片变成圆形 

 头像部分完成了,右边的个人信息部分的有三个东西,姓名,粉丝数和一个关注按钮

按钮使用bootstrap提供的一个样式

效果如下

用户信息部分总体代码:  这里的个人信息也使用了一个card将其包围起来

<template>
    <div class="card">
        <div class="card-body">
            <div class="row">
                <div class="col-3">
                    <img class="img-fluid" src="https://cdn.acwing.com/media/user/profile/photo/150603_lg_5b00f49635.jpg"
                        alt="我图片呢" />
                </div>
                <div class="col-9">
                    <div class="name">yanghuiyu</div>
                    <div class="fans">粉丝数:123</div>
                    <button type="button" class="btn btn-primary btn-sm">关注</button>
                    <!---此处的btn-primary是控制按钮颜色,btn-sm是控制按钮大小 -->
                </div>
            </div>
        </div>
    </div>
</template>
<script>
export default {
    name: "UserInfo",

}
</script>
<style scoped>
img {
    border-radius: 50%;
}

.username {
    /* 变成粗体 */
    font-weight: bold;
}

.fans {
    font-size: 15px;
    color: gray;
}

button {
    padding: 2px, 4px;
    font-size: 15px
}
</style>

UserProfileView.vue和UserInfo.vue之间传递信息实现

这里UserProfile页面需要有很多信息,这些信息都需要存储在UserProfile这个组件里面。

知识点

这里信息存储不再是data形式的vue2写法,而是使用一个新的api里面set up函数这个东西.

在setup函数里面可以定义变量,方法。

使用方法,

如果在一个对象里面的一个属性是函数,也可以简写成另外一个格如下所示

 定义需要的变量

这里定义变量有两种方式:

一个使用ref,另一个是使用reative

两个的效果差不多,但是ref的运行效率会比reative慢一些。

  • ref定义变量,可以用.value属性重新赋值  
  • reactive定义对象,不可重新赋值

根据上面,可以知道需要一个user的对象,这里用到了reative这个东西需要先进行引入 

然后这个user是需要在子组件里面使用的,所以这里又有一个新的知识点,组件之间的信息传递。

知识点

  • props存储父组件传递过来的数据
  • context.emit():触发父组件绑定的函数

使用:

详细的内容可以看下面这个

Vue3----props和emit的使用_vue3接收props_北岭山脚鼠鼠的博客-CSDN博客

父组件里面

子组件标签里面使用   :属性=“值”  方式进行传递。 

子组件里面

将接收到的参数都放到props的属性里面进行接收

在父组件里面的name信息应该是由两个部分组合而成的,也就是需要动态计算的

有需要用到一个新的东西

  • computed:动态计算某个数据

具体实现:(需要用到setup进行传值)

在setup当中是不能使用this.value这种东西的,所以要将props作为参数传进去,动态计算出一个fullname

然后return出去后就可以直接使用了

关注按钮实现

在一个个人页面中,如果是已经关注了应该显示以关注,如果是未关注应该显示取消关注。

这里使用到一个v-if标签,根据父组件传过来的信息判断显示哪一个按钮

然后需要点击修改状态,绑定两个函数

这两个函数需要去修改父组件的is_followed这个东西的状态,这里用到另外一个东西

  • context.emit():触发父组件绑定的函数

 在父组件当中

@follow="follow"左边是子组件里面的函数,右边是父组件里面的函数,要在下面定义,涉及到修改粉丝数之类的。

这里两个事件的名字不一定是一样的,只要能和对应组件对应上就可以了

 在子组件当中

使用context.emit(),上下文触发父组件里面的函数,这里要使用context要通过setup的参数列表先传进来,然后才能使用 

帖子列表组件实现

帖子列表那一栏要渲染一堆从父组件传过来的数据,也要用到props

先在父组件定义好数据:

定义的这个数组级的要返回

然后在组件的标签里面绑定子组件里面的posts

在子组件当中

首先要到props中去接收一个posts对象,然后使用到一个v-for标签进行数组内容的遍历

在vue和react当中都不推荐使用下标来当做key

<template>
    <div class="card">
        <div class="card-body">
            <div v-for="(post, index) in posts.posts" :key="index">
                <div class="card single-post">
                    <div class="card-body">
                        {{ post.content }}
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>
<script>
export default {
    name: "UserPosts",
    props: {
        posts: {
            type: Object,
            required: true,
        }
    }
}
</script>


<style scoped>
.single-post {
    margin-bottom: 10px;
}
</style>

编辑发帖组件实现

在上面新建好的UserWrite.vue组件里面准备好格式在父组件中引入并使用

在该组件内部就直接到bootstrap里面copy一个编辑框的样式下来直接就可以了 

<template>
    <div class="card edit-filed">
        <div class="card-body">
            <label for="edit-post" class="form-label">编辑你的帖子 </label>
            <textarea class="form-control" id="exampleFormControlTextarea1" rows="3"></textarea>
            <button type="button" class="btn btn-primary btn-sm">发表</button>
        </div>
    </div>
</template>
<script>
export default {
    name: "UserWrite"
}
</script>

<style scoped>
.edit-filed {
    margin-top: 15px;
}
button {
    margin-top: 10px
}
</style>

效果图:

在发表的时候需要获取到textarea里面的内容,并将其存储起来返回到父组件的数据post当中,这里首先要在子组件当中准备一个变量接收数据内容,使用到一个v-model标签绑定textarea标签里面的内容和一个变量.

然后又使用到emit这个东西去绑定父组件里面定义的函数,并将帖子内容传了过去新增到post数组当中。

此处使用到ref时必须使用.value获取内容值。

<template>
    <div class="card edit-filed">
        <div class="card-body">
            <label for="edit-post" class="form-label">编辑你的帖子 </label>
            <textarea v-model="content" class="form-control" id="exampleFormControlTextarea1" rows="3"></textarea>
            <button @click="post_a_post" type="button" class="btn btn-primary btn-sm">发表</button>
        </div>
    </div>
</template>
<script>
import { ref } from 'vue'
export default {
    name: "UserWrite",

    setup(props, context) {
        let content = ref('');
        const post_a_post = () => {
            context.emit("post_a_post", content.value)
            content.value = "";
        };
        return {
            content,
            post_a_post
        }
    }
}
</script>


<style scoped>
.edit-filed {
    margin-top: 15px;
}

button {
    margin-top: 10px
}
</style>

父组件中

 这里的发帖以及帖子以后都要存储到数据库里面,然后今后都是从数据库获取数据来更新页面。

到此为止,已经完成了一大段内容了————————————

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

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

相关文章

物联网|uart串口相关寄存器|波特率设置及计算|发送处理代码|串口接收中断处理函数|物联网之蓝牙4.0 BLE基础-学习笔记(7)

文章目录 13 uart串口基础开发基本电路图&#xff1a;实验相关寄存器波特率设置及计算计算过程&#xff1a;设置中断发送处理代码串口接收中断处理函数main.c 13 uart串口基础开发 基本电路图&#xff1a; 实验相关寄存器 相关寄存器UxCSR、UxCSR、UxGCR、UxBUF、UxBAUD、CLK…

大厂设计师青睐的十大设计网站

设计绝对是薪酬差距最大的职业之一&#xff0c;有些人年薪100万&#xff0c;有些人月薪3000。 你有没有想过普通人和高薪设计师之间的差距在哪里&#xff1f; 在这篇文章中&#xff0c;我们将解密大厂设计师青睐的十大设计网站。让我们看看&#xff01; 1.即时设计 即时设计…

眺望高阶智能驾驶的远方,北醒驶入新“平台”

从4月到5月&#xff0c;关于2023上海国际车展的话题热度始终不减。 这次车展既让外界感受到了车企们的“卷”&#xff0c;也把智能汽车产业发展的蓝图更加清晰地呈现了出来——智能汽车正在进入产业布局的关键期&#xff0c;产业链上下游发展不断提速。 作为推动汽车产业的“…

基于边缘的图像分割

文章目录 基于边缘的图像分割基本原理常用的算法实现步骤示例代码结论 基于边缘的图像分割 基于边缘的图像分割是数字图像处理中常用的一种方法&#xff0c;它通过检测图像中的边缘信息来实现图像的分割。边缘通常代表着图像中不同区域之间的边界或目标的轮廓&#xff0c;因此…

Java 8 腰斩,Java 17 暴涨 430% (文末惊喜福利)

文末送出惊喜赠书福利一份&#xff0c;绝对high到爆&#xff01; 预约视频号&#xff1a;《Java核心技术》新书发布会暨"Java核心技术大会2023"启动仪式 New Relic 最新发布了一份 “2023 年 Java 生态系统状况报告”&#xff0c;旨在提供有关当今 Java 生态系统状态…

51单片机(十六)AD/DA

❤️ 专栏简介&#xff1a;本专栏记录了从零学习单片机的过程&#xff0c;其中包括51单片机和STM32单片机两部分&#xff1b;建议先学习51单片机&#xff0c;其是STM32等高级单片机的基础&#xff1b;这样再学习STM32时才能融会贯通。 ☀️ 专栏适用人群 &#xff1a;适用于想要…

罗马斗兽场在古罗马时期为什么这么流行,它对罗马有何影响?

在古罗马时期&#xff0c;斗兽场可谓是当时的一大热门娱乐场所。为何斗兽场如此受欢迎&#xff0c;它又如何影响了罗马社会呢&#xff1f; 斗兽场是古罗马人民的一种独特的娱乐形式。无论贵族、平民还是奴隶&#xff0c;他们都喜欢观看这种刺激的竞技。 有人认为&#xff0c;斗…

弹性盒子的属性

display&#xff1a;指定元素使用弹性盒子布局&#xff0c;属性值为 flex 或 inline-flex。 flex-direction&#xff1a;指定弹性盒子主轴的方向&#xff0c;属性值可以是 row&#xff08;默认值&#xff0c;主轴为水平方向&#xff09;、row-reverse&#xff08;主轴为水平方…

第11章:约束

一、数据完整性与约束的分类 1.为什么需要约束constraint SQL以约束方式对表数据进行额外的条件限制。 为了保证数据的完整性&#xff0c;SQL对表数据进行条件限制 ①实体完整性&#xff1a;同一个表&#xff0c;不能存在两条相同无法区分的记录 ②域完整性&#xff1a;年…

【数据结构】入门及时间空间复杂度的介绍

&#x1f331;博客主页&#xff1a;大寄一场. &#x1f331;系列专栏&#xff1a;数据结构与算法 &#x1f618;博客制作不易欢迎各位&#x1f44d;点赞⭐收藏➕关注 目录 前言 1.什么是数据结构&#xff1f; 2.什么是算法&#xff1f; 3.数据结构和算法的重要性 4.常见的数…

【杂记】Rest风格

文章目录 1.什么是Rest&#xff1f;2.URI URL URN3.什么是Restful架构风格4.状态转换 1.什么是Rest&#xff1f; Rest是一种软件架构的风格。 英文名称&#xff1a;REpresentational State Transfer&#xff08;表现层状态转移&#xff09; 加上主语&#xff1a;Resource Repr…

Linux网络基础-3

在上一篇网络基础的博客当中&#xff0c;我们对应用层协议--HTTP协议进行了详解&#xff0c;接下来我们对传输层协议进行详解 目录 1.传输层协议 2.UDP协议 2.1协议内容 2.2协议格式 2.3协议特性 3.TCP协议 3.1协议内容 3.2协议格式 3.3协议特性 3.3.1三次握手建立连…

Bootstrap开发之——Bootstrap安装及使用(02)

一 概述 Bootstrap下载npm安装bootstrap并使用(vue中使用)bootstrap通过本地lib导入并使用(html)bootstrap通过cdn导入并使用(html) 二 Bootstrap下载 2.1 Bootstrap下载(v3.x版本为例) 在Bootstrap中文官网&#xff0c;点击顶部的入门标签&#xff0c;在如下图页面点击下载…

Linux——对权限的理解

文章目录 总述Linux权限的概念Linux 权限管理Linux对文件访问者的分类文件类型和访问权限a.文件类型b.基本权限文件权限修改的相关方法 其他问题在首次创建时文件的权限属性是固定的吗&#xff1f;目录的权限粘滞位 总述 本篇博客将主要讲解linux系统中权限的概念&#xff0c;权…

Sort练习题

sort 练习 练习题 题目&#xff1a;浮点数排序 #define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <algorithm> //sort()排序 #include <cmath> //round()来找最近的整数 using namespace std; const double EPSILON 1e-6; //两个浮点…

web框架:Iris快速入门

web框架&#xff1a;Iris快速入门 1 介绍及安装 介绍 Iris是一款用Go开发的web应用框架&#xff0c;被称为速度最快的Go后端开发框架。官网地址&#xff1a;https://www.iris-go.com/中文教程地址&#xff1a;http://www.codebaoku.com/iris/iris-index.html 安装 环境要求&a…

QTableView编程——Model/View架构(单元格随意拖拽交换)

QTableView编程——Model/View架构 基础知识 添加表头 //准备数据模型QStandardItemModel *student_model new QStandardItemModel();student_model->setHorizontalHeaderItem(0, new QStandardItem(QObject::tr("Name")));student_model->setHorizontalHea…

【Redis】Redis位图(bitmap)介绍和在签到场景的应用

文章目录 一、前言二、redis位图相关指令setbit命令getbit命令bitcount命令bitfield命令bitpos命令bitop命令 三、应用场景累计签到应用场景连续签到应用场景日期签到场景应用详情 一、前言 基本原理&#xff1a; 《Redis设计与实现》中对位图的实现描述是&#xff1a;Redis使…

做软件测试我该如何快速摸清一家公司的基本情况?

当你准备进入一家新的公司作为软件测试人员时&#xff0c;了解公司的基本情况对于你快速适应新环境和工作非常重要。下面是几个方面可以帮助你快速摸清一家公司的基本情况&#xff1a; 如果你想学习软件测试&#xff0c;我这边给你推荐一套视频&#xff0c;这个视频可以说是B站…

8. 高性能业务表结构设计和索引知识深化

MySQL性能调优 1. 数据库表设计1.1 范式化设计1.1.1 什么是范式&#xff1f;1.1.2 第一范式&#xff08;1NF&#xff09;1.1.2 第二范式&#xff08;2NF&#xff09;1.1.3 第三范式&#xff08;3NF&#xff09; 1.2 反范式设计1.2.1 什么叫反范式化设计 1.3 范式化和反范式总结…