上周完成了 IC 入门课程第五课的作业

现将答案贴出,欢迎同学们参考,禁止抄袭作业哦

课程作业 (完善 microblog 前端)
1. 显示消息的发布者名字
  a. 给 Message 增加 author 字段
  b. 增加 set_name 和 get_name 公共方法
2. 增加以下新 UI
  a. 显示目前 follow 的作者列表
  b. 在 timeline 中显示消息作者和时间
3. 关注(follow)其它学员的 canister
  a. 关注三个以上作者
  b. 点击作者名字,会显示对方发布的消息列表

  前端页面:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<title>Microblog</title>
<base href="/" />
<link rel="icon" href="favicon.ico" />
<link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css"/>
</head>
<body>
<header><h1>Microblog</h1></header>
<main>
<div>
<label for="message">What do you want to post?</label>
<textarea id="message"></textarea>
<label for="pwd">password</label>
<input id="pwd"/><br/>
<button id="post">Post</button>
<span id="error"></span>
<section id="posts"></section>
</div>
<br/>
<div>
<label for="name">Get or set name:</label>
<input id="name"/>
<span id="info"></span><br/>
<button id="getName">Get</button>
<button id="setName">Set</button>
</div>
<br/>
<div>
<section id="follow"></section>
</div>
</main>
</body>
</html>

  JS:

import { Int } from "@dfinity/candid/lib/cjs/idl";
import { goodbye_backend } from "../../declarations/goodbye_backend"; async function post() {
let post_button = document.getElementById("post");
let err = document.getElementById("error");
err.innerText = "";
post_button.ariaDisabled = true;
let textarea = document.getElementById("message");
let text = textarea.value;
let pwd = document.getElementById("pwd").value;
try {
await goodbye_backend.post(pwd, text);
textarea.value = "";
} catch (error) {
console.error(error);
err.innerText = "Failed";
}
post_button.ariaDisabled = false;
} var num_posts = 0;
async function load_posts() {
let posts_section = document.getElementById("posts");
let posts = await goodbye_backend.posts(1);
if (num_posts == posts.length) return;
posts_section.replaceChildren([]);
num_posts = posts.length;
for(var i = num_posts - 1; i >= 0; i --) {
let post = document.createElement("p");
post.innerText = posts[i].author + " SAY: " + posts[i].text + " - " + Date((BigInt(posts[i].time) / BigInt(1000000000))).toLocaleString();
posts_section.appendChild(post);
}
} async function getName() {
let get_button = document.getElementById("getName");
get_button.disabled = true;
let name = await goodbye_backend.get_name();
document.getElementById("name").value = name;
get_button.disabled = false;
} async function setName() {
let set_button = document.getElementById("setName");
let info = document.getElementById("info");
info.innerText = "";
set_button.disabled = true;
let nameIn = document.getElementById("name");
let name = nameIn.value;
try {
await goodbye_backend.set_name(name);
nameIn.value = "";
info.innerText = "Success";
} catch (error) {
console.error(error);
info.innerText = "Failed";
}
set_button.disabled = false;
} var num_follows = 0;
async function follows() {
let follows = await goodbye_backend.follows();
if (num_follows == follows.length) return;
num_follows = follows.length;
let info = "";
for(var i = 0; i < num_follows; i ++) {
let id = follows[i]['uid'];
info += "<button class='info_btn' id= " + id + ">" + follows[i]['uname'] + "</button>";
info += "<section id=" + id + "-msg" + "></section></br>";
}
document.getElementById("follow").innerHTML = info;
for(var i = 0; i < num_follows; i ++) {
let id = follows[i]['uid'];
document.getElementById(id).addEventListener('click', function handleClick(event) {
load_posts2(id);
})
}
} var num_posts2 = 0;
async function load_posts2(id) {
alert("Id: " + id + " , Please wait");
let posts_section2 = document.getElementById(id + "-msg");
try {
let posts2 = await goodbye_backend.posts2(id, 1);
if (num_posts2 == posts2.length) return;
posts_section2.replaceChildren([]);
num_posts2 = posts2.length;
for(var i = num_posts2 - 1; i >= 0; i --) {
let post2 = document.createElement("p");
post2.innerText = posts2[i].author + " SAY: " + posts2[i].text + " - " + Date((BigInt(posts2[i].time) / BigInt(1000000000))).toLocaleString();
posts_section2.appendChild(post2);
}
} catch (error) {
console.error(error);
}
} async function load() {
let post_button = document.getElementById("post");
post_button.onclick = post;
load_posts();
setInterval(load_posts, 5000); let get_button = document.getElementById("getName");
get_button.onclick = getName; let set_button = document.getElementById("setName");
set_button.onclick = setName; follows();
} window.onload = load;

  Motoko:

