关于 v-model

vue 开发开发中, v-model 是一个非常常用的属性.

常规模式下,我们给定当前组件的某个 data 属性值,并设置 v-model 到对应的 表单元素 的属性上.

这样就建立了 input 表单元素和 data 数据的双向绑定了.


<div id="app">
    <input type="text" v-model="userName" />
</div>

<script>
    new Vue({
        el: '#app',
        data: {
            userName: ''
        }
    })
</script>

这个时候:

  • 我们在 input 文本框里修改 value 值,会影响 userName 这个 data 属性.
  • 我们在代码逻辑中,修改 this.userName = 'xxxx' 也会影响到 input 的 value 值.

原理也很简单.

  • data里的userName,被 Object.defineProperty() 定义后,具备了 set/get 的监听器.
  • input 元素本身就有 input 事件,能监听自己的 value 值修改.
  • 在对应的自己修改的时机里,修改对方的值即可.
image.png

也就是说,当我们使用 v-model 指令时,这个指令实质上帮我们做了两件事情:

  • 将对应的 data 属性 userName 绑定到 Dom.value 上.由于 data.userName 有 set,当值修改的时候,会同步更新 DOM.value
  • 被绑定的 DOM 元素会发布 @input 事件,当前组件根根据这个 input 来获取最新的 DOM.value 并同步被绑定的 data.userName

v-model 到底是怎么做的?

现在不使用 v-model 指令,而是利用上述得出的规律,手动的完成 v-model 的特性.

HTML 部分

 <div id='app'>
    <!-- v-model 等价于下面这段HTML -->
    <input type="text" v-model="userName" />
    <!-- v-model做的事情. -->
    <input type="text" :value="userName" @input="hanlderInputClick" />
  </div>

JavaScript 部分

var app = new Vue({
    el: '#app',
    data: {
      userName: '李四'
    },
    methods: {
      // 我们在使用 v-model 时 会我们隐式添加这个事件响应方法.
      hanlderInputClick (e) {
        this.userName = e.target.value
        console.log(this.userName)
      }
    },
  })
  • 首先在 input 元素中,我们使用 :value='userName' 建立了 data -> dom 之间的单向数据流动关系.这样在 data 属性发生改变时(监听到 set),就可以同步的修改 input 的 value 值了.
  • 其次,我们在让 input 元素发布 input 事件,并让组件提供事件响应方法. 建立了 dom -> data 直接单向数据流动的关系. 这样,input 元素才发生 value 的 change 时,能同步的修改 data 里的值. dom -> data

所以, v-model 指令,就帮我们做了两件事情.

  • 利用 :value="data" 建立 data -> dom 的流动关系.
  • 利用 @inutput 建立 dom -> data 的流动关系.

于是数据的双向流动关系就打通了.

所以 v-model="userName" 等价于 :value="userName" & @input="hanlderInputChange".(@input 事件监听以及 handlerInputChange 是 vue 在后帮我们自动提供的)

将数据绑定到 dom 上,并提供 dom 的@input 事件.


关于组件间的 v-model

根据上述内容,我们已经知道了 v-model 无非就是做了两件事情.

  • 属性绑定到对应的 input
  • 对应的 input 像外发布 @input 事件.

第一点什么好说的. 属性绑定任何元素可组件都可以非常方便的执行.

关键在于第二点,像外发布 @input 事件.

为什么 v-model 不能绑定在 DIV,p,<img /> .... 上 ?

常规情况下,这些元素都这是用于容器,或者展示静态文字和图片的 HTML 元素.

它基本不具备用户交互(这里的交互指的是编辑和修改)的功能(没有数据修改)

同时,它们也不具备类似 @input 事件. (即使有数据修改,也不能发布出来)

数据只能是单项的,从 data -> div,p, img.

所以我们现在知道了 v-model 一个非常重要的前提:

被绑定的元素必须包含可以变化自身数据 & 以及能将这种变化传递出去的能力.

那在组件上使用 v-model 是想表达什么意思呢?

组件是什么?

组件就是一个 js 对象.

