账号密码保存
======

密码保险箱在应用的登录、注册、修改密码等场景中具备自动保存用户名和密码的能力。

保存后的用户名和密码可以在下次登录、修改密码时自动填充到界面上的对应输入框，用户可以在密码保险箱内对已保存的用户名和密码进行查看，修改，添加备注，删除。

当应用界面触发账号密码自动保存时，若密码保险箱中不存在同应用下的相同账号，系统将弹出账号密码保存提示框，用户点击“保存密码”按钮后，本次使用的账号和密码将被保存至密码保险箱。

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/cf/v3/ZYIttRlYR-Wb56bS1k-bDw/zh-cn_image_0000002594668586.png?HW-CC-KV=V1&HW-CC-Date=20260612T073353Z&HW-CC-Expire=86400&HW-CC-Sign=C11E2B6C5CACF5FDD66107E458B1A131FC50AB23280CCA9DB3AB9D3C7C67F36F)

当应用触发账号登录或注册时，均可触发保存功能，以下分别介绍两种布局的标准适配场景。

**触发条件及注意事项：**

1.  **已设置锁屏密码**，并且开启密码保险箱中“自动填充和保存”开关。
    
2.  界面中TextInput输入框组件的enableAutoFill属性的值应为true（默认为true）。
    
3.  密码保险箱的自动保存功能只适用于用户名和密码保存场景，在界面中必须同时存在用户名和密码的TextInput输入框组件。具体类型请参考[输入框类型说明](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/passwordvault-quick-adaptation#约束与限制)。
    
    用户名输入框应设置type属性为InputType.USER\_NAME。
    
    密码输入框应设置type属性为InputType.Password或InputType.NEW\_PASSWORD。
    
    其中，InputType.Password表示普通密码输入框，适用于登录界面的密码和修改密码界面的旧密码。
    
    InputType.NEW\_PASSWORD表示新密码输入框，适用于注册界面和修改密码界面的新密码。
    
4.  用户名和密码输入框中需要输入内容，不能为空也不能超长。用户名长度不能超过128字符，密码长度不能超过256字符。
    
5.  页面跳转时触发保存功能。
    
6.  在只有type为InputType.USER\_NAME和InputType.Password的两个TextInput组件时，如果使用[账号密码填充-修改密码](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/passwordvault-autofill-acc-password#修改密码)自动填充了用户名和密码并没有修改，则不会触发保存和更新功能。
    

#### 账号密码登录

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/11/v3/5ee281bwTwCJn3i8Axa2aA/zh-cn_image_0000002594828514.png?HW-CC-KV=V1&HW-CC-Date=20260612T073353Z&HW-CC-Expire=86400&HW-CC-Sign=069A3F01F066DE84EF69874AD6297F18337F86E7AD7A9ED0DE032D162C5646D0)

示例代码如下：

@Entry
@Component
struct LoginExample {
  pathInfos: NavPathStack = new NavPathStack();
  @State ReserveAccount: string = '';
  @State ReservePassword: string = '';

  @Builder
  PageMap(name: string) {
    if (name === 'home\_page') {
      HomePage()
    }
  }

  build() {
    Navigation(this.pathInfos) {
      Column({ space: 16 }) {
        Text("账户登录").commonTitleStyles()

        TextInput({ placeholder: '用户名' })
          .commonInputStyles()
          .type(InputType.USER\_NAME) // 账号框使用USER\_NAME属性
          .onChange((value: string) => {
            this.ReserveAccount = value;
          })

        TextInput({ placeholder: '密码' })
          .showPasswordIcon(true)
          .commonInputStyles()
          .type(InputType.Password) // 密码框使用Password属性
          .onChange((value: string) => {
            this.ReservePassword = value;
          })

        Button('登录')
          .width('100%')
          .enabled((this.ReserveAccount !== '') && (this.ReservePassword !== ''))
          .onClick(() => {
            this.pathInfos.pushPathByName('home\_page', null)
          })
      }
      .padding(16)
    }
    .navDestination(this.PageMap)
    .height('100%')
    .width('100%')
  }
}

@Component
struct HomePage {
  pathInfos: NavPathStack = new NavPathStack();

  build() {
    NavDestination() {
      Column() {
        Text("Home Page").commonTitleStyles()
      }.width('100%').height('100%')
    }.title("Home Page")
    .onReady((context: NavDestinationContext) => {
      this.pathInfos = context.pathStack;
    })
  }
}

@Extend(Text)
function commonTitleStyles() {
  .fontSize(24)
  .fontColor('#000000')
  .fontWeight(FontWeight.Medium)
  .margin({ top: 24, bottom: 16 })
}

@Extend(TextInput)
function commonInputStyles() {
  .placeholderColor(0x182431)
  .width('100%')
  .opacity(0.6)
  .placeholderFont({ size: 16, weight: FontWeight.Regular })
  .margin({ top: 16 })
}

@Extend(Button)
function commonButtonStyles() {
  .width('100%')
  .height(40)
  .borderRadius(20)
  .margin({ top: 24 })
}

#### 账号密码注册

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/b1/v3/26DeSKOyT6edgzd00rtJug/zh-cn_image_0000002625187961.png?HW-CC-KV=V1&HW-CC-Date=20260612T073353Z&HW-CC-Expire=86400&HW-CC-Sign=00EFFA5544A2D63D910513FAD7C5ADF04DA84BD4E37403B3CAD0405B65AEB909)