import List "mo:base/List";
import Iter "mo:base/Iter";
import Principal "mo:base/Principal";
import Time "mo:base/Time";
import Nat "mo:base/Nat"; actor {
public type Message = {
author: ?Text;
text: Text;
time: Time.Time;
}; public type User = {
uid: Principal;
uname: ?Text;
}; var king: Text = "Linnuo"; public type Microblog = actor {
follow: shared(Principal) -> async (); // add关注对象
follows: shared query () -> async [User]; // return关注对象列表
post: shared (Text) -> async (); // 发布新消息
posts: shared (Time.Time) -> async [Message]; // return 发布消息列表
posts2: shared (Text) -> async [Message]; // return 所有关注对象发布的消息
timeline: shared (Time.Time) -> async [Message]; // return 所有关注对象发布的消息
set_name: shared (Text) -> async (); // set 名字
get_name: shared query () -> async ?Text; // get 名字
unfollow: shared () -> async (); // 清空跟随
}; // stable 修饰:升级不清空内存
stable var followed : List.List<User> = List.nil(); public shared func follow(id: Principal) : async (){
let canister : Microblog = actor(Principal.toText(id));
let name: ?Text = await canister.get_name();
let u = {
uid = id;
uname = name;
};
followed := List.push(u, followed);
}; public shared query func follows() : async [User] {
List.toArray(followed);
}; stable var messages : List.List<Message> = List.nil(); // (msg):获取消息属性
public shared (msg) func post(pwd: Text, text: Text) : async (){
// 获取发送者: dfx identity get-principal
// assert(Principal.toText(msg.caller) == "vw7ov-537vk-abslh-s2gx7-gw2ff-v4u6y-thlcs-hejxf-hkkc5-bjiq7-pqe"); //消息发送者
assert(pwd == "qwe123");
let m = {
author = ?king;
text = text;
time = Time.now();
};
messages := List.push(m, messages);
// 用钱包调用正常返回失败:dfx canister --wallet=$(dfx identity get-wallet) call microblog_backend post "(\"Second post\")"
}; public shared func posts(since: Time.Time) : async [Message] {
var list : List.List<Message> = List.nil(); for (m in Iter.fromList(messages)) {
if (m.time >= since){
list := List.push(m, list);
}
}; List.toArray(list);
}; public shared func posts2(pid: Principal, since: Time.Time) : async [Message] {
try {
let canister : Microblog = actor(Principal.toText(pid));
await canister.posts(since);
} catch (err) {
[]
}
}; public shared func timeline(since: Time.Time) : async [Message] {
var all : List.List<Message> = List.nil(); for (user in Iter.fromList(followed)){
let canister : Microblog = actor(Principal.toText(user.uid));
let msgs = await canister.posts(since); for(msg in Iter.fromArray(msgs)){
all := List.push(msg, all);
};
}; List.toArray(all);
}; public shared func set_name(name: Text) {
king := name;
}; public shared query func get_name() : async ?Text {
return ?king;
}; public shared func unfollow() : async (){
followed := List.nil();
}; // 发送消息:id和名称可以呼唤
// dfx canister call rrkah-fqaaa-aaaaa-aaaaq-cai post "(\"First post\")" // 用Id发消息
// dfx canister call microblog_backend post "(\"Second post\")" // 用名称发消息
// dfx canister call rrkah-fqaaa-aaaaa-aaaaq-cai posts "()" // 获取消息列表
// dfx canister call microblog_backend2 follow "(principal \"$(dfx canister id microblog_backend)\")" // 添加关注对象
// dfx canister call microblog_backend2 follows "()" // 获取关注对象列表
// dfx canister call microblog_backend2 timeline "()" // 获取所有关注对象发布的消息
};

代码的实现并不复杂,欢迎童鞋们指导哈

为了避免直接下载项目,这里就不贴 Github 入口了,好好学习,加油

