Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

谈谈你对v-model双向绑定原理的理解? #108

Open
GGXXMM opened this issue Mar 10, 2022 · 0 comments
Open

谈谈你对v-model双向绑定原理的理解? #108

GGXXMM opened this issue Mar 10, 2022 · 0 comments
Labels

Comments

@GGXXMM
Copy link
Owner

GGXXMM commented Mar 10, 2022

双向绑定的定义

vue中双向绑定是一个指令v-model,可以绑定一个响应式数据到视图,同时视图中变化能改变该值。

双向绑定的好处

v-model是语法糖,默认情况下相当于 :value和@input。使用 v-model 可以减少大量繁琐的事件处理代码,提高开发效率。

v-model的使用

通常在表单项上使用v-model,还可以在自定义组件上使用,表示某个值的双向绑定。

使用方式

vue2

1. 用在表单项
通过 <input v-model="xxx"> 的方式将xxx值绑定到表单元素的value上。还可以结合 .lazy, .number, .trim修饰符对 v-model 的行为做进一步限定。

2. 用在自定义组件
自定义组件绑定v-model使用,需要在组件内绑定输入事件。

  • text 和 textarea 使用 value 属性和 input 事件
  • checkbox 和 radio 使用 checked 属性和 change 事件
  • select 字段将 value 作为 prop 并将 change 作为事件
// 子组件
<template>
 <div>
  <button @click="increase">increase</button>
 </div>
</template>
<script>
let sum = 0
export default {
 name: 'vmodel',
 props: {
  value: {
   type: Number,
   default: 0
  }
 },
 methods: {
  increase () {
   this.$emit('input', ++sum)
   console.log('value1', this.value)
   
   setTimeout(() => {
    console.log('value2', this.value)
   }, 50)
  }
 }
}
</script>
// 父组件
<div>
  <increase v-model="rangeValue"></increase>
  <p>value:{{rangeValue}}</p>
</div>
<script>
data () {
  return {
   rangeValue: 0
  }
}
</script>

vue3

vue3中可以用参数的形式绑定表单和自定义组件,例如:v-model:foo。(v-model用法统一,非常强大)

双向绑定的原理

v-model 只是语法糖,编译器转换为渲染函数之后,可以看到实际上是对表单项的value属性做了事件监听。
输出的渲染函数如下:

// <input type="text" v-model="foo">
_c('input', {
  directives: [{ name: "model", rawName: "v-model", value: (foo), expression: "foo" }],
  attrs: { "type": "text" },
  domProps: { "value": (foo) },
  on: {
    "input": function ($event) {
      if ($event.target.composing) return;
      foo = $event.target.value
} }
})

上述代码可见,input文本框监听了input事件。

// <input type="checkbox" v-model="bar">
_c('input', {
directives: [{ name: "model", rawName: "v-model", value: (bar), expression: "bar" }],
  attrs: { "type": "checkbox" },
  domProps: {
    "checked": Array.isArray(bar) ? _i(bar, null) > -1 : (bar)
  },
  on: {
    "change": function ($event) {
      var $$a = bar, $$el = $event.target, $$c = $$el.checked ? (true) : (false);
      if (Array.isArray($$a)) {
        var $$v = null, $$i = _i($$a, $$v);
        if ($$el.checked) { $$i < 0 && (bar = $$a.concat([$$v])) }
        else {
          $$i > -1 && (bar = $$a.slice(0, $$i).concat($$a.slice($$i + 1))) }
      } else {
bar = $$c }
} }
})

checkbox复选框监听了change事件。

// <select v-model="baz">
//     <option value="vue">vue</option>
//     <option value="react">react</option>
// </select>
_c('select', {
  directives: [{ name: "model", rawName: "v-model", value: (baz), expression: "baz" }],
  on: {
    "change": function ($event) {
      var $$selectedVal = Array.prototype.filter.call(
        $event.target.options,
        function (o) { return o.selected }
      ).map(
        function (o) {
          var val = "_value" in o ? o._value : o.value;
          return val
} );
      baz = $event.target.multiple ? $$selectedVal : $$selectedVal[0]
    }
} }, [
  _c('option', { attrs: { "value": "vue" } }, [_v("vue")]), _v(" "),
  _c('option', { attrs: { "value": "react" } }, [_v("react")])
])

select下拉选框监听了change事件。

@GGXXMM GGXXMM added the vue label Mar 10, 2022
@GGXXMM GGXXMM changed the title 谈谈你对vue双向数据绑定原理的理解? 谈谈你对v-model双向绑定原理的理解? Mar 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant