没有更新函数调用神秘更新的对象

时间:2018-04-12 05:05:42

标签: javascript html dom model

预期的行为是让用户能够单独设置所有三个元素的样式。

工作原理:

  • 单击每个元素时,它将存储在selected.elements
  • 单击“粗体/斜体”时,它将存储在selected.settings
  • 单击“应用”时,将使用元素&更新DOM。 “selected”对象中的设置和selected.elements已清除

重现的步骤:

  1. 点击“elementOne”
  2. 选择“Bold”
  3. 点击“应用”
  4. 点击“elementTwo”
  5. 选择“Italic”
  6. 点击“应用”
  7. 预期: elementOne是Bold; elementTwo是Italic

    实际:两者都是斜体

    在步骤5,即使没有被调用的函数,也会更新model.elementOne.settings。

    const selected = {
      elements: [],
      settings: {}
    }
    const model = {
      elementOne: {
        slug: 'elementOne',
        settings: {}
      },
      elementTwo: {
        slug: 'elementTwo',
        settings: {}
      },
      elementThree: {
        slug: 'elementThree',
        settings: {}
      }
    }
    const elementContainer = document.getElementById('elementContainer')
    const buttonContainer = document.getElementById('buttonContainer')
    const fontStyleContainer = document.getElementById('fontStyleButtonContainer')
    
    const setupEventListeners = _ => {
      elementContainer.addEventListener('click', e => {
        // add the selected element to selected.elements
        selected.elements.push(e.target.id)
      })
    
      fontStyleContainer.addEventListener('click', e => {
        // add the selected font style to the selected.settings
        for (let i = 0; i < selected.elements.length; i++) {
          if (e.target.hasAttribute('data-bold')) {
            selected.settings.fontStyle = 'bold'
          } else if (e.target.hasAttribute('data-italic')) {
            selected.settings.fontStyle = 'italic'
          }
        }
      })
    
      buttonContainer.addEventListener('click', e => {
        // update the model for each selected element using the selected settings
        for (let i = 0; i < selected.elements.length; i++) {
          model[selected.elements[i]].settings = selected.settings
        }
        // update the DOM based on the new model
        updateDOMFromModel()
        // reset the selected elements & settings
        selected.elements.length = 0
      })
    }
    const updateDOMFromModel = _ => {
      // update the DOM based on the new model
      for (const el in model) {
        if (model.hasOwnProperty(el)) {
          const element = model[el]
          const elementDOM = document.getElementById(element.slug)
          switch (element.settings.fontStyle) {
            case 'bold':
              elementDOM.style = 'font-weight: 800;'
              break
            case 'italic':
              elementDOM.style = 'font-style: italic;'
              break
            default:
          }
        }
      }
    }
    setupEventListeners()
    <body>
      <div id="elementContainer" style="cursor: pointer;">
        <p>1. Select an element to style</p>
        <ul>
          <li id="elementOne">elementOne</li>
          <li id="elementTwo">elementTwo</li>
          <li id="elementThree">elementThree</li>
        </ul>
      </div>
      <div id="fontStyleButtonContainer" style="cursor: pointer;">
        <p>2. Select a font style</p>
        <div id="fontStyleButton" data-bold>Bold</div>
        <div id="fontStyleButton" data-italic>Italic</div>
      </div>
      <div id="buttonContainer" style="cursor: pointer;">
        <p>3. Apply changes</p>
        <button id="btnApply">Apply</button>
      </div>
    </body>

1 个答案:

答案 0 :(得分:2)

通过在selected.settings中始终使用相同的对象,您可以在它们之间绑定模型元素的设置,因为它们最终指向相同的东西。

在这里,我只是为fontStyleContainer重新设置一个新对象,它可以正常工作! (签入const selected = { elements: [], settings: {} } const model = { elementOne: { slug: 'elementOne', settings: {} }, elementTwo: { slug: 'elementTwo', settings: {} }, elementThree: { slug: 'elementThree', settings: {} } } const elementContainer = document.getElementById('elementContainer') const buttonContainer = document.getElementById('buttonContainer') const fontStyleContainer = document.getElementById('fontStyleButtonContainer') const setupEventListeners = _ => { elementContainer.addEventListener('click', e => { // add the selected element to selected.elements selected.elements.push(e.target.id) }) fontStyleContainer.addEventListener('click', e => { // add the selected font style to the selected.settings for (let i = 0; i < selected.elements.length; i++) { if (e.target.hasAttribute('data-bold')) { // Each time a new object! selected.settings = {fontStyle: 'bold'} } else if (e.target.hasAttribute('data-italic')) { // Each time a new object! selected.settings = {fontStyle: 'italic'} } } }) buttonContainer.addEventListener('click', e => { // update the model for each selected element using the selected settings for (let i = 0; i < selected.elements.length; i++) { model[selected.elements[i]].settings = selected.settings } // update the DOM based on the new model updateDOMFromModel() // reset the selected elements & settings selected.elements.length = 0 }) } const updateDOMFromModel = _ => { // update the DOM based on the new model for (const el in model) { if (model.hasOwnProperty(el)) { const element = model[el] const elementDOM = document.getElementById(element.slug) switch (element.settings.fontStyle) { case 'bold': elementDOM.style = 'font-weight: 800;' break case 'italic': elementDOM.style = 'font-style: italic;' break default: } } } } setupEventListeners()点击监听器) 注意你是否使用了值或引用;)

<body>
  <div id="elementContainer" style="cursor: pointer;">
    <p>1. Select an element to style</p>
    <ul>
      <li id="elementOne">elementOne</li>
      <li id="elementTwo">elementTwo</li>
      <li id="elementThree">elementThree</li>
    </ul>
  </div>
  <div id="fontStyleButtonContainer" style="cursor: pointer;">
    <p>2. Select a font style</p>
    <div id="fontStyleButton" data-bold>Bold</div>
    <div id="fontStyleButton" data-italic>Italic</div>
  </div>
  <div id="buttonContainer" style="cursor: pointer;">
    <p>3. Apply changes</p>
    <button id="btnApply">Apply</button>
  </div>
</body>
clr.dll