浏览本文

你将:

  • 弄明确: v-model 是什么的语法糖? vue2 对原生组件到底做了什么非凡解决?
  • 弄明确: v-model 到底是单向数据流还是数据双向绑定
  • 弄明确: v-model 在语法糖之外的『副作用』?
  • 学会如何让你的组件也反对 v-model 语法。

一、v-model 的实质是语法糖。

v-model 实质上不过是语法糖。它负责监听用户的输出事件以更新数据,并对一些极其场景进行一些非凡解决。』 -- 官网文档

什么是语法糖?

语法糖,简略来说就是『便捷写法』。

在大部分状况下, v-model="foo" 等价于 :value="foo" 加上 @input="foo = $event"

<!-- 在大部分状况下,以下两种写法是等价的 --><el-input v-model="foo" /><el-input :value="foo" @input="foo = $event" />

没错,在大部分状况下如此。
但也有例外:

  1. vue2 给组件提供了 model 属性,能够让用户自定义传值的prop名更新值的事件名。这个暂且略过,第四节会细说。
  2. 对于原生 html 原生元素,vue 干了大量『脏活儿』,目标是为了能让咱们漠视 html 在api上的差异性。以下元素的左右两种写法是等价的:

    • textarea 元素:
    • select 下拉框:
    • input type='radio' 单选框:
    • input type='checkbox' 多选框:

在编程思维上,这种帮忙使用者『暗藏细节』的形式叫封装

二、v-model 仅仅是语法糖吗?(冷常识)

v-model 不仅仅是语法糖,它还有副作用。

副作用如下:如果 v-model 绑定的是响应式对象上某个不存在的属性,那么 vue 会悄悄地减少这个属性,并让它响应式。

举个例子,看上面的代码:

// template中:<el-input v-model="user.tel"></el-input>// script中:export default {  data() {    return {      user: {        name: '公众号: 前端要摸鱼',      }    }  }}

响应式数据中没有定义 user.tel 属性,然而 template 里却用 v-model 绑定了 user.tel,猜一猜当你输出时会产生什么?

看成果:

揭晓答案吧:
user 上会新增 tel 属性,并且 tel 这个属性还是响应式的。

这就是『副作用』带来的成果,你学会了吗?

三、 v-model 是双向绑定还是单向数据流?

2.1 v-model 是双向绑定吗?

是,官网说是。

『你能够用 v-model 指令在表单 <input><textarea><select> 元素上创立双向数据绑定。』 —— vue2官网文档

2.2 那 v-model 是单向数据流吗?

是的,它甚至是单向数据流的典型范式。

尽管官网没有明确示意这点,但咱们能够捋一捋两者的关系。

  • 什么是单项数据流?
    子组件不能扭转父组件传递给它的 prop 属性,举荐的做法是它抛出事件,告诉父组件自行扭转绑定的值。
  • v-model 的做法是怎么的?
    v-model 做法完全符合单项数据流。甚至于,它给出了一种在命名和事件定义上的标准。

家喻户晓 .sync 修饰符是单向数据流的另一个典型范式。

『单向数据流』总结起来其实也就8个字:『数据向下,事件向上』。

四、如何让你开发的组件反对 v-model

尽管不想说,但这的确是高频面试题。

在定义 vue 组件时,你能够提供一个 model 属性,用来定义该组件以何种形式反对 v-model

model 属性自身是有默认值的,如下:

// 默认的 model 属性export default {  model: {    prop: 'value',    event: 'input'  }}

也就是说,如果你不定义 model 属性,或者你依照当面办法定义属性,当其他人应用你的自定义组件时,v-model="foo" 就齐全等价于 :value="foo" 加上 @input="foo = $event"

如果把 model 属性进行一些改装,如下:

// 默认的 model 属性export default {  model: {    prop: 'ame',    event: 'zard'  }}

那么,v-model="foo" 就等价于 :ame="foo" 加上 @zard="foo = $event"

没错,就是这么容易,让咱们看个例子。

先定义一个自定义组件:

<template><div>  咱们是TI{{ ame }}冠军  <el-button @click="playDota2(1)">加</el-button>  <el-button @click="playDota2(-1)">减</el-button></div></template><script>export default {  props: {    ame: {      type: Number,      default: 8    }  },  model: { // 自定义v-model的格局    prop: 'ame', // 代表 v-model 绑定的prop名    event: 'zard' // 代码 v-model 告诉父组件更新属性的事件名  },  methods: {    playDota2(step) {      const newYear = this.ame + step      this.$emit('zard', newYear)    }  }}</script>

而后咱们在父组件中应用该组件:

// template中<dota v-model="ti"></dota>// script中export default {  data() {    return {      ti: 8    }  }}

看看成果:

让你的组件反对 v-model 就这么容易。

五、demo和源码

获取源码请拜访github zhangshichun的github

六、完结

我是春哥
我酷爱 vue.js , ElementUI , Element Plus 相干技术栈,我的指标是给大家分享最实用、最有用的知识点,心愿大家都能够早早上班,并能够飞速实现工作,淡定摸鱼。

你能够在公众号里找到我:前端要摸鱼
心愿大家玩得开心。