HarmonyOS开发实战:如何实现一个运动排名榜页面

news2024/11/28 19:06:00

HarmonyOS开发实战:如何实现一个运动排名榜页面

代码仓库: 运动排名榜页面

项目介绍

本项目使用声明式语法和组件化基础知识,搭建一个可刷新的排行榜页面。在排行榜页面中,使用循环渲染控制语法来实现列表数据渲染,使用@Builder创建排行列表布局内容,使用装饰器@State、@Prop、@Link来管理组件状态。最后我们点击系统返回按键,来学习自定义组件生命周期函数。完成效果如图所示:

在这里插入图片描述

新建项目工程

选择Create Project新建项目,点击Application选择第一个Empty Ability应用,点击“Next”进行下一步
在这里插入图片描述
配置页中,详细信息如下:

Project name是开发者可以自行设置的项目名称,这里根据自己选择修改为自己项目名称。
Bundle name是包名称,默认情况下应用ID也会使用该名称,应用发布时对应的ID需要保持一致。
Save location为工程保存路径,建议用户自行设置相应位置。
Compile SDK是编译的API版本,这里默认选择API9。
Model选择Stage模型,其他保持默认即可。
点击“Finish”进行下一步
在这里插入图片描述

项目创建成功
在这里插入图片描述

代码实现

编写应用入口页面

RankPage是应用入口页面

@Entry
@Component
struct RankPage {
  @State message: string = 'My Ranking'

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
      }
      .width('100%')
    }
    .height('100%')
  }
}

修改EntryAbility.ts应用配置,入口页面更改为pages/RankPage
在这里插入图片描述
运行成功
在这里插入图片描述

编写公共常量

公共常量的好处包括:

  • 代码可读性: 使用公共常量可以提高代码的可读性和可维护性,因为它们可以清晰地表达出程序中使用的固定数值或字符串。
  • 便于修改和维护: 如果程序中的某个数值或字符串需要修改,只需修改公共常量的定义,而不需要在整个程序中逐个修改。
  • 避免魔法数值: 使用公共常量可以避免在代码中出现“魔法数值”,即难以理解和维护的硬编码数值。
  • 提高代码重用性: 公共常量可以在整个程序中被引用和使用,从而提高代码的重用性。
  • 统一管理: 将所有的固定数值或字符串集中管理在公共常量中,有利于统一管理和维护。
/**
 * The font size of application.
 */
export enum FontSize {
  SMALL = 14,
  MIDDLE = 16,
  LARGE = 20,
};

/**
 * The font weight of application.
 */
export enum FontWeight {
  BOLD = '400',
  BOLDER = '500',
};

/**
 * The weight is global default value for component size.
 */
export const WEIGHT = '100%';

/**
 * The duration of toast.
 */
export const TIME = 1000;

/**
 * The interval time of exit.
 */
export const APP_EXIT_INTERVAL: number = 4500;

/**
 * The tag is the page name,which is used to print.
 */
export const TAG: string = 'RankPage';

/**
 * The title of TitleComponent.
 */
export const TITLE: Resource = $r('app.string.title');

class style {
  RANK_PADDING: number = 15;
  CONTENT_WIDTH: string = '90%';
  BORDER_RADIUS: number = 20;
  STROKE_WIDTH: number = 1;
  HEADER_MARGIN_TOP: number = 20;
  HEADER_MARGIN_BOTTOM: number = 15;
  LIST_HEIGHT: string = '65%';
}

/**
 * The Style of RankPage.
 */
export const Style: style = {
  /**
   * The padding of ranking.
   */
  RANK_PADDING: 15,

  /**
   * The width of ranking content.
   */
  CONTENT_WIDTH: '90%',

  /**
   * The border radius.
   */
  BORDER_RADIUS: 20,

  /**
   * The stroke width of divider.
   */
  STROKE_WIDTH: 1,

  /**
   * The top margin of ranking header.
   */
  HEADER_MARGIN_TOP: 20,

  /**
   * The bottom margin of ranking header.
   */
  HEADER_MARGIN_BOTTOM: 15,

  /**
   * The height of list.
   */
  LIST_HEIGHT: '65%'
};

