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/

相关文章:

php - 输入 PHP 后显示带有回显的输入文本

javascript - 直接通过ID访问DOM元素有什么弊端?

javascript - 在进入 Mozilla Firefox 中的 JavaScript 引擎之前拦截 JavaScript

javascript - INVALID_STATE_ERR : DOM Exception 11 (WebKit)

javascript - 重写prototype.toString不起作用

javascript - main.bundle.js 大小在 Angular 4 中负载过大

jquery - 为什么 animate() 不能在此 jQuery 代码中工作?

html - CSS line-clamp 在 Safari 中对内部 block 级元素不起作用

javascript - 是否可以在某些条件下关闭信息窗口

javascript - javascript 函数无法生成精确的更改