如何在每个表单元素的状态上更新嵌套数据结构的正确属性,该嵌套数据结构是嵌套表单元素DOM的模型?

发布于 2025-02-03 12:08:05 字数 1761 浏览 4 评论 0原文

我想在JavaScript中修改深嵌套对象中的属性,然后返回修改后的对象。对于例如,我在应用程序中渲染复选框,结构如下所示,

{
    level1: {
    name: 'Level 1',
    key: 'level1',
    checked: false,
    subLevels: {
      level2: {
        name: 'Level 2',
        key: 'level2',
        checked: false,
        subLevels: {
          level3: {
            name: 'Level 3',
            key: 'level3',
            checked: true,
          },
          level4: {
            name: 'Level 4',
            key: 'level4',
            checked: false,
          }
        }
      }
    }
  }
}

我正在呈现上述结构,如下所示,

现在,如果用户单击任何复选框,我想用更新的状态返回修改后的对象,因此,如果用户单击 Level4 复选框,我想要下面要返回的对象。另外,我的密钥与检查复选框相对应,因此,对于上述方案,我有' level4 '。

{
    level1: {
    name: 'Level 1',
    key: 'level1',
    checked: false,
    subLevels: {
      level2: {
        name: 'Level 2',
        key: 'level2',
        checked: false,
        subLevels: {
          level3: {
            name: 'Level 3',
            key: 'level3',
            checked: true,
          },
          level4: {
            name: 'Level 4',
            key: 'level4',
            checked: true,
          }
        }
      }
    }
  }
}

我编写了以下功能来修改值,但是在返回新对象方面面临困难。另外,该物体可以将其深深嵌套到任何层次上,

function changeVal(obj, checkedKey) {
    for(const key in obj) {
        if(key === 'subLevels' && typeof obj.subLevels === 'object') {
            changeVal(obj[key].subLevels);
        } 
        if(key === checkedKey) {
            obj[key].checked = !obj[key].checked;
        } 
    }
}

您可以帮忙吗?

I want to modify a property in deeply nested object in Javascript and return the modified object. For eg, I am rendering checkboxes in my application and the structure looks like below,

{
    level1: {
    name: 'Level 1',
    key: 'level1',
    checked: false,
    subLevels: {
      level2: {
        name: 'Level 2',
        key: 'level2',
        checked: false,
        subLevels: {
          level3: {
            name: 'Level 3',
            key: 'level3',
            checked: true,
          },
          level4: {
            name: 'Level 4',
            key: 'level4',
            checked: false,
          }
        }
      }
    }
  }
}

I am rendering the above structure like below,
Rendered checkboxes

Now, if a user clicks on any of the checkboxes, I want to return the modified object with the updated state, so let's say if the user clicked on level4 checkbox, I want the below object to be returned. Also, I have the key corresponding to the checked checkbox, so for above scenario, i have 'level4'.

{
    level1: {
    name: 'Level 1',
    key: 'level1',
    checked: false,
    subLevels: {
      level2: {
        name: 'Level 2',
        key: 'level2',
        checked: false,
        subLevels: {
          level3: {
            name: 'Level 3',
            key: 'level3',
            checked: true,
          },
          level4: {
            name: 'Level 4',
            key: 'level4',
            checked: true,
          }
        }
      }
    }
  }
}

I wrote the below function to modify the value, but facing difficulty in returning a new object. Also, the object could be deeply nested to any level,

function changeVal(obj, checkedKey) {
    for(const key in obj) {
        if(key === 'subLevels' && typeof obj.subLevels === 'object') {
            changeVal(obj[key].subLevels);
        } 
        if(key === checkedKey) {
            obj[key].checked = !obj[key].checked;
        } 
    }
}

Could you please help out?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

庆幸我还是我 2025-02-10 12:08:05

下面介绍的是实现预期目标的一种可能方法。

代码片段

const myUpdate = (obj, k) => (
  [k] in obj
    ? obj[k].checked = !obj[k].checked
    : Object.values(obj).forEach(
        v => myUpdate(v?.subLevels ?? {}, k)
      ),
  obj
);

