AJAX——黑马头条-数据管理平台项目

1.项目介绍

功能:

  1. 登录和权限判断
  2. 查看文章内容列表(筛选,分页)
  3. 编辑文章(数据回显)
  4. 删除文章
  5. 发布文章(图片上传,富文本编辑器)

2.项目准备

技术:

  • 基于Bootstrap搭建网站标签和样式
  • 集成wangEditor插件实现富文本编辑器
  • 使用原生JS完成增删改查等业务
  • 基于axios与黑马头条线上接口交互
  • 使用axios拦截器进行权限判断
  • 准备配套的素材代码
  • 包含:html、css、js,静态图片,第三方插件等等

目录管理:建议这样管理,方便查找

  • assets:资源文件夹(图片,字体等)
  • lib:资料文件夹(第三方插件,例如:form-serialize)
  • page:页面文件夹
  • utils:实用程序文件夹(工具插件)

3.验证码登录

目标:完成验证码登录,后端设置验证码默认为246810

原因:因为短袖接口不是免费的,防止攻击者恶意盗刷

步骤:

  1. 在utils/request.js配置axios请求基地址
    1. 作用:提取公共前缀地址,配置后axios请求时都会 baseURL+ url
      // axios 公共配置
      // 基地址
      axios.defaults.baseURL = 'http://geek.itheima.net'
  2. 收集手机号和验证码数据
  3. 基于axios调用验证码登录接口
  4. 使用Bootstrap的Alert警告框反馈结果给用户

 index.js

/*** 目标1:验证码登录* 1.1 在 utils/request.js 配置 axios 请求基地址* 1.2 收集手机号和验证码数据* 1.3 基于 axios 调用验证码登录接口* 1.4 使用 Bootstrap 的 Alert 警告框反馈结果给用户*/// 1.2 收集手机号和验证码数据document.querySelector('.btn').addEventListener('click', () => {const form = document.querySelector('.login-form')const data = serialize(form, { hash: true, empty: true})console.log(data)// 1.3 基于 axios 调用验证码登录接口axios({url: '/v1_0/authorizations',method: 'POST',data: data}).then( result => {// 1.4 使用 Bootstrap 的 Alert 警告框反馈结果给用户myAlert(true, '登录成功')console.log(result)}).catch(error => {myAlert(false, error.response.data.message)console.dir(error.response.data.message)})
})

验证码登录流程

4.token的介绍

概念:访问权限的令牌,本质上是一串字符串

创建:正确登录后,由后端签发并返回

作用:判断是否有登录状态等,控制访问权限

注意:前端只能判断token有无,而后端才能判断token的有效性

5.token的使用

目标:只有登录状态,才可以访问内容页面

步骤:

1.在utils/auth.js中判断无token令牌字符串,则强制跳转到登录页(手动修改地址栏测试)

2.在登录成功后,保存token令牌字符串到本地,再跳转到首页(手动修改地址栏测试)

// 权限插件(引入到了除登录页面,以外的其他所有页面)
/*** 目标1:访问权限控制* 1.1 判断无 token 令牌字符串,则强制跳转到登录页* 1.2 登录成功后,保存 token 令牌字符串到本地,并跳转到内容列表页面*/
// 1.1 判断无 token 令牌字符串,则强制跳转到登录页
const token = localStorage.getItem('token')
if (!token) {location.href = '../login/index.html'
}
/*** 目标1:验证码登录* 1.1 在 utils/request.js 配置 axios 请求基地址* 1.2 收集手机号和验证码数据* 1.3 基于 axios 调用验证码登录接口* 1.4 使用 Bootstrap 的 Alert 警告框反馈结果给用户*/// 1.2 收集手机号和验证码数据document.querySelector('.btn').addEventListener('click', () => {const form = document.querySelector('.login-form')const data = serialize(form, { hash: true, empty: true})console.log(data)// 1.3 基于 axios 调用验证码登录接口axios({url: '/v1_0/authorizations',method: 'POST',data: data}).then( result => {// 1.4 使用 Bootstrap 的 Alert 警告框反馈结果给用户myAlert(true, '登录成功')console.log(result)//  登录成功后,保存 token 令牌字符串到本地,并跳转到内容列表页面localStorage.setItem('token', result.data.data.token)setTimeout(() => {// 延迟跳转,让alert警告框停留一会location.href = '../content/index.html'},1500)}).catch(error => {myAlert(false, error.response.data.message)console.dir(error.response.data.message)})
})

