<p><code></p> <h2 id="articleHeader0">vue深入响应式式原理</h2> <h2 id="articleHeader1">1.在vue初始化实例的时候,data选项的理解</h2> <p>1.1 把一个普通 JavaScript 对象传给 <a href="http://www.js-code.com/tag/vue" title="Vue" target="_blank">Vue</a> 实例的 data 选项,<a href="http://www.js-code.com/tag/vue" title="Vue" target="_blank">Vue</a> 将遍历此对象所有的属性,并使用 Object.define<a href="http://www.js-code.com/tag/prop" title="Prop" target="_blank">Prop</a>erty 把这些属性全部转为 getter/setter。Object.define<a href="http://www.js-code.com/tag/prop" title="Prop" target="_blank">Prop</a>erty 是仅 ES5 支持,且无法 shim 的特性,这也就是为什么 <a href="http://www.js-code.com/tag/vue" title="浏览关于“Vue”的文章" target="_blank" class="tag_link">Vue</a> 不支持 IE8 以及更低版本浏览器的原因。</p> <p>1.2 用户看不到 getter/setter,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。这里需要注意的问题是浏览器控制台在打印数据对象时 getter/setter 的格式化并不同,所以你可能需要安装 vue-devtools 来获取更加友好的检查接口。</p> <div class="google-auto-placed ap_container" style="text-align: center; width: 100%; height: auto; clear: none;"><ins data-ad-format="auto" class="adsbygoogle adsbygoogle-noablate" data-ad-client="ca-pub-6330872677300335" data-adsbygoogle-status="done" style="display: block; margin: auto; background-color: transparent;"><ins id="aswift_4_expand" style="display:inline-table;border:none;height:175px;margin:0;padding:0;position:relative;visibility:visible;width:697px;background-color:transparent;"><ins id="aswift_4_anchor" style="display:block;border:none;height:175px;margin:0;padding:0;position:relative;visibility:visible;width:697px;background-color:transparent;"><iframe width="697" height="175" frameborder="0" marginwidth="0" marginheight="0" vspace="0" hspace="0" allowtransparency="true" scrolling="no" allowfullscreen="true" onload="var i=this.id,s=window.google_iframe_oncopy,H=s&amp;&amp;s.handlers,h=H&amp;&amp;H[i],w=this.contentWindow,d;try{d=w.document}catch(e){}if(h&amp;&amp;d&amp;&amp;(!d.body||!d.body.firstChild)){if(h.call){setTimeout(h,0)}else if(h.match){try{h=s.upd(h,i)}catch(e){}w.location.replace(h)}}" id="aswift_4" name="aswift_4" style="left:0;position:absolute;top:0;border:0px;width:697px;height:175px;"></iframe></ins></ins></ins></div> <p>1.3 每个组件实例都有相应的 watcher 实例对象,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。</p> <h2 id="articleHeader2">2.对象</h2> <p>2.1 由于 Vue 会在初始化实例时对属性执行 getter/setter 转化过程,所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="var vm = new Vue({ data:{ a:1 } }) // `vm.a` 是响应的 vm.b = 2 // `vm.b` 是非响应的" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs scala"><code><span class="hljs-keyword">var</span> vm = <span class="hljs-keyword">new</span> <span class="hljs-type">Vue</span>({ data:{ a:<span class="hljs-number">1</span> } }) <span class="hljs-comment">// `vm.a` 是响应的</span> vm.b = <span class="hljs-number">2</span> <span class="hljs-comment">// `vm.b` 是非响应的</span></code></pre> <p>2.2 Vue 不允许在已经创建的实例上<br /><strong><em>动态添加新的根级响应式属性(root-level reactive property)。</em></strong><br />然而它可以使用 Vue.set(object, key, value) 方法将 <br /><strong>响应属性</strong> <br />添加到嵌套的对象上:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="Vue.set(vm.someObject, 'b', 2)" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs kotlin"><code style="word-break: break-word; white-space: initial;">Vue.<span class="hljs-keyword">set</span>(vm.someObject, <span class="hljs-string">'b'</span>, <span class="hljs-number">2</span>)</code></pre> <p>您还可以使用 vm.$set 实例方法,这也是全局 Vue.set 方法的别名:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="this.$set(this.someObject,'b',2)" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs kotlin"><code style="word-break: break-word; white-space: initial;"><span class="hljs-keyword"><a href="http://www.js-code.com/tag/this" title="浏览关于“this”的文章" target="_blank" class="tag_link">this</a></span>.$<span class="hljs-keyword">set</span>(<span class="hljs-keyword">this</span>.someObject,<span class="hljs-string">'b'</span>,<span class="hljs-number">2</span>)</code></pre> <p>2.3 有时你想向已有对象上添加一些属性,例如使用 Object.assign() 或 _.extend() 方法来添加属性。但是,添加到对象上的新属性不会触发更新。在这种情况下可以创建一个新的对象,让它包含原对象的属性和新的属性:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text=" this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs groovy"><code style="word-break: break-word; white-space: initial;"> <span class="hljs-keyword">this</span>.someObject = Object.assign({}, <span class="hljs-keyword">this</span>.someObject, { <span class="hljs-string">a:</span> <span class="hljs-number">1</span>, <span class="hljs-string">b:</span> <span class="hljs-number">2</span> })</code></pre> <h2 id="articleHeader3">3.<a href="http://www.js-code.com/tag/%e6%95%b0%e7%bb%84" title="数组" target="_blank">数组</a></h2> <p>3.1 可以实现动态响应的变异方法<br />变异方法(mutation method),顾名思义,会改变被这些方法调用的原始<a href="http://www.js-code.com/tag/%e6%95%b0%e7%bb%84" title="数组" target="_blank">数组</a></p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="Vue 包含一组观察数组的变异方法,所以它们也将会 触发视图更新 这些方法如下: push() pop() shift() unshift() splice() sort() reverse()" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs perl"><code>Vue 包含一组观察<a href="http://www.js-code.com/tag/%e6%95%b0%e7%bb%84" title="浏览关于“数组”的文章" target="_blank" class="tag_link">数组</a>的变异方法,所以它们也将会 触发视图更新 这些方法如下: <span class="hljs-keyword">push</span>() <span class="hljs-keyword">pop</span>() <span class="hljs-keyword">shift</span>() <span class="hljs-keyword">unshift</span>() <span class="hljs-keyword">splice</span>() <span class="hljs-keyword">sort</span>() <span class="hljs-keyword">reverse</span>()</code></pre> <p>3.2 重塑数组 <br />filter(), concat(), <a href="http://www.js-code.com/tag/slice" title="slice" target="_blank">slice</a>() 。这些不会改变原始数组,但总是返回一个新数组。当使用非变异方法时,可以用新数组替换旧数组:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="example1.items = example1.items.filter(function (item) { return item.message.match(/Foo/) })" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs lua"><code>example1.items = example1.items.filter(<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(item)</span></span> { <span class="hljs-keyword">return</span> item.message.<span class="hljs-built_in">match</span>(/Foo/) })</code></pre> <p>3.3 由于 JavaScript 的限制, Vue 不能检测以下变动的数组:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="3.3.1 当你利用索引直接设置一个项时, 例如: vm.items[indexOfItem] = newValue 以下两种方式都可以实现和 vm.items[indexOfItem] = newValue 相同的效果, 同时也将触发状态更新: // Vue.set Vue.set(example1.items, indexOfItem, newValue) // Array.prototype.splice` example1.items.splice(indexOfItem, 1, newValue)" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs kotlin"><code><span class="hljs-number">3.3</span>.1 当你利用索引直接设置一个项时, 例如: vm.items[indexOfItem] = newValue 以下两种方式都可以实现和 vm.items[indexOfItem] = newValue 相同的效果, 同时也将触发状态更新: <span class="hljs-comment">// Vue.set</span> Vue.<span class="hljs-keyword">set</span>(example1.items, indexOfItem, newValue) <span class="hljs-comment">// <a href="http://www.js-code.com/tag/array" title="浏览关于“Array”的文章" target="_blank" class="tag_link">Array</a>.prototype.splice`</span> example1.items.splice(indexOfItem, <span class="hljs-number">1</span>, newValue)</code></pre> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="3.3.2 当你修改数组的长度时,例如: vm.items.length = newLength example1.items.splice(newLength)" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs"><code>3.3.2 当你修改数组的长度时,例如: vm.items.length = newLength example1.items.splice(newLength)</code></pre> <p>3.4 显示过滤/排序结果</p> <p>有时,我们想要显示一个数组的过滤或排序副本,而不实际改变或重置原始数据。在这种情况下,可以创建返回过滤或排序数组的计算属性。</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text=" <li v-for=&quot;n in evenNumbers&quot;>{{ n }}</li> <p>data: {<br /> numbers: [ 1, 2, 3, 4, 5 ]<br /> },<br /> computed: {<br /> evenNumbers: function () {<br /> return this.numbers.filter(function (number) {<br /> return number % 2 === 0<br /> })<br /> }<br /> }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs actionscript"><code>&lt;li v-<span class="hljs-keyword">for</span>=<span class="hljs-string">"n in evenNumbers"</span>&gt;{{ n }}&lt;/li&gt; data: { numbers: [ <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span> ] }, computed: { evenNumbers: <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">()</span> </span>{ <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.numbers.filter(<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(number)</span> </span>{ <span class="hljs-keyword">return</span> number % <span class="hljs-number">2</span> === <span class="hljs-number">0</span> }) } }</code></pre> <p>你也可以在计算属性不适用的情况下 (例如,在嵌套 v-for 循环中) 使用 method 方法:</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text=" <li v-for=&quot;n in even(numbers)&quot;>{{ n }}</li> <p>data: {<br /> numbers: [ 1, 2, 3, 4, 5 ]<br /> },<br /> methods: {<br /> even: function (numbers) {<br /> return numbers.filter(function (number) {<br /> return number % 2 === 0<br /> })<br /> }<br /> }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs actionscript"><code>&lt;li v-<span class="hljs-keyword">for</span>=<span class="hljs-string">"n in even(numbers)"</span>&gt;{{ n }}&lt;/li&gt; data: { numbers: [ <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span> ] }, methods: { even: <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(numbers)</span> </span>{ <span class="hljs-keyword">return</span> numbers.filter(<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(number)</span> </span>{ <span class="hljs-keyword">return</span> number % <span class="hljs-number">2</span> === <span class="hljs-number">0</span> }) } }</code></pre> <p></code></p>

本文固定链接: http://www.js-code.com/vue-js/vue-js_25949.html