class listHeaderStyle {
  FONT_WEIGHT: number = 400;
  LAYOUT_WEIGHT_LEFT: string = '30%';
  LAYOUT_WEIGHT_CENTER: string = '50%';
  LAYOUT_WEIGHT_RIGHT: string = '20%';
}

/**
 * The Style of ListHeaderComponent.
 */
export const ListHeaderStyle: listHeaderStyle = {
  /**
   * The weight of font.
   */
  FONT_WEIGHT: 400,

  /**
   * The layout weight of left.
   */
  LAYOUT_WEIGHT_LEFT: '30%',

  /**
   * The layout weight of center.
   */
  LAYOUT_WEIGHT_CENTER: '50%',

  /**
   * The layout weight of right.
   */
  LAYOUT_WEIGHT_RIGHT: '20%',
};

class itemStyle {
  TEXT_LAYOUT_SIZE: number = 24;
  CIRCLE_TEXT_BORDER_RADIUS: number = 24;
  CIRCLE_TEXT_SIZE: number = 24;
  CIRCLE_TEXT_COLOR_STOP_1: number = 0.5;
  CIRCLE_TEXT_COLOR_STOP_2: number = 1.0;
  BAR_HEIGHT: number = 48;
  LAYOUT_WEIGHT_LEFT: string = '30%';
  LAYOUT_WEIGHT_CENTER: string = '50%';
  LAYOUT_WEIGHT_RIGHT: string = '20%';
  BORDER_WIDTH: number = 1;
  COLOR_GREEN: Resource = $r('app.color.item_color');
  COLOR_BLACK: Resource = $r('app.color.item_color_black');
}

/**
 * The Style of ListItemComponent.
 */
export const ItemStyle: itemStyle = {
  /**
   * The line height of text.
   */
  TEXT_LAYOUT_SIZE: 24,

  /**
   * The border radius of circle text.
   */
  CIRCLE_TEXT_BORDER_RADIUS: 24,

  /**
   * The size of circle text.
   */
  CIRCLE_TEXT_SIZE: 24,

  /**
   * Gradient color proportion.
   */
  CIRCLE_TEXT_COLOR_STOP_1: 0.5,

  /**
   * Gradient color proportion.
   */
  CIRCLE_TEXT_COLOR_STOP_2: 1.0,

  /**
   * The height of item.
   */
  BAR_HEIGHT: 48,

  /**
   * The layout weight of left.
   */
  LAYOUT_WEIGHT_LEFT: '30%',

  /**
   * The layout weight of center.
   */
  LAYOUT_WEIGHT_CENTER: '50%',

  /**
   * The layout weight of right.
   */
  LAYOUT_WEIGHT_RIGHT: '20%',

  /**
   * The width of border.
   */
  BORDER_WIDTH: 1,

  /**
   * The green color of item.
   */
  COLOR_GREEN: $r('app.color.item_color'),

  /**
   * The black color of item.
   */
  COLOR_BLACK: $r('app.color.item_color_black')
};

class titleBarStyle {
  IMAGE_BACK_SIZE: number = 21;
  IMAGE_BACK_MARGIN_RIGHT: number = 18;
  IMAGE_LOADING_SIZE: number = 22;
  BAR_HEIGHT: number = 47;
  BAR_MARGIN_HORIZONTAL: number = 26;
  BAR_MARGIN_TOP: number = 10;
  WEIGHT: string = '50%';
}

/**
 * The Style of TitleComponent.
 */
export const TitleBarStyle: titleBarStyle = {
  /**
   * The image size of back button.
   */
  IMAGE_BACK_SIZE: 21,

  /**
   * The right margin of back button.
   */
  IMAGE_BACK_MARGIN_RIGHT: 18,

  /**
   * The size of loading image.
   */
  IMAGE_LOADING_SIZE: 22,

  /**
   * The height of TitleComponent.
   */
  BAR_HEIGHT: 47,

  /**
   * The horizontal margin of TitleComponent.
   */
  BAR_MARGIN_HORIZONTAL: 26,

  /**
   * The top margin of TitleComponent.
   */
  BAR_MARGIN_TOP: 10,

  /**
   * The weight of Row layout.
   */
  WEIGHT: '50%',
};

静态资源

