问题
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 thetextarea
will be whatever is in thev-model
's variable (in this case, the variablecontent
). 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
indata()
.
Second:
- Vue does not respond to changes in
.value
directly.v-model
actually watches forinput
✱ events from the DOM element.- ✱ it actually varies depending on the type of element, sometimes it is the
change
event, or other
- ✱ it actually varies depending on the type of element, sometimes it is the
- If you just set the
value
, Vue will simple override it back (to whatever is incontent
) 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