/* EXPLANATION of the code ---
// method to update a "cloned" object
// the caller passes a deep-cloned object
// by using "structuredClone()"
const myUpdate = (obj, k) => {
  // if "k" (say "level4") is in "obj"
  if ([k] in obj) {
  // just flip the "checked" prop (false to true, or vice-versa)
    obj[k].checked = !obj[k].checked
  } else {
  // else, recursive call using the "subLevels" prop
  // if there are no values in obj or no "subLevels"
  // simply pass empty object for recursion
    Object.values(obj).forEach(
      v => myUpdate(v?.subLevels ?? {}, k)
    )
  };
  // always return "obj"
  return obj;
};
*/

const dataObj = {
    level1: {
    name: 'Level 1',
    key: 'level1',
    checked: false,
    subLevels: {
      level2: {
        name: 'Level 2',
        key: 'level2',
        checked: false,
        subLevels: {
          level3: {
            name: 'Level 3',
            key: 'level3',
            checked: true,
          },
          level4: {
            name: 'Level 4',
            key: 'level4',
            checked: false,
          }
        }
      }
    }
  }
};

console.log(
  '\n\n setting level-4 to true :\n',
  myUpdate(structuredClone(dataObj), 'level4'),
  '\n\n setting level-3 to false :\n',
  myUpdate(structuredClone(dataObj), 'level3'),
  '\n\nand now the existing obj, un-altered:\n',
  dataObj,
);
.as-console-wrapper { max-height: 100% !important; top: 0 }

解释评论

上以上片段中添加了评论。

Presented below is one possible way to achieve the desired objective.

Code Snippet

const myUpdate = (obj, k) => (
  [k] in obj
    ? obj[k].checked = !obj[k].checked
    : Object.values(obj).forEach(
        v => myUpdate(v?.subLevels ?? {}, k)
      ),
  obj
);

/* EXPLANATION of the code ---
// method to update a "cloned" object
// the caller passes a deep-cloned object
// by using "structuredClone()"
const myUpdate = (obj, k) => {
  // if "k" (say "level4") is in "obj"
  if ([k] in obj) {
  // just flip the "checked" prop (false to true, or vice-versa)
    obj[k].checked = !obj[k].checked
  } else {
  // else, recursive call using the "subLevels" prop
  // if there are no values in obj or no "subLevels"
  // simply pass empty object for recursion
    Object.values(obj).forEach(
      v => myUpdate(v?.subLevels ?? {}, k)
    )
  };
  // always return "obj"
  return obj;
};
*/

const dataObj = {
    level1: {
    name: 'Level 1',
    key: 'level1',
    checked: false,
    subLevels: {
      level2: {
        name: 'Level 2',
        key: 'level2',
        checked: false,
        subLevels: {
          level3: {
            name: 'Level 3',
            key: 'level3',
            checked: true,
          },
          level4: {
            name: 'Level 4',
            key: 'level4',
            checked: false,
          }
        }
      }
    }
  }
};

console.log(
  '\n\n setting level-4 to true :\n',
  myUpdate(structuredClone(dataObj), 'level4'),
  '\n\n setting level-3 to false :\n',
  myUpdate(structuredClone(dataObj), 'level3'),
  '\n\nand now the existing obj, un-altered:\n',
  dataObj,
);
.as-console-wrapper { max-height: 100% !important; top: 0 }

Explanation

Comments added to the snippet above.

杀お生予夺 2025-02-10 12:08:05

以下示例代码提供了基于视图模型的方法的香草实现,该方法启用了双向状态变更...它是...(1)视图变更更新视图模型,(2)View-Model触发状态 - 更改更新视图。

主函数名为createControlViewModel,根据提供的嵌套形式控制的圆顶结构创建嵌套的视图模型。

由于实现遵循一些通用规则,因此可以从不同/变化的HTML标记创建视图模型。它最重要的特征是嵌套模型不是递归构建的。但是基于...

  • 另外提供的控件特定选择器
  • 和一个针对每个控件的父组件/节点的选择器,

...每个控件的嵌套层次结构级别可以以更灵活的/通用方式来识别,并相比固定的蓝图模型。后者将不允许在HTML标记的内部和/或种类内进行任何灵活性。

一个人还可以提供属性/属性名称的列表,这些名称预先定义了一个想要成为双向状态变更处理的键。

// +++ proof of concept / demo related code +++

