鸿蒙NEXT开发案例:随机密码生成

b14.gif

【引言】

本案例将实现一个随机密码生成器。用户可以自定义密码的长度以及包含的字符类型(大写字母、小写字母、数字、特殊字符),最后通过点击按钮生成密码,并提供一键复制功能。

【环境准备】

•操作系统:Windows 10
•开发工具:DevEco Studio NEXT Beta1 Build Version: 5.0.3.806
•目标设备:华为Mate60 Pro
•开发语言:ArkTS
•框架:ArkUI
•API版本:API 12

【项目结构】

本项目主要由一个入口组件PasswordGeneratorPage和一个可观察的类PasswordOption组成。PasswordOption类用于定义密码选项,包括选项名称、字符集、是否选中和是否启用的状态。

  1. PasswordOption类
@ObservedV2
class PasswordOption {
  name: string; // 选项名称
  characters: string; // 该选项对应的字符集
  @Trace selected: boolean = true; // 是否选中,默认为true
  @Trace enabled: boolean = true; // 是否启用,默认为true

  constructor(name: string, characters: string) {
    this.name = name;
    this.characters = characters;
  }
}
  1. PasswordGeneratorPage组件
    该组件包含密码选项、密码长度设置、生成密码和复制密码的功能。
@Entry
@Component
struct PasswordGeneratorPage {
  @State options: PasswordOption[] = [
    new PasswordOption("大写字母", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
    new PasswordOption("小写字母", "abcdefghijklmnopqrstuvwxyz"),
    new PasswordOption("数字", "0123456789"),
    new PasswordOption("特殊字符", "!@#$%^&*()_+-=[]{}|;:,.<>?"),
  ];
  @State passwordLength: number = 10; // 默认密码长度
  @State generatedPassword: string = ''; // 生成的密码

  // 生成密码的方法
  generatePassword() {
    let characterSet = '';
    for (let option of this.options) {
      if (option.selected) {
        characterSet += option.characters;
      }
    }
    let password = '';
    for (let i = 0; i < this.passwordLength; i++) {
      const randomIndex = Math.floor(Math.random() * characterSet.length);
      password += characterSet[randomIndex];
    }
    this.generatedPassword = password;
  }

  // 复制到剪贴板的方法
  copyToClipboard(text: string) {
    const pasteboardData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, text);
    const systemPasteboard = pasteboard.getSystemPasteboard();
    systemPasteboard.setData(pasteboardData);
    promptAction.showToast({ message: '已复制' });
  }

  // 构建页面布局的方法
  build() {
    // 页面布局代码...
  }
}

功能实现

  1. 生成密码
    用户可以选择不同的字符集(大写字母、小写字母、数字、特殊字符),并设置密码长度。点击“生成密码”按钮后,系统将根据选中的选项生成随机密码。

  2. 复制密码
    生成的密码可以通过点击“复制”按钮复制到剪贴板,用户将收到“已复制”的提示。

用户界面
用户界面采用了简洁的设计,包含标题、密码长度设置、选项选择、生成密码按钮和复制按钮。通过动态生成选项的UI元素,用户可以方便地选择所需的字符集。

总结
本文介绍了如何使用鸿蒙NEXT框架开发一个随机密码生成器。通过简单的代码实现,我们可以快速构建出实用的功能。希望这个案例能为你的开发提供灵感和帮助。

【完整代码】

// 导入剪贴板服务
import { pasteboard } from '@kit.BasicServicesKit';
// 导入弹窗提示服务
import { promptAction } from '@kit.ArkUI';

// 使用装饰器定义一个可观察的类,用于密码选项
@ObservedV2
class PasswordOption {
  name: string; // 选项名称
  characters: string; // 该选项对应的字符集
  // 定义是否选中,默认为true
  @Trace selected: boolean = true;
  // 定义是否启用,默认为true
  @Trace enabled: boolean = true;

  // 构造函数,初始化name和characters
  constructor(name: string, characters: string) {
    this.name = name;
    this.characters = characters;
  }
}

