How to modify the value of v-model property via custom directive?

可紊 提交于 2019-12-18 17:29:06

问题


When I use custom directive to change component's value, there is not effect:

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>

when I use v-bind:input directive to change value is ok!


回答1:


First:

  • You are using v-model, the value of the textarea will be whatever is in the v-model's variable (in this case, the variable content). This means that the initial value of the DOM is ignored.
  • To handle this, I moved (see below) the string from the DOM declaration to the content in data().

Second:

  • Vue does not respond to changes in .value directly. v-model actually watches for input✱ events from the DOM element.
    • ✱ it actually varies depending on the type of element, sometimes it is the change event, or other
  • If you just set the value, Vue will simple override it back (to whatever is in content) next time an update happens.

Solution:

After changing the .value, trigger input event. Vue will pick the event up and update the v-model variable from the current .value before it overrides it.

Demo:

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>



回答2:


Just create a input event using Event function.

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

then modify the value and then dispatch the event, it will update the v-model value

el.dispatchEvent(event);

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);
      }
  }
});

hope it will helpful.



来源:https://stackoverflow.com/questions/49598541/how-to-modify-the-value-of-v-model-property-via-custom-directive

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!