// returns control specific pure model-data (according to the OP's model)
// from the control specific view-model.
function createCurrentChangeSnapshot({ node, children, ...modelData }) {
  return { ...modelData };
}
// returns the pure overall model-data (according to the OP's model)
// from the overall view-model.
function createOverallModelSnapshot(model) {
  return Object
    .entries(model)
    .reduce((snapshot, [key, value]) => {
      const { node, children = null, ...modelData } = value;

      snapshot[key] = { ...modelData };
      
      if (children !== null) {
        Object
          .assign(snapshot[key], {
            children: createOverallModelSnapshot(children)
          });
      }
      return snapshot;
    }, {});
}

// proof of concept related logging.
function logModelSnapshots(viewModel, { model }) {
  // console.log({ model });

  const overallModel = createOverallModelSnapshot(viewModel);
  const currentChange = createCurrentChangeSnapshot(model);

  console.log({ snapshots: { currentChange, overallModel } });
}


// +++ model and view implementation related code +++

function handleViewStateChange(root, model, mutation) {
  const { target, attributeName, oldValue: recentValue = null } = mutation;
  root.dispatchEvent(
    new CustomEvent('view:state:change', {
      detail: {
        model,
        target,  
        ...(
          (recentValue === null)
          // omit `recentValue` and alias `attributeName` as `propertyName`
          // in case mutation observer was not involved in the state change.
            ? { propertyName: attributeName }
            : { recentValue, attributeName }
        ),
      }
    })
  );
}

function applyViewToModelHandling(model, key, control, root) {
  // an 'attributes' type mutation does not cover an element's
  // property state change like `checked` for radio/checkbox
  // controls or even a form control's `value` change ...
  const observer = new MutationObserver(
    (mutationList/*, observer*/) => {
      mutationList.forEach(mutation => {
      debugger;
        if (
          mutation.type === 'attributes' &&
          mutation.attributeName === key
        ) {
          handleViewStateChange(root, model, mutation);
        }
      });
    }
  );
  observer.observe(control, { attributes: true });

  // ... thus in order to compensate PROPERTY state changes 
  // which are left unhandled by observing ATTRIBUTES mutations,
  // a form control additionally listens to an 'input' event and
  // forwards the change to a common view-state change-handler.
  control
    .addEventListener('input', ({ currentTarget }) =>
      handleViewStateChange(
        root, model, { target: currentTarget, attributeName: key },
      )
    );
}
function applyModelToViewHandling(model, key, control) {
  Object.defineProperty(model, key, {
    get() { return control[key]; },
    set(value) { control[key] = value; },
    enumerable: true,
  });
}

function applyStateChangeHandlingToBoundContext(key) {
  const { root, model } = this;
  const { node: control } = model;

  applyModelToViewHandling(model, key, control);
  applyViewToModelHandling(model, key, control, root);
}
function enableStateChangeHandling(root, model, propertyNames) {
  propertyNames
    .forEach(applyStateChangeHandlingToBoundContext, { root, model });
}

/**
 *  - The main function creates a nested view-model according
 *    to the provided nested form-control's DOM-structure.
 *  - Since the implementation follows some generic rules, one can
 *    create view-models from different/varying HTML markup.
 *  - Its most important feature is that the nested model is not
 *    build recursively. But based on ...
 *     - an additionally provided control specific selector
 *     - and an additionally provided selector which targets
 *       each control's parent component/node,
 *    ... the nested hierarchy level of each control can be
 *    identified in a far more flexible/generic way in comparison
 *    to a fixed blueprint model. The latter would not allow any
 *    flexibility within and/or variety of the HTML markup.
 * - One also can provide a list of property/attribute names which
 *   predefine the keys one wants to be part of the bidirectional
 *   state change handling.
 */