静态资源从代码仓库去获取
在这里插入图片描述

实现标题组件

TitleComponent.ets代码实现

import AppContext from '@ohos.app.ability.common';
import { FontSize, TitleBarStyle, WEIGHT } from '../common/constants/Constants';

// 标题组件
@Component
export struct TitleComponent {
  @Link isRefreshData: boolean; // 是否刷新数据
  @State title: Resource = $r('app.string.title_default'); // 标题

  build() {
    Row() {
      Row() {
        // 返回箭头
        Image($r('app.media.ic_public_back'))
          .height(TitleBarStyle.IMAGE_BACK_SIZE) // 高度
          .width(TitleBarStyle.IMAGE_BACK_SIZE) // 宽度
          .margin({ right: TitleBarStyle.IMAGE_BACK_MARGIN_RIGHT }) // 外边距
          .onClick(() => { // 返回上一个界面
            let handler = getContext(this) as AppContext.UIAbilityContext;
            handler.terminateSelf();
          })
        Text(this.title) // 标题
          .fontSize(FontSize.LARGE)
      }
      .width(TitleBarStyle.WEIGHT)
      .height(WEIGHT)
      .justifyContent(FlexAlign.Start) // 水平起始位置对齐

      // 刷新图标
      Row() {
        Image($r('app.media.loading'))
          .height(TitleBarStyle.IMAGE_LOADING_SIZE)
          .width(TitleBarStyle.IMAGE_LOADING_SIZE)
          .onClick(() => { // 点击刷新列表数据
            this.isRefreshData = !this.isRefreshData;
          })
      }
      .width(TitleBarStyle.WEIGHT)
      .height(WEIGHT)
      .justifyContent(FlexAlign.End)
    }
    .width(WEIGHT)
    .padding({ left: TitleBarStyle.BAR_MARGIN_HORIZONTAL,
      right: TitleBarStyle.BAR_MARGIN_HORIZONTAL })
    .margin({ top: TitleBarStyle.BAR_MARGIN_TOP })
    .height(TitleBarStyle.BAR_HEIGHT)
    .justifyContent(FlexAlign.SpaceAround)
  }
}

应用入口页RankPage引入TitleComponent组件

import { APP_EXIT_INTERVAL, Style, TIME, TITLE, WEIGHT } from '../common/constants/Constants';
import { TitleComponent } from '../view/TitleComponent';

@Entry
@Component
struct RankPage {

  @State isSwitchDataSource: boolean = true; // 是否切换数据源

  build() {
    Column() {
      // 标题
      TitleComponent({ isRefreshData: $isSwitchDataSource, title: TITLE })
    }
  }
}

运行代码:
在这里插入图片描述

实现列表头部

ListHeaderComponent .ets代码实现

import { FontSize, ListHeaderStyle } from '../common/constants/Constants';

@Component
export struct ListHeaderComponent {
  paddingValue: Padding | Length = 0; // 内边距
  widthValue: Length = 0; // 宽度

  build() {
    Row() {
      Text('排名')
        .fontSize(FontSize.SMALL) // 字体大小
        .width(ListHeaderStyle.LAYOUT_WEIGHT_LEFT) // 宽度
        .fontWeight(ListHeaderStyle.FONT_WEIGHT) // 字体宽度
        .fontColor($r('app.color.font_description')) // 字体颜色
      Text('姓名')
        .fontSize(FontSize.SMALL)
        .width(ListHeaderStyle.LAYOUT_WEIGHT_CENTER)
        .fontWeight(ListHeaderStyle.FONT_WEIGHT)
        .fontColor($r('app.color.font_description'))
      Text('步数')
        .fontSize(FontSize.SMALL)
        .width(ListHeaderStyle.LAYOUT_WEIGHT_RIGHT)
        .fontWeight(ListHeaderStyle.FONT_WEIGHT)
        .fontColor($r('app.color.font_description'))
    }
    .width(this.widthValue) // 宽度
    .padding(this.paddingValue) // 内边距
  }
}

应用入口页RankPage引入ListHeaderComponent 组件

import { APP_EXIT_INTERVAL, Style, TIME, TITLE, WEIGHT } from '../common/constants/Constants';
import { TitleComponent } from '../view/TitleComponent';
import { ListHeaderComponent } from '../view/ListHeaderComponent';

