javascript - 对象神秘更新而没有调用更新函数

标签 javascript html dom model

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

工作原理:

  • 当每个元素被点击时,它被存储在selected.elements
  • 单击“粗体/斜体”时,它存储在 selected.settings 中
  • 单击“应用”后,DOM 将使用“选定”对象中的元素和设置进行更新,并清除选定元素。

重现步骤:

  1. 点击“elementOne”
  2. 选择“粗体”
  3. 点击“应用”
  4. 点击“elementTwo”
  5. 选择“斜体”
  6. 点击“应用”

预期: elementOne 为粗体; elementTwo 是斜体

实际:都是斜体

在第 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>

最佳答案

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

在这里,我只是为 selected.settings 重新设置了一个新对象,它起作用了! ( checkin 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>

关于javascript - 对象神秘更新而没有调用更新函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49788385/

相关文章:

javascript - `<component-name>.vue.html` 中的重音显示为�

javascript - 正确的 element.getElementsByTagName() 实现

javascript - 从音频 html5 标签下载

javascript - 从 json 对象创建定义列表

html - 调整 svg 元素的大小

javascript - 如何在 html 5 Canvas 上使用 FontAwesome 图标

javascript - jQuery .on() 方法在 Chrome 中不起作用(但在 IE 和 FF 中起作用)

javascript - 清除不再引用且从未添加到文档中的元素

javascript - 更改 Google map 上路线的默认标记

javascript - 除了添加类名进行过滤之外,是否有更优化的 DOM 分类方法?