token的作用?

  • 判断用户是否有登录状态等

token的注意:

  • 前端只能判断token的有无
  • 后端通过解密可以提取token字符串的原始信息,判断有效性

 6.个人信息设置和axios请求拦截器

需求:设置用户昵称

语法:axios可以在headers选项传递请求头参数

问题:很多接口,都需要携带token令牌字符串

解决:在请求拦截器统一设置公共headers选项

axios请求拦截器:发起请求之前,触发的配置函数,对请求参数进行额外配置

对应代码

/*** 目标2:设置个人信息* 2.1 在 utils/request.js 设置请求拦截器,统一携带 token* 2.2 请求个人信息并设置到页面*/
// 2.2 请求个人信息并设置到页面
axios({url: '/v1_0/user/profile'
}).then(result => {console.log(result)const username = result.data.data.namedocument.querySelector('.nick-name').innerHTML = username
})
// 添加请求拦截器
axios.interceptors.request.use(function (config) {// 在发送请求之前做些什么// 统一携带 token 令牌字符串在请求头上const token = localStorage.getItem('token')token && (config.headers.Authorization = `Bearer ${token}`)return config;
}, function (error) {// 对请求错误做些什么return Promise.reject(error);
})

总结

1.什么是axios请求拦截器?

发起请求之前,调用的一个函数,对请求参数进行设置

2.axios请求拦截器,什么时候使用?

有公共配置和设置时,统一设置在请求拦截器中

7.axios响应拦截器和身份验证失败 

axios响应拦截器:响应回到 then/catch 之前,触发的拦截函数,对响应结果统一处理

例如:身份验证失败,统一判断并做处理

// 添加响应拦截器
axios.interceptors.response.use(function (response) {// 2xx 范围内前状态码都会触发该函数// 对响应数据做点什么return response;
},function (error) {// 超出 2xx 范围的状态码都会触发该函数// 对响应错误数做点什么,例如:统一对 401 身份验证失败错误做出处理console.dir(error)if (error?.response?.status === 401) {alert('身份验证失败,请重新登录')localStorage.clear()location.href = '../login/index.html'}return Promise.reject(error)
})

总结

1.什么是axios响应拦截器?

响应回到then/catch之前,触发的拦截函数,对响应结果统一处理

2.axios响应拦截器,什么时候触发成功/失败的回调函数?

状态为2xx触发成功回调,其他则触发失败的回调函数

 8.优化-axios响应结果

目标:axios直接接收服务器返回的响应结果

讲解:其实就是在响应拦截器里,response.data把后台返回的数据直接取出来统一返回给所有使用这个axios函数的逻辑页面位置的 then 的形参上

好处:可以让逻辑页面少一层data就能拿到后端返回的真正数据对象

对应代码

axios.interceptors.response.use(function (response) {// 2xx 范围内的状态码都会触发该函数。// 对响应数据做点什么,例如:直接返回服务器的响应结果对象const result = response.datareturn result
}, function (error) {// 超出 2xx 范围的状态码都会触发该函数。// 对响应错误做点什么,例如:判断响应状态为 401 代表身份验证失败if (error?.response?.status === 401) {alert('登录状态过期,请重新登录')window.location.href = '../login/index.html'}return Promise.reject(error);
})

9.发布文章-富文本编辑器

富文本:带样式,多格式的文本,在前端一般使用标签配合内联样式实现

