没时间学 Vue (14) —— 组件(三):双向数据传递

上一篇 《没时间学 Vue (13) —— 绑定(五):计算属性和侦听器》中 “乱入” 讲了计算属性和侦听器,本篇咱们接着《没时间学 Vue (12) —— 组件(二):组件的创建、使用和数据传递》,继续讲组件的数据传递。

本篇的主要内容如下

    • 1、组件把数据传递给使用者
    • 2、 第一版(v-bind 版,无法更新)
    • 3、第二版 (v-model 版,好大一颗语法糖)
    • 4、第三版($emit 自定义事件)
    • 5、第四版 ($emit + v-bind.sync)
    • 6、第五版(回调函数)
    • 7、思考题

1、组件把数据传递给使用者

我们前篇的例子中,组件本身只有展示功能,而没有编辑功能 —— 也就是没有各种 的功能。
实际的项目中会用到这类组件,但也有不少情况下会用到带编辑功能的组件 —— 比如说,基于某些数据字典(Master)数据的选择组件(如:权限、用户类型、或者其他的某业务数据类型等),也可能是点赞、打分这种点击后执行某种业务逻辑的组件。
我们先从模拟选择地理位置的组件开始入手。为了简化模型,我们只做选择省级行政区的组件。
民政部对县级和以上的行政区划有标准编码(http://www.mca.gov.cn/article/sj/xzqh/2020/),咱们从中选择省级行政区的即可。比如:

行政区划代码 地名
110000 北京市
120000 天津市
130000 河北省
140000 山西省
150000 内蒙古自治区

我们还是写好省级行政区的组件,然后在 App.vue 中使用和测试。
没时间学 Vue (14) —— 组件(三):双向数据传递_第1张图片

2、 第一版(v-bind 版,无法更新)

根据前两篇的内容,我们很快就能写出 “第一版” 来,大概是这样的。
省份选择组件 Location.vue:

<template>
  <span class="location">
    <select v-model="selected">
      <option
        v-for="location in locations"
        :key="location.code"
        :value="location.code"
        >{{ location.name }}option
      >
    select>
  span>
template>

<script>
export default {
  name: "Location",
  props: {
    selected: Number,
  },
  data: function() {
    return {
      locations: [
        { code: 110000, name: "北京市" },
        { code: 120000, name: "天津市" },
        { code: 130000, name: "河北省" },
        { code: 140000, name: "山西省" },
      ]
    };
  }
};
script>

<style>style>

App.vue

<template>
  <div id="app">
    <div>请选择位置:<Location :selected="location">Location>div>
    <div>您选择的位置是:{{ location }}div>
  div>
template>

<script>
import Location from "./components/Location";

export default {
  name: "App",
  components: {
    Location,
  },
  data: function() {
    return {
      location: 110000,
    };
  },
};
script>


<style>style>

验证一下效果。初始显示 OK!
但是,修改位置之后,App.vue 中的值并没有跟着改变 …
没时间学 Vue (14) —— 组件(三):双向数据传递_第2张图片
如果你对之前的章节还有印象,那么你很容易能推测出来:

  • 没时间学 Vue (12) —— 组件(二):组件的创建、使用和数据传递
    props 是用来单向接收来自使用者指定的数据的(参见:单向数据流
  • 没时间学 Vue (3) —— 绑定(二):v-bind 和 v-model
    v-bind 的数据是单向绑定的,因此无法更新 App.vue 中的 location 数据。

3、第二版 (v-model 版,好大一颗语法糖)

接着上面的原因分析,我们很容易想到:
既然 v-bind 是单向绑定的,那我们用双向绑定的 v-model 就好了。
于是我们像下面这样修改了代码:在这里插入图片描述
结果发现画面显示反而更糟糕了
没时间学 Vue (14) —— 组件(三):双向数据传递_第3张图片
不要吃惊,其实 Vue 官网(《表单输入绑定 - 基础用法》)上已经说了,

你可以用 v-model 指令在表单