百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 博客教程 > 正文

做个开源博客学习Vite2 + Vue3 (四)实现博客功能

connygpt 2024-09-12 13:52 8 浏览

我们再来看一下管理类的设计。

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'

// 连接数据库 
const help = new webSQLHelp('vite2-blog', 1.0, '测试用的博客数据库')

// =====================数据库==============================
/**
 * 建立 vite2-blog 数据库,blog表、discuss表
 * @returns 建立数据库和表
 */
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, // 点赞数量
        discussCount: 0 // 讨论数量
      })

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

  /**
   * 修改博文
   * @param { object } blog 博文 的 model
   * @return {*} promise,修改状态
   */
  const updateBlog = (blog) => {
    return new Promise((resolve, reject) => {
      help.update('blog', blog, blog.ID).then((state) => {
         resolve(state)
      })
    })
  }

  /**
   * 根据博文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({})
        }
      })
    })
  }

  /**
   * 依据分组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)
        })
    })
  }

  // 状态管理
  const { getBlogState } = blogStateManage()
  const blogState = getBlogState()

  /**
   * 依据状态,分页查询博文
   * @returns 博文列表
   */
  const getBlogList = () => {
    // 根据状态设置查询条件和分页条件
    const _query = blogState.findQuery || {}
    _query.state = [401, 2] // 显示发布的博文,设置固定查询条件
 
    return new Promise((resolve, reject) => {
      help.select('blog', blogList(), _query, blogState.page).then((data) => {
        resolve(data)
      })
    })
  }

  const getBlogCount = () => {
    // 根据状态设置查询条件和分页条件
    const _query = blogState.findQuery || {}
    _query.state = [401, 2] // 显示发布的博文,设置固定查询条件
  
    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 // 点赞数量
      })

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

  /**
   * 依据博文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, // 依据博文ID获取讨论列表。
    addNewBlog, // 添加 新博文
    updateBlog, // 修改博文
    getArtcileById, // 根据博文ID获取博文
    getBlogListByGroupId, // 获取博文列表
    getBlogList, // 获取博文列表
    getBlogCount // 统计数量
  }
}

其实应该分成两个类,一个是博文的管理类,一个是讨论的管理类,以后还可以有分组的管理类。
现在因为讨论相关的只有两个函数,所以就没有分开。

把需要的功能集中起来,便于管理和复用,减少组件里面的代码,也便于代码的升级更换。
比如现在是把数据保存在前端的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/', // 修改发布网站的目录
  build: {
    outDir: 'blog' // 修改打包的默认文件夹
  }
})
  • base,设置发布网站的目录。
    发布的时候默认项目会部署在网站根目录,如果不是根目录的话,可以使用 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 的参数要去掉之外,没啥变化。
路由设置也很简单,只有首页、编写博文、博文详细、分组显示博文这四项。

网页入口

/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)

// 建立数据库
import { databaseInit, deleteBlogTable } from './model/blogManage'
// deleteBlogTable()
databaseInit()

// 注入状态
import { blogState } from './model/blogState'
const state = reactive(blogState)

createApp(App)
  .provide('blogState', state) // 注入状态
  .use(router) // 路由
  .use(ElementPlus, { locale, size: 'small' }) // UI库
  .use(VueMarkdownEditor) // markDown编辑器
  .use(VMdPreview) // markDown 显示
  .mount('#app')

这里的代码稍微有点长,除了常规操作外,还使用了 MarkdownEditor 用于编辑博文,这个部分代码有点多。

然后又加入了设计webSQL数据库的代码,以及自己用 provide 实现的简易的状态管理。

首页、博文列表

模板部分:

<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> {{item.viewCount}}  
        <i class="el-icon-circle-check"></i> {{item.agreeCount}}  
        <i class="el-icon-chat-dot-square"></i> {{item.discussCount}} 
      </el-card>
      <!--没有找到数据-->
      <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 实现分页功能。

代码部分:

<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()
// 状态管理
const { getBlogState } = blogStateManage()
// 博文的状态
const blogState = getBlogState()
// 博文列表
const blogList = reactive([])

【后面就不写这些引入的代码了】

/**
 * 按照首页、分组、查询显示博文列表。
 * 显示第一页,并且统计总记录数
 */
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
  }
  // 统计符合条件的总记录数
  getBlogCount().then((count) => {
    blogState.page.pageTotal = count
  })
  // 获取第一页的数据
  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
  }
})

// 监控选择的分组的ID
watch(() => blogState.currentGroupId, () => {
  showBlog()
})

