最近在学习 vue 的过程中,遇到如下场景:

有两个表单,提供两种登陆方式,账号登录或邮箱登录,用户点击 button 按钮进行切换。

过 vue 的 v-if 指令,很容易就能实现如上需求。但有一个小问题,当用户选择 账号登录 时,在输入框内输入账号,突然改变主意,选择改用 邮箱登录,于是点击按钮切换,这时输入框内 账号登陆 模式下输入的字符却被保留了下来,并没有随着 input 输入框的改变而改变,这显然是设计者不想看到的,也对用户体验造成了一定影响。

示例


<span v-if="isUser"> <label for="username">用户账号</label> <input type="text" id="username"> </span> <span v-else> <label for="email">用户邮箱</label> <input type="text" id="email"> </span> <button @click="isUser = !isUser">切换方式</button>





从代码中可以看到,我们的确是用了两个不同的 input 元素。那是什么原因导致了这种情况的发生呢?

通过查阅资料发现,原来 vue 在更新页面时并不是直接把元素渲染到 DOM 上,而是先用 JS 模拟 DOM 结构,通过比对,再把变化的部分最终渲染到真实 DOM 上,这样做的好处是可以减少对真实 DOM 的操作,从而提升网页性能。
而且,为了进一步提升网页渲染的速度,vue 内部还对虚拟 DOM 进行了一些优化。当 vue 发现同一结构内渲染的元素相同时,它不会对原先的元素进行替换,而是保留之前的元素,然后对元素的属性进行比对,只对不同的属性进行更新。就如示例中的两个 input 元素,vue 只是替换了它的 id 属性,并没有重新渲染整个 input 元素。

元素被复用,就是导致我们输入框内容保留的原因。

解决这个问题的方法其实也很简单,就是在你不需要复用的元素上添加一个 key 属性,作为元素唯一的标识符,如:key="username",这样,被添加标识符的元素就不会再被复用了。

示例二


<span v-if="isUser"> <label for="username">用户账号</label> <input type="text" id="username" key="username"> </span> <span v-else> <label for="email">用户邮箱</label> <input type="text" id="email" key="email"> </span> <button @click="isUser = !isUser">切换方式</button>