里面包含一个数据,方法,以及最重要的 template 模板(render).

我们肉眼能看到的组件,就是 template 里的 HTML 模板外加一个数据展示.

那如果,我们在组件上使用 v-model ,对于这个组件来说,意味着什么呢?

查看下面这段代码

<div id='root'>
    <child v-model="parentData"></child>
</div>

  • 首先 parentData 是 顶层 root 组件的一个 data 属性.
  • 接着在 child 组件标签上设置了 v-model='parentData'

在视觉上,就好像我们给一个 input 元素设置了 v-model 一样.

但是问题是:

  • 在 input 元素,它有一个位置可以显示这个 parentData, 一般是 value 值.
  • 第二个,input 元素有 @input 事件,可以将自身 value 的改变,同步到 parentData 上.

在组件上写 v-model 是个什么鬼??

首先,不管是什么鬼.

我们在组件上写 v-model 并传递了数据 parentData.

主要的目的之一,肯定是希望在将 root 组件的 parentData 传递到 child 组件内部的.

child 组件内部如何去接受这个 parentData 这个值呢?

官方文档介绍说:

在组件上使用 v-model 会默认的设置到组件的 props 中名为 value 的属性值上.

根据上述说明,在组件上使用 v-model 可以等价于.

<div id='root'>
    <!--<child v-model='parentData'></child>-->
    <!--等价于-->
    <child :value='parentData'></child>
</div>

<child :value='parentData'></child>???

这不就是父组件向子组件传递数据的 props 语法么?

Vue.component('child',{
    props:['value']
    template: `<h1>{{value}}</h1>`
})

这样,在组件上使用 v-model 将数据从 root -> child 就已经打通了.

<div id='app'>
    <p>一般v-model在常规的情况下,我们是用作于input表单元素的</p>
    <input type="text" v-model="userName" />
    <!-- v-model到底做了什么事情? -->
    <!-- <input type="text" :value="userName" @input="hanlderInputClick">
    <button @click="hanlderClick">getUserName</button> -->
    <p>当一个v-model作用与一个组件的时候,到底代表的是什么意思?</p>
    <comp-one v-model="userName"></comp-one>
  </div>
  let CompOne = {
    props:['value'], //v-model 等价于 :value='parentData' 所以这里写的是 value
    data () {
      return {
        msg: '我是compone组件'
      }
    },
    template: `<div @click="hanlderClick">
        <label>{{msg}}</label>
        <input type='text' :value="value" />
      </div>`
  }
image.png

到目前为止,v-model 的数据从父组件传递到了子组件,且可以在子组件内部通过 props 在任意元素上去显示了.

但是数据流动只是单向的,从父组件传递到了子组件.

怎么才能在子组件中的数据修改之后,能够会传到父组件呢?

对于不可编辑修改以及没有往外发布变动实际的 span 来说,肯定是没戏了.

那如果我们利用组件内的那个 input 元素的事件呢?

 let CompOne = {
    props:['value'], //v-model 等价于 :value='parentData' 所以这里写的是 value
    data () {
      return {
        msg: '我是compone组件'
      }
    },
    template: `<div>
        <label>{{msg}}</label> <br />
        一个可以发布 input 事件的元素:<input type='text' :value="value" @input="hanlderClick" /> <br/>
        一个普的 span 标签,没有 input 事件: <span>{{value}}</span>
      </div>`,
    methods: {
    // 让组件内的 input 元素,往外发布 input 事件.
      hanlderClick (e) {
        this.$emit('input',e.target.value)
      }
    },
  }

查看结果:

image.png

结论

  • 在组件上使用 v-model ,会默认将这个值以 :value 的形式传递到组件的 props 上.
  • 我们在组件的内部,仍然需要自己拿到这个 props.value 在使用.
  • 一般使用到 input 元素上,可以在组件内部发布一个当前表单元素的 input 事件到外部.
  • 外部组件会默认的帮我们注册 input 事件的响应函数,并同步更新 v-model 传递过去的数据.

未完待续......

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容