function createControlViewModel(
  root,
  controlSelector,
  parentComponentSelector,
  propertyNames,
) {
  const modelStorage = new Map;

  const controlList = [
    ...root
      .querySelectorAll(controlSelector)
  ];
  const viewModel = controlList
    .reduce((modelRoot, control) => {

      const parentComponent = control
        .closest(parentComponentSelector)
        ?.parentElement
        ?.closest(parentComponentSelector);

      // retrieve model data from control.
      const { name: key, dataset: { name } } = control;

      // create control specific view-model.
      const controlModel = { node: control, key, name };

      // store the control specific view-model
      // by the control element's reference.
      modelStorage.set(control, controlModel);

      // enable bidirectional state change
      // handling for any specified property.
      enableStateChangeHandling(root, controlModel, propertyNames);

      if (!parentComponent || !root.contains(parentComponent)) {

        // first level controls within root.
        modelRoot[key] = controlModel;

      } else {
        const parentControl = parentComponent
          .querySelector(controlSelector);

        // retrieve parent control model from view-model storage.
        const parentControlModel = modelStorage.get(parentControl);

        // child level controls of related parent.
        (parentControlModel.children ??= {})[key] = controlModel;

      // use `children` rather than the OP's `subLevels` property name.
      // (parentControlModel.subLevels ??= {})[key] = controlModel;
      }
      return modelRoot;

    }, {});

  // proof of concept related logging.
  console.log({ controlList, viewModel });
  root
    .addEventListener(
      'view:state:change',
      ({ detail }) => logModelSnapshots(viewModel, detail),
    );

  return viewModel;
}


// +++ proof of concept / demo +++

const viewModel = createControlViewModel(
  document.body,
  'li > label > [type="checkbox"]',
  'li',
  ['checked'],
);

// - change view states, here the checkbox control's
//   `checked` properties via the overall view model.
viewModel['level-1-a']
  .children['level-2-a']
  .children['level-3-b'].checked = true;

viewModel['level-1-a']
  .children['level-2-b'].checked = true;

viewModel['level-1-b']
  .checked = true;
body { margin: 0; }
ul { margin: 0; padding: 0 0 0 20px; }
.as-console-wrapper { left: auto!important; width: 75%; min-height: 100%!important; }
<ul>
  <li>

    <label>
      <input
        type="checkbox"
        name="level-1-a"
        data-name="Level 1 a"
      >
      <span class="label">
        Level 1 a
      </span>
    </label>

    <ul>
      <li>

        <label>
          <input
            type="checkbox"
            name="level-2-a" 
            data-name="Level 2 a"
          >
          <span class="label">
            Level 2 a
          </span>
        </label>

        <ul>
          <li>

            <label>
              <input
                type="checkbox"
                name="level-3-a"
                data-name="Level 3 a"
              >
              <span class="label">
                Level 3 a
              </span>
            </label>

          </li>
          <li>

            <label>
              <input
                type="checkbox"
                name="level-3-b"
                data-name="Level 3 b"
              >
              <span class="label">
                Level 3 b
              </span>
            </label>

          </li>
        </ul>

      </li>
      <li>

        <label>
          <input
            type="checkbox"
            name="level-2-b"
            data-name="Level 2 b"
          >
          <span class="label">
            Level 2 b
          </span>
        </label>

      </li>
    </ul>
    
  </li>
  <li>

    <label>
      <input
        type="checkbox"
        name="level-1-b"
        data-name="Level 1 b"
      >
      <span class="label">
        Level 1 b
      </span>
    </label>
    
  </li>
</ul>

The following example code provides a vanilla-implementation of a view-model based approach which enables bidirectional state-changes ... which is ... (1) view-changes update the view-model and (2) view-model triggered state-changes update the view.

The main function, named createControlViewModel, creates a nested view-model according to the provided nested form-control's DOM-structure.

Since the implementation follows some generic rules, one can create view-models from different/varying HTML markup. Its most important feature is that the nested model is not build recursively. But based on ...

  • an additionally provided control specific selector
  • and an additionally provided selector which targets each control's parent component/node,

... the nested hierarchy level of each control can be identified in a far more flexible/generic way in comparison to a fixed blueprint model. The latter would not allow any flexibility within and/or variety of the HTML markup.

One also can provide a list of property/attribute names which predefine the keys one wants to be part of the bidirectional state change handling.

// +++ proof of concept / demo related code +++

// returns control specific pure model-data (according to the OP's model)
// from the control specific view-model.
function createCurrentChangeSnapshot({ node, children, ...modelData }) {
  return { ...modelData };
}
// returns the pure overall model-data (according to the OP's model)
// from the overall view-model.
function createOverallModelSnapshot(model) {
  return Object
    .entries(model)
    .reduce((snapshot, [key, value]) => {
      const { node, children = null, ...modelData } = value;

      snapshot[key] = { ...modelData };
      
      if (children !== null) {
        Object
          .assign(snapshot[key], {
            children: createOverallModelSnapshot(children)
          });
      }
      return snapshot;
    }, {});
}

