做個開源博客學習Vite2 + Vue3 (四)實現(xiàn)博客功能

我們再來看一下管理類的設計崔泵。

Composition API,就是組合API的意思址晕,那么是不是應該把js代碼分離出來,做成獨立的管理類的形式呢顿锰?

這樣代碼可以更整潔一些谨垃,主要是setup里面的代碼就不會亂掉了。

管理類

import webSQLHelp from '../store/websql-help'
import { blog, blogForm, blogList, articleList, discuss, discussList } from './blogModel'
import blogStateManage from '../model/blogState'

// 連接數(shù)據(jù)庫 
const help = new webSQLHelp('vite2-blog', 1.0, '測試用的博客數(shù)據(jù)庫')

// =====================數(shù)據(jù)庫==============================
/**
 * 建立 vite2-blog 數(shù)據(jù)庫硼控,blog表刘陶、discuss表
 * @returns 建立數(shù)據(jù)庫和表
 */
export const databaseInit = () => {
  help.createTable('blog', blog())
  help.createTable('discuss', discuss())
}

/**
 * 刪除:blog表、discuss表
 * @returns 刪除表
 */
export const deleteBlogTable = () => {
  help.deleteTable('blog')
  help.deleteTable('discuss')
}
 
/**
 * 博客的管理類
 * @returns 添加牢撼、修改匙隔、獲得列表等
 */
export const blogManage = () => {
  // =====================博文==============================
  /**
   * 添加新的博文
   * @param { object } blog 博文 的 model
   * @return {*} promise,新博文的ID
   */
  const addNewBlog = (blog) => {
    return new Promise((resolve, reject) => {
      const newBlog = {}
      Object.assign(newBlog, blog, {
        addTime: new Date(), // 添加時間
        viewCount: 0, // 瀏覽量
        agreeCount: 0, // 點贊數(shù)量
        discussCount: 0 // 討論數(shù)量
      })

      help.insert('blog', newBlog).then((id) => {
        resolve(id)
      })
    })
  }

  /**
   * 修改博文
   * @param { object } blog 博文 的 model
   * @return {*} promise熏版,修改狀態(tài)
   */
  const updateBlog = (blog) => {
    return new Promise((resolve, reject) => {
      help.update('blog', blog, blog.ID).then((state) => {
         resolve(state)
      })
    })
  }

  /**
   * 根據(jù)博文ID獲取博文纷责,編輯博文、顯示博文用
   * @param { number } id 博文ID
   * @returns 
   */
  const getArtcileById = (id) => {
    return new Promise((resolve, reject) => {
      help.getDataById('blog', id).then((data) => {
        if (data.length > 0) {
          resolve(data[0])
        } else {
          console.log('沒有找到記錄', data)
          resolve({})
        }
      })
    })
  }

  /**
   * 依據(jù)分組ID獲取博文列表撼短,編輯博文列表用再膳。
   * @param {number} groupId 分組ID
   * @returns 
   */
  const getBlogListByGroupId = (groupId) => {
    return new Promise((resolve, reject) => {
      help.select('blog', articleList(), {groupId: [401, groupId]})
        .then((data) => {
          resolve(data)
        })
    })
  }

  // 狀態(tài)管理
  const { getBlogState } = blogStateManage()
  const blogState = getBlogState()

  /**
   * 依據(jù)狀態(tài),分頁查詢博文
   * @returns 博文列表
   */
  const getBlogList = () => {
    // 根據(jù)狀態(tài)設置查詢條件和分頁條件
    const _query = blogState.findQuery || {}
    _query.state = [401, 2] // 顯示發(fā)布的博文曲横,設置固定查詢條件
 
    return new Promise((resolve, reject) => {
      help.select('blog', blogList(), _query, blogState.page).then((data) => {
        resolve(data)
      })
    })
  }

  const getBlogCount = () => {
    // 根據(jù)狀態(tài)設置查詢條件和分頁條件
    const _query = blogState.findQuery || {}
    _query.state = [401, 2] // 顯示發(fā)布的博文喂柒,設置固定查詢條件
  
    return new Promise((resolve, reject) => {
      help.getCountByWhere('blog', _query).then((count) => {
        resolve(count)
      })
    })
  }

  // =====================討論==============================
  /**
   * 添加一個新討論
   * @param {object}} discuss 討論的model
   * @returns 
   */
  const addDiuss = (discuss) => {
    return new Promise((resolve, reject) => {
      const newDiscuss = {}
      Object.assign(newDiscuss, discuss, {
        addTime: new Date(), // 添加時間
        agreeCount: 0 // 點贊數(shù)量
      })

      help.insert('discuss', newDiscuss).then((id) => {
        resolve(id)
      })
    })
  }

  /**
   * 依據(jù)博文ID獲取討論列表。
   * @param {number} blogId 分組ID
   * @returns 
   */
   const getDiscussListByBlogId = (blogId) => {
    return new Promise((resolve, reject) => {
      help.select('discuss', discussList(), {blogId: [401, blogId]})
        .then((data) => {
          resolve(data)
        })
    })
  }
  
  return {
    addDiuss, // 添加新討論
    getDiscussListByBlogId, // 依據(jù)博文ID獲取討論列表禾嫉。
    addNewBlog, // 添加 新博文
    updateBlog, // 修改博文
    getArtcileById, // 根據(jù)博文ID獲取博文
    getBlogListByGroupId, // 獲取博文列表
    getBlogList, // 獲取博文列表
    getBlogCount // 統(tǒng)計數(shù)量
  }
}