@Entry
@Component
struct RankPage {

  @State isSwitchDataSource: boolean = true; // 是否切换数据源

  build() {
    Column() {
      // 标题
      TitleComponent({ isRefreshData: $isSwitchDataSource, title: TITLE })
      // 列表头部
      ListHeaderComponent({
        paddingValue: {
          left: Style.RANK_PADDING,
          right: Style.RANK_PADDING
        },
        widthValue: Style.CONTENT_WIDTH
      })
        .margin({ // 外边距
          top: Style.HEADER_MARGIN_TOP,
          bottom: Style.HEADER_MARGIN_BOTTOM
        })
    }
  }
}

运行代码:
在这里插入图片描述

准备排名榜数据

RankData.ets 排序类

// 排名类
export class RankData {
  name: string; // 姓名
  stepNum: string; // 步数
  id: string;

  // 构造函数
  constructor(id: string, name: string, stepNum: string) {
    this.id = id;
    this.name = name;
    this.stepNum = stepNum;
  }
}

DataModel.ets初始化排名数据

import { RankData } from '../viewmodel/RankData';

export { rankData1, rankData2 }

// 初始化排名数据1
const rankData1: RankData[] = [
  new RankData('1', '喜羊羊', '12080'),
  new RankData('2', '美羊羊', '10320'),
  new RankData('3', '灰太狼', '9801'),
  new RankData('4', '红太狼', '8431'),
  new RankData('5', '懒羊羊', '7546'),
  new RankData('6', '暖羊羊', '7431'),
  new RankData('7', '沸羊羊', '7187'),
  new RankData('8', '蕉太狼', '7003'),
  new RankData('9', '小灰灰', '6794'),
  new RankData('10', '慢羊羊', '6721')
];

// 初始化排名数据2
const rankData2: RankData[] = [
  new RankData('11', '曹操', '8836'),
  new RankData('12', '马超', '8521'),
  new RankData('13', '关羽', '8431'),
  new RankData('14', '吕布', '7909'),
  new RankData('15', '张飞', '7547'),
  new RankData('16', '赵云', '7433'),
  new RankData('17', '刘备', '7186'),
  new RankData('18', '孙策', '7023'),
  new RankData('19', '黄忠', '6794'),
  new RankData('20', '许褚', '6721')
];

RankViewModel.ets获取排序数据

import { RankData } from './RankData';
import { rankData1, rankData2 } from '../model/DataModel';

// 获取排序数据
export class RankViewModel {
  loadRankDataSource1(): RankData[] {
    return rankData1;
  }

  loadRankDataSource2(): RankData[] {
    return rankData2;
  }
}

RankPage.ets引入排名数据源

  • let rankModel: RankViewModel = new RankViewModel();
  • 通过aboutToAppear函数初始化数据源
import { RankViewModel } from '../viewmodel/RankViewModel';
import { RankData } from '../viewmodel/RankData';
import { APP_EXIT_INTERVAL, Style, TIME, TITLE, WEIGHT } from '../common/constants/Constants';
import { TitleComponent } from '../view/TitleComponent';
import { ListHeaderComponent } from '../view/ListHeaderComponent';

let rankModel: RankViewModel = new RankViewModel();

@Entry
@Component
struct RankPage {

  @State dataSource1: RankData[] = [];
  @State dataSource2: RankData[] = [];
  @State isSwitchDataSource: boolean = true; // 是否切换数据源

  // 初始化数据源
  aboutToAppear() {
    this.dataSource1 = rankModel.loadRankDataSource1();
    this.dataSource2 = rankModel.loadRankDataSource2();
  }

  build() {
    Column() {
      // 标题
      TitleComponent({ isRefreshData: $isSwitchDataSource, title: TITLE })
      // 列表头部
      ListHeaderComponent({
        paddingValue: {
          left: Style.RANK_PADDING,
          right: Style.RANK_PADDING
        },
        widthValue: Style.CONTENT_WIDTH
      })
        .margin({ // 外边距
          top: Style.HEADER_MARGIN_TOP,
          bottom: Style.HEADER_MARGIN_BOTTOM
        })
    }
  }
}