IC入门课第五课作业:完善 Microblog 前端(1、显示发布者的名字;2、增加新UI、3、关注其他学员的 canister)的更多相关文章

  1. Elasticsearch7.X 入门学习第五课笔记---- - Mapping设定介绍

    原文:Elasticsearch7.X 入门学习第五课笔记---- - Mapping设定介绍 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本 ...

  2. 普林斯顿算法课第五周作业_KdTree

    作业地址:http://coursera.cs.princeton.edu/algs4/assignments/kdtree.html 作业难点: 1.如何构建KdTree,使用什么样的数据结构? 根 ...

  3. Spring入门第二十五课

    使用具名参数 直接看代码: db.properties jdbc.user=root jdbc.password=logan123 jdbc.driverClass=com.mysql.jdbc.Dr ...

  4. NeHe OpenGL教程 第四十五课:顶点缓存

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  5. 【Linux探索之旅】第一部分第五课:Unity桌面,人生若只如初见

    内容简介 1.第一部分第五课:Unity桌面,人生若只如初见 2.第一部分第六课预告:Linux如何安装在虚拟机中 Unity桌面,人生若只如初见 不容易啊,经过了前几课的学习,我们认识了Linux是 ...

  6. 【C语言探索之旅】 第二部分第五课:预处理

    内容简介 1.课程大纲 2.第二部分第五课: 预处理 3.第二部分第六课预告:   创建你自己的变量类型 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C语 ...

  7. 【C语言探索之旅】 第一部分第五课:运算那点事

    内容简介 1.课程大纲 2.第一部分第五课:运算那点事 3.第一部分第六课预告:条件表达式 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C语言编写三个游戏 ...

  8. Linux云自动化运维第五课

    Linux云自动化运维第五课 一.进程定义 进程就是cpu未完成的工作 二.ps命令 ps a ###关于当前环境的所有进程 x ###与当前环境无关的所有进程 f ###显示进程从属关系 e ### ...

  9. [译]Quartz.NET 框架 教程(中文版)2.2.x 之第五课 SimpleTrigger

    第五课 SimpleTrigger 如果你需要在一个指定时间段内执行一次作业任务或是在指定的时间间隔内多次执行作业任务,SimpleTrigger应该能满足你的调度需求.例如,你希望触发器在2015年 ...

随机推荐

  1. 苹果手机和Windows之间互传文件

    参考链接:https://jingyan.baidu.com/article/a378c960c46804f229283064.html 实现原理:就是使用Samba服务,windows共享一个文件夹 ...

  2. esp8266模拟输入(ADC)检测问题

    今天使用esp12f读取A0数据时一直出现错误; Serial.println(analogRead(A0));读取值一直为1024 因为前段时间一直用的是开发板,读取电压值正常 而从昨天换为了esp ...

  3. 【每天学一点-06】在Vue中使用Vant-Picker选择器,并且给选择器添加一个类似Antd-Select-showSearch的搜索功能

    一.在Vant文档中,Picker组件的API中是没有showSearch这一选项的 1.Vant-Picker 文档 2.Antd-Select 文档 3.需要完成的需求 4.因为在H5项目中出现了 ...

  4. 平衡树——splay 三

    前文链接: 平衡树--splay 一 - yi_fan0305 - 博客园 (cnblogs.com) 平衡树--splay 二 - yi_fan0305 - 博客园 (cnblogs.com) 再补 ...

  5. IO概述(概念&分类)和字节输入流+OUTputStream类&FileOutPutStream类介绍

    IO概述 什么是IO 生活中,你肯定经历过这样的场景.当你编辑一个文本文件,忘记了保存,可能文件就白白编辑了.当你的电脑上插入一个U盘,可以吧一个视频,拷贝到你的电脑硬盘里,那么数据都是在哪些设备上的 ...

  6. linux安全之网络设置

    可以通过/etc/sysctl.conf控制和配置Linux内核及网络设置. # 避免放大攻击 net.ipv4.icmp_echo_ignore_broadcasts = 1 # 开启恶意icmp错 ...

  7. Vs 快捷键---探索不一样的编程

    前言:现在很多工具都支持各式各样的快捷键,vs作为后起之秀,多功能的快捷键自然是必不可少的, 而且针对单行操作的快捷键是无需选中整行的,只需要光标停留在所操作的代码上面即可. 1.注释:CTRL+K+ ...

  8. C#async\await组合

    一.概述 编译器提供的便捷功能,就是语法糖.我的理解是为了优化代码.被async修饰的函数被称之为异步函数,主要用于异步编程,着重于靠await实现回调机制. 二.声明 //async用在方法名之前 ...

  9. 如何基于WPF写一款数据库文档管理工具(二)

    系列目录 基于WPF重复造轮子,写一款数据库文档管理工具(一) 本篇重点 上次发表了基于WPF重复造轮子,写一款数据库文档管理工具(一) 得到不少人支持,文章一度上到了博客园推荐表首页,看来大家对这个 ...

  10. 【AGC】构建服务1-云函数示例

    ​ 前言:上一次笔者给大家带来了AGC领域的远程配置服务的学习.这次我们再继续深化学习AGC的相关知识.在文章开始之前,再给读者简单介绍一下AGC,以免第一次来的读者不了解.所谓AGC就是AppGal ...