网站搜索

javascript - 使用 Vue 监听应用外的 DOM 事件


我需要使用 Vue.js 来逐步增强现有的服务器端渲染表单。我需要根据表单上另一个字段的值更改 <select> 的 <options>。

在我看来,我无法将 Vue 挂载到父 <form>(或其他父元素)上,因为这样我会失去所有的服务器端渲染内容,而我需要保持这些内容。

我已经挂载了我希望动态化的 <select>。这允许我按照自己的方式动态生成 <option>。然而,另一个表单输入元素(挂载的 <select> 的兄弟元素)现在不在我的 Vue 范围内。我的 Vue 应用如何才能收到依赖字段变化的通知,从而相应地更新我的 <option>?

据我理解,Vue 有它自己的事件系统,所以我得自己挂接一个 DOM 事件监听器——这完全没问题。这就是我目前为止的进展。

旁注:我明白,假如有无限的时间、金钱和资源,我应该顺应趋势,让我的整个用户体验成为一个单页应用(SPA),这样可以以一种用火箭发射器打钉子的方式解决这个问题。然而,这不是一个可行的选择。我必须逐步增强服务器端渲染(SSR)的输出。

答案#1

你仍然可以使用 document.querySelector() 查询文档中的兄弟元素,并且在 Vue 实例中调用 addEventListener():

const ALL_DATA = [
  {id: 1, value: 1, text: 'One'},
  {id: 2, value: 2, text: 'Two'},
  {id: 3, value: 3, text: 'Three'},
];

new Vue({
  el: '#app',
  data: () => ({
    options: [
      ...ALL_DATA,
    ]
  }),
  mounted() {
    document.querySelector('#option-type').addEventListener('change', e => {
      switch (e.target.value) {
        case 'even':
          this.options = ALL_DATA.filter(x => x.value % 2 === 0);
          break;

        case 'odd':
        default:
          this.options = ALL_DATA.filter(x => x.value % 2 !== 0);
          break;
      }
    })
  }
});

document.getElementById('myForm').addEventListener('submit', e => {
  e.stopPropagation();
  e.preventDefault();
});
<script src="https://unpkg.com/[email "></script>

<form action="#" id="myForm">

  <fieldset id="option-type">
    <label>Even
      <input name="option-type" type="radio" value="even">
    </label>
    <label>Odd
      <input name="option-type" type="radio" value="odd">
    </label>
  </fieldset>

  <select name="option" id="app">
    <option v-for="o in options"
            value="o.value"
            :key="o.id">{{o.text}}</option>
  </select>
</form>