实现排名列表

ListItemComponent .ets代码实现

import { FontSize, FontWeight, ItemStyle, WEIGHT } from '../common/constants/Constants';

@Component
export struct ListItemComponent {
  index?: number;
  private name?: string;
  stepNum: string = '';
  @State isChange: boolean = false;

  build() {
    Row() {
      // 排名
      Column() {
          if (this.isRenderCircleText()) {
            this.CircleText(this.index);
          } else {
            Text(this.index?.toString())
              .lineHeight(ItemStyle.TEXT_LAYOUT_SIZE) // 行高
              .textAlign(TextAlign.Center) // 文本居中
              .width(ItemStyle.TEXT_LAYOUT_SIZE) // 宽度
              .fontWeight(FontWeight.BOLD) // 字体宽度
              .fontSize(FontSize.SMALL) // 字体大小
          }
      }
      .width(ItemStyle.LAYOUT_WEIGHT_LEFT) // 宽度
      .alignItems(HorizontalAlign.Start) // 垂直起始位置对齐

      // 姓名
      Text(this.name)
        .width(ItemStyle.LAYOUT_WEIGHT_CENTER)
        .fontWeight(FontWeight.BOLDER)
        .fontSize(FontSize.MIDDLE)
        // ture:绿色字体,false:黑色字体
        .fontColor(this.isChange ? ItemStyle.COLOR_GREEN : ItemStyle.COLOR_BLACK)
      // 步数
      Text(this.stepNum)
        .width(ItemStyle.LAYOUT_WEIGHT_RIGHT)
        .fontWeight(FontWeight.BOLD)
        .fontSize(FontSize.SMALL)
        .fontColor(this.isChange ? ItemStyle.COLOR_GREEN : ItemStyle.COLOR_BLACK)
    }
    .height(ItemStyle.BAR_HEIGHT)
    .width(WEIGHT)
    .onClick(() => { // 点击事件
      this.isChange = !this.isChange;
    })
  }

  // 圆圈背景
  @Builder CircleText(index: number) {
    Row() {
      Text(this.index?.toString())
        .fontWeight(FontWeight.BOLD)
        .fontSize(FontSize.SMALL)
        .fontColor(Color.White);
    }
    .justifyContent(FlexAlign.Center)
    .borderRadius(ItemStyle.CIRCLE_TEXT_BORDER_RADIUS)
    .size({ width: ItemStyle.CIRCLE_TEXT_SIZE,
      height: ItemStyle.CIRCLE_TEXT_SIZE })
    .backgroundColor($r('app.color.circle_text_background'))
  }

  // 是否显示圆圈
  isRenderCircleText(): boolean {
    return this.index === 1 || this.index === 2 || this.index === 3;
  }
}

应用入口页RankPage引入ListItemComponent组件

  • @Builder RankList装饰的方法用于定义组件的声明式UI描述,在一个自定义组件内快速生成多个布局内容。
import { RankViewModel } from '../viewmodel/RankViewModel';
import { RankData } from '../viewmodel/RankData';
import { APP_EXIT_INTERVAL, Style, TIME, TITLE, WEIGHT } from '../common/constants/Constants';
import { TitleComponent } from '../view/TitleComponent';
import { ListHeaderComponent } from '../view/ListHeaderComponent';
import { ListItemComponent } from '../view/ListItemComponent';

let rankModel: RankViewModel = new RankViewModel();

@Entry
@Component
struct RankPage {

  @State dataSource1: RankData[] = [];
  @State dataSource2: RankData[] = [];
  @State isSwitchDataSource: boolean = true; // 是否切换数据源

  // 初始化数据源
  aboutToAppear() {
    this.dataSource1 = rankModel.loadRankDataSource1();
    this.dataSource2 = rankModel.loadRankDataSource2();
  }

  build() {
    Column() {
      // 标题
      TitleComponent({ isRefreshData: $isSwitchDataSource, title: TITLE })
      // 列表头部
      ListHeaderComponent({
        paddingValue: {
          left: Style.RANK_PADDING,
          right: Style.RANK_PADDING
        },
        widthValue: Style.CONTENT_WIDTH
      })
        .margin({ // 外边距
          top: Style.HEADER_MARGIN_TOP,
          bottom: Style.HEADER_MARGIN_BOTTOM
        })
      // 排名列表
      this.RankList(Style.CONTENT_WIDTH)
    }
    .backgroundColor($r('app.color.background')) // 背景色
    .height(WEIGHT) // 高度
    .width(WEIGHT) // 宽度
  }

