mirror of
https://github.com/ZiuChen/ZiuChen.github.io.git
synced 2025-08-18 23:49:33 +08:00
40 lines
15 KiB
JavaScript
40 lines
15 KiB
JavaScript
import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.eaa7ef56.js";const b=JSON.parse('{"title":"浅析defineProperty与Proxy实现的双向绑定","description":"","frontmatter":{},"headers":[],"relativePath":"article/浅析defineProperty与Proxy实现的双向绑定.md","filePath":"article/浅析defineProperty与Proxy实现的双向绑定.md","lastUpdated":1700152426000}'),p={name:"article/浅析defineProperty与Proxy实现的双向绑定.md"},o=l(`<h1 id="浅析defineproperty与proxy实现的双向绑定" tabindex="-1">浅析defineProperty与Proxy实现的双向绑定 <a class="header-anchor" href="#浅析defineproperty与proxy实现的双向绑定" aria-label="Permalink to "浅析defineProperty与Proxy实现的双向绑定""></a></h1><blockquote><p>文章内容总结自Vue官网 <a href="https://cn.vuejs.org/v2/guide/reactivity.html#%E5%A6%82%E4%BD%95%E8%BF%BD%E8%B8%AA%E5%8F%98%E5%8C%96" target="_blank" rel="noreferrer">深入响应式原理</a></p></blockquote><h2 id="🔰-vue2的响应式原理" tabindex="-1">🔰 Vue2的响应式原理 <a class="header-anchor" href="#🔰-vue2的响应式原理" aria-label="Permalink to "🔰 Vue2的响应式原理""></a></h2><p><img src="https://v2.cn.vuejs.org/images/data.png" alt="image.png"></p><blockquote><p>当你把一个普通的 JavaScript 对象传入 Vue 实例作为 <code>data</code> 选项,Vue 将遍历此对象所有的 property,并使用 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty" target="_blank" rel="noreferrer"><code>Object.defineProperty</code></a> 把这些 property 全部转为 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Working_with_Objects#%E5%AE%9A%E4%B9%89_getters_%E4%B8%8E_setters" target="_blank" rel="noreferrer">getter/setter</a>。</p><p>每个组件实例都对应一个 <strong>watcher</strong> 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。</p></blockquote><p>Vue2的响应式原理,利用的是 <code>Object.defineProperty()</code> 的 <code>setter</code> 属性:</p><p><code>defineProperty()</code> 方法用于<strong>精确</strong>定义一个对象的属性,能够指定属性的各种特征,其中的 <code>set</code> 属性能够为对象指定一个 <code>setter</code> 函数,每次该属性的值发生修改,就会调用此函数。</p><blockquote><p>更多可以配置的属性请参看:<a href="https://juejin.cn/post/7088335075061792782" target="_blank" rel="noreferrer">什么是对象的数据属性描述符?存储属性描述符?</a></p></blockquote><p>这也是Vue2实现响应式数据、数据双向绑定的原理。</p><p>可以使用此方法实现一个简单的数据双向绑定的Demo:</p><p><img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f241135dbeb04e829fe6897c2e418aa2~tplv-k3u1fbpfcp-watermark.image?" alt="image.png"></p><ul><li>输入框内的内容改变,<code>.vBox</code> 展示的文本会随之改变。</li><li>点击按钮修改 <code>vm.text</code>,输入框内的值和 <code>.vBox</code> 的文本都会发生改变。</li></ul><div class="language-html vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">html</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#E1E4E8;"> <</span><span style="color:#85E89D;">body</span><span style="color:#E1E4E8;">></span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> <</span><span style="color:#85E89D;">input</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">type</span><span style="color:#E1E4E8;">=</span><span style="color:#9ECBFF;">"text"</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">id</span><span style="color:#E1E4E8;">=</span><span style="color:#9ECBFF;">"input"</span><span style="color:#E1E4E8;"> /></span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> <</span><span style="color:#85E89D;">button</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">onclick</span><span style="color:#E1E4E8;">=</span><span style="color:#9ECBFF;">"</span><span style="color:#E1E4E8;">vm</span><span style="color:#9ECBFF;">.</span><span style="color:#E1E4E8;">text</span><span style="color:#F97583;">=</span><span style="color:#9ECBFF;">'Hello, World.'"</span><span style="color:#E1E4E8;">>Modify vm.text</</span><span style="color:#85E89D;">button</span><span style="color:#E1E4E8;">></span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> <</span><span style="color:#85E89D;">div</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">class</span><span style="color:#E1E4E8;">=</span><span style="color:#9ECBFF;">"vBox"</span><span style="color:#E1E4E8;">></</span><span style="color:#85E89D;">div</span><span style="color:#E1E4E8;">></span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> <</span><span style="color:#85E89D;">script</span><span style="color:#E1E4E8;">></span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#6A737D;">// 定义响应式数据</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">let</span><span style="color:#E1E4E8;"> vm </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> {}</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> Object.</span><span style="color:#B392F0;">defineProperty</span><span style="color:#E1E4E8;">(vm, </span><span style="color:#9ECBFF;">"text"</span><span style="color:#E1E4E8;">, {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">set</span><span style="color:#E1E4E8;">: (</span><span style="color:#FFAB70;">value</span><span style="color:#E1E4E8;">) </span><span style="color:#F97583;">=></span><span style="color:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#6A737D;">// 对象属性值被修改时,setter函数被自动触发</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> document.</span><span style="color:#B392F0;">querySelector</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">"#input"</span><span style="color:#E1E4E8;">).value </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> value</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> document.</span><span style="color:#B392F0;">querySelector</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">".vBox"</span><span style="color:#E1E4E8;">).innerHTML </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> value</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> },</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> })</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#6A737D;">// 监听输入行为</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> document.</span><span style="color:#B392F0;">querySelector</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">"#input"</span><span style="color:#E1E4E8;">).</span><span style="color:#B392F0;">addEventListener</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">"input"</span><span style="color:#E1E4E8;">, (</span><span style="color:#FFAB70;">e</span><span style="color:#E1E4E8;">) </span><span style="color:#F97583;">=></span><span style="color:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> vm.text </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> e.target.value</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> })</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </</span><span style="color:#85E89D;">script</span><span style="color:#E1E4E8;">></span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </</span><span style="color:#85E89D;">body</span><span style="color:#E1E4E8;">></span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292E;"> <</span><span style="color:#22863A;">body</span><span style="color:#24292E;">></span></span>
|
||
<span class="line"><span style="color:#24292E;"> <</span><span style="color:#22863A;">input</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">type</span><span style="color:#24292E;">=</span><span style="color:#032F62;">"text"</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">id</span><span style="color:#24292E;">=</span><span style="color:#032F62;">"input"</span><span style="color:#24292E;"> /></span></span>
|
||
<span class="line"><span style="color:#24292E;"> <</span><span style="color:#22863A;">button</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">onclick</span><span style="color:#24292E;">=</span><span style="color:#032F62;">"</span><span style="color:#24292E;">vm</span><span style="color:#032F62;">.</span><span style="color:#24292E;">text</span><span style="color:#D73A49;">=</span><span style="color:#032F62;">'Hello, World.'"</span><span style="color:#24292E;">>Modify vm.text</</span><span style="color:#22863A;">button</span><span style="color:#24292E;">></span></span>
|
||
<span class="line"><span style="color:#24292E;"> <</span><span style="color:#22863A;">div</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">class</span><span style="color:#24292E;">=</span><span style="color:#032F62;">"vBox"</span><span style="color:#24292E;">></</span><span style="color:#22863A;">div</span><span style="color:#24292E;">></span></span>
|
||
<span class="line"><span style="color:#24292E;"> <</span><span style="color:#22863A;">script</span><span style="color:#24292E;">></span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6A737D;">// 定义响应式数据</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#D73A49;">let</span><span style="color:#24292E;"> vm </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> {}</span></span>
|
||
<span class="line"><span style="color:#24292E;"> Object.</span><span style="color:#6F42C1;">defineProperty</span><span style="color:#24292E;">(vm, </span><span style="color:#032F62;">"text"</span><span style="color:#24292E;">, {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">set</span><span style="color:#24292E;">: (</span><span style="color:#E36209;">value</span><span style="color:#24292E;">) </span><span style="color:#D73A49;">=></span><span style="color:#24292E;"> {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6A737D;">// 对象属性值被修改时,setter函数被自动触发</span></span>
|
||
<span class="line"><span style="color:#24292E;"> document.</span><span style="color:#6F42C1;">querySelector</span><span style="color:#24292E;">(</span><span style="color:#032F62;">"#input"</span><span style="color:#24292E;">).value </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> value</span></span>
|
||
<span class="line"><span style="color:#24292E;"> document.</span><span style="color:#6F42C1;">querySelector</span><span style="color:#24292E;">(</span><span style="color:#032F62;">".vBox"</span><span style="color:#24292E;">).innerHTML </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> value</span></span>
|
||
<span class="line"><span style="color:#24292E;"> },</span></span>
|
||
<span class="line"><span style="color:#24292E;"> })</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6A737D;">// 监听输入行为</span></span>
|
||
<span class="line"><span style="color:#24292E;"> document.</span><span style="color:#6F42C1;">querySelector</span><span style="color:#24292E;">(</span><span style="color:#032F62;">"#input"</span><span style="color:#24292E;">).</span><span style="color:#6F42C1;">addEventListener</span><span style="color:#24292E;">(</span><span style="color:#032F62;">"input"</span><span style="color:#24292E;">, (</span><span style="color:#E36209;">e</span><span style="color:#24292E;">) </span><span style="color:#D73A49;">=></span><span style="color:#24292E;"> {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> vm.text </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> e.target.value</span></span>
|
||
<span class="line"><span style="color:#24292E;"> })</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </</span><span style="color:#22863A;">script</span><span style="color:#24292E;">></span></span>
|
||
<span class="line"><span style="color:#24292E;"> </</span><span style="color:#22863A;">body</span><span style="color:#24292E;">></span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br></div></div><p>通过 <code>defineProperty</code> 实现的响应式,<strong>不能检测</strong>数组和对象的变化:</p><p><strong>对于对象:</strong></p><p>Vue 无法检测 property 的添加或移除。</p><p>var vm = new Vue({ data:{ a:1 } }) // <code>vm.a</code> 是响应式的 vm.b = 2 // <code>vm.b</code> 是非响应式的</p><p><strong>对于数组:</strong></p><ol><li>当你利用索引直接设置一个数组项时,例如:<code>vm.items[indexOfItem] = newValue</code></li><li>当你修改数组的长度时,例如:<code>vm.items.length = newLength</code></li></ol><h2 id="🔰-vue3的响应式原理" tabindex="-1">🔰 Vue3的响应式原理 <a class="header-anchor" href="#🔰-vue3的响应式原理" aria-label="Permalink to "🔰 Vue3的响应式原理""></a></h2>`,20),e=[o];function t(r,c,E,y,i,u){return n(),a("div",null,e)}const m=s(p,[["render",t]]);export{b as __pageData,m as default};
|