如何在vue3中优雅地使用v-model?

news/2024/7/19 15:08:15 标签: vue, js, javascript

文章目录

  • ps:vue3中推荐使用的是reactive写法,文中这种格式只是为了和vue2做对照,只是为了凸显vue3中对v-model的改进,仅供参考。
  • Vue中的数据绑定
      • v-bind
      • v-bind支持的类型
      • v-bind使用
      • v-model
  • vue2中v-model用法
    • 不使用v-model的双向绑定
      • 父组件
      • 子组件
    • 使用v-model后
      • 父组件
      • 子组件
      • 问题
  • .sync
  • vue2中使用v-model + .sync
      • 父组件
      • 子组件
  • vue3中v-model的使用
    • 父组件
    • 子组件
  • 总结

vue3reactivevue2vue3vmodel_4">ps:vue3中推荐使用的是reactive写法,文中这种格式只是为了和vue2做对照,只是为了凸显vue3中对v-model的改进,仅供参考。

Vue中的数据绑定

绑定数据有三种方式:

  • 插值,也就是{{name}}的形式,以文本的形式和实例data中对应的属性进行绑定
  • v-bind
  • v-model

v-bind

eg:v-bind:class 可简写为 :class

当加上v-bind:之后,它的值classe不是字符串,而是vue实例对应的data.class的这个变量。也就是说data.class是什么值,它就会给class属性传递什么值,当data.class发生变化的时候,class属性也发生变化,这非常适合用在通过css来实现动画效果的场合。他只是单向变动

v-bind支持的类型

html中的属性、css的样式、对象、数组、number 类型、bool类型

v-bind使用

// 绑定文本
<p v-bind="message"></p>

// 绑定属性

<p v-bind:src="http://...."></p>
<p v-bind:class="http://...."></p>
<p v-bind:style="http://...."></p>
// 绑定表达式
:class{className:true}

v-model

v-model 指令在表单 、 及 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理

主要是用在表单元素中,它实现了双向绑定。在同时使用v-bind和v-model中,v-model建立的双向绑定对输入型元素input, textarea, select等具有优先权,会强制实行双向绑定。很多时候v-model使用在表单的<input>中实现双向绑定。

v-model实现了表单输入的双向绑定,一般是这么写的:

 <div id="app">
     <input v-model="price">
 </div>
<script>javascript">
    new Vue({
        el: '#app',
        data: {
            price: ''
        }
    });
</script>

通过该语句实现price变量与输入值双向绑定

实际上v-model只是一个语法糖,真正的实现是这样的:

<input type="text" 
      :value="price" 
      @input="price=$event.target.value">

以上代码分几个步骤:

  • 将输入框的值绑定到price变量上,这个是单向绑定,意味着改变price变量的值可以改变input的value,但是改变value不能改变price

  • 监听input事件(input输入框都有该事件,当输入内容时自动触发该事件),当输入框输入内容就单向改变price的值

这样就实现了双向绑定。

<input v-model="giveDate" />
<input :value="giveDate" @input="giveDate = $event.target.value" /> 

第一行的代码其实只是第二行的语法糖。

vue2vmodel_95">vue2中v-model用法

不使用v-model的双向绑定

如下代码所示,这是不用v-model时候的写法。

父组件使用v-bind给子组件中的props传值。

子组件需要使用emit方法来实现子组件---->父组件方向上的绑定。

父组件

<!--父组件-->
<template>
    <div>
        <!--在子组件中用emit("test")传达给父组件的getData方法中-->
        <search @test="getData" :keywords="keywords"></search>
        <button @click="submit">提交</button>
    </div>
</template>
<script>javascript">
import search from '@/components/index/search.vue'
export default {
    data() {
        return {
            keywords: ''
        }
    },
    components: {
        search
    },
    methods: {
        // 在这里实现更改父组件的值
        getData(val){
            this.keywords = val
        },
        submit() {
            console.log('keywords:', this.keywords)
        }
    }
}
</script>

子组件

<!--子组件-->
<template>
    <div>
        <input @input="inputChange" type="text" name="keywords">
    </div>
</template>
<script>javascript">
export default {
    props: ['keywords'],
    methods: {
        inputChange(e) {
          	// 传给父元素的test函数
            this.$emit('test', e.target.value)
        }
    }
}
</script>

即,在父组件中,通过v-bind给子组件传参,同时指定v-on和指定修改目标值的函数。

