乐趣区

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

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

退出移动版