示例代码如下：

@Entry
@Component
struct RegisterExample {
  pathInfos: NavPathStack = new NavPathStack();
  @State ReserveAccount: string = '';
  @State ReservePassword: string = '';
  @State enableAutoFill: boolean = true;

  onBackPress() {
    // 当非成功登录、返回等页面跳转时，将enableAutoFill设置为false，密码保险箱将不启用自动填充功能
    this.enableAutoFill = false;
    return false;
  }

  @Builder
  PageMap(name: string) {
    if (name === 'register\_result\_page') {
      RegisterResultPage()
    }
  }

  build() {
    Navigation(this.pathInfos) {
      Column() {
        Text("注册账号")
          .commonTitleStyles()

        TextInput({ placeholder: '用户名' })
          .commonInputStyles()
          .type(InputType.USER\_NAME) // 账号框使用USER\_NAME属性
          .onChange((value: string) => {
            this.ReserveAccount = value;
          })

        TextInput({ placeholder: '新密码' })
          .showPasswordIcon(true)
          .commonInputStyles()
          .type(InputType.NEW\_PASSWORD) // 密码框使用NEW\_PASSWORD属性，可以触发生成强密码。
          .enableAutoFill(this.enableAutoFill)
          .passwordRules('begin:\[upper\],special:\[yes\],len:\[maxlen:32,minlen:12\]')
          .onChange((value: string) => {
            this.ReservePassword = value;
          })

        Button('页面跳转')
          .commonButtonStyles()
          .enabled((this.ReserveAccount !== '') && (this.ReservePassword !== ''))
          .onClick(() => {
            this.pathInfos.pushPathByName('register\_result\_page', null)
          })

        Button('页面跳转（跳转前关闭autofill）')
          .commonButtonStyles()
          .enabled((this.ReserveAccount !== '') && (this.ReservePassword !== ''))
          .onClick(() => {
            this.enableAutoFill = false;
            this.pathInfos.pushPathByName('register\_result\_page', null)
          })
      }
    }
    .navDestination(this.PageMap)
    .height('100%')
    .width('100%')
  }
}

@Component
struct RegisterResultPage {
  pathInfos: NavPathStack = new NavPathStack();

  build() {
    NavDestination() {
      Column() {
        Text("Result Page").commonTitleStyles()
      }.width('100%').height('100%')
    }.title("Result Page")
    .onReady((context: NavDestinationContext) => {
      this.pathInfos = context.pathStack;
    })
  }
}

@Extend(Text)
function commonTitleStyles() {
  .fontSize(24)
  .fontColor('#000000')
  .fontWeight(FontWeight.Medium)
  .margin({ top: 24, bottom: 16 })
}

@Extend(TextInput)
function commonInputStyles() {
  .placeholderColor(0x182431)
  .width('100%')
  .opacity(0.6)
  .placeholderFont({ size: 16, weight: FontWeight.Regular })
  .margin({ top: 16 })
}

@Extend(Button)
function commonButtonStyles() {
  .width('100%')
  .height(40)
  .borderRadius(20)
  .margin({ top: 24 })
}