vue
vue copied to clipboard
<input> rerenders while changes affects only sibling elements
Version
2.5.2
Reproduction link
https://codepen.io/anon/pen/OxKqbL?editors=1111
Steps to reproduce
Please open codepen example and type something into input
What is expected?
Input should not lose focus
What is actually happening?
input rerenders and loses focus
happens only if there is such conditional elements exists before and after input. Workaround is to use v-show instead of v-if in such cases.
You can also simply give the <input> a key to ensure it is not replaced.
i tried your solution in codepen and still cant get it working.
i tried this
<input type="text" v-model="inputVal" :key="1">
U need to have same DOM structure before your input. Look this. It can be after update your DOM before your input tag
Actually, it is the same input element, but first remove from the document then move it to other places, for example:
it first renders like
<!----> // A
<input />
<!----> // B
then you focus input and input some words, then virtual dom insert <span>before</span>, and it then parent.insertBefore(input, A), it moves the input element before the A comment element, so it will eventually lose focus, then it will delete the comment node.
so, I think you could use v-show better to avoid the insertBefore move problem(remove from the document then insert before the reference node, in this case, which is comment A ). This is the default action for virtual dom of vue which doesn't replace comment node.
You can also simply give the
<input>a key to ensure it is not replaced.
<input> element focus is lost in either case.
https://github.com/google/incremental-dom/issues/237
seems like this one
I have tried to fix this issue
But I encountered some problem
have we got some way to access vnode from html element?
I want to get vnode path as https://github.com/google/incremental-dom/issues/237
But I did not find a good way to do that
have i missing something? or have other better solution?😅
@Kingwl you can use v-show. It works correctly.
Alternative way: https://codepen.io/furrya_black/pen/ZVVLpQ
Just html-layout usually has a more complex structure. What do you thing? As a proof you can see any css framework: material disign, bulma, bootstrap, etc (what else)
UPD: if your case require rerender-mehanic (with v-if)
It also seems to break (loose focus) if the spans are shown initially:
https://codepen.io/janschoenherr/pen/NoJpoY?editors=1111
I would think that it doesn't need to do insertBefore in this case.
Other reproductions:
https://codepen.io/adamwathan/pen/vMJrYj https://codesandbox.io/s/q9mqnjnxr9
F.Y.I. It seems that #9473, #9496, #9808 all share the same root cause.
I'm using Vue 2.6.7 and this issue is still relevant, i was able to work it out by using v-show instead of v-if on a sibling, but it's still confusing why it doesn't work when v-if is used
I found that @focus is not reliable when using DOM manipulation, such as v-if and therefore, directives would be the best approach:
<template>
<form method="POST"
autocomplete="off"
@submit.prevent="onSubmit">
<!-- We set the directive here v-focus with the function prop handleFocus -->
<div class="flex mt-1 rounded-md shadow-sm">
<input id="title"
type="text"
v-focus="handleFocus"
v-model="form.title">
</div>
</form>
</template>
<script>
export default {
name: "FormComponent",
data() {
return {
// A form class example, but you could just have a var
form: new this.$form({
title: null,
})
}
},
directives: {
focus: {
inserted(el,binding) {
// We set focus on the element
el.focus();
// optional if you had other operations. Data and props, etc. are not available inside
// a direective uless yoru decorate the provider, which is a pain. So we call the binding
// which is the handleFocus set on input. We pass the el but we could inject nothing or a event, binding, etc
if (!_.isUndefined(binding.value)) binding.value(el)
}
}
},
methods: {
handleFocus: function() {
// For example reset a form v-model
this.form.title = null;
},
}
}
</script>
v-show it worked thanks.
I had the problem where a v-if causes the parent modal to lose focus so that pressing <esc> does not close the modal. v-show did not fix my problem since rendering the element when the v-if condition is not met results in an error due to a null value.
I worked around this by focusing an invisible dummy <Input /> in the modal whenever the v-if condition changes.