在子组件中,接受父组件v-bind传过来的值,实现父->子方向上的绑定,然后通过emit方法,向父组件传出$event.target.value,实现子->父方向上的绑定。

使用v-model后

父组件

<!-- parent -->
<template>
  <div class="parent"><p>父组件将传递给子组件的数据是:
    <input type="text" v-model="giveChildData"/></p>
    <Child v-model="giveChildData"></Child>
  </div>
</template>
<script>javascript">
import Child from './Child.vue';
export default {
  name: "Father",
  data() {
    return {
      todosth: 0,
      giveChildData: '儿子,爸要把家产传给你啊!'
    };
  },
  components: {
    Child
  }
}
</script>

子组件

<!-- child -->
<template>
  <div class="child">
    <p>子组件将通过$emit调用父组件的函数并修改数据:{{ give }}</p>
    <span @mousemove="returnBackFn">答复</span>
  </div>
</template>
<script>javascript">
export default {
  name: "Child",
  props: {
    give:
        {
          type: String,
          default: '0'
        }
  },
  model: {
    prop: 'give',
    event: 'returnBack'
  },
  methods: {
    returnBackFn() {
      this.$emit('returnBack', '啥家产?有矿啊!');
    }
  }
};</script>


这里的 giveChildData 的值将会传入这个名为 give 的 prop。同时当 <Child>触发一个 returnBack 事件并附带一个新的值的时候,这个 giveChildData 的属性将会被更新。

问题

但是当有多个数据需要父子组件之间双向绑定时,v-model只能传其中一个值。这时候需要使用.sync来实现其他数据的绑定。

.sync

从 2.3.0 起,vue重新引入了 .sync 修饰符,但是这次它只是作为一个编译时的语法糖存在。它会被扩展为一个自动更新父组件属性的 v-on 监听器。
示例代码如下:

<comp :foo.sync="bar"></comp>

会被扩展为:

<comp :foo="bar" @update:foo="val => bar = val"></comp>

当子组件需要更新 foo 的值时,它需要显式地触发一个更新事件:

this.$emit('update:foo', newValue)

实例如下。(弹窗的关闭事件)

<template>
  <div class="details">
    <myComponent
        :show.sync='valueChild'
        style="padding: 30px 20px 30px 5px;border:1px solid #ddd;margin-bottom: 10px;"
    >
    </myComponent>
    <button @click="changeValue">toggle</button>
  </div>
</template>
<script>javascript">
import Vue from 'vue'

Vue.component(
    'myComponent', {
      template: `
        <div v-if="show">
        <p>默认初始值是{{ show }},所以是显示的</p>
        <button @click.stop="closeDiv">关闭</button>
        </div>`,
      props: ['show'],
      methods: {
        closeDiv() {
          this.$emit('update:show', false); //触发 input 事件,并传入新值
        }
      }
    })
export default {
  data() {
    return {
      valueChild: true,
    }
  },
  methods: {
    changeValue() {
      this.valueChild = !this.valueChild
    }
  }
}
</script>

效果如下图。

img

vue2vmodel__sync_306">vue2中使用v-model + .sync

由于v-model只能默认传进去一个值,剩下的需要使用.sync实现双向绑定。

对于v-model传进来的数,子组件用emit方法向父组件的“input”传值(注:是v-model默认监听的方法)。

而对于.sync传进来的数,则是通过在子组件中,使用emit向父组件的update:绑定数据名,进行传值(注:默认提供了update方法,当然也可以自己在父组件中自定义一个修改绑定值的函数)。

父组件

<h1>name01:{{ name01 }} </h1>
<h1>age01:{{ age01 }} </h1>
<model01
         :model="age01"
         :name.sync="name01"
         >
</model01>
...

<script>javascript">
export default{
    data(){
        return{
            age01: 18,
            name01: "username"
        }
    }
}
    
</script>

子组件

<template>
  <div class="custom-input">
    <h1>vue2中的v-model</h1>
    <input
        type="text"
        :value="age"
        @input="$emit('input', $event.target.value)"
    />
    <!--上面的emit中的“input”是v-model默认监听的函数-->
    <br>
    <input type="text" :value="name" @input="$emit('update:name', $event.target.value)"/>
     <!--name使用的是.sync实现绑定的-->
  </div>
</template>

<script>javascript">
export default {
  name: "Model01",
  props: [
    'age',
    'name'
  ],
  model:{
      
  }
  methods: {
  }
}
</script>

<style scoped>

</style>

vue3vmodel_378">vue3中v-model的使用