// 使用装饰器定义一个入口组件
@Entry
@Component
struct PasswordGeneratorPage {
  // 定义密码选项数组
  @State options: PasswordOption[] = [
    new PasswordOption("大写字母", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
    new PasswordOption("小写字母", "abcdefghijklmnopqrstuvwxyz"),
    new PasswordOption("数字", "0123456789"),
    new PasswordOption("特殊字符", "!@#$%^&*()_+-=[]{}|;:,.<>?"),
  ];
  // 定义密码长度状态,默认值为10
  @State passwordLength: number = 10;
  // 基础间距
  @State baseSpacing: number = 30;
  // 生成的密码
  @State generatedPassword: string = '';
  // 是否启用复制按钮
  @State isCopyButtonEnabled: boolean = false;
  // 主题色
  @State primaryColor: string = '#71dec7';
  // 字体颜色
  @State fontColor: string = "#2e2e2e";

  // 生成密码的方法
  generatePassword() {
    let characterSet = ''; // 初始化字符集合
    // 遍历所有选项,如果选项被选中则加入字符集合
    for (let option of this.options) {
      if (option.selected) {
        characterSet += option.characters
      }
    }
    let password = ''; // 初始化密码字符串
    // 根据密码长度生成随机密码
    for (let i = 0; i < this.passwordLength; i++) {
      const randomIndex = Math.floor(Math.random() * characterSet.length);
      password += characterSet[randomIndex];
    }
    this.generatedPassword = password; // 更新生成的密码
  }

  // 复制到剪贴板的方法
  copyToClipboard(text: string) {
    const pasteboardData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, text); // 创建剪贴板数据
    const systemPasteboard = pasteboard.getSystemPasteboard(); // 获取系统剪贴板
    systemPasteboard.setData(pasteboardData); // 将数据放入剪切板
    promptAction.showToast({ message: '已复制' }); // 显示复制成功的提示
  }

  // 检查选项选择状态的方法
  checkOptionsSelection() {
    let selectedCount = 0; // 记录已选中的选项数量
    let lastSelectedIndex = 0; // 记录最后一个选中的选项索引
    // 遍历所有选项
    for (let i = 0; i < this.options.length; i++) {
      this.options[i].enabled = true; // 默认启用所有选项
      if (this.options[i].selected) {
        lastSelectedIndex = i; // 更新最后一个选中的选项索引
        selectedCount++; // 增加选中计数
      }
    }
    // 如果只有一个选项被选中,则禁用该选项防止其被取消选中
    if (selectedCount === 1) {
      this.options[lastSelectedIndex].enabled = false;
    }
  }