// proof of concept related logging.
function logModelSnapshots(viewModel, { model }) {
  // console.log({ model });

  const overallModel = createOverallModelSnapshot(viewModel);
  const currentChange = createCurrentChangeSnapshot(model);

  console.log({ snapshots: { currentChange, overallModel } });
}


// +++ model and view implementation related code +++

function handleViewStateChange(root, model, mutation) {
  const { target, attributeName, oldValue: recentValue = null } = mutation;
  root.dispatchEvent(
    new CustomEvent('view:state:change', {
      detail: {
        model,
        target,  
        ...(
          (recentValue === null)
          // omit `recentValue` and alias `attributeName` as `propertyName`
          // in case mutation observer was not involved in the state change.
            ? { propertyName: attributeName }
            : { recentValue, attributeName }
        ),
      }
    })
  );
}

function applyViewToModelHandling(model, key, control, root) {
  // an 'attributes' type mutation does not cover an element's
  // property state change like `checked` for radio/checkbox
  // controls or even a form control's `value` change ...
  const observer = new MutationObserver(
    (mutationList/*, observer*/) => {
      mutationList.forEach(mutation => {
      debugger;
        if (
          mutation.type === 'attributes' &&
          mutation.attributeName === key
        ) {
          handleViewStateChange(root, model, mutation);
        }
      });
    }
  );
  observer.observe(control, { attributes: true });

  // ... thus in order to compensate PROPERTY state changes 
  // which are left unhandled by observing ATTRIBUTES mutations,
  // a form control additionally listens to an 'input' event and
  // forwards the change to a common view-state change-handler.
  control
    .addEventListener('input', ({ currentTarget }) =>
      handleViewStateChange(
        root, model, { target: currentTarget, attributeName: key },
      )
    );
}
function applyModelToViewHandling(model, key, control) {
  Object.defineProperty(model, key, {
    get() { return control[key]; },
    set(value) { control[key] = value; },
    enumerable: true,
  });
}

function applyStateChangeHandlingToBoundContext(key) {
  const { root, model } = this;
  const { node: control } = model;

  applyModelToViewHandling(model, key, control);
  applyViewToModelHandling(model, key, control, root);
}
function enableStateChangeHandling(root, model, propertyNames) {
  propertyNames
    .forEach(applyStateChangeHandlingToBoundContext, { root, model });
}

/**
 *  - The main function creates a nested view-model according
 *    to the provided nested form-control's DOM-structure.
 *  - Since the implementation follows some generic rules, one can
 *    create view-models from different/varying HTML markup.
 *  - Its most important feature is that the nested model is not
 *    build recursively. But based on ...
 *     - an additionally provided control specific selector
 *     - and an additionally provided selector which targets
 *       each control's parent component/node,
 *    ... the nested hierarchy level of each control can be
 *    identified in a far more flexible/generic way in comparison
 *    to a fixed blueprint model. The latter would not allow any
 *    flexibility within and/or variety of the HTML markup.
 * - One also can provide a list of property/attribute names which
 *   predefine the keys one wants to be part of the bidirectional
 *   state change handling.
 */
function createControlViewModel(
  root,
  controlSelector,
  parentComponentSelector,
  propertyNames,
) {
  const modelStorage = new Map;

  const controlList = [
    ...root
      .querySelectorAll(controlSelector)
  ];
  const viewModel = controlList
    .reduce((modelRoot, control) => {

      const parentComponent = control
        .closest(parentComponentSelector)
        ?.parentElement
        ?.closest(parentComponentSelector);

      // retrieve model data from control.
      const { name: key, dataset: { name } } = control;

      // create control specific view-model.
      const controlModel = { node: control, key, name };

      // store the control specific view-model
      // by the control element's reference.
      modelStorage.set(control, controlModel);

      // enable bidirectional state change
      // handling for any specified property.
      enableStateChangeHandling(root, controlModel, propertyNames);

      if (!parentComponent || !root.contains(parentComponent)) {

        // first level controls within root.
        modelRoot[key] = controlModel;

      } else {
        const parentControl = parentComponent
          .querySelector(controlSelector);

        // retrieve parent control model from view-model storage.
        const parentControlModel = modelStorage.get(parentControl);

        // child level controls of related parent.
        (parentControlModel.children ??= {})[key] = controlModel;

      // use `children` rather than the OP's `subLevels` property name.
      // (parentControlModel.subLevels ??= {})[key] = controlModel;
      }
      return modelRoot;

    }, {});

  // proof of concept related logging.
  console.log({ controlList, viewModel });
  root
    .addEventListener(
      'view:state:change',
      ({ detail }) => logModelSnapshots(viewModel, detail),
    );

  return viewModel;
}