  @Builder RankList(widthValue: Length) {
    Column() {
      List() { // 列表
        ForEach(this.isSwitchDataSource ? this.dataSource1 : this.dataSource2,
          (item: RankData, index?: number) => {
            ListItem() {
              ListItemComponent({ index: (Number(index) + 1), name: item.name, stepNum: item.stepNum})
            }
          }, (item: RankData) => JSON.stringify(item))
      }
      .width(WEIGHT) // 宽度
      .height(Style.LIST_HEIGHT) // 高度
      .divider({ strokeWidth: Style.STROKE_WIDTH }) // 分割线
    }
    .padding({ // 内边距
      left: Style.RANK_PADDING,
      right: Style.RANK_PADDING
    })
    .borderRadius(Style.BORDER_RADIUS) // 边框半径
    .width(widthValue) // 宽度
    .alignItems(HorizontalAlign.Center) // 垂直居中对齐
    .backgroundColor(Color.White) // 背景色
  }
}

运行代码:
在这里插入图片描述
刷新列表:
在这里插入图片描述

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

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

相关文章

PyCharm community 安装教程

目录 链接cudatoolkit 下载地址:https://www.jetbrains.com/pycharm/download/other.html 双击打开 安装路径,可自行更换到D盘 不导入设置 链接cudatoolkit

雪花算法(几种常见的雪花算法生成ID方案简单介绍:Hutool、百度Uid-Generator、美团Leaf、Yitter)

