鸿蒙NEXT项目实战-百得知识库03

代码仓地址,大家记得点个star

IbestKnowTeach: 百得知识库基于鸿蒙NEXT稳定版实现的一款企业级开发项目案例。 本案例涉及到多个鸿蒙相关技术知识点: 1、布局 2、配置文件 3、组件的封装和使用 4、路由的使用 5、请求响应拦截器的封装 6、位置服务 7、三方库的使用和封装 8、头像上传 9、应用软件更新等https://gitee.com/xt1314520/IbestKnowTeach

Home页面开发

设计图

需求分析

Home页面一共可以分为三块部分

1、头部-最新、热门

2、搜索框

3、内容主体

搭建Home页面布局

1、头部-最新、热门

最新、热门可以用Text文本组件,下面下划线用Divider组件

// 标题栏
Row({ space: 10 }) {Column() {Text($r('app.string.article_best_new')).textStyles()// 选中标题会出现下划线if (this.newDividerShow) {Divider().dividerStyles()}}.onClick(() => {// 展示下划线this.hotDividerShow = falsethis.newDividerShow = true// 查询最新文章数据this.isShow = falsethis.page = 1this.getArticleNewDataList(true, true)})Column() {Text($r('app.string.article_best_hot')).textStyles()// 选中标题会出现下划线if (this.hotDividerShow) {Divider().dividerStyles()}}.onClick(() => {this.newDividerShow = falsethis.hotDividerShow = true// 查询最热门文章数据this.isShow = falsethis.page = 1this.getArticleHotDataList(true, true)})}.justifyContent(FlexAlign.Start).margin({ top: 10, bottom: 20 }).width(CommonConstant.WIDTH_FULL)

2、搜索框

搜索框可以使用鸿蒙原生组件Search

// 搜索
Search({ placeholder: '请输入关键字', value: $$this.keyword }).placeholderFont({ size: 14 }).textFont({ size: 14 }).onSubmit(() => {// 处理标题this.title = encodeURIComponent(this.keyword)// 分页查询文章内容this.isShow = falsethis.page = 1this.getArticleDataList(true)}).width(CommonConstant.WIDTH_FULL).height(30)
3、内容主体

内容主体相当于我们把文章单条内容封装成一个组件,然后使用List组件进行布局嵌套使用Foreach进行循环遍历文章数组对象数据

整体大家看一条文章数据,分为三行,行使用的是Row布局,整体三行布局从上到下是列所以组件整体用Column进行包裹

封装单条文章组件(在ets下面创建component目录然后创建ArticleComponent.ets文件)

import { ArticleContentData } from '../api/ArticleContentApi.type'
import { CommonConstant } from '../contants/CommonConstant'@Componentexport struct ArticleComponent {// 文章数据@Prop articleContentData: ArticleContentDatabuild() {Column() {Row({ space: 10 }) {// 头像Image(this.articleContentData.avatarUri).width($r('app.float.common_width_tiny')).aspectRatio(1).borderRadius(10)// 姓名Text(this.articleContentData.nickname).fontSize($r('app.float.common_font_size_medium')).fontColor($r('app.color.common_gray')).width('70%').maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis })}.width(CommonConstant.WIDTH_FULL)Row() {// 内容标题Text(this.articleContentData.title).fontSize($r('app.float.common_font_size_small')).width('80%').maxLines(3).textOverflow({ overflow: TextOverflow.Ellipsis })Image(this.articleContentData.coverUrl).width($r('app.float.common_width_medium')).aspectRatio(1).objectFit(ImageFit.Contain).borderRadius(5)}.width(CommonConstant.WIDTH_FULL).justifyContent(FlexAlign.SpaceBetween)// 展示阅读、点赞、收藏Row({ space: 3 }) {Text(this.articleContentData.readCount + '阅读').textStyles()Text('|').textStyles()Text(this.articleContentData.time).textStyles()Text('|').textStyles()// 文章内容标签if (this.articleContentData.contentCategory === '1') {Text('鸿蒙').textLabelStyles()} else if (this.articleContentData.contentCategory === '2') {Text('Java').textLabelStyles()} else if (this.articleContentData.contentCategory === '3') {Text('Web前端').textLabelStyles()} else if (this.articleContentData.contentCategory === '4') {Text('运维').textLabelStyles()} else {Text('未知级别').textLabelStyles()}Text('|').textStyles()// 文章难度分类标签if (this.articleContentData.difficultyCategory === '1') {Text(this.articleContentData.platformCategory === '1' ? '基础知识' : '简单面试题').textLabelStyles()} else if (this.articleContentData.difficultyCategory === '2') {Text(this.articleContentData.platformCategory === '1' ? '进阶知识' : '中等面试题').textLabelStyles()} else if (this.articleContentData.difficultyCategory === '3') {Text(this.articleContentData.platformCategory === '1' ? '高级知识' : '困难面试题').textLabelStyles()} else {Text('未知级别').textLabelStyles()}}.width(CommonConstant.WIDTH_FULL)}.padding(10).width(CommonConstant.WIDTH_FULL).height(110).margin({ top: 13 }).backgroundColor($r('app.color.common_white')).justifyContent(FlexAlign.SpaceBetween).borderRadius(10)}
}@Extend(Text)
function textStyles() {.fontColor($r('app.color.common_gray')).fontSize($r('app.float.common_font_size_tiny'))
}@Extend(Text)
function textLabelStyles() {.fontSize($r('app.float.common_font_size_tiny')).fontColor(Color.Black)
}

然后我们整体在Home页面里面展示我们的文章内容数组数据

if (this.isShow) {Refresh({ refreshing: $$this.isRefreshing }) {// 内容组件List() {ForEach(this.articleContentList, (item: ArticleContentData) => {ListItem() {ArticleComponent({ articleContentData: item }).onClick(() => {// 路由到内容详情页router.pushUrl({url: RouterConstant.VIEWS_HOME_ARTICLE_INFO, params: {"articleId": item.id}})})}})if (this.textShow) {ListItem() {Text($r('app.string.no_have_article')).fontColor($r('app.color.common_gray')).fontSize($r('app.float.common_font_size_small')).width(CommonConstant.WIDTH_FULL).textAlign(TextAlign.Center).margin({ top: 80 })}}}.width(CommonConstant.WIDTH_FULL).height(CommonConstant.HEIGHT_FULL).scrollBar(BarState.Off).onReachEnd(() => {if (!this.isLoad) {if (this.total > this.page * this.pageSize) {this.isLoad = truethis.page++if (this.newDividerShow) {// 分页查询最新文章数据this.getArticleNewDataList(false, false)}if (this.hotDividerShow) {// 分页查询最热门文章数据this.getArticleHotDataList(false, false)}} else {this.textShow = true}}})}.onRefreshing(() => {if (!this.isLoad) {this.isLoad = truethis.textShow = false// 页面恢复到1this.page = 1if (this.newDividerShow) {// 分页查询最新文章数据this.getArticleNewDataList(true, true)}if (this.hotDividerShow) {// 分页查询最热门文章数据this.getArticleHotDataList(true, true)}}})
} else {// 加载组件LoadingComponent()
}

加载组件 LoadingComponent()是我们自己进行封装的,因为我们的数据可能因为网络原因还没在服务端查询出来,界面为了不要展示长时间空白让用户误会,所以展示我们数据正在加载中

import { CommonConstant } from '../contants/CommonConstant'@Componentexport struct LoadingComponent {@State message: string = '数据正在加载中'build() {Row() {LoadingProgress().width(30).height(30).color(Color.Gray)Text(this.message).fontSize((14)).fontColor(Color.Gray)}.height("80%").width(CommonConstant.WIDTH_FULL).justifyContent(FlexAlign.Center)}}
4、整体Home页面代码

import { router } from '@kit.ArkUI'
import { RouterConstant } from '../../contants/RouterConstant'
import { CommonConstant } from '../../contants/CommonConstant'
import { ArticleComponent } from '../../components/ArticleComponent'
import articleContentApi from '../../api/ArticleContentApi'
import { LoadingComponent } from '../../components/LoadingComponent'
import { ArticleContentData } from '../../api/ArticleContentApi.type'
import { showToast } from '../../utils/Toast'@Entry@Componentexport struct Home {// 是否展示最新标题的下划线@State newDividerShow: boolean = true// 是否展示热门标题的下划线@State hotDividerShow: boolean = false// 搜索词@State keyword: string = ''// 标题@State title: string = ''// 文章数据数组@State articleContentList: ArticleContentData[] = []// 学习打卡总记录数@State total: number = 0// 当前页@State page: number = 1// 每一页大小@State pageSize: number = 7// 控制当前页面展示@State isShow: boolean = false// 定义一个状态属性,用来和Refresh组件进行双向数据绑定@State isRefreshing: boolean = false// 节流, false表示未请求, true表示正在请求isLoad: boolean = false// 是否展示文本,列表到底@State textShow: boolean = false/*** 生命周期函数*/async aboutToAppear() {// 默认获取首页最新文章内容this.getArticleNewDataList(true, false)}/*** 分页查询最新文章数据*/async getArticleNewDataList(isFlushed: boolean, isUpdate: boolean) {// 分页查询最新文章数据const articleDataList =await articleContentApi.getNewArticle({ page: this.page, pageSize: this.pageSize, title: this.title })isFlushed ? this.articleContentList = articleDataList.records :this.articleContentList.push(...articleDataList.records)this.total = articleDataList.total// 判断总数据if (this.total > this.page * this.pageSize) {this.textShow = false} else {this.textShow = true}// 页面展示this.isShow = true// 节流,防止用户重复下拉this.isLoad = falsethis.isRefreshing = false// 是否刷新if (isUpdate) {showToast("已更新")}}/*** 分页查询最热门文章数据*/async getArticleHotDataList(isFlushed: boolean, isUpdate: boolean) {// 分页查询最热门文章数据const articleDataList =await articleContentApi.getHotArticle({ page: this.page, pageSize: this.pageSize, title: this.title })isFlushed ? this.articleContentList = articleDataList.records :this.articleContentList.push(...articleDataList.records)this.total = articleDataList.total// 判断总数据if (this.total > this.page * this.pageSize) {this.textShow = false} else {this.textShow = true}// 页面展示this.isShow = true// 节流,防止用户重复下拉this.isLoad = falsethis.isRefreshing = false// 是否刷新if (isUpdate) {showToast("已更新")}}/*** 分页查询文章数据*/async getArticleDataList(isFlushed: boolean) {// 分页查询文章数据if (this.newDividerShow) {this.getArticleNewDataList(isFlushed, true)}if (this.hotDividerShow) {this.getArticleHotDataList(isFlushed, true)}}build() {Column() {// 标题栏Row({ space: 10 }) {Column() {Text($r('app.string.article_best_new')).textStyles()// 选中标题会出现下划线if (this.newDividerShow) {Divider().dividerStyles()}}.onClick(() => {// 展示下划线this.hotDividerShow = falsethis.newDividerShow = true// 查询最新文章数据this.isShow = falsethis.page = 1this.getArticleNewDataList(true, true)})Column() {Text($r('app.string.article_best_hot')).textStyles()// 选中标题会出现下划线if (this.hotDividerShow) {Divider().dividerStyles()}}.onClick(() => {this.newDividerShow = falsethis.hotDividerShow = true// 查询最热门文章数据this.isShow = falsethis.page = 1this.getArticleHotDataList(true, true)})}.justifyContent(FlexAlign.Start).margin({ top: 10, bottom: 20 }).width(CommonConstant.WIDTH_FULL)// 搜索Search({ placeholder: '请输入关键字', value: $$this.keyword }).placeholderFont({ size: 14 }).textFont({ size: 14 }).onSubmit(() => {// 处理标题this.title = encodeURIComponent(this.keyword)// 分页查询文章内容this.isShow = falsethis.page = 1this.getArticleDataList(true)}).width(CommonConstant.WIDTH_FULL).height(30)if (this.isShow) {Refresh({ refreshing: $$this.isRefreshing }) {// 内容组件List() {ForEach(this.articleContentList, (item: ArticleContentData) => {ListItem() {ArticleComponent({ articleContentData: item }).onClick(() => {// 路由到内容详情页router.pushUrl({url: RouterConstant.VIEWS_HOME_ARTICLE_INFO, params: {"articleId": item.id}})})}})if (this.textShow) {ListItem() {Text($r('app.string.no_have_article')).fontColor($r('app.color.common_gray')).fontSize($r('app.float.common_font_size_small')).width(CommonConstant.WIDTH_FULL).textAlign(TextAlign.Center).margin({ top: 80 })}}}.width(CommonConstant.WIDTH_FULL).height(CommonConstant.HEIGHT_FULL).scrollBar(BarState.Off).onReachEnd(() => {if (!this.isLoad) {if (this.total > this.page * this.pageSize) {this.isLoad = truethis.page++if (this.newDividerShow) {// 分页查询最新文章数据this.getArticleNewDataList(false, false)}if (this.hotDividerShow) {// 分页查询最热门文章数据this.getArticleHotDataList(false, false)}} else {this.textShow = true}}})}.onRefreshing(() => {if (!this.isLoad) {this.isLoad = truethis.textShow = false// 页面恢复到1this.page = 1if (this.newDividerShow) {// 分页查询最新文章数据this.getArticleNewDataList(true, true)}if (this.hotDividerShow) {// 分页查询最热门文章数据this.getArticleHotDataList(true, true)}}})} else {// 加载组件LoadingComponent()}}.padding($r('app.float.common_padding')).height(CommonConstant.HEIGHT_FULL).width(CommonConstant.WIDTH_FULL)}
}@Extend(Text)
function textStyles() {.fontSize($r('app.float.common_font_size_huge')).fontWeight(FontWeight.Medium)
}@Extend(Divider)
function dividerStyles() {.color(Color.Black).width($r('app.float.common_width_tiny')).strokeWidth(3)
}

5、数据渲染,接口封装

查询最新文章数据,这个函数里面有个 articleContentApi.getNewArticle方法,这个方法是作者封装的接口

/*** 分页查询最新文章数据*/
async getArticleNewDataList(isFlushed: boolean, isUpdate: boolean) {// 分页查询最新文章数据const articleDataList =await articleContentApi.getNewArticle({ page: this.page, pageSize: this.pageSize, title: this.title })isFlushed ? this.articleContentList = articleDataList.records :this.articleContentList.push(...articleDataList.records)this.total = articleDataList.total// 判断总数据if (this.total > this.page * this.pageSize) {this.textShow = false} else {this.textShow = true}// 页面展示this.isShow = true// 节流,防止用户重复下拉this.isLoad = falsethis.isRefreshing = false// 是否刷新if (isUpdate) {showToast("已更新")}
}

大家可以根据东林提供的接口文档,将我们的调用接口封装成方法

这是涉及到文章的所有接口

import http from '../request/Request'
import {ArticleContentData,ArticleContentHotPageParam,ArticleContentNewPageParam,ArticleContentPageParam,PageVo
} from './ArticleContentApi.type'/*** 文章接口*/
class ArticleContentApi {/*** 分页查询文章内容*/pageListArticleContent = (data: ArticleContentPageParam): Promise<PageVo<ArticleContentData>> => {return http.get('/v1/article/page?page=' + data.page + '&&pageSize=' + data.pageSize + '&&title=' + data.title +'&&contentCategory=' + data.contentCategory + '&&platformCategory=' + data.platformCategory +'&&difficultyCategory=' + data.difficultyCategory)}/*** 根据文章id查询文章详情*/getArticleContentInfo = (data: number): Promise<ArticleContentData> => {return http.get('/v1/article/info?id=' + data)}/***  用户点赞/取消点赞文章*/likeArticleContent = (data: number) => {return http.put('/v1/article/like?id=' + data)}/***  用户收藏/取消收藏文章*/collectArticleContent = (data: number) => {return http.put('/v1/article/collect?id=' + data)}/*** 查看我的点赞,最近100条*/getUserLike = (): Promise<Array<ArticleContentData>> => {return http.get('/v1/article/myLike')}/***查看我的收藏,最近100条*/getUserCollect = (): Promise<Array<ArticleContentData>> => {return http.get('/v1/article/myCollect')}/***分页查看最新文章*/getNewArticle = (data: ArticleContentNewPageParam): Promise<PageVo<ArticleContentData>> => {return http.get('/v1/article/new?page=' + data.page + '&&pageSize=' + data.pageSize + '&&title=' + data.title)}/***分页查看最热文章*/getHotArticle = (data: ArticleContentHotPageParam): Promise<PageVo<ArticleContentData>> => {return http.get('/v1/article/hot?page=' + data.page + '&&pageSize=' + data.pageSize + '&&title=' + data.title)}
}const articleContentApi = new ArticleContentApi();export default articleContentApi as ArticleContentApi;
/*** 时间*/
export interface BaseTime {/*** 创建时间*/createTime?: Date/*** 更新时间*/updateTime?: Date
}/*** 分页参数*/
export interface PageParam {/*** 当前页*/page?: number/*** 每一页展示的数据条数*/pageSize?: number
}/*** 分页响应参数*/
export interface PageVo<T> {current: number,size: number,total: number,records: Array<T>
}/*** 分页查询文章内容*/
export interface ArticleContentPageParam extends PageParam {/*** 标题*/title?: string/*** 内容分类:1鸿蒙 2 Java 3 web 4 运维*/contentCategory?: string/*** 平台分类:1学习平台 2面试题*/platformCategory?: string/*** 难度分类:1 简单 2 中等 3 困难*/difficultyCategory?: string
}/*** 分页查询最新文章内容入参*/
export interface ArticleContentNewPageParam extends PageParam {/*** 标题*/title: string}/*** 分页查询最热文章内容入参*/
export interface ArticleContentHotPageParam extends PageParam {/*** 标题*/title: string}/*** 文章内容数据*/
export interface ArticleContentData extends BaseTime {/*** 文章id*/id: number/*** 用户头像*/avatarUri: string/*** 用户昵称*/nickname: string/*** 文章标题*/title: string/*** 文章内容*/content: string/*** 阅读数*/readCount: number/*** 点赞数*/likeCount: number/*** 收藏数*/collectCount: number/*** 封面url*/coverUrl: string/*** 内容分类:1鸿蒙 2 Java 3 web 4 运维*/contentCategory: string/*** 平台分类:1学习平台 2面试题*/platformCategory: string/*** 难度分类:1 简单 2 中等 3 困难*/difficultyCategory: string/*** 用户是否点赞*/isLike: boolean/*** 用户是否收藏*/isCollect: boolean/*** 创建时间字符串格式*/time: string
}

文章详情界面布局

当我们点击文章的话会跳转到文章详情页面,携带当前点击的文章id

这边路由我们使用的是router.push()

1、新建文章详情页面

在ets/views/Home下面新建ArticleInfo.ets文件

2、设计图

3、需求分析

整个文章详情页面呈现的是使用Column布局的,里面分为多行,其他最上面标题我们可以使用Navigation组件做,鸿蒙官方推荐的,下面的文章内容按理说是渲染的html格式(富文本)的,所以我们使用RichText组件,还有点赞和收藏按理说有两种状态(未点赞、点赞,未收藏、收藏),整体文章数据也是根据路由跳转传过来的文章id进行查询的文章数据。

4、封装富文本组件

在components目录下面新建LearnRichText.ets文件

@Componentexport struct LearnRichText {// 富文本@Prop richTextContent: string = ""build() {Scroll() {RichText(`<html><body><div style="font-size:54px">${this.richTextContent}</div><body></html>`)}.layoutWeight(1)}}

5、整体代码
import { ArticleContentData } from '../../api/ArticleContentApi.type';
import { ArticleExtraInfoComponent } from '../../components/ArticleExtraInfoComponent'
import { LearnRichText } from '../../components/LearnRichText';
import { LoadingComponent } from '../../components/LoadingComponent';
import { CommonConstant } from '../../contants/CommonConstant'
import { router } from '@kit.ArkUI';
import articleContentApi from '../../api/ArticleContentApi';
import { showToast } from '../../utils/Toast';@Entry@Componentstruct ArticleInfo {// 文章数据数组@Prop articleInfo: ArticleContentData// 控制当前页面展示@State isShow: boolean = false// 文章id@State articleId: number = 1// 节流,防止用户重复点击isLoad: boolean = false/*** 生命周期函数*/async aboutToAppear() {// 获取路由传递的文章idconst param = router.getParams() as objectif (param) {this.articleId = param["articleId"] as number// 根据文章id查询文章数据this.articleInfo = await articleContentApi.getArticleContentInfo(this.articleId)// 展示数据this.isShow = true}}/*** 点赞* @param id*/async likeArticle(id: number) {// 点赞或者取消点赞if (this.articleInfo.isLike) {// 取消点赞await articleContentApi.likeArticleContent(id)this.articleInfo.isLike = falsethis.articleInfo.likeCount--this.isLoad = falseshowToast('取消点赞成功')} else {// 点赞await articleContentApi.likeArticleContent(id)this.articleInfo.isLike = truethis.articleInfo.likeCount++this.isLoad = falseshowToast('点赞成功')}}/*** 收藏* @param id*/async collectArticle(id: number) {// 收藏或者取消收藏if (this.articleInfo.isCollect) {// 取消收藏await articleContentApi.collectArticleContent(id)this.articleInfo.isCollect = falsethis.articleInfo.collectCount--this.isLoad = falseshowToast('取消收藏成功')} else {// 收藏await articleContentApi.collectArticleContent(id)this.articleInfo.isCollect = truethis.articleInfo.collectCount++this.isLoad = falseshowToast('收藏成功')}}build() {Navigation() {if (this.isShow) {Column({ space: 15 }) {Flex() {Text(this.articleInfo.title).fontSize($r('app.float.common_font_size_medium')).maxLines(3).textOverflow({ overflow: TextOverflow.Ellipsis }).fontColor(Color.Black).fontWeight(FontWeight.Medium)}Row({ space: 10 }) {// 头像Image(this.articleInfo.avatarUri).width(30).aspectRatio(1).borderRadius(20)// 昵称Text(this.articleInfo.nickname).fontSize($r('app.float.common_font_size_medium')).width('80%').maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis })}.width(CommonConstant.WIDTH_FULL)// 展示阅读、点赞、收藏数Row() {// 文章额外信息组件ArticleExtraInfoComponent({ articleInfo: this.articleInfo })Row({ space: 15 }) {// 点赞Image(this.articleInfo.isLike ? $r('app.media.icon_like_selected') : $r('app.media.icon_like_default')).width(15).onClick(() => {// 点赞if (!this.isLoad) {this.isLoad = truethis.likeArticle(this.articleInfo.id)}})// 收藏Image(this.articleInfo.isCollect ? $r('app.media.icon_collect_selected') :$r('app.media.icon_collect_default')).width(15).onClick(() => {// 收藏if (!this.isLoad) {this.isLoad = truethis.collectArticle(this.articleInfo.id)}})}}.width(CommonConstant.WIDTH_FULL).justifyContent(FlexAlign.SpaceBetween)}.padding($r('app.float.common_padding'))// 分割线Divider().strokeWidth((4)).color('#e6f2fe')// 内容正文LearnRichText({ richTextContent: this.articleInfo.content }).padding($r('app.float.common_padding'))} else {// 加载组件LoadingComponent()}}.height(CommonConstant.HEIGHT_FULL).width(CommonConstant.WIDTH_FULL).title($r('app.string.article_info_title')).titleMode(NavigationTitleMode.Mini).mode(NavigationMode.Stack).expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP])}
}
6、注意事项

当前系统除了登录、分页查询文章等部分接口,其他接口功能都是需要登录之后才可以使用的,这就是系统的权限控制,当前查询文章详情、收藏、点赞功能是需要登录得,未登录状态下使用是报错的。

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

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

相关文章

【测试篇】关于allpairs实现正交测试用例保姆级讲解,以及常见的错误问题

前言 &#x1f31f;&#x1f31f;本期讲解关于测试工具相关知识介绍~~~ &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 &#x1f525; 你的点赞就是小编不断更新的最大动力 &#x1f386;那么废话不多说…

OpenCV图像拼接(4)图像拼接模块的一个匹配器类cv::detail::BestOf2NearestRangeMatcher

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::detail::BestOf2NearestRangeMatcher 是 OpenCV 库中用于图像拼接模块的一个匹配器类&#xff0c;专门用于寻找两幅图像之间的最佳特征点匹配…

C++: AVL树(实现旋转操作)

前言 map/set容器有个共同点是&#xff1a;其底层都是按照二叉搜索树来实现的&#xff0c;但是二叉搜索树有其自身的缺陷&#xff0c;假如往树中插入的元素有序或者接近有序&#xff0c;二叉搜索树就会退化成单支树&#xff0c;时间复杂度会退化成O(N)&#xff0c;因此map、set…

OpenCV中距离公式

一、各类距离公式总结 常见距离公式 欧氏距离&#xff1a; 曼哈顿距离&#xff08;L1&#xff09;‌&#xff1a; 切比雪夫距离&#xff08;Chessboard&#xff09;‌&#xff1a; 1、点与点距离(欧氏距离) ‌二维空间‌ 设两点坐标为 P1(x1,y1)、P2(x2,y2)&#xff0c;其距离…

六十天前端强化训练之第二十四天之Vue 模板语法与 v-for 指令大师级详解

欢迎来到编程星辰海的博客讲解 看完可以给一个免费的三连吗&#xff0c;谢谢大佬&#xff01; 目录 一、模板语法与指令知识精讲 1.1 模板语法三大核心 1.2 常见指令全家福 1.3 v-for 深度解析 二、商品列表示例完整实现 2.1 完整可运行代码 2.2 代码解析 2.3 运行效果…

XSS跨站脚本攻击漏洞(Cross Site Scripting)

前提概要 本文章主要用于分享XSS跨站脚本攻击漏洞基础学习&#xff0c;以下是对XSS跨站脚本攻击漏洞的一些个人解析&#xff0c;请大家结合参考其他文章中的相关信息进行归纳和补充。 XSS跨站脚本攻击漏洞描述 跨站脚本攻击&#xff08;XSS&#xff09;漏洞是一种常见且危害较…

用ArcGIS做一张符合环评要求的植被类型图

植被类型图是环境影响评价&#xff08;环评&#xff09;中的重要图件&#xff0c;需满足数据准确性、制图规范性和信息完整性等要求。本教程将基于ArcMap平台&#xff0c;从数据准备到成果输出&#xff0c;详细讲解如何制作符合环评技术规范的植被类型图。 ArcGIS遥感解译土地…

详解string类+迭代器

迭代器 概念&#xff1a;在 C 中&#xff0c;迭代器是访问容器&#xff08;如数组、列表、向量、字符串等&#xff09;元素的一种方式。迭代器提供了一种统一的接口&#xff0c;使得你可以使用相同的代码来遍历不同类型的容器。迭代器本质上是一个指针或者指针的封装&#xff0…

Sqoop安装部署

Apache Sqoop 简介 Sqoop&#xff08;SQL-to-Hadoop&#xff09;是 Apache 开源项目&#xff0c;主要用于&#xff1a; 将关系型数据库中的数据导入 Hadoop 分布式文件系统&#xff08;HDFS&#xff09;或相关组件&#xff08;如 Hive、HBase&#xff09;。 将 Hadoop 处理后…

软件工程之软件验证计划Software Verification Plan

个人主页&#xff1a;云纳星辰怀自在 座右铭&#xff1a;“所谓坚持&#xff0c;就是觉得还有希望&#xff01;” 本文为基于ISO26262软件验证计划模板&#xff0c;仅供参考。 软件验证计划&#xff0c;包括&#xff1a; 1. 软件需求验证计划 2. 软件架构设计验证计划 3. 软件单…

Windows系统本地部署OpenManus对接Ollama调用本地AI大模型

文章目录 前言1. 环境准备1.1 安装Python1.2. 安装conda 2. 本地部署OpenManus2.1 创建一个新conda环境2.2 克隆存储库2.3 安装依赖环境 3. 安装Ollama4. 安装QwQ 32B模型5. 修改OpenManus配置文件6. 运行OpenManus7.通过网页使用OpenManus8. 安装内网穿透8.1 配置随机公网地址…

计算机网络总结

一、IP地址及子网掩码、MAC 二、DNS、ARP 三、DHCP、UDP、TCP 四、NAT、NAPT、端口、网关 五、路由器与交换机 六、OSI模型 一、IP地址及子网掩码、MAC 1.1 IP地址的作用 用来全局网络通信&#xff08;门牌号&#xff09;用来区分相同网络之间的主机 1.2 子网掩码的作用 …

MySQL0基础学习记录-下载与安装

下载 下载地址&#xff1a; &#xff08;Windows&#xff09;https://dev.mysql.com/downloads/file/?id536787 安装 直接点next&#xff0c;出现&#xff1a; 点execute 然后一直next到这页&#xff1a; next 然后需要给root设置一个密码&#xff1a; 在next。。很多页…

React基础语法速览

一、项目创建 npm create vite 这里选择react即可&#xff0c;如图&#xff1a; 二、基本文件说明 react函数式编程时&#xff0c;用的是JSX语法进行开发的&#xff0c;这里注意&#xff0c;return时只能有一个根标签&#xff1b; 三、React核心语法 1.插值功能 插值可以使用…

IT工具 | node.js 进程管理工具 PM2 大升级!支持 Bun.js

P(rocess)M(anager)2 是一个 node.js 下的进程管理器&#xff0c;内置负载均衡&#xff0c;支持应用自动重启&#xff0c;常用于生产环境运行 node.js 应用&#xff0c;非常好用&#x1f44d; &#x1f33c;概述 2025-03-15日&#xff0c;PM2发布最新版本v6.0.5&#xff0c;这…

teaming技术

一.介绍 在CentOS 6与RHEL 6系统中&#xff0c;双网卡绑定采用的是bonding技术。到了CentOS 7&#xff0c;不仅能继续沿用bonding&#xff0c;还新增了teaming技术。在此推荐使用teaming&#xff0c;因其在查看与监控方面更为便捷 。 二.原理 这里介绍两种最常见的双网卡绑定…

SpringSecurity配置(自定义认证过滤器)

文末有本篇文章的项目源码文件可供下载学习 在这个案例中,我们已经实现了自定义登录URI的操作,登录成功之后,我们再次访问后端中的API的时候要在请求头中携带token,此时的token是jwt字符串,我们需要将该jwt字符串进行解析,查看解析后的User对象是否处于登录状态.登录状态下,将…

【机器学习-模型评估】

“评估”已建立的模型 在进行回归和分类时&#xff0c;为了进行预测&#xff0c;定义了预测函数fθ(x) 然后根据训练数据求出了预测函数的参数θ(即对目标函数进行微分&#xff0c;然后求出参数更新表达式的操作) 之前求出参数更新表达式之后就结束了。但是&#xff0c;其实我…

区块链开发技术公司:引领数字经济的创新力量

在数字化浪潮席卷全球的今天&#xff0c;区块链技术作为新兴技术的代表&#xff0c;正以其独特的去中心化、不可篡改和透明性等特点&#xff0c;深刻改变着各行各业的发展格局。区块链开发技术公司&#xff0c;作为这一领域的先锋和推动者&#xff0c;正不断研发创新&#xff0…

油候插件、idea、VsCode插件推荐(自用)

开发软件&#xff1a; 之前的文章&#xff1a; 开发必装最实用工具软件与网站 推荐一下我使用的开发工具 目前在用的 油候插件 AC-baidu-重定向优化百度搜狗谷歌必应搜索_favicon_双列 让查询变成多列&#xff0c;而且可以流式翻页 Github 增强 - 高速下载 github下载 TimerHo…