V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
ifanrcloud
V2EX  ›  前端开发

实战教程|使用知晓云快速制作一个简单的个人博客

  •  
  •   ifanrcloud ·
    ifanrx · 2021-09-10 10:23:59 +08:00 · 1030 次点击
    这是一个创建于 1205 天前的主题,其中的信息可能已经有所发展或是发生改变。

    本文将介绍如何通过知晓云的内容库以及数据表,快速制作一个包含评论功能的个人博客。

    适用人群:

    • 🙋刚接触编程的大学生(中小学生有多余精力也可,知晓云用户最小年龄 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 表添加两个字段,分别是 commentarticle。由于知晓云已经贴心地默认帮我们加上了 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

    3 条回复    2021-09-10 15:26:13 +08:00
    shpkng
        1
    shpkng  
       2021-09-10 10:40:10 +08:00
    功能看着还不错, 但是还是建议发推广区
    dilu
        2
    dilu  
       2021-09-10 10:55:41 +08:00
    长文直接拉倒最后,果然有个二维码
    ifanrcloud
        3
    ifanrcloud  
    OP
       2021-09-10 15:26:13 +08:00
    @shpkng 好的,感谢建议
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2650 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 15:17 · PVG 23:17 · LAX 07:17 · JFK 10:17
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.