vue双向数据绑定原理

Vue应用的是mvvm框架,view和model分离,然后通过vm双向数据绑定,`

<code class="hljs handlebars has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="xml" style="box-sizing: border-box;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"><!-- 模板 --></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">div</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0, 102);">id</span>=<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 0);">"app"</span>></span>
    </span><span class="hljs-expression" style="box-sizing: border-box;">{{<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">msg</span>}}</span><span class="xml" style="box-sizing: border-box;">
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">div</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">!-模型-</span>></span>
// 原生对象即数据
var data = {
    msg: 'hello!'
}
// 创建一个 ViewModel 实例
var vm = new Vue({
    // 选择目标元素
    el: '#app',
    // 提供初始数据
    data: data
})</span></code><code class="hljs handlebars has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="xml" style="box-sizing: border-box;"></span></code><p style="box-sizing: border-box; margin-top: 0px; margin-bottom: 1.1em; color: rgb(54, 46, 43); font-family: "microsoft yahei"; font-size: 14px; line-height: 26px;">然而一个动态数据的绑定,是怎么实现的呢,首先Vue利用es5的defineProperty方法里的get,set方法,进行数据的设置和获取。</p><pre class="prettyprint" name="code" style="white-space: nowrap; word-wrap: break-word; box-sizing: border-box; position: relative; overflow-y: hidden; overflow-x: auto; margin-top: 0px; margin-bottom: 1.1em; font-family: "Source Code Pro", monospace; padding: 5px 5px 5px 60px; font-size: 14px; line-height: 1.45; word-break: break-all; color: rgb(51, 51, 51); border: 1px solid rgba(128, 128, 128, 0.0745098); border-radius: 0px; background-color: rgba(128, 128, 128, 0.0470588);"><code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> Object.defineProperty(Vue.prototype, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'$data'</span>, {
     <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">get</span> () {
      <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>._data
     },
     <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">set</span> (newData) {
       <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (newData !== <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>._data) {
         <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>._setData(newData)
       }
     }   })
</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>

从这段源码可以看出设置数据时会调用setData方法,而setData的实现如下

<code class="hljs javascript has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">Vue.prototype._setData = <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(newData)</span> {</span>
    newData = newData || {}
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> oldData = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>._data
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>._data = newData
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> keys, key, i
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// unproxy keys not present in new data</span>
    keys = <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Object</span>.keys(oldData)
    i = keys.length
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> (i--) {
      key = keys[i]
      <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!(key <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> newData)) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>._unproxy(key)
      }
    }
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// proxy keys not already proxied,</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// and trigger change for changed values</span>
    keys = <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Object</span>.keys(newData)
    i = keys.length
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> (i--) {
      key = keys[i]
      <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!hasOwn(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>, key)) {
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// new property</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>._proxy(key)
      }
    }
    oldData.__ob__.removeVm(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>)
    observe(newData, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>)
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>._digest()
  }</code>

这段代码的后三行可知首先移除旧的数据,然后调用observe(newData, this);

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">export function observe (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">value</span>, vm) {
  <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">value</span> || <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typeof</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">value</span> !== <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'object'</span>) {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>
  }
  <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> ob
  <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (
    hasOwn(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">value</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'__ob__'</span>) &&
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">value</span>.__ob__ instanceof Observer
  ) {
    ob = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">value</span>.__ob__
  } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (
    shouldConvert &&
    (isArray(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">value</span>) || isPlainObject(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">value</span>)) &&
    Object.isExtensible(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">value</span>) &&
    !<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">value</span>._isVue
  ) {
    ob = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Observer(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">value</span>)
  }
  <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (ob && vm) {
    ob.addVm(vm)
  }
  <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> ob</code>


根据新的数据建立一个新的观察对象,这里提一下,vue用的是订阅模式,首先会把每个数据订阅一下,当数据变化时,会通知watcher重新计算值 
最后一行代码this._digest()就是通知更新对象的值,把对象设置成newData,我理解的大概过程是这样的,大家看到有错误理解的欢迎给我指出来。这里提醒一下之前犯过的错误,例如:

<code class="hljs handlebars has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="xml" style="box-sizing: border-box;"><span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">template</span>></span>
  <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">p</span>></span></span><span class="hljs-expression" style="box-sizing: border-box;">{{<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">user.sex</span>}}</span><span class="xml" style="box-sizing: border-box;"><span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">p</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">template</span>></span>

Data(){
User:{}
}
Ready(){
This.user={name:’smx’,age:12};
This.user.sex=’女’;
}</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul>

这将在视图里面无法显示,this.user是通过defineProperty里set方法设置进去的,所以在后面再设置属性的时候对象将不能跟踪到该属性



                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值