文章目录 1.生成id的几种方式2. 雪花算法2.1 雪花算法介绍2.2 市面上几种雪花算法的实现2.2.1 hutool版2.2.1.1 hutool版本雪花算法 关于时钟回拨的处理: ---------------百度UidGenerator 介绍开始--------------2.2.2 百度版:[UidGenerator](https://g…

【动态规划精选题目】2、路径问题模型

此动态规划系列主要讲解大约10个系列【后续持续更新】 本篇讲解路径问题模型中的6道经典题,会在讲解题目同时给出AC代码 目录 1、不同路径 2、不同路径2 3、珠宝的最大价值 4、下降路径最小和 5、最小路径和 6、地下城游戏 1、不同路径 class Solution { publi…

二叉树前,中序推后续_中,后续推前序

文章目录 介绍思路例子 介绍 二叉树是由根、左子树、右子树三部分组成。 二叉树的遍历方式又可以分为前序遍历,中序遍历,后序遍历。 前序遍历:根,左子树,右子树 中序遍历:左子树,根&#xff0…

Tor网络原理详解

引入 匿名通信是一种通过采用数据转发、内容加密、流量混淆等措施来隐藏通信内容及关系的隐私保护技术。为了提高通信的匿名性,这些数据转发链路通常由多跳加密代理服务节点构成,而所有这些节点即构成了匿名通信系统(或称匿名通信网络&#…

ReenterLock重入锁

synchronized就是一种最简单的控制方法,它决定了一个线程释放可以访问临界区资源。 同时,Object.wait()方法和Object.notify()方法起到了线程等待和通知的作用。 ReenterLock重入锁可以完全替代关键字Synchoronized.重入锁是Synchoronized、Object.wait(…

使用podman管理容器

目录 1.安装及配置podman 2.镜像的命名 3.对镜像重新做标签 4.删除镜像 5.查看镜像的层结构 6.导出和导入镜像 7.创建容器 8.创建一个简单的容器 9.容器的生命周期 10.创建临时容器 11.指定容器中运行的命令 12.创建容器时使用变量 对于初学者来说,不太容易理…

深入解析HashMap数据结构及其应用

目录 引言 1. HashMap简介 2. 哈希表的基本原理 3. HashMap的内部结构 4. 哈希冲突的处理 5. HashMap的常见操作 6. HashMap的性能优化 7. 实际应用场景 结论 引言 在计算机科学中,数据结构是构建和组织数据的一种方式,而HashMap是其中一种常用…

TCP单人聊天

TCP和UDP两种通信方式它们都有着自己的优点和缺点 这两种通讯方式不通的地方就是TCP是一对一通信 UDP是一对多的通信方式 TCP通信 TCP通信方式呢 主要的通讯方式是一对一的通讯方式,也有着优点和缺点 它的优点对比于UDP来说就是可靠一点 因为它的通讯方式是需…

ripro后台登录后转圈和图标不显示的原因及解决方法

最近,好多小伙伴使用ripro主题的小伙伴们都发现,登录后台后,进入主题设置就转圈,等待老半天后好不容易显示页面了,却发现图标不显示了,都统一显示为方框。 这是因为后台的js、css这类静态资源托管用的是js…

02-分组查询group by和having的使用

分组查询 MySQL中默认是对整张表的数据进行操作即整张表为一组, 如果想对每一组的数据进行操作,这个时候我们需要使用分组查询 分组函数的执行顺序: 先根据where条件筛选数据,然后对查询到的数据进行分组,最后也可以采用having关键字过滤取得正确的数据 group by子句 在一条…

FME之FeatureReader转换器按表格内容读取矢量数据

问题:平时会遇到只用某个大数据里某小部分数据参与下一步数据处理,此时我们会用到FeatureReader转换器,一般是通过空间关系(相交、包含)来读取相应涉及的图斑矢量,但就有一个问题,加入你的启动器…

JS中浅拷贝和深拷贝

本篇文章咱们一起来学习下JS中的浅拷贝和深拷贝,了解它们在内存上的区别,并掌握浅拷贝和深拷贝的常用实现方法。 引用赋值 在学习拷贝之前,咱们先来看一个常见的情景,如下图: 大家觉得这是深拷贝还是浅拷贝&#xff0…

ensp创建配置环境,实现全网互访

文章目录 创建配置环境,实现全网互访配置步骤接入层交换机(sw4、sw5)划分vlan汇聚层交换机(sw2、sw3)配置ip地址作为vlan网关、与sw1 ip地址直连核心层交换机(sw1)配置ip地址与汇聚层交换机&…

计算机网络:数据链路层(VLAN)

今天又学到一个知识,加油! 目录 一、传统局域网的局限(促进VLAN的诞生) 二、VLAN简介 三、VLAN的实现 总结 一、传统局域网的局限(促进VLAN的诞生) 缺乏流量隔离:即使把组流量局域化道一个单一交换机中…

Java小案例-RocketMQ的11种消息类型,你知道几种?(请求应答消息)

前言 Rocket的请求应答消息是指在使用Rocket(这里可能是RocketMQ或者Rocket框架)进行通信时,客户端发送一个请求到服务端,然后服务端处理该请求并返回一个响应的过程中的数据交换。 在RocketMQ中: 请求应答消息通常…

MySQL性能测试(完整版)

MySQL性能测试之SysBench 一、SysBench安装 1、mac安装命令:(其他系统安装对应的命令即可,不影响后面的使用) brew install sysbench2、查看是否安装成功; sysbench --version附: (1&#x…

The Grid – Responsive WordPress Grid响应式网格插件

点击阅读The Grid – Responsive WordPress Grid响应式网格插件原文 The Grid – Responsive WordPress Grid响应式网格插件是一个高级 wordpress 网格插件,它允许您在完全可定制且响应迅速的网格系统中展示任何自定义帖子类型。 Grid WordPress 非常适合展示您的博…

runCatching异常捕获onSuccess/onFailure返回函数,Kotlin

runCatching异常捕获onSuccess/onFailure返回函数,Kotlin fun test(a: Int, b: Int) {runCatching {a / b}.onSuccess {println("onSuccess: $it")return ok(it)}.onFailure {println("onFailure: $it")return fail(it)} }fun ok(o: Any) {prin…

QT第一步

文章目录 软件下载软件安装QT的程序组新建项目 软件下载 qt下载网址:https://download.qt.io/archive/qt/   关于版本:     我选择的版本是5.14.2,这个版本是最后的二进制安装包的版本,在往后的版本就需要在线安装了。并且5…