【问题标题】:Vuejs html checkbox check state not updated correctlyVuejs html复选框检查状态未正确更新
【发布时间】:2021-10-05 06:04:41
【问题描述】:

在使某些复选框正常工作时遇到问题。所以在我的组件中,我在状态变量tokenPermissions 中设置了一个对象数组,看起来像这样

tokenPermissions: [
        {
          groupName: "App",
          allSelected: false,
          someSelected: false,
          summary: "Full access to all project operations",
          permissions: [
            {
              name: "can_create_app",
              summary: "Create new projects",
              selected: false,
            },
            {
              name: "can_delete_app",
              summary: "Delete existing projects",
              selected: false,
            },
            {
              name: "can_edit_app",
              summary: "Edit an existing project",
              selected: false,
            },
          ],
        }
      ],

我们的目标是遍历这个数组,并让父复选框和子复选框像 tokenPermissions[i].allSelected 绑定到父复选框,并为 tokenPermissions[i].permissions 中的每个对象绑定到 selected 属性的相应复选框,就像这样 @987654327 @。

选中父复选框时的期望行为,

  1. 如果选中所有子复选框,则取消选中所有复选框,包括父复选框
  2. 如果未选中子复选框,则检查所有复选框,包括父复选框
  3. 如果只选择了部分子复选框,父级将显示不确定的- 图标或符号,并在单击时取消选中包括父级在内的所有子复选框。

问题是第 3 点。问题是有时未根据绑定到的属性的状态正确检查父复选框。例如allSelected 可以是false,但父复选框被选中。

我在这里https://github.com/oaks-view/vuejs-checkbox-issue在github上放了一个完整的工作示例。

绑定的部分代码如下

<ul
      class="list-group"
      v-for="(permissionGroup, permissionGroupIndex) in tokenPermissions"
      :key="`${permissionGroup.groupName}_${permissionGroupIndex}`"
    >
      <li class="list-group-item">
        <div class="permission-container">
          <div>
            <input
              type="checkbox"
              :indeterminate.prop="
                !permissionGroup.allSelected && permissionGroup.someSelected
              "
              v-model="permissionGroup.allSelected"
              :id="permissionGroup.groupName"
              v-on:change="
                permissionGroupCheckboxChanged($event, permissionGroupIndex)
              "
            />
            <label :for="permissionGroup.groupName" class="cursor-pointer"
              >{{ permissionGroup.groupName }} -
              <span style="color: red; margin-left: 14px; padding-right: 3px">{{
                permissionGroup.allSelected
              }}</span></label
            >
          </div>
          <div class="permission-summary">
            {{ permissionGroup.summary }}
          </div>
        </div>
        <ul class="list-group">
          <li
            class="list-group-item list-group-item-no-margin"
            v-for="(permission, permissionIndex) in permissionGroup.permissions"
            :key="`${permissionGroup.groupName}_${permission.name}_${permissionIndex}`"
          >
            <div class="permission-container">
              <div>
                <input
                  type="checkbox"
                  :id="permission.name"
                  v-bind:checked="permission.selected"
                  v-on:change="
                    permissionGroupCheckboxChanged(
                      $event,
                      permissionGroupIndex,
                      permissionIndex
                    )
                  "
                />
                <label :for="permission.name" class="cursor-pointer"
                  >{{ permission.name
                  }}<span
                    style="color: red; margin-left: 3px; padding-right: 3px"
                    >&nbsp; {{ permission.selected }}</span
                  ></label
                >
              </div>
              <div class="permission-summary">
                {{ permission.summary }}
              </div>
            </div>
          </li>
        </ul>
      </li>
    </ul>

以及用于更新复选框

    getPermissionGroupSelectionStatus: function (permissionGroup) {
      let allSelected = true;
      let someSelected = false;

      permissionGroup.permissions.forEach((permission) => {
        if (permission.selected === false) {
          allSelected = false;
        }
        if (permission.selected === true) {
          someSelected = true;
        }
      });

      return { allSelected, someSelected };
    },
    permissionGroupCheckboxChanged: function (
      $event,
      permissionGroupIndex,
      permissionIndex
    ) {
      const { checked } = $event.target;

      // its single permission selected
      if (permissionIndex !== undefined) {
        this.tokenPermissions[permissionGroupIndex].permissions[
          permissionIndex
        ].selected = checked;

        const { allSelected, someSelected } =
          this.getPermissionGroupSelectionStatus(
            this.tokenPermissions[permissionGroupIndex]
          );

        this.tokenPermissions[permissionGroupIndex].allSelected = allSelected;
        this.tokenPermissions[permissionGroupIndex].someSelected = someSelected;
      } else {
        // its selectAll check box
        const { allSelected, someSelected } =
          this.getPermissionGroupSelectionStatus(
            this.tokenPermissions[permissionGroupIndex]
          );

        let checkAll;

        // no checkbox / permission is selected then set all
        if (!someSelected && !allSelected) {
          checkAll = true;
        } else {
          checkAll = false;
        }

        this.tokenPermissions[permissionGroupIndex].allSelected = checkAll;
        this.tokenPermissions[permissionGroupIndex].someSelected = checkAll;

        for (
          let i = 0;
          i < this.tokenPermissions[permissionGroupIndex].permissions.length;
          i++
        ) {
          this.tokenPermissions[permissionGroupIndex].permissions[i].selected =
            checkAll;
        }
      }
    },

【问题讨论】:

    标签: javascript html vue.js checkbox


    【解决方案1】:

    这是一个渲染问题。 Vue 将allSelected 复选框设置为选中,然后在同一循环中将其更新为false;您可以在此处阅读有关 Vue 生命周期的信息:https://it.vuejs.org/v2/guide/instance.html

    一种非常残酷(但简单)的解决方法(我不建议这样做,但了解正在发生的事情很有用)是延迟更新。

    this.$nextTick包裹方法permissionGroupCheckboxChanged的最后一部分:

    this.$nextTick(() => {
            this.tokenPermissions[permissionGroupIndex].allSelected = checkAll;
          this.tokenPermissions[permissionGroupIndex].someSelected = checkAll;
    
          for (
            let i = 0;
            i < this.tokenPermissions[permissionGroupIndex].permissions.length;
            i++
          ) {
            this.tokenPermissions[permissionGroupIndex].permissions[i].selected =
              checkAll;
          }
        })
    

    这样,当您更改值时,引擎会做出相应的反应。 我仍然不推荐它(我认为nextTick 有助于理解 Vue 生命周期,但我建议尽可能不要使用它)。


    checkAll 不为真permissionGroupCheckboxChanged 时,将allSelected 设置为null 而不是false,一种不那么残酷(也更简单)的方法:

    // this
    this.tokenPermissions[permissionGroupIndex].allSelected = checkAll ? checkAll : null;
    
    // instead of this
    this.tokenPermissions[permissionGroupIndex].allSelected = checkAll;
    

    这样,道具就战胜了模型(模型值变为null)。


    但更好的选择(恕我直言)是在v-for 循环内使用它自己的组件,并将allSelectedsomeSelected 作为计算属性,而不是绑定到实变量的值。 通常,当可以从真实数据中推断出 ui 状态时,通常不应将其存储为数据(我可能是错的,因为我不知道您的应用程序,但在您的情况下,我怀疑您对单个复选框的值感兴趣,而 @ 987654337@/someSelected仅用于ui)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-14
      • 1970-01-01
      • 2013-06-12
      • 1970-01-01
      • 1970-01-01
      • 2017-10-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多