富文本编辑器:用于编写富文本内容的容器

目标:发布文章页,富文本编辑器的集成

使用:wangEditor插件

步骤:参考文档

  1. 引入CSS定义样式
  2. 定义HTML结构
  3. 引入JS创建编辑器
  4. 监听内容改变,保存在隐藏文本域(便于后期收集)

对应代码

// 富文本编辑器
// 创建编辑器函数,创建工具栏函数
const { createEditor, createToolbar } = window.wangEditorconst editorConfig = {// 占位提示文字placeholder: '发布文章内容...',// 编辑器变化时回调函数onChange(editor) {// 获取富文本内容const html = editor.getHtml()console.log('editor content', html)// 也可以同步到 <textarea>// 为了后续快速收集整个表单内容做铺垫document.querySelector('.publish-content').value = html}
}const editor = createEditor({// 创建位置selector: '#editor-container',// 默认内容html: '<p><br></p>',// 配置项config: editorConfig,// 配置集成模式(default 全部) (simple 简洁)mode: 'default', // or 'simple'
})// 工具栏配置对象
const toolbarConfig = {}// 创建工具栏
const toolbar = createToolbar({// 为指定编辑器创建工具栏editor,// 工具栏创建的位置selector: '#toolbar-container',// 工具栏配置对象config: toolbarConfig,// 配置集成模式mode: 'default', // or 'simple'
})

10.发布文章-频道列表

目标:展示频道列表,供用户选择

步骤:

  1. 获取频道列表数据
  2. 展示到下拉菜单中
/*** 目标1:设置频道下拉菜单*  1.1 获取频道列表数据*  1.2 展示到下拉菜单中*/// 1.1 获取频道列表数据
async function setChannleList() {const res = await axios({url: '/v1_0/channels'})// 1.2 展示到下拉菜单中const htmlStr =  `<option value="" selected="">请选择文章频道</option>` + res.data.channels.map(item => `<option value="${item.id}">${item.name}</option>`).join('')console.log(htmlStr)document.querySelector('.form-select').innerHTML = htmlStr
}
// 网页运行后,默认调用一次
setChannleList()

11.发布文章-封面设置

目标:文章封面的设置

步骤:

  1. 准备标签结构和样式
  2. 选择文件并保存在FormData
  3. 单独上传图片并得到图片URL地址
  4. 回显并切换img标签展示(隐藏 + 号上传标签)

注意:图片地址临时存储在img标签上,并未和文章关联保存

/*** 目标2:文章封面设置*  2.1 准备标签结构和样式*  2.2 选择文件并保存在 FormData*  2.3 单独上传图片并得到图片 URL 网址*  2.4 回显并切换 img 标签展示(隐藏 + 号上传标签)*/
// 2.2 选择文件并保存在 FormData
document.querySelector('.img-file').addEventListener('change', async e => {const file = e.target.files[0]const fd = new FormData()fd.append('image', file)// 2.3 单独上传图片并得到图片 URL 网址const res = await axios({url: '/v1_0/upload',method: 'POST',data: fd})console.log(res)// 2.4 回显并切换 img 标签展示(隐藏 + 号上传标签)const imgUrl = res.data.urldocument.querySelector('.rounded').src = imgUrldocument.querySelector('.rounded').classList.add('show')document.querySelector('.place').classList.add('hide')
})// 优化:点击 img 可以重新切换封面
// 思路: img 点击 => 用JS方式触发文件选择元素 click 事件方法
document.querySelector('.rounded').addEventListener('click', () => {document.querySelector('.img-file').click()
})

12.发布文章-收集并保存

目标:收集文章内容,并提交保存

步骤:

1.基于form-serialize插件收集表单数据对象

2.基于axios提交到服务器保存

3.调用Alert警告框反馈结果给用户