其實應該分成兩個類灾杰,一個是博文的管理類,一個是討論的管理類夭织,以后還可以有分組的管理類吭露。
現(xiàn)在因為討論相關的只有兩個函數(shù),所以就沒有分開尊惰。

把需要的功能集中起來讲竿,便于管理和復用,減少組件里面的代碼弄屡,也便于代碼的升級更換题禀。
比如現(xiàn)在是把數(shù)據(jù)保存在前端的webSQL里面,那么以后要提交到后端怎么辦膀捷?
只需要在這里改代碼即可迈嘹,不需要修改xxx.vue里面的代碼。
把變化限制在最小的范圍內

編碼

設計好了之后可以動手編碼了秀仲,先看一下文件結構:

文件結構

文件結構

個人感覺還是比較清晰的融痛。

config設置

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  base: '/vue3-blog/', // 修改發(fā)布網站的目錄
  build: {
    outDir: 'blog' // 修改打包的默認文件夾
  }
})
  • base,設置發(fā)布網站的目錄神僵。
    發(fā)布的時候默認項目會部署在網站根目錄雁刷,如果不是根目錄的話,可以使用 base 來更改保礼。

  • build.outDir
    修改默認(dist)的構建輸出路徑沛励。

其他設置方式可以看這里:https://cn.vitejs.dev/config/,內容非常多炮障。

路由設置

src/router/index.js

import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/home.vue'

const routes = [
  {
    path: '/',
    name: 'home',
    component: Home
  },
  {
    path: '/write',
    name: 'write',
    component: () => import('../views/write.vue')
  },
  {
    path: '/blogs/:id',
    name: 'blogs',
    props: true,
    component: () => import('../views/blog.vue')
  },
  {
    path: '/groups/:groupId',
    name: 'groups',
    props: true,
    component: Home
  }
]

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

除了 createWebHistory 的參數(shù)要去掉之外目派,沒啥變化。
路由設置也很簡單胁赢,只有首頁企蹭、編寫博文、博文詳細徘键、分組顯示博文這四項练对。

網頁入口

/index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>vite2 + vue3 做的簡單的個人博客</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.js"></script>
  </body>
</html>

非常簡潔遍蟋,我們可以設置一個標題吹害,用 type="module" 的方式加載入口js文件。其他的可以按照需要自行設置虚青。

代碼入口

/src/main.js

import { createApp, provide, reactive } from 'vue'
import App from './App.vue'
import router from './router' // 路由

// UI庫
import ElementPlus from 'element-plus'
import 'element-plus/lib/theme-chalk/index.css'
import 'dayjs/locale/zh-cn'
import locale from 'element-plus/lib/locale/lang/zh-cn'

// Markdown 編輯插件
import VueMarkdownEditor from '@kangc/v-md-editor'
import '@kangc/v-md-editor/lib/style/base-editor.css'
import vuepressTheme from '@kangc/v-md-editor/lib/theme/vuepress.js'
import '@kangc/v-md-editor/lib/theme/style/vuepress.css'
VueMarkdownEditor.use(vuepressTheme)

