本文介绍: # 双向绑定 vmodel– `vmodel:value=”值”` 可简写为 `vmodel=”值”`,用于**双向绑定** [表单元素] 的信息双向绑定表单元素的 `value` attribute 的值 ↔ data 中对应的值- 本质上,vmodel 是由 vbind 配合 input 事件实现的 ① vbind 绑定 value 属性、② 在 input 事件的回调函数更新 value 的值## 文本 input [text]`

双向绑定 vmodel

文本 input [text]

<div id="app">
    &lt;p&gt;Message is: {{ msg }}</p>
    <!-- 给 input 标签元素设置 v-model 属性 -->
    <input
        v-model="msg"
        type="text"
    />
</div>
let vm = new Vue({
    el: '#app',
    data: { msg: 'superman' },
});

上例中,input默认值data 中的 msg,更新 input 的 value 值 → msg 也会被更新 → p 显示的内容也会被更新

多行文本 textarea

<textarea v-model="msg"></textarea>

单选框 input [radio]

<input type="radio" id="male" value="male" v-model="sex" />
<label for="male">male</label>
<br />
<input type="radio" id="female" value="female" v-model="sex" />
<label for="female">female</label>
<br />
<span>sex: {{ sex }}</span>
let vm = new Vue({
    el: '#app',
    data: {
        sex: '',
        // sex: "male" // 设置默认值 'male',默认选中 male 选项
    },
});

复选框 input [checkbox]

  1. 没有配置 value 属性,收集的是 checkboxchecked 状态,所以会收集到布尔值
<input type="checkbox" id="checkbox" v-model="checked" />
<label for="checkbox">{{checked}}</label>
let vm = new Vue({
    el: '#app',
    data: { checked: true }, // 绑定 [布尔值]
});
  1. 配置value 属性,绑定 [非数组],收集的也还是 checkboxchecked 状态
    所以也还是会收集到布尔值 → ture-全选、false-全不选
篮球
<input type="checkbox" value="篮球" v-model="checked" />
足球
<input type="checkbox" value="足球" v-model="checked" />
网球
<input type="checkbox" value="网球" v-model="checked" />
<p>{{checked}}</p>
  1. 配置value 属性,绑定 [数组],才能收集到多选框的 value
篮球
<input type="checkbox" value="篮球" v-model="checked" />
足球
<input type="checkbox" value="足球" v-model="checked" />
网球
<input type="checkbox" value="网球" v-model="checked" />
<p>{{checked}}</p>
let vm = new Vue({
    el: '#app',
    data: {
        checked: [], // 绑定到数组
    },
});

选择select > option

<select v-model="selected">
    <option
        disabled
        value=""
    >
        国家
    </option>
    <option value="China">中国</option>
    <option value="America">美国</option>
    <option value="Japan">日本</option>
</select>
<span>Selected: {{ selected }}</span>
let vm = new Vue({
    el: '#app',
    data: {
        selected: '',
        // selected: "China" // 设置默认值
    },
});
<select v-model="selected">
    <option
        disabled
        value=""
    >
        国家
    </option>
    <option>中国</option>
    <option>美国</option>
    <option>日本</option>
</select>
<span>Selected: {{ selected }}</span>
<select multiple v-model="selected">
    <option
        disabled
        value=""
    >
        国家
    </option>
    <option>中国</option>
    <option>美国</option>
    <option>日本</option>
</select>
<span>Selected: {{ selected }}</span>
let vm = new Vue({
    el: '#app',
    data: {
        selected: [], // 绑定到数组
    },
});

