【问题标题】:How to modify the value of v-model property via custom directive?如何通过自定义指令修改 v-model 属性的值?
【发布时间】:2018-04-01 13:24:22
【问题描述】:

当我使用自定义指令更改组件的值时,没有效果:

Vue.directive('maxchars', {
  bind(el, binding, vnode) {
    let maxChars = binding.value;
    let handler = function(e) {
      if (e.target.value.length > maxChars) {
        e.target.value = e.target.value.substr(0, maxChars)
      }
    }
    el.addEventListener('input', handler);
  }
});
let app = new Vue({
  el: '#app',
  data() {
    return {
      content: '',
      totalCount: 140
    }
  }
})
<script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>
<div id='app'>
  <div>
    <div class='content'>
      <textarea v-model='content' v-maxchars='140'>tell me something</textarea>
    </div>
  </div>
</div>

当我使用v-bind:input 指令来改变值是好的!

【问题讨论】:

    标签: events vue.js vuejs2 directive dom-events


    【解决方案1】:

    第一:

    • 您正在使用v-modeltextarea 的值将是v-model 的变量(在本例中为变量content)中的任何值。这意味着 DOM 的初始值被忽略
    • 为了处理这个问题,我将字符串从 DOM 声明移动(见下文)到 data() 中的 content

    第二:

    • Vue 不会直接响应 .value 中的更改。 v-model 实际上监视来自 DOM 元素的 input✱ 事件。
      • ✱它实际上取决于元素的类型,有时是change事件,或其他
    • 如果您只是设置了 value,Vue 会在下次更新时简单地覆盖它(到 content 中的任何内容)。

    解决方案:

    更改.value 后,触发input 事件。 Vue 将选择该事件并从当前.value 更新v-model 变量在覆盖它之前。

    演示:

    Vue.directive('maxchars', {
      bind(el, binding, vnode) {
        let maxChars = binding.value;
        let handler = function(e) {
          if (e.target.value.length > maxChars) {
            e.target.value = e.target.value.substr(0, maxChars);
            vnode.elm.dispatchEvent(new CustomEvent('input')); // added this
          }
        }
        el.addEventListener('input', handler);
      }
    });
    let app = new Vue({
      el: '#app',
      data() {
        return {
          content: 'tell me something',
          totalCount: 140
        }
      }
    })
    <script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>
    <div id='app'>
      <div>
        <div class='content'>
          <textarea v-model='content' v-maxchars='18'></textarea>
        </div>
        <pre>
        content: {{ content }}
        Max chars is 18, current is {{ content.length }}.
        </pre>
      </div>
    </div>

    【讨论】:

    • 请注意,Internet Explorer 不支持 CustomEvent。
    • 为什么我们已经在 html 中有 maxlength attr 的情况下需要这个?
    • @santosh 我同意,但我认为重点不在于我们对模型做了什么,而是如何去做,即如何通过自定义指令。 (作为旁注,我最近不得不实现一个这样的 max-chars 东西,并且更喜欢类似 twitter 的解决方案,显示过去允许的字符数,而不是截断它们。)
    • unbind中的事件监听器不需要去掉吗?
    • @abhim 也许。根据您的情况,如果el 仍然存在,则在unbinding 时删除侦听器可能是明智的。
    【解决方案2】:

    只需使用 Event 函数创建一个 input 事件。

    var event = new Event("input", { bubbles: true });

    然后修改值然后派发事件,它会更新v-model值

    el.dispatchEvent(事件);

    Vue.directive('maxchars', {
      update(el, binding, vnode) {
        var event = new Event("input", { bubbles: true });
        let maxChars = binding.value;
          if (el.value.length > maxChars) {
            el.value = e.value.substr(0, maxChars);
            el.dispatchEvent(event);
          }
      }
    });
    

    希望对您有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-27
      • 1970-01-01
      • 2020-01-05
      • 1970-01-01
      相关资源
      最近更新 更多