// markdown 顯示插件
import VMdPreview from '@kangc/v-md-editor/lib/preview'
import '@kangc/v-md-editor/lib/style/preview.css'
// 引入你所使用的主題 此處以 github 主題為例
// import githubTheme from '@kangc/v-md-editor/lib/theme/github'
VMdPreview.use(vuepressTheme)

// 建立數(shù)據(jù)庫
import { databaseInit, deleteBlogTable } from './model/blogManage'
// deleteBlogTable()
databaseInit()

// 注入狀態(tài)
import { blogState } from './model/blogState'
const state = reactive(blogState)

createApp(App)
  .provide('blogState', state) // 注入狀態(tài)
  .use(router) // 路由
  .use(ElementPlus, { locale, size: 'small' }) // UI庫
  .use(VueMarkdownEditor) // markDown編輯器
  .use(VMdPreview) // markDown 顯示
  .mount('#app')

這里的代碼稍微有點長它呀,除了常規(guī)操作外,還使用了 MarkdownEditor 用于編輯博文棒厘,這個部分代碼有點多纵穿。

然后又加入了設計webSQL數(shù)據(jù)庫的代碼,以及自己用 provide 實現(xiàn)的簡易的狀態(tài)管理奢人。

首頁谓媒、博文列表

模板部分:

<template>
  <!--博文列表-->
  <el-row :gutter="12">
    <el-col :span="5">
      <!--分組-->
      <blogGroup :isDetail="true"/>
    </el-col>
    <el-col :span="18">
      <el-card shadow="hover"
        v-for="(item, index) in blogList"
        :key="'bloglist_' + index"
      >
        <template #header>
          <div class="card-header">
            <router-link :to="{name:'blogs', params:{id:item.ID}}">
              {{item.title}}
            </router-link>
            <span class="button">({{dateFormat(item.addTime).format('YYYY-MM-DD')}})</span>
          </div>
        </template>
        <!--簡介-->
        <div class="text item" v-html="item.introduction"></div>
        <hr>
        <i class="el-icon-view"></i>&nbsp;{{item.viewCount}}&nbsp;&nbsp;
        <i class="el-icon-circle-check"></i>&nbsp;{{item.agreeCount}}&nbsp;&nbsp;
        <i class="el-icon-chat-dot-square"></i>&nbsp;{{item.discussCount}}&nbsp;
      </el-card>
      <!--沒有找到數(shù)據(jù)-->
      <el-empty description="沒有找到博文呢。" v-if="blogList.length === 0"></el-empty>
      <el-pagination
        background
        layout="prev, pager, next"
        v-model:currentPage="blogState.page.pageIndex"
        :page-size="blogState.page.pageSize"
        :total="blogState.page.pageTotal">
      </el-pagination>
    </el-col>
  </el-row>
</template>

模板部分沒啥變化何乎,還是老樣子句惯,使用 el-row 做了一個簡單的布局:

  • 左面,blogGroup 顯示分組的組件支救。
  • 右面抢野,用 el-card 做了一個列表,用于顯示博文各墨。
  • 下面指孤,用 el-pagination 實現(xiàn)分頁功能。

代碼部分:

<script setup>
import { watch, reactive } from 'vue'
import { useRoute } from 'vue-router'
import blogGroup from '../components/blog-group.vue'
import blogStateManage from '../model/blogState'
import { blogManage } from '../model/blogManage'

// 日期格式化
const dateFormat = dayjs

// 博文管理
const { getBlogList, getBlogCount } = blogManage()
// 狀態(tài)管理
const { getBlogState } = blogStateManage()
// 博文的狀態(tài)
const blogState = getBlogState()
// 博文列表
const blogList = reactive([])

【后面就不寫這些引入的代碼了】

/**
 * 按照首頁、分組恃轩、查詢顯示博文列表结洼。
 * 顯示第一頁,并且統(tǒng)計總記錄數(shù)
 */
