关于vue.js:面试官你真的了解-vmodel-吗vue2

浏览本文📖

你将:

  • 弄明确: 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 相干技术栈,我的指标是给大家分享最实用、最有用的知识点,心愿大家都能够早早上班,并能够飞速实现工作,淡定摸鱼🐟。

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

评论

发表回复

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

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理