Web学习笔记-Vue3(用户动态页面设计)

笔记内容转载自 AcWing 的 Web 应用课讲义,课程链接:AcWing Web 应用课。

CONTENTS

  • 1. 实现用户信息模块
  • 2. 实现关注用户功能
  • 3. 实现历史动态模块
  • 4. 实现发动态模块

1. 实现用户信息模块

用户动态页面可以划分为三个模块:用户信息部分、发动态部分(如果是自己才有发动态功能)、历史动态展示部分,因此我们可以用三个组件来实现(在 components 目录下创建 UserNewsInfo.vueUserNewsSend.vue 以及 UserNewsPosts.vue 三个组件)。

其中 UserNewsInfo 内容如下:

<template><div class="card"><div class="card-body"><div class="row"><div class="col-md-4"><imgclass="img-fluid"src="https://cdn.acwing.com/media/user/profile/photo/82581_lg_e9bdbcb8aa.jpg"/></div><div class="col-md-8"><div class="username">AsanoSaki</div><div class="fans">粉丝:123</div><button type="button" class="btn btn-secondary btn-sm">+关注</button></div></div></div></div>
</template><script>
export default {name: "UserNewsInfo",
};
</script><style scoped>
img {border-radius: 50%;
}button {padding: 2px 4px;font-size: 14px;width: 70px;
}.username {font-size: 20px;font-weight: bold;
}.fans {font-size: 14px;color: gray;
}
</style>

UserNewsPosts 内容如下:

<template><div class="card"><div class="card-body"></div></div>
</template><script></script><style scoped></style>

然后我们在 UserNewsView 中先将这两个组件添加进去:

<template><Card title="用户动态"><div class="row"><div class="col-md-3"><UserNewsInfo /></div><div class="col-md-9"><UserNewsPosts /></div></div></Card>
</template><script>
// @ is an alias to /src
import Card from "@/components/Card.vue";
import UserNewsInfo from "@/components/UserNewsInfo.vue";
import UserNewsPosts from "@/components/UserNewsPosts.vue";export default {name: "UserNewsView",components: {Card: Card,UserNewsInfo: UserNewsInfo,UserNewsPosts: UserNewsPosts,},
};
</script>

现在我们的网页是静态的,用户头像、名字这些内容应该都是参数,每个用户是不一样的,且用户发动态后需要在历史动态组件中展示,因此这几个组件都是需要数据交互的。

一般情况下我们会将数据存到需要交互的这几个组件的最顶层组件中,即 UserNewsView。我们可以使用 setup() 函数初始化变量,当前页面的用户一般是不会变的,因此可以定义一个 reactive,注意 reactive 只能接收对象。未来我们需要在模板中用到的属性都需要从 setup() 函数中 return 出去。在 UserNewsView 中传递数据给 UserNewsInfo

