Files
DefectingCat.github.io/defect/response-data-in-Vue3.html
DefectingCat 8c7085f18f
2020-11-02 02:17:54 +00:00

56 lines
19 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html><html lang="zh-CN" data-default-color-scheme="&#34;auto&#34;"><head><meta charset="UTF-8"><link rel="apple-touch-icon" sizes="76x76" href="/images/img/apple-touch-icon.webp"><link rel="icon" type="image/png" href="/images/img/favicon.webp"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no,shrink-to-fit=no"><meta http-equiv="x-ua-compatible" content="ie=edge"><meta name="theme-color" content="#9DC8C8"><meta name="description" content=""><meta name="author" content="Defectink"><meta name="keywords" content=""><title>Vue3中的响应数据 - 🍭Defectink</title><link rel="stylesheet" href="https://cdn.defectink.com/static/twitter-bootstrap/4.5.3/css/bootstrap.min.css"><link rel="stylesheet" href="https://cdn.defectink.com/static/github-markdown-css/4.0.0/github-markdown.min.css"><link rel="stylesheet" href="/lib/hint/hint.min.css"><link rel="stylesheet" href="https://cdn.defectink.com/static/highlight.js/10.0.0/styles/github-gist.min.css"><link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_ba1fz6golrf.css"><link rel="stylesheet" href="https://cdn.defectink.com/static/t/font_1736178_kmeydafke9r.css"><link rel="stylesheet" href="/css/main.css"><link rel="stylesheet" href="/css/xfy.css"><script src="/js/utils.js"></script><script src="/js/color-schema.js"></script><meta name="generator" content="Hexo 5.2.0"><link rel="alternate" href="/xml/atom.xml" title="🍭Defectink" type="application/atom+xml"><link rel="alternate" href="/xml/rss.xml" title="🍭Defectink" type="application/rss+xml"></head><body><header style="height:75vh"><nav id="navbar" class="navbar fixed-top navbar-expand-lg navbar-dark scrolling-navbar"><div class="container"><a class="navbar-brand" href="/">&nbsp;<strong>🍭Defectink</strong>&nbsp;</a> <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"><div class="animated-icon"><span></span><span></span><span></span></div></button><div class="collapse navbar-collapse" id="navbarSupportedContent"><ul class="navbar-nav ml-auto text-center"><li class="nav-item"><a class="nav-link" href="/">🏠 首页</a></li><li class="nav-item dropdown"><a class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">📕 索引</a><div class="dropdown-menu" aria-labelledby="navbarDropdown"><a class="dropdown-item" href="/categories/">🎁 分类</a> <a class="dropdown-item" href="/tags/">🎐 标签</a></div></li><li class="nav-item"><a class="nav-link" href="/archives/">📂 归档</a></li><li class="nav-item"><a class="nav-link" href="/about/">🎃 关于</a></li><li class="nav-item"><a class="nav-link" href="/links/">🙆‍♀️ 小伙伴</a></li><li class="nav-item"><a class="nav-link" href="/pgp/">🔐 PGP</a></li><li class="nav-item" id="search-btn"><a class="nav-link" data-toggle="modal" data-target="#modalSearch">&nbsp;<i class="iconfont icon-search"></i>&nbsp;</a></li><li class="nav-item" id="color-toggle-btn"><a class="nav-link" href="javascript:">&nbsp;<i class="iconfont icon-dark" id="color-toggle-icon"></i>&nbsp;</a></li></ul></div></div></nav><div class="banner intro-2" id="background" parallax="true" style="background:url(/images/img/post.webp) no-repeat center center;background-size:cover"><div class="full-bg-img"><div class="mask flex-center" style="background-color:rgba(0,0,0,.3)"><div class="container page-header text-center fade-in-up"><span class="h2" id="subtitle"></span><div class="mt-3"><span class="post-meta mr-2"><i class="iconfont icon-author" aria-hidden="true"></i> Defectink</span><span class="post-meta"><i class="iconfont icon-date-fill" aria-hidden="true"></i> <time datetime="2020-11-02 10:01" pubdate>2020年11月2日 上午</time></span></div><div class="mt-1"><span class="post-meta mr-2"><i class="iconfont icon-chart"></i> 1.2k 字</span><span class="post-meta mr-2"><i class="iconfont icon-clock-fill"></i> 15 分钟</span></div></div></div></div></div></header><main><div class="container-fluid"><div class="row"><div class="d-none d-lg-block col-lg-2"></div><div class="col-lg-8 nopadding-md"><div class="container nopadding-md" id="board-ctn"><div class="py-5" id="board"><article class="post-content mx-auto" id="post"><h1 style="display:none">Vue3中的响应数据</h1><p class="note note-info">本文最后水于2020年11月2日 凌晨</p><div class="markdown-body" id="post-body"><h2 id="实时渲染"><a href="#实时渲染" class="headerlink" title="实时渲染"></a>实时渲染</h2><p>在学习Vue2.x的过程中做过一个更改数据从而触发实时渲染DOM的小实例。期间很顺利而后在同样方法测试Vue3的时候发现遇到了一些不同的行为。根据查阅了一些文档以及源码做出了一些推测。</p><h2 id="数据与方法"><a href="#数据与方法" class="headerlink" title="数据与方法"></a>数据与方法</h2><p>当一个 Vue 实例被创建时,它将 data 对象中的所有的 property 加入到 Vue 的响应式系统中。当这些 property 的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。</p><p>在Vue2.x中可以创建一个数据对象为实例提供数据。虽然这样的写法和直接在实例中为<code>data</code>添加属性没有多少差别:</p><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;app&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
&#123;&#123; message &#125;&#125;
<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span>
<span class="javascript"> <span class="hljs-keyword">let</span> data = &#123;</span>
<span class="javascript"> message: <span class="hljs-string">&#x27;Hello World!&#x27;</span></span>
&#125;
<span class="javascript"> <span class="hljs-keyword">let</span> app = <span class="hljs-keyword">new</span> Vue(&#123;</span>
<span class="javascript"> el: <span class="hljs-string">&#x27;#app&#x27;</span>,</span>
data: data
&#125;);
<span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre><p>这时我们单独创建的<code>data</code>对象与实例中的<code>data</code>成立了引用关系:</p><pre><code class="hljs js">app.$data.message === data.message
<span class="hljs-comment">// true</span></code></pre><p>并且他们三者是互等的:</p><pre><code class="hljs js">app.message === app.$data.message
app.$data.message === data.message</code></pre><p>并且我们单独创建的<code>data</code>对象也被转换成了检测数据变化的Observer对象</p><p><img src="../images/Vue3%E4%B8%AD%E7%9A%84%E5%93%8D%E5%BA%94%E6%95%B0%E6%8D%AE/2020-10-20-14-23-58.webp" srcset="/images/img/loading.gif"></p><p>因此,我们在修改<code>data</code>对象的内容时app实例的属性也会被改变从而实时渲染到DOM上。</p><p><img src="../images/Vue3%E4%B8%AD%E7%9A%84%E5%93%8D%E5%BA%94%E6%95%B0%E6%8D%AE/2020-10-20-14-25-25.webp" srcset="/images/img/loading.gif"></p><p>但在Vue3上发生了一些小小的改变。在Vue3上我们将实例的<code>data</code>函数直接return为我们在父作用域中创建的对象这个对象不会被修改为检测属性数据变化的对象。</p><pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;app&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
&#123;&#123; message &#125;&#125;
<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span>
<span class="javascript"> <span class="hljs-keyword">let</span> data = &#123;</span>
<span class="javascript"> message: <span class="hljs-string">&#x27;Hello World!&#x27;</span></span>
&#125;;
<span class="javascript"> <span class="hljs-keyword">let</span> app = Vue.createApp(&#123;</span>
<span class="javascript"> <span class="hljs-function"><span class="hljs-title">data</span>(<span class="hljs-params"></span>)</span> &#123;</span>
<span class="javascript"> <span class="hljs-keyword">return</span> data;</span>
&#125;
&#125;);
<span class="javascript"> <span class="hljs-keyword">let</span> vm = app.mount(<span class="hljs-string">&#x27;#app&#x27;</span>);</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre><p>这里的app是我们创建的实例但最终挂载DOM后返回的实例为vm。不同于2.x的地方是这里我们在父作用域中创建的对象并没用任何的变化它还是一个普通的对象。</p><p><img src="../images/Vue3%E4%B8%AD%E7%9A%84%E5%93%8D%E5%BA%94%E6%95%B0%E6%8D%AE/2020-10-20-14-31-01.webp" srcset="/images/img/loading.gif"></p><p>并且,他们也互相建立了引用的关系;</p><pre><code class="hljs js">vm.message === data.message
<span class="hljs-comment">// true</span></code></pre><p>虽然他们已经是互相引用,但是<code>data</code>还是一个普通的对象。这里就会发现一个有意思的现象,只更新<code>data.message</code>的值,<code>vm.message</code>或者说<code>vm.$data.message</code>的值会同样更新,保持和<code>data</code>对象一样。但是DOM却没用被实时渲染。</p><p><img src="../images/Vue3%E4%B8%AD%E7%9A%84%E5%93%8D%E5%BA%94%E6%95%B0%E6%8D%AE/2020-10-20-15-42-32.webp" srcset="/images/img/loading.gif"></p><p>这一点2和3有着很大的差距在vue2中我们是可以通过<code>data</code>对象来实时更新DOM的。而在3中就不行了。</p><p>据我的猜测主要是Vue3没有对父作用域的<code>data</code>对象设置Proxy代理的原因。虽然二者已经是互相引用修改一个对象值另一个对象也会被修改。<strong>但是通过修改<code>data</code>的属性,并不会触发<code>vm.$data</code>对象的<code>set()</code>方法。</strong></p><h2 id="模仿行为"><a href="#模仿行为" class="headerlink" title="模仿行为"></a>模仿行为</h2><p>我使用了一个小例子模仿了一下Vue3的行为</p><pre><code class="hljs js"><span class="hljs-comment">// 这是在父作用域中的data对象它是一个普通对象</span>
<span class="hljs-keyword">let</span> data = &#123;
message: <span class="hljs-string">&#x27;xfy&#x27;</span>
&#125;
<span class="hljs-comment">// 这是模拟set方法成功set时会打印一条信息</span>
<span class="hljs-keyword">let</span> handler = &#123;
set: <span class="hljs-function">(<span class="hljs-params">obj, prop, value</span>) =&gt;</span> &#123;
obj[prop] = value;
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">&#x27;set success: &#x27;</span> + value);
&#125;
&#125;
<span class="hljs-comment">// 通过proxy创建一个继承自data属性的实例</span>
<span class="hljs-keyword">let</span> vm = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Proxy</span>(data, handler);</code></pre><p>这是一个很简单的例子,我们为<code>vm</code>对象设置了一个来自<code>data</code>对象的代理。现在二者就是互相引用的关系了就和Vue3一样。</p><pre><code class="hljs js">data.message === vm.message
<span class="hljs-comment">// true</span></code></pre><p>我在代理的拦截中配置了一个setter<code>vm</code>对象成功设置了值后就会触发这个setter并在控制台打印一则信息。用来模拟更新DOM。也就是说现在的<code>vm</code>实例就相当于Vue实例当我更新其属性时会在控制台动态的打印信息就相当于实时更新了DOM。就和Vue实例一样。</p><p>现在我们直接对<code>vm.message</code>赋值则会成功触发预先设置的setter函数成功的更新了值并且在控制打印了消息。</p><pre><code class="hljs js">vm.message
<span class="hljs-comment">// &quot;xfy&quot;</span>
vm.message = <span class="hljs-string">&#x27;hello xfy&#x27;</span>;
<span class="hljs-comment">// set success: hello xfy</span>
<span class="hljs-comment">// &quot;hello xfy&quot;</span></code></pre><p>并且<code>data</code>对象也同样的被修改了。</p><pre><code class="hljs js">data.message
<span class="hljs-comment">// &quot;hello xfy&quot;</span></code></pre><p>直接设置<code>data.message</code>可以成功修改<code>vm.message</code>的值,但是却不会触发<code>vm</code>对象的setter方法。</p><pre><code class="hljs js">data.message = <span class="hljs-string">&#x27;嘤嘤嘤&#x27;</span>;
<span class="hljs-comment">// &quot;嘤嘤嘤&quot;</span>
vm.message
<span class="hljs-comment">// 属性被修改但是没有触发setter</span>
<span class="hljs-comment">// &quot;嘤嘤嘤&quot;</span></code></pre><p>这里的小例子最简化的模拟了Vue3的实例行为在真正的Vue3的实例上我们也可以很清晰的看到其Proxy属性</p><p><img src="../images/Vue3%E4%B8%AD%E7%9A%84%E5%93%8D%E5%BA%94%E6%95%B0%E6%8D%AE/2020-10-20-16-28-03.webp" srcset="/images/img/loading.gif"></p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>总的来说就是因为data对象修改时不会触发实例的set方法但数据依然会改变只是DOM不会实时更新。</p></div><hr><div><div class="post-metas mb-3"><div class="post-meta mr-3"><i class="iconfont icon-category"></i> <a class="hover-with-bg" href="/categories/%E7%AC%94%E8%AE%B0/">笔记</a></div><div class="post-meta"><i class="iconfont icon-tags"></i> <a class="hover-with-bg" href="/tags/JavaScript/">JavaScript</a> <a class="hover-with-bg" href="/tags/Vue/">Vue</a></div></div><p class="note note-warning"><a target="_blank" href="https://zh.wikipedia.org/wiki/Wikipedia:CC_BY-SA_3.0%E5%8D%8F%E8%AE%AE%E6%96%87%E6%9C%AC" rel="nofollow noopener noopener">CC BY-SA 3.0❤</a></p><div class="post-prevnext row"><article class="post-prev col-6"></article><article class="post-next col-6"><a href="/defect/javascript-iterable-object-and-for-of.html"><span class="hidden-mobile">JavaScript-可迭代对象与for-of</span> <span class="visible-mobile">下一篇</span><i class="iconfont icon-arrowright"></i></a></article></div></div><article class="comments" id="comments"><div id="vcomments"></div><script type="text/javascript">function loadValine(){addScript("https://cdn.defectink.com/static/valine/1.4.14/Valine.min.js",function(){new Valine({el:"#vcomments",app_id:"dD9t7mcIBVzJWag5ez6GPy2v-MdYXbMMI",app_key:"bWG6pmKsEscrH4JjrpNNAAy6",placeholder:"嘤嘤嘤???",path:window.location.pathname,avatar:"retro",meta:["nick","mail","link"],pageSize:"10",lang:"zh-CN",highlight:!0,recordIP:!1,serverURLs:""})})}waitElementVisible("vcomments",loadValine)</script><noscript>Please enable JavaScript to view the <a target="_blank" href="https://valine.js.org" rel="nofollow noopener noopener">comments powered by Valine.</a></noscript></article></article></div></div></div><div class="d-none d-lg-block col-lg-2 toc-container" id="toc-ctn"><div id="toc"><p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;目录</p><div id="tocbot"></div></div></div></div></div></main><a id="scroll-top-button" href="#" role="button"><i class="iconfont icon-arrowup" aria-hidden="true"></i></a><div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel" aria-hidden="true"><div class="modal-dialog modal-dialog-scrollable modal-lg" role="document"><div class="modal-content"><div class="modal-header text-center"><h4 class="modal-title w-100 font-weight-bold">搜索</h4><button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button></div><div class="modal-body mx-3"><div class="md-form mb-5"><input type="text" id="local-search-input" class="form-control validate"> <label data-error="x" data-success="v" for="local-search-input">关键词</label></div><div class="list-group" id="local-search-result"></div></div></div></div></div><footer class="text-center mt-5 py-3"><div class="footer-content"><a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a><i class="iconfont icon-love"></i> <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"><span>Fluid</span></a></div><div class="beian"><a href="http://beian.miit.gov.cn/" target="_blank" rel="nofollow noopener">皖ICP备17017808号</a></div></footer><script src="https://cdn.defectink.com/static/jquery/3.4.1/jquery.min.js"></script><script src="https://cdn.defectink.com/static/twitter-bootstrap/4.5.3/js/bootstrap.min.js"></script><script src="/js/debouncer.js"></script><script src="/js/main.js"></script><script src="/js/lazyload.js"></script><script defer="defer" src="https://cdn.defectink.com/static/clipboard.js/2.0.6/clipboard.min.js"></script><script src="/js/clipboard-use.js"></script><script src="/js/xfy.js"></script><script src="https://cdn.defectink.com/static/tocbot/4.11.1/tocbot.min.js"></script><script>$(document).ready(function(){var t=$("#board-ctn").offset().top;tocbot.init({tocSelector:"#tocbot",contentSelector:"#post-body",headingSelector:"h1,h2,h3,h4,h5,h6",linkClass:"tocbot-link",activeLinkClass:"tocbot-active-link",listClass:"tocbot-list",isCollapsedClass:"tocbot-is-collapsed",collapsibleClass:"tocbot-is-collapsible",collapseDepth:3,scrollSmooth:!0,headingsOffset:-t}),0<$(".toc-list-item").length&&$("#toc").css("visibility","visible")})</script><script src="https://cdn.defectink.com/static/typed.js/2.0.11/typed.min.js"></script><script>var typed=new Typed("#subtitle",{strings:[" ","Vue3中的响应数据&nbsp;"],cursorChar:"❤",typeSpeed:70,loop:!1});typed.stop(),$(document).ready(function(){$(".typed-cursor").addClass("h2"),typed.start()})</script><script src="/js/local-search.js"></script><script>var path="/xml/local-search.xml",inputArea=document.querySelector("#local-search-input");inputArea.onclick=function(){searchFunc(path,"local-search-input","local-search-result"),this.onclick=null}</script><script src="https://cdn.defectink.com/static/fancybox/3.5.7/jquery.fancybox.min.js"></script><link rel="stylesheet" href="https://cdn.defectink.com/static/fancybox/3.5.7/jquery.fancybox.min.css"><script>$("#post img:not(.no-zoom img, img[no-zoom]), img[zoom]").each(function(){var t=document.createElement("a");$(t).attr("data-fancybox","images"),$(t).attr("href",$(this).attr("src")),$(this).wrap(t)})</script><script src="https://cdn.defectink.com/static/mermaid/8.5.0/mermaid.min.js"></script><script>window.mermaid&&mermaid.initialize({theme:"default"})</script></body></html>