表单双向响应 v-model
一、单向响应与双向响应
1、变量与DOM属性响应是单向的
即DOM属性响应变量更新,但变量不会响应DOM更新。如下:
<template>
<input :value="text">
{{text}}
</template>
<script setup>
import {ref} from 'vue'
const text=ref('我会响应DOM的value值更新吗')
</script>
2、通过调用函数实现双向响应
要想实现双向响应,需要调用函数,在函数里将DOM属性值赋给变量,如下:
<template>
<input :value="text" @input="yy">
{{text}}
</template>
<script setup>
import {ref} from 'vue'
const text=ref('我会响应DOM的value值更新吗')
function yy(){text.value=event.target.value}
</script>
3、v-model实现双向响应
通过v-model能很方便的实现双向响应,只需将变量赋值给v-model,不需要调用函数赋值就能实现,如下是使用v-model实现变量与DOM的value属性双向响应。
<template>
<input v-model="text">
{{text}}
</template>
<script setup>
import {ref} from 'vue'
const text=ref('我是一')
const yi=function(event) {console.log(text.value)}
</script>
二、v-model局限
v-model只对表单类的<input>
、<textarea>
、<select>
、<select multiple>
标签有效。对其它标签无效。
三、等式双向响应与不等式双向响应
采用v-model实现响应分为等式双向响应与不等式双向响应。
1、等式双向响应
DOM属性值与变量的值相等的双向响应。如下:checked属性与text变量全等
<template>
<input type="checkbox" value="我是一" v-model="text" @change="yy">
<h1>{{text}}</h1>
</template>
<script setup>
import {ref} from 'vue'
const text=ref()
function yy(){console.log(event.target.checked===text.value)}
</script>
2、不等式双向响应
DOM属性值与变量虽然一一对应双向响应,但他们的值并不相等。如下:checked属性与text变量不相等。
<template>
<input type="checkbox" value="我是一" v-model="text" @change="yy">
<input type="checkbox" value="我是二" v-model="text" @change="yy">
<h1>{{text}}</h1>
</template>
<script setup>
import {ref} from 'vue'
const text=ref([])
function yy(){console.log(event.target.checked===text.value)}
</script>
3、模拟v-model不等式双向响应
如下是模拟v-model在成组复选框标签实现不等式双向响应。
定义textbu中间数组存储value值快照,定义tt数组存储checked值,定义text数组不等式双向响应变量
- 通过change事件,实现tt数组与属性checked的等式双向响应;
- 通过watch侦听tt,把tt值为真对应的中间数组项增加到变量text数组,tt值假则从变量text数组中删除对应的中间数组项。
- 通过watch侦听text,中间数组与text变量比对,有与中间数组相等的项则将对应tt值设为真,无则设为假。
借助了中间数组实现了tt与text的不等式双向响应。代码如下:
<template>
<input type="checkbox" value="我是一" :checked="tt[0]" @change="yi($event,0)" >
<input type="checkbox" value="我是二" :checked="tt[1]" @change="yi($event,1)" >
<h1>{{text}}</h1>
<button @click="yt">修改变量</button>
</template>
<script setup>
import {ref,nextTick, watch} from 'vue'
const textbu=ref(["我是一","我是二"])
const text=ref([])
const tt=ref([false,false])
const yi=function(event,xx) {if(event.target.checked){tt.value[xx]=true}else{tt.value[xx]=false}}
watch(()=>[...tt.value], (a,b)=>{for(var i=0;i<=1;i++){
if(a[i]!=b[i]){
if(a[i]){text.value.push(textbu.value[i])}else{text.value=text.value.filter(function (x,y,z) { return x!=textbu.value[i]})}}}
})
watch(()=>[...text.value], (a,b)=>{for(var i=0;i<=1;i++){
if(a.includes(textbu.value[i])){tt.value[i]=true}else{tt.value[i]=false}}})
function yt(){text.value[1]='我'}
</script>
4、v-model依靠中间比对数组实现不等式双向响应
中间比对数组不可见,但不等式双向响应却借助了这个看不见的中间比对数组实现,中间比对数组与DOM属性一一对应,变量与DOM的不等式双向响应依靠向变量增删中间比对数组项实现。
如下,变量增删的值只要不是中间比对值,DOM无响应。
<template>
<input type="checkbox" value="我是一" id="one" v-model="text">
<input type="checkbox" value="我是二" v-model="text">
<h1>{{text}}</h1>
<button @click="yy">测试</button>
</template>
<script setup>
import {ref,nextTick} from 'vue'
const text=ref([])
function yy(){text.value[0]='我是三'}
</script>
5、中间比对数组是value快照
中间比对数组取的value值是初始化时value的快照,如下改变
<input type="checkbox" value="我是一" id="one" v-model="text">
的value属性为“我是三”,变量并不会取新的value值,还是使用初始化时的快照。
因此要注意:对中间数组value值改变对变量不生效。
<template>
<input type="checkbox" value="我是一" id="one" v-model="text">
<input type="checkbox" value="我是二" v-model="text">
<h1>{{text}}</h1>
<button @click="yy">测试</button>
</template>
<script setup>
import {ref,nextTick} from 'vue'
const text=ref([])
var el
nextTick(() => {el=document.getElementById("one")})
function yy(){el.value='我是三'}
</script>
注意:getElementById在setup阶段还没有生成DOM,需生成DOM之后才能使用,如上是通过放置在nextTick里来达到生成DOM之后使用。
6、快照污染
<select>
与类型为复选、单选框的<input>
的value属性默认值为“on”(不赋值),当标签内无value属性赋值时,中间数组取的快照各项会一模一样,都为“on”,将失去比对的作用,快照污染会使v-model功能混乱,因此一定要手动给value属性赋值(且value不能赋相同的值)以避免快照污染。
7、快照功能丧失
变量是数组才能向变量增删中间比对数组项,实现不等式双向响应,任何更改数组型变量为其它类型变量的操作都会使快照功能丧失。丧失了快照功能的v-model,将会由不等式双向响应转换为等式双向响应,且各DOM的状态同步,如下:
<template>
<input type="checkbox" value="我是一" v-model="text">
<input type="checkbox" value="我是二" v-model="text">
<h1>{{text}}</h1>
<button @click="yy">测试</button>
</template>
<script setup>
import {ref,nextTick} from 'vue'
const text=ref([])
function yy(){text.value={}}
</script>
8、快照转为动态绑定
给快照属性使用v-bind动态绑定指令,会使中间比对数组改变取初始化的value快照,转变为与value动态绑定,改变value值会即时对变量生效。
9、假性不等式双向响应
true-value与false-value
这是两个仅和 v-model 配套使用的属性
当变量为数组时,变量与属性是不等式双向响应,变量的值是value快照;当变量不是数组时,变量与属性是等式双向响应,变量的值是。
变量不为数组时,可使用true-value与false-value属性,能使等式双向响应变成假性不等式双向响应。
只有一个标签的情况
当标签有true-value和false-value时,选中变量值为true-value值、未选变量值为false-value值;
当标签只有true-value时,选中变量值为true-value值,未选变量值为fals;
当标签只有false-value时,选中变量值为true,未选变量值为false-value值;
有多个标签的情况
- true-value与false-value快照也能转为动态绑定。
- 可以只有true-value或false-value属性。
- 不等式双向响应的v-model中,true-value与false-value属性无效。
true-value设为不同值时,可以使复选框当单选框用,如下:
<template>
<input type="checkbox" value="我是一" v-model="text" true-value="笑">
<input type="checkbox" value="我是二" v-model="text" true-value="话">
<h1>{{text}}</h1>
</template>
<script setup>
import {ref,nextTick} from 'vue'
const text=ref()
</script>
四、v-model细节
1、不同类型的标签绑定的属性不同
<input type="text">
和<textarea>
绑定value属性,value值===变量值。<input type="checkbox">
绑定checked属性,checked值===变量值。
当变量是数组时,checked属性归为checked数组,checked数组与数组变量是不等式双向响应,变量取value属性快照值。<input type="radio">
绑定checked属性,checked属性归为checked数组,checked数组与变量是不等式双向响应,变量取value属性快照值。<select>
绑定selected属性,selected属性归为options数组,options数组与变量是不等式双向响应,变量取value属性快照值。<select multiple>
绑定selected属性,selected属性归为options数组,options数组与数组变量是不等式双向响应,变量取value属性快照值。
2、禁止双重绑定
v-model绑定的属性不能再绑定其它变量,如下会出错:
<input :value="tt" v-model="text">
<input type="checkbox" :checked="fa" v-model="text" >
3、v-model在标签内最后读取
在标签内,v-model读取要晚于其它属性,因此双向响应的属性初始值会被v-model刷新,标签内对双向响应的属性赋值无效。如下:
<template>
<input type="checkbox" value="我是一" v-model="text" checked="false">
<input type="checkbox" value="我是二" v-model="text" checked="false">
<button @click="yy">测试</button>
</template>
<script setup>
import {ref,nextTick} from 'vue'
const text=ref(["我是一","我是二"])
</script>
4、变量对非默认的不响应
变量并不是响应属性的所有更新,对非DOM默认事件引起的属性变化,变量并不会响应更新。如下:非默认事件对绑定的checked改变,变量并不会响应更新。
<template>
<input type="checkbox" value="我是一" v-model="text" @keydown.a="yy" id="one" :checked="tt">
<input type="checkbox" value="我是二" v-model="text" checked="false">
<h1>{{text}}</h1>
<button @click="yy">测试</button>
</template>
<script setup>
import {ref,nextTick} from 'vue'
const text=ref(["我是一","我是二"])
const tt=ref()
const t=ref(true)
var el
nextTick(() => {el=document.getElementById("one")})
function yy(){if(t){tt.value=!tt.value}else{el.checked=!el.checked};console.log(el.checked)}
</script>
5、修饰符
v-model也可带与输入有关的修饰符,三个v-model修饰符如下
.lazy: 确定输完才触发(也就是说只有光标离开input输入框或enter回车后,绑定的值才会改变)
.number: input输入的内容为字符串类型,即使你输入的是数字也会是字符串类型,number修饰符能把你输入的数字保存为Number类型
.trim: 自动过滤用户输入的首尾空格赋给绑定的变量
五、一些标签特性
1、复选框标签
在标签中,只要出现了 checked,不论他带不带值,或带什么值,都是选中状态,如:
<input type="checkbox" checked>
<input type="checkbox" checked="true">
<input type="checkbox" checked="false">
<input type="checkbox" checked="狗屎">
使用了绑定指令,只有值为true才是选中状态。如:
<input type="checkbox" :checked> 语法错误
<input type="checkbox" :checked="true"> 选中
<input type="checkbox" :checked="false"> 未选中
<input type="checkbox" :checked="狗屎"> 未选中
2、单选框标签
单选框标签通过name属性来归组,name值相同的为同一组;
v-model不需通过name属性归组,v-model值相同的单选框会编为一组。
在标签中,只要出现了 checked,不论他带不带值,或带什么值,都是选中状态;
使用了绑定指令,只有值为true才是选中状态。
在一组中有多个值为选中状态时,最后一个标签会是选中。
3、选择器(单选)标签
- 选择器标签
<select>
内含选择项标签<option>
,<select>
的options属性相等于<option>
选择标签组属性。 <option>
的value值缺省为<option>
显示的内容,如:<option>A</option>
,value='A'。自定义value的值与<option>
显示的内容互不影响,如:<option value='B'>A</option>
。<option>
的selected属性定义选中状态,options选项组中除标了disabled外的最前一个标签的selected缺省为选中,也可自定义selected属性值。
4、选择器(多选)标签
通过给<select> 添加 multiple 属性使多单选择器变成多选选择器。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。