<template><Card title="用户动态"><div class="row"><div class="col-md-3"><UserNewsInfo :user="user" /></div><div class="col-md-9"><UserNewsPosts /></div></div></Card>
</template><script>
// @ is an alias to /src
import Card from "@/components/Card.vue";
import UserNewsInfo from "@/components/UserNewsInfo.vue";
import UserNewsPosts from "@/components/UserNewsPosts.vue";
import { reactive } from "vue";export default {name: "UserNewsView",components: {Card: Card,UserNewsInfo: UserNewsInfo,UserNewsPosts: UserNewsPosts,},setup() {const user = reactive({username: "AsanoSaki",fansCount: 1,is_followed: false,  // 是否关注这个用户});return {user: user,}},
};
</script>

Vue 中传递数据的方式类似于 React,父组件通过 props 传递属性给子组件,子组件通过调用函数(事件)给父组件传递信息。可以使用 :v-bind: 给子组件绑定属性,其后是一个表达式而非普通字符串。子组件需要将接受的数据放在 props 中,接受的 user 数据类型为 Object,且是必填的 required

如果某个数据是动态被计算出来的可以使用 computed。在 UserNewsInfo 中接收并使用数据:

<template><div class="card"><div class="card-body"><div class="row"><div class="col-md-4"><imgclass="img-fluid"src="https://cdn.acwing.com/media/user/profile/photo/82581_lg_e9bdbcb8aa.jpg"/></div><div class="col-md-8"><div class="username">{{ user.username }}</div><div class="fans">粉丝:{{ doubleFansCount }}</div><button type="button" class="btn btn-secondary btn-sm">+关注</button></div></div></div></div>
</template><script>
import { computed } from 'vue';export default {name: "UserNewsInfo",props: {user: {type: Object,required: true,},},setup(props) {let doubleFansCount = computed(() => props.user.fansCount * 2);return {doubleFansCount: doubleFansCount,}},
};
</script><style scoped>
...
</style>

2. 实现关注用户功能

当没有关注当前用户时才会显示加关注的按钮,否则应该显示取消关注按钮。我们可以使用 v-if 属性判断某个表达式是否成立,即可以判断 user.is_followed 是否为 true 来动态显示关注和取关按钮。

还有就是当我们点击按钮时需要更改 user.is_followed 的状态,需要定义一个事件处理函数并绑定(使用 v-on:click@click)到按钮的 click 属性上。

由于状态是从父组件 UserNewsView 中传过来的,因此不能直接在子组件中修改状态,而是需要在父组件中定义好函数并绑定(使用 @)到子组件上:

<template><Card title="用户动态"><div class="row"><div class="col-md-3"><UserNewsInfo @follow="follow" @unfollow="unfollow" :user="user" /></div><div class="col-md-9"><UserNewsPosts /></div></div></Card>
</template><script>
// @ is an alias to /src
import Card from "@/components/Card.vue";
import UserNewsInfo from "@/components/UserNewsInfo.vue";
import UserNewsPosts from "@/components/UserNewsPosts.vue";
import { reactive } from "vue";export default {name: "UserNewsView",components: {Card: Card,UserNewsInfo: UserNewsInfo,UserNewsPosts: UserNewsPosts,},setup() {const user = reactive({username: "AsanoSaki",fansCount: 1,is_followed: false,  // 是否关注这个用户});const follow = () => {if (user.is_followed) return;user.is_followed = true;user.fansCount++;};const unfollow = () => {if (!user.is_followed) return;user.is_followed = false;user.fansCount--;};return {user: user,follow: follow,unfollow: unfollow,}},
};
</script>

然后由子组件触发绑定的函数来修改父组件中的状态,其 API 为 context.emit()setup() 函数中可以接收第二个参数 context

<template><div class="card"><div class="card-body"><div class="row"><div class="col-md-4"><imgclass="img-fluid"src="https://cdn.acwing.com/media/user/profile/photo/82581_lg_e9bdbcb8aa.jpg"/></div><div class="col-md-8"><div class="username">{{ user.username }}</div><div class="fans">粉丝:{{ user.fansCount }}</div><button @click="handleFollow" v-if="!user.is_followed" type="button" class="btn btn-secondary btn-sm">+关注</button><button @click="handleUnfollow" v-if="user.is_followed" type="button" class="btn btn-secondary btn-sm">取消关注</button></div></div></div></div>
</template><script>
import { computed } from 'vue';export default {name: "UserNewsInfo",props: {user: {type: Object,required: true,},},setup(props, context) {let doubleFansCount = computed(() => props.user.fansCount * 2);const handleFollow = () => {context.emit("follow");};const handleUnfollow = () => {context.emit("unfollow");};return {doubleFansCount: doubleFansCount,handleFollow: handleFollow,handleUnfollow: handleUnfollow,}},
};
</script><style scoped>
...
</style>

3. 实现历史动态模块

我们先在 UserNewsView 中创建几条动态并传给 UserNewsPosts 子组件:

<template><Card title="用户动态"><div class="row"><div class="col-md-3"><UserNewsInfo @follow="follow" @unfollow="unfollow" :user="user" /></div><div class="col-md-9"><UserNewsPosts :posts="posts" /></div></div></Card>
</template><script>
// @ is an alias to /src
import Card from "@/components/Card.vue";
import UserNewsInfo from "@/components/UserNewsInfo.vue";
import UserNewsPosts from "@/components/UserNewsPosts.vue";
import { reactive } from "vue";export default {...setup() {const user = reactive({id: 1,  // 给每个用户一个唯一编号username: "AsanoSaki",fansCount: 1,is_followed: false,  // 是否关注这个用户});const posts = reactive({count: 3,posts: [{id: 1,userId: 1,content: "今天天气真好!",},{id: 2,userId: 1,content: "随便发个动态",},{id: 3,userId: 1,content: "今天吃些什么?",},],});...return {user: user,follow: follow,unfollow: unfollow,posts: posts,}},
};
</script>

在子组件 UserNewsPosts 中我们就需要循环渲染出每条动态,可以使用 v-for 实现,注意循环时类似于 React,需要绑定一个不重复的 key 属性:

<template><div class="card"><div class="card-header text-center">历史动态</div><div class="card-body"><div v-for="post in posts.posts" :key="post.id"><div class="card post"><div class="card-body">{{ post.content }}</div></div></div></div></div>
</template><script>
export default {name: "UserNewsPosts",props: {posts: {type: Object,required: true,},},
};
</script><style scoped>
.post {margin: 10px 0;
}
</style>

4. 实现发动态模块

Vue 可以使用 v-model 获取 <textarea> 的内容并绑定到某个变量上,我们先在父组件 UserNewsView 中导入子组件 UserNewsSend,然后创建发动态的函数传递给子组件:

<template><Card title="用户动态"><div class="row"><div class="col-md-3"><UserNewsInfo @follow="follow" @unfollow="unfollow" :user="user" /><hr /><UserNewsSend @send="send" /></div><div class="col-md-9"><UserNewsPosts :posts="posts" /></div></div></Card>
</template><script>
// @ is an alias to /src
import Card from "@/components/Card.vue";
import UserNewsInfo from "@/components/UserNewsInfo.vue";
import UserNewsPosts from "@/components/UserNewsPosts.vue";
import UserNewsSend from "@/components/UserNewsSend.vue";
import { reactive } from "vue";export default {name: "UserNewsView",components: {Card: Card,UserNewsInfo: UserNewsInfo,UserNewsPosts: UserNewsPosts,UserNewsSend: UserNewsSend,},setup() {...const posts = reactive({count: 3,posts: [{id: 1,userId: 1,content: "今天天气真好!",},{id: 2,userId: 1,content: "随便发个动态",},{id: 3,userId: 1,content: "今天吃些什么?",},],});...const send = (content) => {posts.count++;posts.posts.unshift({  // 在数组末尾加元素是push(),在首部加元素是unshift()id: posts.count,userId: 1,content: content,});}return {user: user,follow: follow,unfollow: unfollow,posts: posts,send: send,}},
};
</script>

最后是实现 UserNewsSend

<template><div class="card"><div class="card-body"><label for="input" class="form-label">发一条动态吧~</label><textareav-model="content"class="form-control"id="input"rows="3"></textarea><div class="text-end"><button@click="handleSend"type="button"class="btn btn-outline-primary">发送</button></div></div></div>
</template><script>
import { ref } from "vue";export default {name: "UserNewsSend",setup(props, context) {let content = ref("");const handleSend = () => {if (content.value) {  // 输入框不为空才发送动态context.emit("send", content.value); // 调用父组件的send函数content.value = ""; // 发送后输入框的内容应该清空}};return {content: content,handleSend: handleSend,};},
};
</script><style scoped>
button {margin-top: 15px;border-radius: 20px;width: 90px;
}
</style>

我们理一下执行过程,首先点击发送按钮后会触发绑定的 UserNewsSend 组件中的 handleSend 函数,该函数会调用父组件 UserNewsView 传递过来的 send 事件,参数是 content.value,父组件触发 send 事件后会调用其定义的 send 函数,这个函数会在父组件的 post 对象中添加数据,由于 post 对象是 reactive 类型的,因此当这个对象发生变化时,引用了该对象的组件就会重新渲染,即重新渲染 UserNewsPosts

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

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

相关文章

11-09 周四 CNN 卷积神经网络基础知识

11-09 周四 CNN 卷积神经网络 时间版本修改人描述2023年11月9日09:38:12V0.1宋全恒新建文档 简介 学习一下CNN&#xff0c;卷积神经网络。使用的视频课程。视觉相关的任务&#xff1a; 人脸识别 卷积网络与传统网络的区别&#xff1a; <img altimage-20231109094400591 s…

电脑怎么录制视频,录制的视频怎么剪辑?

在现今数字化的时代&#xff0c;视频成为了人们日常生活中不可或缺的一部分。因此&#xff0c;对于一些需要制作视频教程、录制游戏或者是进行视频演示的人来说&#xff0c;电脑录屏已经成为了一个必不可少的工具。那么&#xff0c;对于这些人来说&#xff0c;如何选择一个好用…

Zigbee—网络层地址分配机制

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;孤雏 0:21━━━━━━️&#x1f49f;──────── 4:14 &#x1f504; ◀️ ⏸ ▶️ ☰ &#x1f497;关注…

maven配置自定义下载路径,以及阿里云下载镜像

1.配置文件 <?xml version"1.0" encoding"UTF-8"?> <settings xmlns"http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation"http://maven.apache.org…

Vue真实技术面试题解析【兄弟组件、vue-router、增量部署】

兄弟组件的传值方式&#xff0c;有两种方式&#xff0c;把你尽可能知道的告诉我 我的答案&#xff1a;使用父组件传值 和 状态管理传值 使用事件总线&#xff08;Event Bus&#xff09;&#xff1a;创建一个空的 Vue 实例作为事件总线&#xff0c;在其中定义事件和对应的处理函…

大厂面试题-MySQL中的RR隔离级别,到底有没有解决幻读问题?

就MySQL中的RR(Repeatable Reads)事务隔离级别&#xff0c;到底有没有解决幻读问题发起了激烈的讨论。 一部分人说有&#xff0c;一部分人说没有。 结论&#xff0c;MySQL中的RR事务隔离级别&#xff0c;在特定的情况下会出现幻读的问题。 所谓的幻读&#xff0c;表示在同一…

景联文科技加入中国人工智能产业发展联盟(AIIA),与行业各方共促AI产业发展

近日&#xff0c;景联文科技加入中国人工智能产业发展联盟&#xff08;AIIA&#xff09;&#xff0c;与行业各方共同挖掘人工智能数据的更多价值&#xff0c;破解中国人工智能AI数据短缺难题。 中国人工智能产业发展联盟&#xff08;简称AIIA&#xff09;是在国家发改委、科技部…

GIS入门,xyz地图瓦片是什么,xyz数据格式详解,如何发布离线XYZ瓦片到nginx或者tomcat中

XYZ介绍 XYZ瓦片是一种在线地图数据格式,由goole公司开发。 与其他瓦片地图类似,XYZ瓦片将地图数据分解为一系列小的图像块,以提高地图显示效率和性能。 XYZ瓦片提供了一种开放的地图平台,使开发者可以轻松地将地图集成到自己的应用程序中。同时,它还提供了高分辨率图像和…

红海云签约和兆服饰,科技引领服饰行业人力资源数字化转型

和兆服饰从事多品牌多品类经营管理&#xff0c;旗下拥有POLOSPORT、POLOKIDS、CARTELO等国际品牌。作为一个主打POLO文化的服饰品牌&#xff0c;诞生于美国的POLOSPORT拥有现代感的产品设计、系列化的产品搭配、全方位的服务&#xff0c;是最具美国马球精神的休闲时尚服饰品牌之…

攻防世界题目练习——Web引导模式(四)(持续更新)

题目目录 1. shrine2. very_easy_sql3. fakebook 1. shrine 打开网页题目内容如下&#xff1a; 是一段代码&#xff0c;我们把它还原一下&#xff1a; import flask import osapp flask.Flask(__name__) app.config[FLAG] os.environ.pop(FLAG) #这里应该是将config配置里…

【Docker】设置容器系统字符集zh_CN.UTF-8退出失效:关于Docker容器配置环境变量,再次进入失效问题

设置容器系统字符集zh_CN.UTF-8退出失效&#xff1a;关于Docker容器配置环境变量&#xff0c;再次进入失效问题 修改正在运行的Docker容器内的字符集: 先进入Docker容器&#xff1a;docker exec -it 容器ID /bin/bash查看是否支持中文字符集&#xff1a;locale -a | grep zh&a…

PCIe寄存器之二

关键字索引&#xff1a; CAP_PM 对应&#xff1a;Capabilities: [c0] Power Management CAP_MSI 对应&#xff1a;Capabilities: [c8] MSI CAP_MSIX对应&#xff1a;Capabilities: [e0] MSI-X CAP_EXP 对应&#xff1a;Capabilities: [70] Express (v2) Endpoint 以上 [] 内的…

uni-app前端H5页面底部内容被tabbar遮挡

问题&#xff1a; 在用uniapp写小程序的时候&#xff0c;底部有一部分内容没显示出来&#xff0c;被底部的tabbar遮挡住了 解决&#xff1a; 给最外部的view设置样式padding-bottom: var(--window-bottom)&#xff0c;如下 参考&#xff1a; 参考1 参考2 使用 uni-app 框…

Spring-推断构造方法

Spring中的Bean实例化对象&#xff0c;需要构造方法 通常一个类只有一个构造方法&#xff1a; 1、无参的构造方法&#xff0c;实例化只能选择这一个 2、有参的构造方法 使用AnnotationConfigApplicationContext&#xff0c;会使用这个构造方法进行实例化&#xff0c;Spring根…

推送效率低?MobPush带着APP消息推送一站式解决方案来了

随着移动应用竞争的日趋激烈&#xff0c;如何拉新促活&#xff0c;保持用户粘性成为各大APP的运营的焦点和核心。作为一种有效的营销和用户保留工具。APP消息推送可以有效提高用户参与度&#xff0c;增强用户忠诚度&#xff0c;并最终提高业务效益。然而随着各大APP推送的高度同…

Android 12.0 开启蓝牙状态栏即显示蓝牙图标

Android 12.0 开启蓝牙状态栏即显示蓝牙图标 最近收到客户反馈想要在开启蓝牙时状态栏就能显示出蓝牙图标&#xff0c;我们系统默认是蓝牙连接上设备后状态栏才显示出蓝牙图标&#xff0c;具体修改参照如下&#xff1a; /vendor/mediatek/proprietary/packages/apps/SystemUI…

UML与PlantUML简介

UML与PlantUML 1、UML与PlantUML概述2、PlantUML使用 1、UML与PlantUML概述 UML&#xff08;Unified Modeling Language&#xff09;是一种统一建模语言&#xff0c;为面向对象开发系统的产品进行说明、可视化、和编制文档的一种标准语言&#xff0c;独立于任何具体程序设计语言…

YOLOv8-Seg改进: 分割小目标系列篇 | SPD-Conv,提升分割小目标和弱小分割图精度

🚀🚀🚀本文改进:SPD-Conv由一个空间到深度(SPD)层和一个无卷积步长(Conv)层组成,可以应用于大多数CNN体系结构,特别是在处理低分辨率图像和分割小目标等更困难的任务时。 🚀🚀🚀SPD-Conv 分割小目标检测首选,暴力涨点 🚀🚀🚀YOLOv8-seg创新专栏:http:…

什么是Node.js的NVM(Node Version Manager)?它的作用是什么?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

YOLOv5检测界面-PyQt5实现

1.将detect.py运用到界面 要将 YOLOv5 的检测结果与 PyQt 界面结合&#xff0c;你需要进行一些额外的步骤。以下是一个简单的示例代码&#xff0c;展示如何使用 YOLOv5 进行目标检测并在 PyQt 界面中显示结果。 首先&#xff0c;确保你已经安装了必要的库&#xff1a; pip …