标签修饰符

  1. .lazy:在 change 事件之后同步,即失焦再同步(默认 input 事件之后同步,即一边写一边同步
  2. .trim过滤首尾空白字符
  3. .number:将输入数据使用 parseFloat() 转为 Number 类型;若这个值无法被 parseFloat() 解析,则会返回输入字符串
<input type="text" v-model.lazy="username" />
<span>{{ username }}</span>
<br />

<input type="text" v-model.trim="password" />
<span>{{ password }}</span>
<br />

<!-- type="number" 能限制 input 只能输入数字 -->
<input type="number" v-model.number="age" />
<span>{{ age }}</span>
<br />

<!-- v-model.number="age" 会将数据转为 Number 类型 -->
<input type="text" v-model.number="height" />
<span>{{ height }}</span>
表单提交事件
<form @submit.prevent="console.log('submit successfully')"></form>

Vue2 组件使用 v-model

v-model 其实是 v-bind:value + v-on:input语法

<template>
    <div>
        {{ demoText }}
        <input
            :value="demoText"
            @input="ev => (demoText = ev.target.value)"
        />
        <input v-model="demoText" />
    </div>
</template>

<script>
export default {
    name: 'App',
    data() {
        return {
            demoText: 'demoText',
        };
    },
};
</script>

同理,在自定义组件使用

<template>
    <div>
        {{ demoText }}
        <HelloWorld
            :value="demoText"
            @input="val => (demoText = val)"
        />
        <HelloWorld v-model="demoText" />
    </div>
</template>

<script>
import HelloWorld from '@/components/HelloWorld.vue';

export default {
    name: 'App',
    components: { HelloWorld },
    data() {
        return {
            demoText: 'demoText',
        };
    },
};
</script>

需要注意的是:自定义组件上的 :value 变成了自定义属性,@input 变成了自定义事件

<template>
    <input
        type="text"
        :value="value"
        @input="$emit('input', $event.target.value)"
    />
    <!-- $emit('input', $event.target.value) 表示触发自定义事件, 传入 $event.target.value 作为参数-->
</template>

<script>
export default {
    name: 'HelloWorld',
    props: ['value'], // 接收自定义属性
};
</script>

.sync 修饰符

上例可以优化成:

<template>
    <div>
        {{ demoText }}
        <HelloWorld
            :title="demoText"
            @update:title="demoText = $event"
        />
    </div>
</template>
<template>
    <input
        type="text"
        :value="title"
        @input="$emit('update:title', $event.target.value)"
    />
</template>

<script>
export default {
    name: 'HelloWorld',
    props: ['title'],
};
</script>

这种写法可以使用语法糖

<template>
    <div>
        {{ demoText }}
        <HelloWorld v-bind:title.sync="demoText" />
    </div>
</template>

注意:带有 .sync 修饰符v-bind 不能表达式一起使用;eg: v-bind:title.sync="doc.title + '!'"无效

<HelloWorld v-bind.sync="doc"></HelloWorld>

这样会把 doc 对象中的每一个 property (如 title) 都作为一个独立的 prop 传进去,然后各自添加用于更新的 v-on 监听

注意:将 v-bind.sync 用在一个字面量的对象上,eg: v-bind.sync="{ title: doc.title }",是无法正常工作
因为在解析一个像这样的复杂表达式的时候,有很多边缘情况需要考虑

Vue3 组件使用 v-model

  • 在普通标签元素上使用 v-model
<template>
    {{ textDemo }}
    <input v-model="textDemo" />
</template>

<script setup lang="ts">
import { ref } from 'vue';
const textDemo = ref('textDemo');
</script>

上例等价于

<template>
    {{ textDemo }}
    <input
        :value="textDemo"
        @input="textDemo = ($event.target as any).value"
    />
</template>
<template>
    <HelloWorld v-model="textDemo" />
</template>

<script lang="ts" setup>
import { ref } from 'vue';
import HelloWorld from '@/components/HelloWorld.vue';

const textDemo = ref('Vue.js');
</script>

上例等价于

<template>
    <HelloWorld
        :modelValue="textDemo"
        @update:modelValue="(newValue:any) => (textDemo = newValue)"
    />
</template>

此时,子组件内需要做两件事:
① 将原生 input 元素的 value attribute 绑定到 modelValue prop
② 当原生的 input 事件触发时,触发一个携带了新值的 update:modelValue 自定义事件

<template>
    {{ modelValue }}
    <input
        type="text"
        :value="modelValue"
        @input="$emit('update:modelValue', ($event.target as any).value)"
    />
</template>

<script lang="ts" setup>
defineProps<{ modelValue: string }>(); // 接收 `modelValue` prop
defineEmits<{ (e: 'update:modelValue', val: string): void }>(); // 接收 `update:modelValue` 自定义事件
</script>

v-model 的参数

  • 默认情况下,v-model 在组件上都是使用 modelValue 作为 prop,并以 update:modelValue 作为对应的事件
  • 可以给 v-model 指定一个参数更改这些名字
<template>
    <!-- 设置 v-model 的参数 title -->
    <HelloWorld v-model:title="textDemo" />
</template>

<script lang="ts" setup>
import { ref } from 'vue';
import HelloWorld from '@/components/HelloWorld.vue';

const textDemo = ref('Vue.js');
</script>
<template>
    {{ title }}
    <input
        type="text"
        :value="title"
        @input="$emit('update:title', ($event.target as any).value)"
    />
</template>

<script lang="ts" setup>
defineProps<{ title: string }>(); // v-model 的参数名 title 作为 prop
defineEmits<{ (e: 'update:title', val: string): void }>(); // 自定义事件名也变成了 update:title
</script>

v-model 的修饰

  • v-model 有一些内置的修饰符 (.trim.number.lazy)
  • 若使用了自定义修饰符,可通过 modelModifiers prop 在组件内访问该自定义修饰符
  • 若 v-model 携带着参数,eg: v-model:title,则 prop 为 titleModifiers
<template>
    {{ title }}
    <input
        type="text"
        :value="title"
        @input="$emit('update:title', ($event.target as any).value)"
    />
</template>

<script lang="ts" setup>
const props = withDefaults(
    defineProps<{
        title: string;
        titleModifiers: {}; // 接收 prop titleModifiers
    }>(),
    {
        title: '',
        titleModifiers: () => ({}), // 设置默认值为空对象
    }
);
defineEmits<{ (e: 'update:title', val: string): void }>();

console.log(props.titleModifiers); // { capitalize: true }
</script>

上例中,props.titleModifiers 的值为 { capitalize: true },是因为 v-model 使用了修饰符 capitalize

有了这个 prop,就可以检查 modelModifiers 对象key,并编写一个处理函数以改变抛出的值

<template>
    {{ title }}
    <input
        type="text"
        :value="title"
        @input="emitValue"
    />
</template>

<script lang="ts" setup>
const props = withDefaults(
    defineProps<{
        title: string;
        titleModifiers: {};
    }>(),
    {
        title: '',
        titleModifiers: () => ({}),
    }
);
const emit = defineEmits<{ (e: 'update:title', val: string): void }>();

function emitValue(e: any) {
    let value = e.target.value;
    if ((props.titleModifiers as any).capitalize) {
        value = value.charAt(0).toUpperCase() + value.slice(1);
    }
    emit('update:title', value);
}
</script>

原文地址:https://blog.csdn.net/Superman_H/article/details/128834328

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

如若转载,请注明出处:http://www.7code.cn/show_7859.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注