// 监听页号的变化,按照页号显示博文列表
watch(() => blogState.page.pageIndex, () => {
  getBlogList().then((data) => {
    blogList.length = 0
    blogList.push(...data)
  })
})

// 默认执行一遍
showBlog()

代码有点长,这说明了啥呢?还有优化的空间。

  • script setup
    vite2 建立的项目,默认推荐的是这种方式,其实 vite2 也是支持 export default { setup (props, ctx) { }} 这种写法的。
    当然 vue-cli 建立的项目也是支持 script setup 这种方式。所以用哪一种可以看个人喜好。

script setup 更简洁,省去了好多“麻烦”,比如组件引入部分,import 就好,不需要再次注册了。
const 后也不用 return 了,模板可以直接读取到。

  • 各种js类
    基于这种“散养”方式,所以必须写各种单独的js文件来实现基础功能,然后在 setup 里面整合,否则 setup 就没法看了。
  • watch等
    watch、ref、reactive这些的用法没有改变。

看一下效果:

后端出身,不会css,也没有艺术细胞所以比较难看,还望谅解

表单 发布博文

这里借鉴一下“简书”的编辑方式,个人感觉还是很方便的,左面是分组目录,中间的选择的分组的博文列表,右面是编辑博文的区域。

<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"> 发布文章 </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())

// 监控编辑文章的ID
watch(() => blogState.editArticleId, (v1, v2) => {
  getArtcileById(v1).then((data) => {
    Object.assign(blogModel, data)
  })
})

// 发布文章
const submit = () => {
  blogModel.ID = blogState.editArticleId
  blogModel.state = 2 // 改为发布状态
  updateBlog(blogModel).then((id) => {
    // 通知列表
  })
}
  • watch(() => blogState.editArticleId
    监听要编辑的博文ID,然后加载博文数据绑定表单,编辑之后用 submit 发布博文。

这里还需要一个自动保存草稿的功能,以后再完善。

  • submit
    发布博文,其实这里是修改博文,因为添加的工作是在 blogArticle 组件里面实现的。
  • updateBlog
    调用管理类里面的方式实现发布博文的功能。

各个平台的发文方式也体验了一下,还是喜欢这种方式,所以个人博客也采用这种方式来实现编辑博文的功能。

看一下效果:

目录导航:

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)
})

这个代码就很简单了,因为只实现了基本的发讨论和显示讨论的功能,其他暂略。

看看效果:

好吧,这个讨论做得蛮敷衍的,其实有好多想法,只是篇幅有限,以后再介绍。

组件级别的代码

虽然在vue里面,除了js文件,就是vue文件了,但是我觉得还是应该细分一下。
比如上面都是是页面级的代码,下面这些是“组件”级别的代码了。

博文分组

多次提到的博文分组。

<template>
  <!--分组,分为显示状态和编辑状态-->
  <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 来实现,后期会改成 NavMenu 来实现。

【引入的代码略】
// 组件的属性
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 }})
  }
}

分组数据暂时写死了,没有做成可以维护的方式,以后再完善。

博文列表,编辑用

<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()
// 状态管理
const { getBlogState, setEditArticleId } = blogStateManage()
// 博文的状态
const blogState = getBlogState()

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

// 监控选择的分组的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> {{item.agreeCount}}  
  </el-card>
  <!--没有找到数据-->
  <el-empty description="没有讨论呢,抢个沙发呗。" v-if="discussList.length === 0"></el-empty>
  

还是用 el-card 做个列表,el-empty 做一个没有讨论的提示。

【引入的代码略】
// 组件的属性
const props = defineProps({
  id: String
})

// 管理
const { getDiscussListByBlogId } = blogManage()
// 获取状态
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)
  })
})

因为功能比较简单,所以代码也很简单,获取讨论数据绑定显示即可,暂时没有实现分页功能。

讨论表单

  <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">发表讨论</el-button>
    <el-button>取消</el-button>
  </el-form-item>
</el-form>

用 el-form 做个表单。

【引入的代码略】
// 组件的属性
const props = defineProps({
  id: String
})

// 管理
const { addDiuss } = blogManage()
// 获取状态
const { getBlogState, setReloadDiussList } = blogStateManage()
const blogState = getBlogState()

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

// 发布讨论
const submit = () => {
  dicussModel.blogId = props.id // 这是博文ID
  addDiuss(dicussModel).then((id) => { // 可以想象成 axios 的提交
      // 通知列表
    setReloadDiussList()
  })
}

分成多个组件,每个组件的代码就可以非常少了,这样便于维护。
发布讨论的函数,先使用blogManage的功能提交数据,回调函数里面,使用的状态管理的功能提醒讨论列表刷新数据。

