<p><code></p> <p><span class="img-wrap"><img data-src="/img/bV1Og9?w=554&amp;h=294" src="/img/bV1Og9?w=554&amp;h=294" alt="图片描述" title="图片描述" style="cursor: pointer; display: inline;"></span></p> <p>接触过vue的童鞋都知道,组件的模板一般都是在template选项内定义的,如:</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="1 <a href="http://www.js-code.com/tag/vue" title="Vue" target="_blank">Vue</a>.component('child-component', {<br /> 2<br /> 3 template: '</p> <h3>我是闰土大叔</h3> <p>'<br /> 4<br /> 5 })<br /> " title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs basic"><code><span class="hljs-symbol">1 </span><a href="http://www.js-code.com/tag/vue" title="浏览关于“Vue”的文章" target="_blank" class="tag_link">Vue</a>.component(<span class="hljs-comment">'child-component', {</span> <span class="hljs-symbol">2 </span> <span class="hljs-symbol">3 </span> template: <span class="hljs-comment">'&lt;h3&gt;我是闰土大叔&lt;/h3&gt;'</span> <span class="hljs-symbol">4 </span> <span class="hljs-symbol">5 </span>}) </code></pre> <p>这个用法都是老生常谈了,今天来聊聊<a href="http://www.js-code.com/tag/vue" title="Vue" target="_blank">Vue</a>的内联模板。看过vue文档的同学都知道,Vue提供了一个内联模板的功能,在使用组件时,给组件标签使用inline-template特性,组件就会把它的内容当做模板,而不是把它当成内容分发,这样做的好处是,让模板更灵活。</p> <p>介绍完内联模板的概念后,接下来我要分享一个我在工作中碰到的bug,关于内联模板,以及我debug的过程。</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=" <div id=&quot;app&quot;> <child-component inline-template></p> <div> <h2>在父组件中定义子组件的模板</h2> <p>{{message}}</p> <p>{{msg}}</p> </p></div> <p> </child-component> </div> <p><script src=&quot;js/vue.js&quot;></script><br /> <script> Vue.component('child-component',{ data:function(){ return { msg: '在子组件声明的数据' } } });</p> <p> var app = new Vue({ el:'#app', data:{ message: '在父组件声明的数据' } }) </script><br /> " title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs xml"><code><span class="hljs-tag">&lt;<span class="hljs-name"><a href="http://www.js-code.com/tag/div" title="浏览关于“div”的文章" target="_blank" class="tag_link">div</a></span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">child-component</span> <span class="hljs-attr">inline-template</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">h2</span>&gt;</span>在父组件中定义子组件的模板<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{{message}}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{{msg}}<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">child-component</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> <span class="hljs-attr">src</span>=<span class="hljs-string">"js/vue.js"</span>&gt;</span><span class="undefined"></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="actionscript"> Vue.component(<span class="hljs-string">'child-component'</span>,{ data:<span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">()</span></span>{ <span class="hljs-keyword">return</span> { msg: <span class="hljs-string">'在子组件声明的数据'</span> } } }); <span class="hljs-keyword">var</span> app = <span class="hljs-keyword">new</span> Vue({ el:<span class="hljs-string">'#app'</span>, data:{ message: <span class="hljs-string">'在父组件声明的数据'</span> } }) </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span> </code></pre> <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=" 1 <div id=&quot;app&quot;> 2<br /> 3 </p> <div> 4<br /> 5 </p> <h2>在父组件中定义子组件的模板</h2> <p> 6<br /> 7 </p> <p>在父组件声明的数据</p> <p> 8<br /> 9 </p> <p>在子组件声明的数据</p> <p>10<br /> 11 </p></div> <p>12<br /> 13 </p></div> <p>" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs properties"><code> <span class="hljs-attr">1</span> <span class="hljs-string">&lt;div id="app"&gt;</span> <span class="hljs-attr">2</span> <span class="hljs-string"></span> <span class="hljs-attr">3</span> <span class="hljs-string">&lt;div&gt;</span> <span class="hljs-attr">4</span> <span class="hljs-string"></span> <span class="hljs-attr">5</span> <span class="hljs-string">&lt;h2&gt;在父组件中定义子组件的模板&lt;/h2&gt;</span> <span class="hljs-attr">6</span> <span class="hljs-string"></span> <span class="hljs-attr">7</span> <span class="hljs-string">&lt;p&gt;在父组件声明的数据&lt;/p&gt;</span> <span class="hljs-attr">8</span> <span class="hljs-string"></span> <span class="hljs-attr">9</span> <span class="hljs-string">&lt;p&gt;在子组件声明的数据&lt;/p&gt;</span> <span class="hljs-attr">10</span> <span class="hljs-string"></span> <span class="hljs-attr">11</span> <span class="hljs-string">&lt;/div&gt;</span> <span class="hljs-attr">12</span> <span class="hljs-string"></span> <span class="hljs-attr">13</span> <span class="hljs-string">&lt;/div&gt; </span> </code></pre> <p>可在Chrome里显示的<a href="http://www.js-code.com/tag/dom" title="DOM" target="_blank">DOM</a>节点却是这样的:</p> <p><span class="img-wrap"><img data-src="/img/bV1OhA?w=373&amp;h=107" src="https://static.segmentfault.com/v-5cc2cd8e/global/img/squares.svg" alt="图片描述" title="图片描述" style="cursor: pointer;"></span></p> <p>不仅第一个P标签内的插值没有渲染出来,而且在控制台里还报了一个错误:</p> <p><span class="img-wrap"><img data-src="/img/bV1OhI?w=698&amp;h=255" src="https://static.segmentfault.com/v-5cc2cd8e/global/img/squares.svg" alt="图片描述" title="图片描述" style="cursor: pointer;"></span></p> <p>说什么<a href="http://www.js-code.com/tag/prop" title="Prop" target="_blank">Prop</a>erty or method "message" is not defined on the instance but referenced during render.(属性或方法“message”不是在实例上定义的,而是在呈现过程中引用的。)</p> <p>这个报错让我一脸懵逼,我可是照着书上的代码敲的,来来回回看了N遍,一模一样啊。而且书内提及 “ 在父组件中声明的数据message和子组件中声明的数据msg,两个都可以渲染。”</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: 0px; margin: 0px; padding: 0px; position: relative; visibility: visible; width: 697px; background-color: transparent;"><ins id="aswift_4_anchor" style="display: block; border: none; height: 0px; margin: 0px; padding: 0px; position: relative; visibility: visible; width: 697px; background-color: transparent; overflow: hidden; opacity: 0;"><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>相信很多刚接触vue的新人童鞋都有这种体会,照着书上的代码敲了一遍,结果运行出错,与书上说的结果不一致。当你仔仔细细地检查了半天还是没发现哪错了的时候,你会不会内心抓狂到怀疑人生?</p> <p>别急,这个时候你一定要有自己的判断,尽信书则不如无书。这句话出自于孟子,释义是读书时应该加以分析,不能盲目的去相信书中所言,一定要辩证的看待问题。万一这本书在排版的时候小编大意写错了呢?也有可能吧。我们对所谓的技术书籍,在尊敬作者的前提下,也要有批判精神。</p> <p>其实,console控制台里的错误提示信息,就给你指明了debug的方向。通读一遍代码,我们可以分析一下,属性message是定义在父组件中的data选项内的,而调用的时候是在子组件里面调用,首先在没有任何干涉的情况下,父子组件是没有互通有无的功能的。所以,这时候你应该会想到,父子组件间传递数据用props啊!有了思路后,那就赶紧把代码敲起来吧:</p> <p><span class="img-wrap"><img data-src="/img/bV1OhM?w=823&amp;h=517" src="https://static.segmentfault.com/v-5cc2cd8e/global/img/squares.svg" alt="图片描述" title="图片描述" style="cursor: pointer;"></span></p> <p>运行一遍后,果然如你所愿,第一个P标签里的插值顺利地渲染出来了。</p> <p>除了内联模板,Vue还提供了另一种效率比较高的定义模板的方式,就是x-template。如果你之前没有使用过webpack、gulp等构件工具,试想下你的组件template的内容很冗长很复杂,如果都在javascript里拼接字符串,效率是很低的,因为不能像写html那么舒服(除非你用ES6里面的<a href="http://www.js-code.com/tag/%e6%a8%a1%e6%9d%bf%e5%ad%97%e7%ac%a6%e4%b8%b2" title="模板字符串" target="_blank">模板字符串</a>)。</p> <p>Vue提供了另一种定义模板的方式,在&lt;script&gt;标签里使用text/template类型,并且指定一个id,将这个id赋给template,举个栗子:</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=" <div id=&quot;app&quot;> <my-component></my-component><br /> <script type=&quot;text/x-template&quot; id=&quot;my-component&quot;></p> <div>这是组件的内容</div> <p> </script> </div> <p><script src=&quot;js/vue.js&quot;></script><br /> <script> Vue.component('my-component',{ template:'#my-component' });</p> <p> var app = new Vue({ el:'#app' }) </script><br /> " title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs xml"><code><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">my-component</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">my-component</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/x-template"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"my-component"</span>&gt;</span><span class="xml"> <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>这是组件的内容<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</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> <span class="hljs-attr">src</span>=<span class="hljs-string">"js/vue.js"</span>&gt;</span><span class="undefined"></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="actionscript"> Vue.component(<span class="hljs-string">'my-component'</span>,{ template:<span class="hljs-string">'#my-component'</span> }); <span class="hljs-keyword">var</span> app = <span class="hljs-keyword">new</span> Vue({ el:<span class="hljs-string">'#app'</span> }) </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span> </code></pre> <p>这样,在&lt;script&gt;标签里,你可以愉快地写html代码了,不用考虑换行等问题。</p> <p>很多刚接触Vue开发的新手会非常喜欢这个功能,因为用它,再加上组件知识,就可以很轻松地完成交互相对复杂的页面和应用了。如果再配合一些构件工具(gulp)组织好代码结构,开发一些中小型产品是没有问题的。</p> <p>不过Vue的初衷并不是滥用它,因为它将模板和组件的其他定义隔离了。在之后的文章里,我会介绍如何使用webpack来编译.vue的文件,从而优雅地解决html书写的问题。</p> <p>今天的文章就分享到这里。</p> <p>作者:闰土大叔<br />链接:<a href="https://segmentfault.com/a/1190000012785631">https://segmentfault.com/a/11...</a><br />来源:segmentfault<br />著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。</p> <p></code></p>

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