const showBlog = () => {
  // 分組ID
  let groupId = blogState.currentGroupId
  if (groupId === 0) {
    // 首頁叉跛,清空查詢條件补君,顯示第一頁
    blogState.findQuery = {} 
    blogState.page.pageIndex = 1
  } else {
    // 分組的博文列表,設置分組條件昧互,顯示第一頁
    blogState.findQuery = {
      groupId: [401, groupId]
    }
    blogState.page.pageIndex = 1
  }
  // 統(tǒng)計符合條件的總記錄數(shù)
  getBlogCount().then((count) => {
    blogState.page.pageTotal = count
  })
  // 獲取第一頁的數(shù)據(jù)
  getBlogList().then((data) => {
    blogList.length = 0
    blogList.push(...data)
  })
}

const route = useRoute()
// 如果是首頁挽铁,把 當前分組ID設置為 0 ,以便于顯示所有分組的博文敞掘。
watch(() => route.fullPath, () => {
  if (route.fullPath === '/' || route.fullPath === '/blog') {
    blogState.currentGroupId = 0
  }
})

// 監(jiān)控選擇的分組的ID
watch(() => blogState.currentGroupId, () => {
  showBlog()
})

// 監(jiān)聽頁號的變化叽掘,按照頁號顯示博文列表
watch(() => blogState.page.pageIndex, () => {
  getBlogList().then((data) => {
    blogList.length = 0
    blogList.push(...data)
  })
})

// 默認執(zhí)行一遍
showBlog()

</script>

代碼有點長,這說明了啥呢玖雁?還有優(yōu)化的空間更扁。

  • script setup
    vite2 建立的項目,默認推薦的是這種方式赫冬,其實 vite2 也是支持 export default { setup (props, ctx) { }} 這種寫法的浓镜。
    當然 vue-cli 建立的項目也是支持 script setup 這種方式。所以用哪一種可以看個人喜好劲厌。

script setup 更簡潔膛薛,省去了好多“麻煩”,比如組件引入部分补鼻,import 就好哄啄,不需要再次注冊了。
const 后也不用 return 了风范,模板可以直接讀取到咨跌。

  • 各種js類
    基于這種“散養(yǎng)”方式,所以必須寫各種單獨的js文件來實現(xiàn)基礎功能硼婿,然后在 setup 里面整合锌半,否則 setup 就沒法看了。

  • watch等
    watch寇漫、ref刊殉、reactive這些的用法沒有改變。

看一下效果:

博客首頁

后端出身猪腕,不會css冗澈,也沒有藝術細胞所以比較難看,還望諒解

表單 發(fā)布博文

這里借鑒一下“簡書”的編輯方式陋葡,個人感覺還是很方便的亚亲,左面是分組目錄,中間的選擇的分組的博文列表,右面是編輯博文的區(qū)域捌归。

<template>
   <el-row :gutter="12">
    <el-col :span="4">
      <!--分組-->
      <blogGroup/>
    </el-col>
    <el-col :span="5">
      <!--標題列表-->
      <blogArticle/>
    </el-col>
    <el-col :span="14">
      <!--寫博文-->
      <el-input
        style="width:90%"
        :show-word-limit="true"
        maxlength="100"
        placeholder="請輸入博文標題肛响,最多100字"
        v-model="blogModel.title"
      />
      <el-button type="primary" plain @click="submit"> 發(fā)布文章 </el-button>
      {{dateFormat(blogModel.addTime).format('YYYY-MM-DD HH:mm:ss')}}
      <v-md-editor
        :include-level="[1, 2, 3, 4]"
        v-model="blogModel.concent" :height="editHeight+'px'"></v-md-editor>1
    </el-col>
  </el-row>
</template>
  • blogGroup
    博文分組的組件,顯示分組列表惜索,便于我們選擇分組特笋。

  • blogArticle
    博文列表,選擇分組后巾兆,顯示分組里面的博文列表猎物。在這里可以添加博文,點擊博文標題角塑,可以在右面加載博文的表單顿痪,進行博文編輯胳嘲。

用過簡書的編輯方式之后茎刚,感覺這個還是非常方便的毙芜。

代碼部分:

【引入的代碼略】
// 組件
import blogGroup from '../components/blog-group.vue'
import blogArticle from '../components/blog-article.vue'

// 可見的高度
const editHeight = document.documentElement.clientHeight - 200
// 管理
const { updateBlog, getArtcileById } = blogManage()

// 表單的model
const blogModel = reactive(blogForm())