源码

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

在线演示

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

相关推荐

自学Python,写一个挨打的游戏代码来初识While循环

自学Python的第11天。旋转~跳跃~,我~闭着眼!学完循环,沐浴着while的光芒,闲来无事和同事一起扯皮,我说:“编程语言好神奇,一个小小的循环,竟然在生活中也可以找到原理和例子”,同事也...

常用的 Python 工具与资源,你知道几个?

最近几年你会发现,越来越多的人开始学习Python,工欲善其事必先利其器,今天纬软小编就跟大家分享一些常用的Python工具与资源,记得收藏哦!不然下次就找不到我了。1、PycharmPychar...

一张思维导图概括Python的基本语法, 一周的学习成果都在里面了

一周总结不知不觉已经自学Python一周的时间了,这一周,从认识Python到安装Python,再到基本语法和基本数据类型,对于小白的我来说无比艰辛的,充满坎坷。最主要的是每天学习时间有限。只...

三日速成python?打工人,小心钱包,别当韭菜

随着人工智能的热度越来越高,许多非计算机专业的同学们也都纷纷投入到学习编程的道路上来。而Python,作为一种相对比较容易上手的语言,也越来越受欢迎。网络上各类网课层出不穷,各式广告令人眼花缭乱。某些...

Python自动化软件测试怎么学?路线和方法都在这里了

Python自动化测试是指使用Python编程语言和相关工具,对软件系统进行自动化测试的过程。学习Python自动化测试需要掌握以下技术:Python编程语言:学习Python自动化测试需要先掌握Py...

Python从放弃到入门:公众号历史文章爬取为例谈快速学习技能

这篇文章不谈江流所专研的营销与运营,而聊一聊技能学习之路,聊一聊Python这门最简单的编程语言该如何学习,我完成的第一个Python项目,将任意公众号的所有历史文章导出成PDF电子书。或许我这个Py...

【黑客必会】python学习计划

阅读Python文档从Python官方网站上下载并阅读Python最新版本的文档(中文版),这是学习Python的最好方式。对于每个新概念和想法,请尝试运行一些代码片段,并检查生成的输出。这将帮助您更...

公布了!2025CDA考试安排

CDA数据分析师报考流程数据分析师是指在不同行业中专门从事行业数据搜集、整理、分析依据数据作出行业研究评估的专业人员CDA证书分为1-3级,中英文双证就业面广,含金量高!!?报考条件:满18...

一文搞懂全排列、组合、子集问题(经典回溯递归)

原创公众号:【bigsai】头条号:程序员bigsai前言Hello,大家好,我是bigsai,longtimenosee!在刷题和面试过程中,我们经常遇到一些排列组合类的问题,而全排列、组合...

「西法带你学算法」一次搞定前缀和

我花了几天时间,从力扣中精选了五道相同思想的题目,来帮助大家解套,如果觉得文章对你有用,记得点赞分享,让我看到你的认可,有动力继续做下去。467.环绕字符串中唯一的子字符串[1](中等)795.区...

平均数的5种方法,你用过几种方法?

平均数,看似很简单的东西,其实里面包含着很多学问。今天,分享5种经常会用到的平均数方法。1.算术平均法用到最多的莫过于算术平均法,考试平均分、平均工资等等,都是用到这个。=AVERAGE(B2:B11...

【干货收藏】如何最简单、通俗地理解决策树分类算法?

决策树(Decisiontree)是基于已知各种情况(特征取值)的基础上,通过构建树型决策结构来进行分析的一种方式,是常用的有监督的分类算法。决策树算法是机器学习中的一种经典算法,它通过一系列的规则...

面试必备:回溯算法详解

我们刷leetcode的时候,经常会遇到回溯算法类型题目。回溯算法是五大基本算法之一,一般大厂也喜欢问。今天跟大家一起来学习回溯算法的套路,文章如果有不正确的地方,欢迎大家指出哈,感谢感谢~什么是回溯...

「机器学习」决策树——ID3、C4.5、CART(非常详细)

决策树是一个非常常见并且优秀的机器学习算法,它易于理解、可解释性强,其可作为分类算法,也可用于回归模型。本文将分三篇介绍决策树,第一篇介绍基本树(包括ID3、C4.5、CART),第二篇介绍Ran...

大话AI算法: 决策树

所谓的决策树算法,通俗的说就是建立一个树形的结构,通过这个结构去一层一层的筛选判断问题是否好坏的算法。比如判断一个西瓜是否好瓜,有20条西瓜的样本提供给你,让你根据这20条(通过机器学习)建立起...