  // 构建页面布局的方法
  build() {
    Column() {
      // 标题栏
      Text("随机密码生成")
        .width('100%')// 设置宽度为100%
        .height(54)// 设置高度为54
        .fontSize(18)// 设置字体大小
        .fontWeight(600)// 设置字体粗细
        .backgroundColor(Color.White)// 设置背景颜色
        .textAlign(TextAlign.Center)// 设置文本居中对齐
        .fontColor(this.fontColor); // 设置字体颜色

      // 密码长度设置部分
      Column() {
        Row() {
          Text(`密码长度:`)// 密码长度标签
            .fontWeight(600)
            .fontSize(18)
            .fontColor(this.fontColor);
          Text(`${this.passwordLength}`)// 显示当前密码长度
            .fontWeight(600)
            .fontSize(18)
            .fontColor(this.primaryColor);
        }
        .margin({ top: `${this.baseSpacing}lpx`, left: `${this.baseSpacing}lpx` });

        // 滑动条设置密码长度
        Row() {
          Text('4').fontColor(this.fontColor).width(20);
          Slider({
            value: this.passwordLength, // 当前值
            min: 4, // 最小值
            max: 32, // 最大值
            style: SliderStyle.InSet // 滑动条样式
          })
            .layoutWeight(1)// 布局权重
            .blockColor(Color.White)// 滑块颜色
            .trackColor('#EBEBEB')// 轨道颜色
            .trackThickness(30)// 轨道厚度
            .blockSize({ width: 55, height: 55 })// 滑块大小
            .selectedColor(this.primaryColor)// 选中颜色
            .onChange((value: number, mode: SliderChangeMode) => {
              this.passwordLength = value; // 更新密码长度
              console.info('value:' + value + 'mode' + mode.toString); // 打印日志
            });
          Text('32').fontColor(this.fontColor).width(20);
        }.margin({
          left: `${this.baseSpacing}lpx`,
          right: `${this.baseSpacing}lpx`,
          top: `${this.baseSpacing}lpx`,
        });

        // 选项设置部分
        Text('选项')
          .fontWeight(600)
          .fontSize(18)
          .fontColor(this.fontColor)
          .margin({ left: `${this.baseSpacing}lpx`, top: `${this.baseSpacing}lpx`, bottom: `${this.baseSpacing}lpx` });

        // 动态生成每个选项的UI元素
        ForEach(this.options, (option: PasswordOption, index: number) => {
          Row() {
            Text(option.name)// 选项名称
              .fontWeight(400)
              .fontSize(16)
              .fontColor(this.fontColor)
              .layoutWeight(1);
            Toggle({ type: ToggleType.Switch, isOn: option.selected })// 切换按钮
              .width('100lpx')
              .height('50lpx')
              .enabled(option.enabled)// 是否启用切换
              .selectedColor(this.primaryColor)
              .onChange((isOn: boolean) => {
                option.selected = isOn; // 更新选项状态
                this.checkOptionsSelection(); // 检查选项选择状态
              });
          }
          .width('100%')
          .padding({
            left: `${this.baseSpacing}lpx`,
            right: `${this.baseSpacing}lpx`,
            top: `${this.baseSpacing / 3}lpx`,
            bottom: `${this.baseSpacing / 3}lpx`
          })
          .hitTestBehavior(HitTestMode.Block)
          .onClick(() => {
            if (option.enabled) {
              option.selected = !option.selected; // 切换选项状态
            }
          });
        });

        // 生成密码按钮
        Text('生成密码')
          .fontColor(Color.White)
          .backgroundColor(this.primaryColor)
          .height(54)
          .textAlign(TextAlign.Center)
          .borderRadius(10)
          .fontSize(18)
          .width(`${650 - this.baseSpacing * 2}lpx`)
          .margin({
            top: `${this.baseSpacing}lpx`,
            left: `${this.baseSpacing}lpx`,
            right: `${this.baseSpacing}lpx`,
            bottom: `${this.baseSpacing}lpx`
          })
          .clickEffect({ level: ClickEffectLevel.HEAVY, scale: 0.8 })// 点击效果
          .onClick(() => {
            this.generatePassword(); // 生成密码
          });
      }
      .width('650lpx')
      .margin({ top: 20 })
      .backgroundColor(Color.White)
      .borderRadius(10)
      .alignItems(HorizontalAlign.Start);

      // 显示生成的密码
      Column() {
        Text(`密码结果:`)
          .fontWeight(600)
          .fontSize(18)
          .fontColor(this.fontColor)
          .margin({
            top: `${this.baseSpacing}lpx`,
            left: `${this.baseSpacing}lpx`,
          });
        Text(`${this.generatedPassword}`)// 显示生成的密码
          .width('650lpx')
          .fontColor(this.primaryColor)
          .fontSize(18)
          .textAlign(TextAlign.Center)
          .padding({ left: 5, right: 5 })
          .margin({
            top: `${this.baseSpacing / 3}lpx`
          });

        // 复制按钮
        Text('复制')
          .enabled(this.generatedPassword ? true : false)// 只有生成了密码才启用复制按钮
          .fontColor(Color.White)
          .backgroundColor(this.primaryColor)
          .height(54)
          .textAlign(TextAlign.Center)
          .borderRadius(10)
          .fontSize(18)
          .width(`${650 - this.baseSpacing * 2}lpx`)
          .margin({
            top: `${this.baseSpacing}lpx`,
            left: `${this.baseSpacing}lpx`,
            right: `${this.baseSpacing}lpx`,
            bottom: `${this.baseSpacing}lpx`
          })
          .clickEffect({ level: ClickEffectLevel.HEAVY, scale: 0.8 })
          .onClick(() => {
            this.copyToClipboard(this.generatedPassword); // 复制密码
          });
      }
      .width('650lpx')
      .backgroundColor(Color.White)
      .borderRadius(10)
      .margin({ top: `${this.baseSpacing}lpx` })
      .alignItems(HorizontalAlign.Start);
    }
    .height('100%')
    .width('100%')
    .backgroundColor("#f2f3f5"); // 页面背景颜色
  }
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,923评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,154评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,775评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,960评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,976评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,972评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,893评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,709评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,159评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,400评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,552评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,265评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,876评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,528评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,701评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,552评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,451评论 2 352

推荐阅读更多精彩内容