// 監(jiān)控編輯文章的ID
watch(() => blogState.editArticleId, (v1, v2) => {
  getArtcileById(v1).then((data) => {
    Object.assign(blogModel, data)
  })
})

// 發(fā)布文章
const submit = () => {
  blogModel.ID = blogState.editArticleId
  blogModel.state = 2 // 改為發(fā)布狀態(tài)
  updateBlog(blogModel).then((id) => {
    // 通知列表
  })
}
  • watch(() => blogState.editArticleId
    監(jiān)聽要編輯的博文ID,然后加載博文數(shù)據(jù)綁定表單窒朋,編輯之后用 submit 發(fā)布博文搀罢。

這里還需要一個自動保存草稿的功能,以后再完善侥猩。

  • submit
    發(fā)布博文榔至,其實這里是修改博文,因為添加的工作是在 blogArticle 組件里面實現(xiàn)的拭宁。

  • updateBlog
    調用管理類里面的方式實現(xiàn)發(fā)布博文的功能洛退。

各個平臺的發(fā)文方式也體驗了一下瓣俯,還是喜歡這種方式杰标,所以個人博客也采用這種方式來實現(xiàn)編輯博文的功能。

看一下效果:

編輯博文

目錄導航:

博文的目錄導航

v-md-editor 提供的目錄導航功能彩匕,還是非常給力的腔剂,看著大綱編寫,思路清晰多了驼仪。

博文內容 + 討論

<template>
  <el-row :gutter="12">
    <el-col :span="5">
      <!--分組-->
      <blogGroup :isDetail="true"/>
    </el-col>
    <el-col :span="18">
      <!--顯示博文-->
      <h1>{{blogInfo.title}}</h1>
      ({{dateFormat(blogInfo.addTime).format('YYYY-MM-DD')}})
      <v-md-preview :text="blogInfo.concent"></v-md-preview>
      <hr>
      <!--討論列表-->
      <discussList :id="id"/>
      <!--討論表單-->
      <discussForm :id="id"/>
    </el-col>
  </el-row>
</template>
【引入的代碼略】
// 組件的屬性掸犬,博文ID
const props = defineProps({
  id: String
})

// 管理
const { getArtcileById } = blogManage()

// 表單的model
const blogInfo = reactive({})

getArtcileById(props.id).then((data) => {
  Object.assign(blogInfo, data)
})

這個代碼就很簡單了,因為只實現(xiàn)了基本的發(fā)討論和顯示討論的功能绪爸,其他暫略湾碎。

看看效果:

博文的討論

好吧,這個討論做的蠻敷衍的奠货,其實有好多想法介褥,只是篇幅有限,以后再介紹。

組件級別的代碼

雖然在vue里面柔滔,除了js文件溢陪,就是vue文件了,但是我覺得還是應該細分一下睛廊。
比如上面都是是頁面級的代碼形真,下面這些是“組件”級別的代碼了。

博文分組

多次提到的博文分組超全。

<template>
  <!--分組咆霜,分為顯示狀態(tài)和編輯狀態(tài)-->
  <el-card shadow="hover"
    v-for="(item, index) in blogGroupList"
    :key="'grouplist_' + index"
  >
    <template #header>
      <div class="card-header">
        <span>{{item.label}}</span>
        <span class="button"></span>
      </div>
    </template>
    <div
      class="text item"
      style="cursor:pointer"
      v-for="(item, index) in item.children"
      :key="'group_' + index"
      @click="changeGroup(item.value)"
    >
      {{item.label}}
    </div>
  </el-card>
</template>

暫時先用 el-card 來實現(xiàn),后期會改成 NavMenu 來實現(xiàn)嘶朱。

【引入的代碼略】
// 組件的屬性
const props = defineProps({
  isDetail: Boolean
})

/** 
* 博文的分組列表
*/
const blogGroupList = reactive([
  {
    value: '1000',
    label: '前端',
    children: [
      {  value: '1001', label: 'vue基礎知識',  },
      {  value: '1002', label: 'vue組件',     },
      {  value: '1003', label: 'vue路由',     }
    ]
  },
  {  value: '2000',  label: '后端',
     children: [
      { value: '2001', label: 'MySQL',     },
      { value: '2002', label: 'web服務',    }
    ]
  }
])

// 選擇分組
const { setCurrentGroupId } = blogStateManage()
 
const router = useRouter()
const changeGroup = (id) => {
  setCurrentGroupId(id)
  // 判斷是不是要跳轉
  // 首頁裕便、編輯頁不跳,博文詳細頁面調整 
  if (props.isDetail) {
    // 跳轉到列表頁
    router.push({ name: 'groups', params: { groupId: id }})
  }
}

分組數(shù)據(jù)暫時寫死了见咒,沒有做成可以維護的方式偿衰,以后再完善。

博文列表改览,編輯用

<template>
  <!--添加標題-->
  <el-card shadow="hover">
    <template #header>
      <div class="card-header">
        <el-button @click="addNewArticle" >添加新文章</el-button>
        <span class="button"></span>
      </div>
    </template>
    <div
      class="text item"
      style="cursor:pointer"
      v-for="(item, index) in blogList"
      :key="'article_' + index"
      @click="changeArticle(item.ID)"
    >
      {{item.ID}}:{{item.title}} ({{dateFormat(item.addTime).format('YYYY-MM-DD')}})
    </div>
    <el-empty description="該分類里面還沒有文章呢下翎。" v-if="blogList.length === 0"></el-empty>
  </el-card>
</template>

用 el-card 做個列表,上面是 添加博文的按鈕宝当,下面是博文列表视事,單擊可以進行修改。

【引入的代碼略】
// 博文列表
const blogList = reactive([])

// 博文管理
const { addNewBlog, getBlogListByGroupId } = blogManage()
// 狀態(tài)管理
const { getBlogState, setEditArticleId } = blogStateManage()
// 博文的狀態(tài)
const blogState = getBlogState()

// 更新列表
const load = () => {
  getBlogListByGroupId(blogState.currentGroupId).then((data) => {
    blogList.length = 0
    blogList.push(...data)
  })
}
load()

// 監(jiān)控選擇的分組的ID
watch(() => blogState.currentGroupId, () => {
  load()
})
 
// 添加新文章庆揩,僅標題俐东、時間
const addNewArticle = () => {
  const newArticle = blogForm()
  // 選擇的分組ID
  newArticle.groupId = blogState.currentGroupId
  // 用日期作為默認標題
  newArticle.title = dayjs(new Date()).format('YYYY-MM-DD')

  addNewBlog(newArticle).then((id) => {
    // 設置要編輯的文章ID
    setEditArticleId(id)
    // 通知列表
    newArticle.ID = id
    blogList.unshift(newArticle)
  })
}

// 選擇要編輯的文章
const changeArticle = (id) => {
  setEditArticleId(id)
}

討論列表

 <el-card shadow="hover"
    v-for="(item, index) in discussList"
    :key="'bloglist_' + index"
  >
    <template #header>
      <div class="card-header">
        {{item.discusser}}
        <span class="button">({{dateFormat(item.addTime).format('YYYY-MM-DD')}})</span>
      </div>
    </template>
    <!--簡介-->
    <div class="text item" v-html="item.concent"></div>
    <hr>
    <i class="el-icon-circle-check"></i>&nbsp;{{item.agreeCount}}&nbsp;&nbsp;
  </el-card>
  <!--沒有找到數(shù)據(jù)-->
  <el-empty description="沒有討論呢,搶個沙發(fā)唄订晌。" v-if="discussList.length === 0"></el-empty>
  

還是用 el-card 做個列表虏辫,el-empty 做一個沒有討論的提示。

【引入的代碼略】
// 組件的屬性
const props = defineProps({
  id: String
})

// 管理
const { getDiscussListByBlogId } = blogManage()
// 獲取狀態(tài)
const { getBlogState } = blogStateManage()
const blogState = getBlogState()

// 表單的model
const discussList = reactive([])
getDiscussListByBlogId(props.id).then((data) => {
  discussList.push(...data)
})

watch(() => blogState.isReloadDiussList, () => {
  getDiscussListByBlogId(props.id).then((data) => {
    discussList.length = 0
    discussList.push(...data)
  })
})

因為功能比較簡單锈拨,所以代碼也很簡單砌庄,獲取討論數(shù)據(jù)綁定顯示即可,暫時沒有實現(xiàn)分頁功能奕枢。

討論表單

  <el-form
    style="width:400px;"
    label-position="top"
    :model="dicussModel"
    label-width="80px"
  >
  <el-form-item label="昵稱">
    <el-input v-model="dicussModel.discusser"></el-input>
  </el-form-item>
  
  <el-form-item label="內容">
    <el-input type="textarea" v-model="dicussModel.concent"></el-input>
  </el-form-item>
  <el-form-item>
    <el-button type="primary" @click="submit">發(fā)表討論</el-button>
    <el-button>取消</el-button>
  </el-form-item>
</el-form>

用 el-form 做個表單娄昆。

【引入的代碼略】
// 組件的屬性
const props = defineProps({
  id: String
})

// 管理
const { addDiuss } = blogManage()
// 獲取狀態(tài)
const { getBlogState, setReloadDiussList } = blogStateManage()
const blogState = getBlogState()

// 表單的model
const dicussModel = reactive(discuss())

// 發(fā)布討論
const submit = () => {
  dicussModel.blogId = props.id // 這是博文ID
  addDiuss(dicussModel).then((id) => { // 可以想象成 axios 的提交
      // 通知列表
    setReloadDiussList()
  })
}

分成多個組件,每個組件的代碼就可以非常少了缝彬,這樣便于維護萌焰。
發(fā)布討論的函數(shù),先使用blogManage的功能提交數(shù)據(jù)谷浅,回調函數(shù)里面扒俯,使用的狀態(tài)管理的功能提醒討論列表刷新數(shù)據(jù)族购。

源碼

https://gitee.com/naturefw/vue3-blog

在線演示

https://naturefw.gitee.io/vue3-blog

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市陵珍,隨后出現(xiàn)的幾起案子寝杖,更是在濱河造成了極大的恐慌,老刑警劉巖互纯,帶你破解...
    沈念sama閱讀 222,681評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瑟幕,死亡現(xiàn)場離奇詭異,居然都是意外死亡留潦,警方通過查閱死者的電腦和手機只盹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來兔院,“玉大人殖卑,你說我怎么就攤上這事》宦埽” “怎么了孵稽?”我有些...
    開封第一講書人閱讀 169,421評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長十偶。 經常有香客問我菩鲜,道長,這世上最難降的妖魔是什么惦积? 我笑而不...
    開封第一講書人閱讀 60,114評論 1 300
  • 正文 為了忘掉前任接校,我火速辦了婚禮,結果婚禮上狮崩,老公的妹妹穿的比我還像新娘蛛勉。我一直安慰自己,他們只是感情好睦柴,可當我...
    茶點故事閱讀 69,116評論 6 398
  • 文/花漫 我一把揭開白布诽凌。 她就那樣靜靜地躺著,像睡著了一般爱只。 火紅的嫁衣襯著肌膚如雪皿淋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,713評論 1 312
  • 那天恬试,我揣著相機與錄音,去河邊找鬼疯暑。 笑死训柴,一個胖子當著我的面吹牛,可吹牛的內容都是我干的妇拯。 我是一名探鬼主播幻馁,決...
    沈念sama閱讀 41,170評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼洗鸵,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了仗嗦?” 一聲冷哼從身側響起膘滨,我...
    開封第一講書人閱讀 40,116評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎稀拐,沒想到半個月后火邓,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 46,651評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡德撬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,714評論 3 342
  • 正文 我和宋清朗相戀三年铲咨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蜓洪。...
    茶點故事閱讀 40,865評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡纤勒,死狀恐怖,靈堂內的尸體忽然破棺而出隆檀,到底是詐尸還是另有隱情摇天,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布恐仑,位于F島的核電站闸翅,受9級特大地震影響,放射性物質發(fā)生泄漏菊霜。R本人自食惡果不足惜坚冀,卻給世界環(huán)境...
    茶點故事閱讀 42,211評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鉴逞。 院中可真熱鬧记某,春花似錦、人聲如沸构捡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽勾徽。三九已至滑凉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間喘帚,已是汗流浹背畅姊。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留吹由,地道東北人若未。 一個月前我還...
    沈念sama閱讀 49,299評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像倾鲫,于是被迫代替她去往敵國和親粗合。 傳聞我的和親對象是個殘疾皇子萍嬉,可洞房花燭夜當晚...
    茶點故事閱讀 45,870評論 2 361

推薦閱讀更多精彩內容