微信图片_20211216220421.jpg

之前只会用不会说,这次扒个干净

啥是双向绑定

在 Vue 中 :value 实现了 模型到视图 的数据绑定,@event 实现了 视图到模型 的事件绑定:

概览

以下是对vue3 v-model变化的总体概述:

  • 非兼容:用于自定义组件时,v-modelprop 和事件默认名称已更改:
    • prop:value -> modelValue
    • 事件:input -> update:modelValue
  • 非兼容v-bind.sync 修饰符和组件的 model 选项已移除,可在 v-model 上加一个参数代替;
  • 新增:现在可以在同一个组件上使用多个 v-model 绑定;
  • 新增:现在可以自定义 v-model 修饰符。

介绍

Vue 2.0中使用 v-model 指令时必须使用名为 value 的 prop。如果开发者出于不同的目的需要使用其他的 prop,他们就不得不使用 v-bind.sync。此外,由于v-modelvalue 之间的这种硬编码关系的原因,产生了如何处理原生元素和自定义元素的问题。

Vue 2.2 中,引入了 model 组件选项,允许组件自定义用于 v-model 的 prop 和事件。但是,这仍然只允许在组件上使用一个 v-model

Vue 3 中,双向数据绑定的 API 已经标准化,以减少开发者在使用 v-model 指令时的混淆,并且更加灵活。

vue3用法

基本用法

3.x 中,自定义组件上的 v-model 相当于传递了 modelValue prop 并接收抛出的 update:modelValue 事件:

<ChildComponent v-model="pageTitle" />

<!-- 是以下的简写: -->

<ChildComponent
  :modelValue="pageTitle"
  @update:modelValue="pageTitle = $event"
/>

我们可以看看编译器编译生成的渲染函数解析模板的结果

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  const _component_ChildComponent = _resolveComponent("ChildComponent")

  return (_openBlock(), _createBlock(_component_ChildComponent, {
    modelValue: _ctx.pageTitle,
    "onUpdate:modelValue": $event => ((_ctx.pageTitle) = $event)
  }, null, 8 /* PROPS */, ["modelValue", "onUpdate:modelValue"]))
}

为了让它正常工作,子组件内的 <input> 必须:

  • 将其 value attribute 绑定到一个名叫 modelValue 的 prop 上
  • 在其 input 事件被触发时,将新的值通过自定义的 update:modelValue 事件抛出

写成代码之后是这样的:

// 子组件
<script setup lang="ts">
const props = defineProps({
  modelValue: String,
});
const emits = defineEmits(["update:modelValue"]);
const update=(e)=>{
    emits('update:modelValue',e.target.value)
}
</script>
<template>
  <div>
    儿子: {{ modelValue }}
    <input
      :value="modelValue"
      @input="update"
    />
  </div>
</template>

需要注意的是父组件在定义接收变量时需要使用ref函数将其变为响应式的,不然其值不会改变

<script setup>
let childMsg = ref("1");
</script>

<template>
  <div>
    父亲:{{ childMsg }}
    <Child v-model="childMsg" />
  </div>
</template>

v-model 参数

若需要更改 model 的名称,现在我们可以为 v-model 传递一个参数,以作为组件内 model 选项的替代,这也可以作为 .sync 修饰符的替代,而且允许我们在自定义组件上使用多个 v-model

<ChildComponent v-model:title="pageTitle" v-model:content="pageContent" />

<!-- 是以下的简写: -->

<ChildComponent
  :title="pageTitle"
  @update:title="pageTitle = $event"
  :content="pageContent"
  @update:content="pageContent = $event"
/>

v-model 修饰符

vue3提供了自定义修饰符,添加到组件 v-model 的修饰符将通过 modelModifiers prop 提供给组件。当组件的 created 生命周期钩子触发时,modelModifiers prop会包含 自定义修饰符,且其值为 true

// 定义一个将手机号码格式化为xxx-xxxx-xxx形式的修饰符formattingPhone
// 父组件
<child v-model.formattingPhone="phone" />

我们可以看看渲染函数

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  const _component_child = _resolveComponent("child")

  return (_openBlock(), _createBlock(_component_child, {
    modelValue: _ctx.phone,
    "onUpdate:modelValue": $event => ((_ctx.phone) = $event),
    modelModifiers: { formattingPhone: true }
  }, null, 8 /* PROPS */, ["modelValue", "onUpdate:modelValue"]))
}
// 子组件
<script setup lang="ts">
const props = defineProps({
  modelValue: String,
  modelModifiers: {
      default: () => ({})
    }
});
const emits = defineEmits(["update:modelValue"]);
const update=(e)=>{
	if(props.modelModifiers.formattingPhone){
		// 格式化操作
	}
	// 当然为了方便数据库存储,传给父组件的值还是原本的手机号
    emits('update:modelValue',e.target.value)
}
</script>
<template>
  <div>
    儿子: {{ modelValue }}
    <input
      :value="modelValue"
      @input="update"
    />
  </div>
</template>

对于带参数的 v-model 绑定,生成的 prop 名称将为 arg + "Modifiers"

// 父组件
<Child v-model:phone.formattingPhone=phone />

// 子组件
const props = defineProps({
  phone: String,
  phoneModifiers: {
      default: () => ({})
    }
});

恭喜你,看到这已经学会基本使用vue3版的v-model,光说不练假把式,去试试吧。

但是你以为这就可以了嘛。看看题目,我们原理还不知道啊。

其实vue中双向绑定是数据劫持+发布订阅模式实现的,我们之前有讨论过响应式原理了,它是采用proxy实现数据劫持

谈谈观察者模式和发布订阅者模式

观察者模式

观察者模式属于行为型模式。

用于定义对象间的一种一对多的依赖关系,当一个对象(被观察者)的状态发生改变时,所有依赖于它的对象(观察者)都得到通知并被自动更新。

优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。

缺点: 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

发布订阅模式

软件架构中,发布订阅是一种消息范式,消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者)。而是将发布的消息分为不同的类别,无需了解哪些订阅者(如果有的话)可能存在。同样的,订阅者可以表达对一个或多个类别的兴趣,只接收感兴趣的消息,无需了解哪些发布者(如果有的话)存在。

发布订阅模式是最常用的一种观察者模式的实现,并且从解耦和重用角度来看,更优于典型的观察者模式

发布者和订阅者是互相不知道对方的存在的,发布者只需要把消息发送到订阅器里面,订阅者只管接受自己需要订阅的内容

由此发布订阅模式是一种松耦合的关系,watcher 和 Observer 之间是互相不受影响