接下来就是正点了。

父组件

vue3中,将之前的v-model和.sync整合到一起了,并淘汰了.sync写法。

现在,v-model在组件之间的使用再也不用像以前那样臃肿了,极其舒爽。

只需要在v-model上指定传值。例如:

<model02
	v-model:age="age02"
	v-model:name="name02"
 ></model02>

这里就是将父组件中的age02变量传入到子模块的props中的age变量中。

子组件只要使用如下调用update:age的方式,就能将age的变化由子组件的age传入到父组件的age02变量上。

$emit('update:age', 传给父组件的值);
....
<h1>name02:{{ name02 }} </h1>
<h1>age02:{{ age02 }} </h1>
<!--     vue3写法-->
<model02
	v-model:age="age02"
	v-model:name="name02"
 ></model02>
....

子组件

<template>
  <div class="custom-input">
    <h1>vue3中的v-model</h1>
    <input type="text" :value="age" @input="onAgeInput"/>
    <br>
    <input type="text" :value="name" @input="onNameInput"/>
  </div>
</template>

<script>javascript">
export default {
  name: "Model02",
  props: [
    'age',
    'name'
  ],
  methods: {
    onAgeInput(e) {
      this.$emit('update:age', parseFloat(e.target.value));
    },
    onNameInput(e) {
      this.$emit('update:name', e.target.value)
    }
  }
}
</script>

<style scoped>

</style>

实现效果图:

img

总结

vue3中的v-model比以前舒爽太多了!

ps:vue3中推荐使用的是setUp()写法,上面这种格式只是为了和vue2做对照,只是为了凸显vue3中对v-model的改进,仅供参考。


http://www.niftyadmin.cn/n/555227.html

相关文章

04_web基础(七)之jsp

39.jsp与el表达式引入 JSP:Java Server Pages:Java的服务网页(Java动态网页):Servlet的缺陷: 输出动态网页,超级麻烦! 没有体现责任分离思想(谁最擅长做什么,就应该做什么!)!实现动态网页:Servlet: Java代码(主) html片段(辅) --->动态网页.JSP: Java代码…

百度地图获取省市边界、设置图片背景

1.获取省市边界 &#xff08;1&#xff09;初始化地图 引入文件&#xff1a; <script type"text/javascript"src"http://api.map.baidu.com/api?v2.0&akW5mG5fGfiU73Yy2WmaWKzaKw"></script>初始化方法&#xff1a; // 初始化地图 in…

Js实现数组的指定位置的插入方法insert()

文章目录前言Array.prototype.splice()定义和用法语法返回值说明实现insert()插入函数前言 js的数组中没有插入方法&#xff0c;实现插入需要通过splice间接地实现。 Array.prototype.splice() 定义和用法 splice() 方法向/从数组中添加/删除项目&#xff0c;然后返回被删除…

WebApiThrottle限流框架使用手册

阅读目录&#xff1a; 介绍基于IP全局限流基于IP的端点限流基于IP和客户端key的端点限流IP和客户端key的白名单IP和客户端key自定义限制频率端点自定义限制频率关于被拒请求的计数器在web.config或app.config中定义限制策略获取API的客户端key存储限流的数据运行期间更新限制频…

elment-ui 树形控件基础用法

1.渲染树形控件 树形控件的结构是一层层嵌套的&#xff0c;官网上定义好的结构中属性名我们无法更改&#xff0c;实际开发中后台返回的字段名与属性名也会不一致&#xff0c;这里我们用到了“递归”的方法将结构中的属性赋予实际开发中的值。 &#xff08;1&#xff09;树形结…

CSS清除浮动的几种常见方法

文章目录浮动优点缺点清除浮动一、额外标签法实例二、父级添加overflow属性实例三、使用&#xff1a;after实例四、使用双伪元素实例五、手动设置父级高度实例注意浮动 当元素浮动以后可以向左或向右移动&#xff0c;直到它的外边缘碰到包含它的框或者另外一个浮动元素的边框为…

Hive入门介绍

hive转载于:https://www.cnblogs.com/duanxz/p/9010625.html

函数的方法Date

在JS中所有时间相关的内容都是使用Date对象来表示。如果我们之间创建一个新的Date对象&#xff0c;则该对象中会封装当前的时间。可以在构造函数中能够传递一个日期的字符串&#xff0c;来创建一个指定日期的Date对象。格式&#xff1a;月/日/年 时:分:秒 1.时间相关方法 get…