// +++ proof of concept / demo +++

const viewModel = createControlViewModel(
  document.body,
  'li > label > [type="checkbox"]',
  'li',
  ['checked'],
);

// - change view states, here the checkbox control's
//   `checked` properties via the overall view model.
viewModel['level-1-a']
  .children['level-2-a']
  .children['level-3-b'].checked = true;

viewModel['level-1-a']
  .children['level-2-b'].checked = true;

viewModel['level-1-b']
  .checked = true;
body { margin: 0; }
ul { margin: 0; padding: 0 0 0 20px; }
.as-console-wrapper { left: auto!important; width: 75%; min-height: 100%!important; }
<ul>
  <li>

    <label>
      <input
        type="checkbox"
        name="level-1-a"
        data-name="Level 1 a"
      >
      <span class="label">
        Level 1 a
      </span>
    </label>

    <ul>
      <li>

        <label>
          <input
            type="checkbox"
            name="level-2-a" 
            data-name="Level 2 a"
          >
          <span class="label">
            Level 2 a
          </span>
        </label>

        <ul>
          <li>

            <label>
              <input
                type="checkbox"
                name="level-3-a"
                data-name="Level 3 a"
              >
              <span class="label">
                Level 3 a
              </span>
            </label>

          </li>
          <li>

            <label>
              <input
                type="checkbox"
                name="level-3-b"
                data-name="Level 3 b"
              >
              <span class="label">
                Level 3 b
              </span>
            </label>

          </li>
        </ul>

      </li>
      <li>

        <label>
          <input
            type="checkbox"
            name="level-2-b"
            data-name="Level 2 b"
          >
          <span class="label">
            Level 2 b
          </span>
        </label>

      </li>
    </ul>
    
  </li>
  <li>

    <label>
      <input
        type="checkbox"
        name="level-1-b"
        data-name="Level 1 b"
      >
      <span class="label">
        Level 1 b
      </span>
    </label>
    
  </li>
</ul>

Hello爱情风 2025-02-10 12:08:05
var data = {
    level1: {
    name: 'Level 1',
    key: 'level1',
    checked: false,
    subLevels: {
      level2: {
        name: 'Level 2',
        key: 'level2',
        checked: false,
        subLevels: {
          level3: {
            name: 'Level 3',
            key: 'level3',
            checked: true,
          },
          level4: {
            name: 'Level 4',
            key: 'level4',
            checked: false,
          }
        }
      }
    }
  }
}


var newJsonObject = traverseNesteddata(data, "level4");
console.log(newJsonObject);

var keepTheLevel4;
function traverseNesteddata(data, checkedKey){
    for(var singleValue in data){
        if(typeof data[singleValue] == 'object'){
            traverseNesteddata(data[singleValue], checkedKey);
        }else{
           if(data[singleValue] === checkedKey)
           {
           if(data.checked === false)
           data.checked = true;
           else
           data.checked = false;
        }}
    }
    
    return data;
}

var data = {
    level1: {
    name: 'Level 1',
    key: 'level1',
    checked: false,
    subLevels: {
      level2: {
        name: 'Level 2',
        key: 'level2',
        checked: false,
        subLevels: {
          level3: {
            name: 'Level 3',
            key: 'level3',
            checked: true,
          },
          level4: {
            name: 'Level 4',
            key: 'level4',
            checked: false,
          }
        }
      }
    }
  }
}


var newJsonObject = traverseNesteddata(data, "level4");
console.log(newJsonObject);

var keepTheLevel4;
function traverseNesteddata(data, checkedKey){
    for(var singleValue in data){
        if(typeof data[singleValue] == 'object'){
            traverseNesteddata(data[singleValue], checkedKey);
        }else{
           if(data[singleValue] === checkedKey)
           {
           if(data.checked === false)
           data.checked = true;
           else
           data.checked = false;
        }}
    }
    
    return data;
}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文