/*** 目标3:发布文章保存*  3.1 基于 form-serialize 插件收集表单数据对象*  3.2 基于 axios 提交到服务器保存*  3.3 调用 Alert 警告框反馈结果给用户*  3.4 重置表单并跳转到列表页*/
// 3.1 基于 form-serialize 插件收集表单数据对象
document.querySelector('.send').addEventListener('click', async e => {const form = document.querySelector('.art-form')const data = serialize(form, { hash: true, empty: true})console.log(data)// 发布文章的时候,不需要 id 属性,所以可以删除掉(id为了后续做编辑使用)delete data.idconsole.log(data)// 自己收集封面图片地址并保存到 data 对象中data.cover = {type: 1, // 封面类型images: [document.querySelector('.rounded').src] // 封面图书 URL网址}// 3.2 基于 axios 提交到服务器保存try {const res = await axios({url: '/v1_0/mp/articles',method:'POST',data: data})// 3.3 调用 Alert 警告框反馈结果给用户myAlert(true, '发布成功')// 3.4 重置表单并跳转到列表页form.reset()// 封面需要手动重置document.querySelector('.rounded').src = ''document.querySelector('.rounded').classList.remove('show')document.querySelector('.place').classList.remove('hide')// 富文本编辑器重置editor.setHtml('')setTimeout(() => {location.href = '../content/index.html'},1500)} catch (error) {console.dir(error)myAlert(false, error.response.data.message)}})

13.内容管理-文章列表展示

目标:获取文章列表并展示

步骤:

1.准备查询参数对象

2.获取文章列表数据

3.展示到指定的标签结构中

/*** 目标1:获取文章列表并展示*  1.1 准备查询参数对象*  1.2 获取文章列表数据*  1.3 展示到指定的标签结构中*/
// 1.1 准备查询参数对象
const queryObj = {status: '', // 文章状态(1-待审核,2-审核通过)空字符串-全部channel_id: '', // 文章频道id,空字符串-全部page: 1, // 当前页码per_page: 2 // 当前页面条数
}
async function setArtileList() {// 1.2 获取文章列表数据const res = await axios({url: '/v1_0/mp/articles',params: queryObj})console.log(res)// 1.3 展示到指定的标签结构中const htmlStr = res.data.results.map( item => `<tr><td><img src=" ${item.cover.type === 0 ? `https://img2.baidu.com/it/u=2640406343,1419332367&amp;fm=253&amp;fmt=auto&amp;app=138&amp;f=JPEG?w=708&amp;h=500` : item.cover.images[0]}" alt=""></td><td>${item.title}</td><td>${item.status === 1 ? `<span class="badge text-bg-primary">待审核</span>` : `<span class="badge text-bg-success">审核通过</span>`} </td><td><span>${ item.pubdate }</span></td><td><span> ${ item.read_count } </span></td><td><span> ${ item.comment_count } </span></td><td><span> ${ item.like_count }</span></td><td><i class="bi bi-pencil-square edit"></i><i class="bi bi-trash3 del"></i></td></tr>`).join('')// console.log(htmlStr)document.querySelector('.art-list').innerHTML = htmlStr
}
setArtileList()

14.内容管理-筛选功能

目标:根据筛选条件,获取匹配数据展示

步骤:

1.设置频道列表数据

2.监听筛选条件改变,保存查询信息到查询参数对象

3.点击筛选时,传递查询参数对象到服务器

4.获取匹配数据,覆盖到页面展示

/*** 目标2:筛选文章列表*  2.1 设置频道列表数据*  2.2 监听筛选条件改变,保存查询信息到查询参数对象*  2.3 点击筛选时,传递查询参数对象到服务器*  2.4 获取匹配数据,覆盖到页面展示*/
async function setChannleList() {const res = await axios({url: '/v1_0/channels'})const htmlStr = `<option value="" selected="">请选择文章频道</option>` + res.data.channels.map(item => `<option value="${item.id}">${item.name}</option>`).join('')document.querySelector('.form-select').innerHTML = htmlStr
}
setChannleList()
// 2.2 监听筛选条件改变,保存查询信息到查询参数对象
// 筛选状态标记数字 -> change事件 -> 绑定到查询参数对象上
document.querySelectorAll('.form-check-input').forEach(radio => {radio.addEventListener('change', e => {// console.log(e.target.value)queryObj.status = e.target.value})
})
// 筛选频道 id -> change事件 -> 绑定到查询参数对象上
document.querySelector('.form-select').addEventListener('change', e => 
{// console.log(e.target.value)queryObj.channel_id = e.target.value
})
// 2.3 点击筛选时,传递查询参数对象到服务器
document.querySelector('.sel-btn').addEventListener('click', () => {// 2.4 获取匹配数据,覆盖到页面展示setArtileList()
})

15.内容管理-分页功能

内容管理-分页功能

目标:完成文章列表,分页管理功能

步骤:

1.保存并设置文章总条数

2.点击下一页,做临界值判断,并切换页面参数请求最新数据

3.点击上一页,做临界值判断,并切换页面参数请求最新数据

/*** 目标3:分页功能*  3.1 保存并设置文章总条数*  3.2 点击下一页,做临界值判断,并切换页码参数并请求最新数据*  3.3 点击上一页,做临界值判断,并切换页码参数并请求最新数据*/
// 3.2 点击下一页,做临界值判断,并切换页码参数并请求最新数据
document.querySelector('.next').addEventListener('click', e => {// 当前页码小于最大页码数if (queryObj.page < Math.ceil(totalCount / queryObj.per_page)) {queryObj.page++document.querySelector('.page-now').innerHTML = `第${queryObj.page}页`setArtileList()}
} )
// 3.3 点击上一页,做临界值判断,并切换页码参数并请求最新数据
document.querySelector('.last').addEventListener('click', e => {// 大于 1 的时候,才能翻到上一页if (queryObj.page > 1) {queryObj.page--document.querySelector('.page-now').innerHTML = `第${queryObj.page}页`}setArtileList()
})

16.内容管理-删除功能

目标:完成删除文章功能

步骤:

  1. 关联文章id到删除图标
  2. 点击删除时,获取文章id
  3. 调用删除接口,传递文章id到服务器
  4. 重新获取文章列表,并覆盖展示
/*** 目标4:删除功能*  4.1 关联文章 id 到删除图标*  4.2 点击删除时,获取文章 id*  4.3 调用删除接口,传递文章 id 到服务器*  4.4 重新获取文章列表,并覆盖展示*  4.5 删除最后一页的最后一条,需要自动向前翻页*/
// 4.2 点击删除时,获取文章 id
document.querySelector('.art-list').addEventListener('click', async e => {// 判断点击的是删除元素if (e.target.classList.contains('del')) {const delId = e.target.parentNode.dataset.idconsole.log(delId)// 4.3 调用删除接口,传递文章 id 到服务器const res = await axios({url:  `v1_0/mp/articles/${delId}` ,method: 'DELETE'})console.log(res)// 4.4 重新获取文章列表,并覆盖展示setArtileList()}
})

17.内容管理-删除最后一条

目标:在删除最后一页,最后一条时有Bug

1.删除成功时,判断DOM元素只剩一条,让当前页码 page--

2.注意,当前页码为1时不能继续向前翻页

3.重新设置页码数,获取最新列表展示

        // 4.5 删除最后一页的最后一条,需要自动向前翻页const children = document.querySelector('.art-list').childrenif (children.length === 1 && queryObj.page !== 1){queryObj.page--document.querySelector('.page-now').innerHTML = `第${queryObj.page }页`}

18.内容管理-编辑文章-回显

目标:编辑文章时,回显数据到表单

步骤:

  1. 页面跳转传参(URL查询参数方式)
    // 点击编辑时,获取文章 id,跳转到发布文章页面传递文章 id 过去
    document.querySelector('.art-list').addEventListener('click', e => {if (e.target.classList.contains('edit')) {const artId = e.target.parentNode.dataset.idconsole.log(artId)location.href = `../publish/index.html?id=${artId}`}
    })
    
  2. 发布文章页面接收参数判断(共用同一套表单)
  3. 修改标题和按钮文字
  4. 获取文章详情数据并回显表单

对应代码:

/*** 目标4:编辑-回显文章*  4.1 页面跳转传参(URL 查询参数方式)*  4.2 发布文章页面接收参数判断(共用同一套表单)*  4.3 修改标题和按钮文字*  4.4 获取文章详情数据并回显表单*/;(function(){// 4.2 发布文章页面接收参数判断(共用同一套表单)const paramsStr = location.searchconst params = new URLSearchParams(paramsStr)params.forEach(async (value, key) => {// 当前有要编辑的文章 id 被传入过来if (key === 'id'){// 4.3 修改标题和按钮文字document.querySelector('.title span').innerHTML = '修改文章'document.querySelector('.send').innerHTML = '修改'// 4.4 获取文章详情数据并回显表单const res = await axios({url: `/v1_0/mp/articles/${value}`})console.log(res)// 组织我仅仅需要的数据对象,为后续遍历回显到页面上做铺垫const dataObj = {channel_id: res.data.channel_id,title: res.data.title,rounded: res.data.cover.images[0], // 封面图片地址content: res.data.content,id: res.data.id}// 遍历数据对象属性,映射到页面元素上,快速赋值Object.keys(dataObj).forEach(key => {if(key === 'rounded'){// 封面设置if(dataObj[key]){// 有封面document.querySelector('.rounded').src = dataObj[key]document.querySelector('.rounded').classList.add('show')document.querySelector('.place').classList.add('hide')}} else if( key === 'content'){// 富文本内容editor.setHtml(dataObj[key])} else {// 用数据对象属性名,作为标签 name 属性选择器值来找到匹配的标签document.querySelector(`[name=${key}]`).value = dataObj[key]}})}})
})();

19.内容管理-编辑文章-保存

目标:确认修改,保存文章到服务器

步骤:

1.判断按钮文字,区分业务(因为共用一套表单)

2.调用编辑文章接口,保存信息到服务器

3.基于Alert反馈结果消息给用户

/*** 目标5:编辑-保存文章*  5.1 判断按钮文字,区分业务(因为共用一套表单)*  5.2 调用编辑文章接口,保存信息到服务器*  5.3 基于 Alert 反馈结果消息给用户*/
document.querySelector('.send').addEventListener('click', async e => {// 5.1 判断按钮文字,区分业务(因为共用一套表单)if (e.target.innerHTML !== '修改') return// 修改文章逻辑const form = document.querySelector('.art-form')const data = serialize(form, { hash: true, empty: true})// console.log(data)// 5.2 调用编辑文章接口,保存信息到服务器try {const res = await axios({url: `/v1_0/mp/articles/${data.id}`,method: 'PUT',data: {...data,cover:{type: document.querySelector('.rounded').src ? 1 : 0,images: [document.querySelector('.rounded').src]}}})console.log(res)myAlert(true,'修改文章成功')} catch (error) {myAlert(false,error.response.data.message)}
})

20.退出登录

目标:完成退出登录效果

步骤:

1.绑定点击事件

2.清空本地缓存,跳转到登录页面

/*** 目标3:退出登录*  3.1 绑定点击事件*  3.2 清空本地缓存,跳转到登录页面*/
document.querySelector('.quit').addEventListener('click', e => {// 3.2 清空本地缓存,跳转到登录页面localStorage.clear()location.href = '../login/index.html'
})

项目素材代码点击这里:【免费】黑马头条数据管理平台的素材、代码资源-CSDN文库

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/3820.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ShardingSphere 5.x 系列【26】 数据分片原理之 SQL 路由

有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 3.1.0 本系列ShardingSphere 版本 5.4.0 源码地址:https://gitee.com/pearl-organization/study-sharding-sphere-demo 文章目录 1. 概述2. 携带分片键2.1 直接路由2.2 标准路由2.3 笛卡尔路由3. 不携带分片…

【内网横向】SSH协议隧道搭建详解

什么是SSH隧道 SSH隧道是通过Secure Shell&#xff08;SSH&#xff09;协议在两个网络节点之间创建的加密通道。它可以用于安全地传输数据&#xff0c;绕过网络限制或保护数据免受窃听。通过SSH隧道&#xff0c;可以在两个网络之间建立安全的连接&#xff0c;例如在本地计算机和…

济宁市中考报名照片要求及手机拍照采集证件照方法

随着中考报名季的到来&#xff0c;并且进入了中考报名演练阶段&#xff0c;济宁市的广大考生和家长都开始忙碌起来。报名过程中&#xff0c;上传一张符合要求的证件照是必不可少的环节。本文将详细介绍济宁市中考报名照片的具体要求&#xff0c;并提供一些实用的手机拍照采集证…

BUUCTF--web(2)

1、[HCTF 2018]admin1 打开题目后发现有注册和登录两个页面&#xff0c;因为题目提示admin&#xff0c;尝试用admin进行爆破 爆破得到密码为123 登录得到flag 2、[护网杯 2018]easy_tornado1 打开题目后有三个文件&#xff0c;分别打开查看 在url地址栏中发现包含两个参数&a…

鸿蒙OpenHarmony【轻量系统 编写“Hello World”程序】 (基于Hi3861开发板)

编写“Hello World”程序 下方将通过修改源码的方式展示如何编写简单程序&#xff0c;输出“Hello world”。请在下载的源码目录中进行下述操作。 确定目录结构。 开发者编写业务时&#xff0c;务必先在./applications/sample/wifi-iot/app路径下新建一个目录&#xff08;或一…

计算机视觉——OpenCV 使用分水岭算法进行图像分割

分水岭算法 分水岭算法&#xff1a;模拟地理形态的图像分割 分水岭算法通过模拟自然地形来实现图像中物体的分类。在这一过程中&#xff0c;每个像素的灰度值被视作其高度&#xff0c;灰度值较高的像素形成山脊&#xff0c;即分水岭&#xff0c;而二值化阈值则相当于水平面&am…

上门服务系统|上门服务小程序搭建流程

随着科技的不断进步和人们生活水平的提高&#xff0c;越来越多的服务开始向线上转型。传统的上门服务业也不例外&#xff0c;随着上门服务小程序的兴起&#xff0c;人们的生活变得更加便捷和高效。本文将为大家介绍上门服务小程序的搭建流程以及应用范围。 一、上门服务小程序搭…

华为OD机试 - 跳格子3 - 动态规划(Java 2024 C卷 200分)

华为OD机试 2024C卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测试…

Taro +vue3 中实现全局颜色css变量的设置和使用

当我们现在需要弄一个随时修改的页面颜色主题色 我们可以随时修改 我使用的是 Taro 框架 一般有一个app.less 文件 我们在这个里面 设置一个root 全局样式 :root {--primary-color: #028fd4;--secondary-color: #028fd6;/* 添加其他颜色变量 */ } 这样在全局我们就可以使用这…

汽车信息安全--如何理解TrustZone(2)

目录 1.概述 2 如何切换安全状态 3 TrustZone里实现了什么功能&#xff1f; 4. 与HSM的比较 1.概述 汽车信息安全--如何理解TrustZone(1)-CSDN博客讲解了什么是Trustzone&#xff0c;下面我们继续讲解与HSM的区别。 2 如何切换安全状态 在引入安全扩展后&#xff0c;Arm…

OpenHarmony硬件合成方案解析

本文档主要讲解在OpenHarmony中&#xff0c;硬件合成适配的方法及原理说明。 环境说明&#xff1a; OHOS版本&#xff1a;3.1-Release及以上 一、背景介绍 1.1 什么是合成 要理解什么是合成&#xff0c;合成做了什么&#xff1f;我们先通过分解设置界面来回答这个问题: 在…

MySQL中的Performance Schema是什么?

MySQL中的Performance Schema是什么&#xff1f; Performance Schema 是 MySQL 的一个特性&#xff0c;主要用于监控 MySQL 服务器在运行时的性能和资源使用情况。它首次引入于 MySQL 5.5 版本&#xff0c;并在后续版本中得到增强。Performance Schema 提供了一种方式来收集数…

base64算法

1 介绍 将二进制数据编码为文本字符串的算法 理解&#xff1a;把一个能看懂的明文变成一个看不懂的密文数据统称为加密 2 使用 A 在浏览器控制台使用 加密 window.btoa(加密的数据) 解密 window.atob(MTIzNDQ) B 在VSconde中使用 加密 解密

机器学习-保险花销预测笔记+代码

读取数据 import numpy as np import pandas as pddatapd.read_csv(rD:\人工智能\python视频\机器学习\5--机器学习-线性回归\5--Lasso回归_Ridge回归_多项式回归\insurance.csv,sep,) data.head(n6) EDA 数据探索 import matplotlib.pyplot as plt %matplotlib inlineplt.hi…

STM32之串口中断接收丢失数据

五六年没搞STM32了&#xff0c;这个项目一切都挺顺利&#xff0c;万万没想到被串口接收中断恶心到了。遇到的问题很奇怪 HAL_UART_Receive_IT(&huart1, &rx_buffer[rx_index], LCD_UART_LEN); 这个代码中 LCD_UART_LEN1的时候&#xff0c;接收过来的数据&#xff0c;数…

如何用Python实现智能客服问答系统

随着人工智能技术的不断发展&#xff0c;机器人客服与聊天系统成为了热门话题。Python作为一种简单易学、功能强大的编程语言&#xff0c;在机器人客服与聊天系统的开发中具有广泛应用。 本文将介绍如何使用Python实现机器人客服与聊天系统&#xff0c;包括实现方式、代码示例和…

[NSSCTF]prize_p5

前言 之前就学过反序列化的字符串逃逸 但是没怎么做题 补一下窟窿 题目 <?phperror_reporting(0);class catalogue{public $class;public $data;public function __construct(){$this->class "error";$this->data "hacker";}public functi…

2023-2024年度广东省职业院校学生技能大赛“ 网络系统管理”赛项竞赛规程(正式稿)

2023-2024年度广东省职业院校学生技能大赛“ 网络系统管理”赛项竞赛规程&#xff08;正式稿&#xff09; 信息安全管理与评估 网络系统管理 网络搭建与应用 云计算 软件测试 移动应用开发 任务书&#xff0c;赛题&#xff0c;解析等资料&#xff0c;知识点培训服务 添加博主wx…

设置Linux开发板开机自启动QT程序的报错解决办法

设置Linux开发板开机自启动QT程序报错解决办法 设置开发板开机自启动QT 打开 /etc/init.d/rsC 文件&#xff0c;添加以下内容 cd / ./my_start_run.shmy_start_run.sh 是自己编写的自启动脚本&#xff0c;内容例如下&#xff1a;(也可以将这些直接写到 /etc/init.d/rsC 文件…

请编写一个函数void fun(char *tt,int pp[]),统计在tt字符串中“a”到“z”26个字母各自出现的次数,并依次放在pp所指数组中。

本文收录于专栏:算法之翼 https://blog.csdn.net/weixin_52908342/category_10943144.html 订阅后本专栏全部文章可见。 本文含有题目的题干、解题思路、解题思路、解题代码、代码解析。本文分别包含C语言、C++、Java、Python四种语言的解法和详细的解析。 题干 请编写一个函…