我们在向大家征集开发课程大纲后,便陆续收到了很多建议。大家的热情与支持,是我们持续更新的动力。
由于大家的课程建议比较散,需要结合实际案例进行讲解,因此我们先从最简单的开始。本文将介绍如何通过知晓云的内容库以及数据表,快速制作一个包含评论功能的个人博客。
适用人群:
- 🙋刚接触编程的大学生(中小学生有多余精力也可,知晓云用户最小年龄 14 岁喔)
- 🙋有兴趣学习前端开发的产品、测试和运营人员
- 🙋业余爱好,有大量的学习时间,希望通过掌握基础开发知识,未来将开发应用作为副业
如果你有兴趣分享你的开发经验,请联系小晓云投稿(微信号:minsupport3),期待你的分享。
本文将使用到的技术:
- 知晓云 Web SDK
- React
- Geist UI 库,用于快速构建样式
- react-router-dom,用于页面跳转
- Moment.js,用于解析日期
假设现在我们有一个完整样式的个人博客,里面包含两个页面,一个是首页,另一个是文章页。首页主要包含文章列表、标题和链接等内容,而文章页包含了文章内容、评论和登录功能。
我们先看一下截图,具体的代码可从这里下载:https://github.com/ifanrx/minapp-blog-example/tree/blog-structure-and-styles
首页:
文章页:
接下来,我们将直接进入具体页面和功能的开发实战(教程较长,可先收藏)。
一、两行代码接入知晓云
首先,在知晓云控制台创建「个人博客」应用,然后我们安装知晓云 Web SDK 依赖:
yarn add minapp-sdk
之后,在 src/index.js
中初始化 SDK。BaaS.init 方法里的 clientID 填入知晓云控制台「设置」中分配的 clientID 即可:
import BaaS from 'minapp-sdk'
BaaS.init('a4d2d62965ddb57fa4xx')
我们还需要在控制台中将本地项目的域名设置安全域名,具体请参考:https://doc.minapp.com/js-sdk/web/how-to.html
二、免开发实现内容库管理文章
对文章的内容进行管理,我们可以利用知晓云控制台提供的内容库进行文章的编写,从而更高效地生产文章。
我们先在知晓云控制台左侧导航栏中点击「开发 - 内容」,进入内容库:
如果之前没有使用过内容库,那么可以先新建一个内容库,点击「马上开始」:
输入内容库名,将访问权限设置为所有人可见,并提交:
之后,我们创建一个分类,这里可自定义名称:
点击添加内容,新建一篇文章:
在新建内容页,我们输入文章标题、分类和内容等信息,并保存提交,这样我们第一篇文章就诞生啦:
我们还可以根据需要创建更多的文章和分类,至此,博客的内容已经完成了。
三、简单几步,实现首页动态获取文章分类和列表
在获取文章分类和列表之前,我们先初始化一下内容库:
const contentGroupId = 1630893238319930
const contentGroup = new BaaS.ContentGroup(contentGroupId)
其中,contentGroupId 可以在控制台,创建一条内容后的内容列表获取。也可以通过点击内容列表左上方标题旁边的「meta」, 查看 contentGroupId 等信息,按需选用。
获取文章分类非常简单,我们可以调用刚才定义的 contentGroup 中的 getCategoryList
方法获取:
/**
* 获取分类列表
*/
const getCategoryList = async () => {
const res = await contentGroup.getCategoryList()
return res.data.objects
}
而获取文章列表(内容库列表)也是十分类似,调用 find
方法即可。另外,我们还可以传入一个分类 id,精准获取该分类下的所有文章:
/**
* 获取内容库列表
*/
const getContentGroupList = async categoryId => {
const query = new BaaS.Query()
query.arrayContains('categories', [categoryId])
const res = await contentGroup.setQuery(query).find()
return res.data.objects
}
接下来,我们开始构建一个根据分类定义的文章列表。我们通过 useState
定义一个 articles
的变量,然后在页面初次渲染完毕的时候,先获取分类列表,然后通过遍历获取分类 ID。之后根据 ID 获取分类下的文章即可:
const [articles, setArticles] = useState()
useEffect(() => {
const getArticleList = async () => {
const categoryList = await getCategoryList()
const articleList = {}
for (const category of categoryList) {
const { name, id } = category
const articles = await getContentGroupList(id)
articleList[name] = articles
}
setArticles(articleList)
}
getArticleList()
}, [])
别忘了在 html 结构也要相应地做修改,且把标题的 href 链接对应修改为文章的 id:
<section style={{ width: 1000, margin: '0 auto' }}>
<Grid.Container direction="column">
{Object.keys(articles).map(category => {
const articleList = articles[category]
return (
<Grid xs="24" direction="column" key={category}>
<Spacer h={5} />
<Text h4>{category}</Text>
{articleList.map(article => {
return (
<Link
href={`/article/${article.id}`}
underline
key={article.id}
>
<Text h2 font="42px">
{article.title}
</Text>
</Link>
)
})}
</Grid>
)
})}
</Grid.Container>
<Spacer h={5} />
</section>
至此,刷新一下页面,我们的首页就完成了。
四、省时省力,快速获取文章内容、结构和样式
相比首页文章列表,文章页获取内容会更简单,只需要传入一个 ID 即可。在上一节我们了解到,如何获取内容库 ID,并实例化一个内容库来获取相应的分类(getCategoryList)和文章列表(find)。
而文章内容,我们可以通过 getContent(id)
获取:
/**
* 获取文章内容
* @param {*} id
*/
const getArticle = async id => {
const res = await contentGroup.getContent(id)
return res.data
}
由于在构建首页文章链接的时候,我们已经传入对应的文章 ID,因此,在进入文章页的时候,我们可以通过 useParams
这个方法来获取:
const { id } = useParams()
有了 ID,我们接下来就可以获取相应的内容了:
const [article, setArticle] = useState()
useEffect(() => {
const getArticleContent = async () => {
const res = await getArticle(id)
setArticle(res)
}
getArticleContent()
}, [id])
在内容库使用富文本编辑的文章,知晓云已经贴心地帮我们处理好 html 的结构、样式和分行,无需特地为其操心。我们只需要把动态内容填入文章页即可,实在是省时省力。
<Layout>
<BlogHeader
title={article.title}
subTitle={article.description}
date={moment.unix(article.created_at).format('YYYY年M月D日')}
/>
<article style={{ width: 1000, margin: '0 auto' }}>
<Spacer h={5} />
<Grid.Container direction="column">
<Grid xs="24" direction="column">
{article?.content && (
<div dangerouslySetInnerHTML={{ __html: article?.content }}></div>
)}
<Spacer h={2} />
</Grid>
</Grid.Container>
<Spacer h={5} />
</article>
<Comment />
</Layout>
五、免接口开发,快速实现登录/注册功能
一个完善的个人博客,少不了评论功能。但每一条评论我们需要知道是哪个人创建的,因此我们要求每个人在评论前必须登录,这样做不但可以更好地跟对方互动,还可以有效减少垃圾评论的产生。
接下来我们来实现登录功能。在我们提供的文章页拉到最下方,点击登录,页面会弹窗让用户输入账号和密码,同时也有一个按钮切换到注册账户。
而实现登录注册的交互也十分简单。知晓云提供了一个非常方便易用的登录方法 BaaS.auth.login
,我们只需要传入账户密码即可。
BaaS.auth.login({username: 'ifanrx', password: 'ifanrx123'}).then(user => {
console.log(user)
})
注册也是通过简单的 BaaS.auth.register
方法调用即可。由于登录和注册我们是共用一个弹窗,在弹窗提交的方法里我们简单地将注册和登录方法通过判断来调用:
/**
* 登录/注册弹窗提交
*/
const onAccountSubmit = async () => {
if (!username) {
setToast({ text: '请输入用户名', type: 'error' })
return
}
if (!password) {
setToast({ text: '请输入密码', type: 'error' })
return
}
const request = isRegister ? BaaS.auth.register : BaaS.auth.login
try {
const user = await request({ username, password })
console.log('登录用户 - ', user)
setCurrentUser(user)
closeModal()
} catch (error) {
console.log('登录/注册错误', error.toString())
setToast({ text: error.toString(), type: 'error' })
}
}
六、实现高实时性、高互动性的评论功能
接下来我们本文最后一个功能:评论。评论功能主要用到数据表,涉及到简单的表设计、数据存储和权限控制等。
我们先设想一下数据表的结构。评论涉及到的字段主要包含以下几个:
- 用户(用户名)
- 评论
- 文章 id(对应某篇文章)
- 创建日期
根据以上的构思,我们可以大概列出如下信息:
得到以上信息,我们开始准备工作。现在控制台新建一张名为 comment
的数据表:
数据表的权限需要限制登录用户才可以录入,但所有人可读。
之后我们往 comment 表添加两个字段,分别是 comment
和 article
。由于知晓云已经贴心地默认帮我们加上了 created_by 和 created_at 字段,这里便可略过。
接着我们在代码里调用知晓云提供的方法新增一条评论。注意这个 id 是文章 id,需要在文章页传入:
/**
* 提交评论
*/
const onCommentSubmit = async () => {
if (!comment) {
setToast({ text: '请输入评论', type: 'error' })
return
}
const commentRecord = CommentTable.create()
try {
await commentRecord.set({ comment, article: id }).save()
getCommentList(id) // 新增后,我们需要刷新一下评论列表
setComment('')
} catch (error) {
console.log('创建评论失败', error.toString())
setToast({ text: '创建评论失败', type: 'error' })
return
}
}
注意在新增后,我们需要刷新一下评论列表。
由于 created_by 是系统默认字段,而且可以展开,我们可以通过 expand(‘created_by’)
来展开用户的账户信息。
同时我们也可以通过 query 查询,指定只显示该文章下的评论。
最后,我们可以通过 orderBy([‘-created_at’])
按创建时间将最新的评论显示在最前面:
/**
* 获取评论列表
*/
const getCommentList = async id => {
const query = new BaaS.Query()
query.compare('article', '=', id)
const res = await CommentTable.expand('created_by')
.orderBy(['-created_at'])
.setQuery(query)
.find()
setCommentList(res.data.objects)
}
最后别忘记修改一下页面结构,改为动态显示:
<Grid.Container direction="column">
{commentList.map(comment => {
return (
<Grid xs={24} direction="column" key={comment.id}>
<Card width="100%">
<div
style={{
display: 'flex',
alignItems: 'center',
marginTop: -20,
}}
>
<Text p b font="20px">
{comment.created_by._username}
</Text>
<Spacer w={1} />
<Text p style={{ color: 'gray' }}>
{moment
.unix(comment.created_at)
.format('YYYY年M月D日 HH:mm:ss')}
</Text>
</div>
<Text p style={{ marginTop: -5 }}>
{comment.comment}
</Text>
</Card>
<Spacer h={1} />
</Grid>
)
})}
</Grid.Container>
至此,本文涉及的所有博客功能均已完成。
总结
本文使用知晓云实现了个人博客数据列表、登录和评论功能的构建。使用知晓云能大大提高开发效率,更多功能等你来发掘。
本项目完整代码可到我们的 GitHub 仓库获取:https://github.com/ifanrx/minapp-blog-example