w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 http://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com zh-hans w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 http://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-methods-and-event-handling.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>前面学习了,在Vue中,可以使用<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/v-on.html"><code>v-on</code></a>给元素绑定事件,而且<" href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/working-with-methods-in-vue.html">Methods</a>可以在Vue中处理一些逻辑方面的事情。Vue事件监听的方式看上去有点违背分离的传统理念。而实际上Vue中所有事件处理方式和表达式都严格绑定在当前视图的ViewModel上,它不会导致维护上的困难。使用<code>v-on</code>有以下好处:</p>" <ul> <li>通过HTML模板就能轻易定位在JavaScript代码里对应的方法</li> <li>不需要在JavaScript里手动绑定事件,ViewModel代码可以是非常纯粹的逻辑,和DOM无全解耦,更易于测试</li> <li>当一个ViewModel被销毁时,所有的事件处理器都会自动被删除,无须担心如何自己清理它们</li> </ul> <p>在Vue中ViewModel中的逻辑处理,一般都在Vue的<code>methods</code>中来处理。那是因为很多事件处理逻辑代码都很复杂,如果我们直接把JavaScript代码写在<code>v-on</code>指令中有时并不可行,所以在<code>methods</code>中定义方法,让<code>v-on</code>指令来接收(调用)。</p> <h2>Methods和事件处理</h2> <p>有关于Methods的详细介绍,这里不做过多阐述,感兴趣的可以<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/working-with-methods-in-vue.html">阅读前面的学习笔记</a>。咱们简单的回忆一下。</p>" <p>给一个<code>button</code>使用<code>v-on</code>指令,绑定一个<code>click</code>事件,给这个事件指定一个方法,这个方法主要用来改变文本的显示。比如:一开始在页面上渲染的文本是“没发生任何事情”,点击<code>button</code>按钮之后,执行<code>prompt</code>方法,然后页面渲染的文本变成了“快来看这里!我是新讯息!”。使用Vue来处理,其实很简单:</p> <pre><code>&lt;!-- HTML --&gt; &lt;div id="app"&gt; &lt;button @click="prompt"&gt;点击我(^_^)&lt;/button&gt; &lt;p&gt;{{ message }}&lt;/p&gt; &lt;/div&gt; let app = new Vue({ el: '#app', data () { return { message: '没发生任何事情!' } }, methods: { prompt: function () { this.message = '快来看这里!我是新讯息!' } } }) </code></pre> <p>点击下面的按钮体验一下:</p> <div style="margin-bottom: 20px;"><iframe id="aLReJP" src="//codepen.io/airen/embed/aLReJP?height=300&amp;theme-id=0&amp;slug-hash=aLReJP&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="300" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>如果需要在内联语句处理器中访问原生DOM事件。可以使用特殊变量<code>$event</code>,把它传入到<code>methods</code>中的方法中。在上面的示例中修改一下,给<code>prompt()</code>中传参数:</p> <pre><code>&lt;!-- HTML --&gt; &lt;div id="app"&gt; &lt;button @click="prompt('快来看这里!我是新讯息!', $event)"&gt;点击我(^_^)&lt;/button&gt; &lt;p&gt;{{ message }}&lt;/p&gt; &lt;/div&gt; let app = new Vue({ el: '#app', data () { return { message: '没发生任何事情!' } }, methods: { prompt: function (message, event) { if (event) { console.log(event) event.preventDefault(); } this.message = message } } }) </code></pre> <p><img src="/sites/default/files/blogs/2017/1710/vue-methods-event-1.gif" alt="Vue的Methods和事件处理" /></p> <p>从<code>console.log(event)</code>的信息中可以看出来,我们每次点击在按钮不同位置时,<code>event</code>出来的信息都不会一样。而且在调用的时候,<code>prompt()</code>可以指定你需要传的<code>message</code>值,并且使用<code>$event</code>传到<code>prompt()</code>中。</p> <h2>事件修饰符</h2> <p>从上面的示例中可以看出,在Vue中可以通过<code>v-on</code>指令来给元素绑定事件,上面的示例是<code>click</code>事件,但除了<code>click</code>的事件之外,还有其他的事件,详细的不在这里阐述,感兴趣的话,可以<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/v-on.html">阅读前面整理的内容</a>。在介绍<code>v-on</code>指令时,提到过事件处理的时候,可以添加一些事件修饰符。</p>" <p>在Vue中,<strong>事件修饰符</strong>处理了许多DOM事件的细节,让我们不再需要花大量的时间去处理这些烦恼的事情,而能有更多的精力专注于程序的逻辑处理。在Vue中事件修饰符主要有:</p> <ul> <li><strong><code>.stop</code></strong>:等同于JavaScript中的<code>event.stopPropagation()</code>,防止事件冒泡</li> <li><strong><code>.prevent</code></strong>:等同于JavaScript中的<code>event.preventDefault()</code>,防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播)</li> <li><strong><code>.capture</code></strong>:与事件冒泡的方向相反,事件捕获由外到内</li> <li><strong><code>.self</code></strong>:只会触发自己范围内的事件,不包含子元素</li> <li><strong><code>.once</code></strong>:只会触发一次</li> </ul> <p>接下来,咱们通过一些简单的示例来看看事件修饰符起的作用。</p> <h3><code>.stop</code></h3> <p>等同于<code>event.stopPropagation()</code>,防止事件冒泡。来看一个简单示例。</p> <p>当点击按钮“点击我”时,不但会触发绑定在按钮上<code>inner</code>方法,还会触发绑定在其容器<code>div</code>的<code>middle</code>和<code>outer</code>方法。</p> <pre><code>&lt;!-- HTML --&gt; &lt;div id="app"&gt; &lt;div class="outeer" @click="outer"&gt; &lt;div class="middle" @click="middle"&gt; &lt;button @click="inner"&gt;点击我(^_^)&lt;/button&gt; &lt;/div&gt; &lt;/div&gt; &lt;p&gt;{{ message }}&lt;/p&gt; &lt;/div&gt; let app = new Vue({ el: '#app', data () { return { message: '测试冒泡事件' } }, methods: { inner: function () { this.message = 'inner: 这是最里面的Button' }, middle: function () { this.message = 'middle: 这是中间的Div' }, outer: function () { this.message = 'outer: 这是外面的Div' } } }) </code></pre> <p>点击<code>button</code>之后,页面渲染的文本“outer: 这是外面的Div”。但整个过程如下:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-methods-event-2.gif" alt="Vue的Methods和事件处理" /></p> <p>整个事件示意图如下:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-methods-event-3.png" alt="Vue的Methods和事件处理" /></p> <p>在Vue中,咱们可以使用<code>.stop</code>防止上例这种事件冒泡状况发生。我们只需要在<code>button</code>上的<code>click</code>事件添加修饰符<code>.stop</code>,比如:</p> <div style="margin-bottom: 20px;"><iframe id="BwGaQe" src="//codepen.io/airen/embed/BwGaQe?height=300&amp;theme-id=0&amp;slug-hash=BwGaQe&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="300" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>这个时候,点击<code>button</code>时,并不会捕获到<code>div.middle</code>和<code>div.outer</code>上的事件:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-methods-event-4.gif" alt="Vue的Methods和事件处理" /></p> <h3><code>.prevent</code></h3> <p><code>.prevent</code>等同于JavaScript的<code>event.preventDefault()</code>,用于取消默认事件。比如我们页面的<code>&lt;a href="http://xxysy.com/quot;#"&gt;</code>标签,当用户点击时,通常在浏览器的网址列出<code>#</code>:</p>" <p><img src="/sites/default/files/blogs/2017/1710/vue-methods-event-5.gif" alt="Vue的Methods和事件处理" /></p> <p>在JavaScript中,常常使用<code>event.preventDefault()</code>来防止浏览器的网址中出现<code>#</code>。在Vue中,可以使用事件修饰符<code>.prevent</code>来取消默认事件。</p> <div style="margin-bottom: 20px;"><iframe id="wrQvbM" src="//codepen.io/airen/embed/wrQvbM?height=300&amp;theme-id=0&amp;slug-hash=wrQvbM&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="300" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>这个时候,点击链接之后,浏览器的网址中再也不会出现<code>#</code>。</p> <h3><code>.capture</code></h3> <p><code>.capture</code>修饰符和<code>.stop</code>刚好相反。<code>.stop</code>是防止事件冒泡,而<code>.capture</code>类似JavaScript的事件捕获,是由外到内的。如下图所示:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-methods-event-3.png" alt="Vue的Methods和事件处理" /></p> <p>用到我们的Vue的事件修饰符中:</p> <pre><code>&lt;!-- HTML --&gt; &lt;div id="app"&gt; &lt;div class="outeer" @click.capture="outer"&gt; &lt;div class="middle" @click.capture="middle"&gt; &lt;button @click.capture="inner"&gt;点击我(^_^)&lt;/button&gt; &lt;/div&gt; &lt;/div&gt; &lt;p&gt;{{ message }}&lt;/p&gt; &lt;/div&gt; let app = new Vue({ el: '#app', data () { return { message: '事件捕获' } }, methods: { inner: function () { this.message = 'inner: 这是最里面的Button' alert(this.message) }, middle: function () { this.message = 'middle: 这是中间的Div' alert(this.message) }, outer: function () { this.message = 'outer: 这是外面的Div' alert(this.message) } } }) </code></pre> <p>看到的行为如下:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-methods-event-6.gif" alt="Vue的Methods和事件处理" /></p> <h3><code>.self</code></h3> <p>修饰符<code>.self</code>只会触发自己范围内的事件,不会包含子元素。</p> <pre><code>&lt;!-- HTML --&gt; &lt;div id="app"&gt; &lt;div class="outer" @click.self="outer"&gt; &lt;div class="middle" @click.self="middle"&gt; &lt;button @click="inner"&gt;点击我(^_^)&lt;/button&gt; &lt;/div&gt; &lt;/div&gt; &lt;p&gt;{{ message }}&lt;/p&gt; &lt;/div&gt; let app = new Vue({ el: '#app', data () { return { message: '修饰符:.self' } }, methods: { inner: function () { this.message = 'inner: 这是最里面的Button' alert(this.message) }, middle: function () { this.message = 'middle: 这是中间的Div' alert(this.message) }, outer: function () { this.message = 'outer: 这是外面的Div' alert(this.message) } } }) </code></pre> <p>咱们分别点击<code>div.outer</code>、<code>div.middle</code>和<code>button</code>,在这几个元素上都绑定了<code>click</code>事件,并且添加了<code>.self</code>修饰符:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-methods-event-7.gif" alt="Vue的Methods和事件处理" /></p> <h3><code>.once</code></h3> <p>还记得我们以前使用Vue写了一个计数器,点击<code>+</code>就会加<code>1</code>,不断点击就会不断累加,反则点击<code>-</code>就会减<code>1</code>,不断点击就会不断减少。</p> <div style="margin-bottom: 20px;"><iframe id="MEzwYL" src="//codepen.io/airen/embed/MEzwYL?height=300&amp;theme-id=0&amp;slug-hash=MEzwYL&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="300" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>如果我们在<code>@click</code>事件上添加<code>.once</code>修饰符,只要点击按钮只会执行一次。</p> <div style="margin-bottom: 20px;"><iframe id="dVQoRN" src="//codepen.io/airen/embed/dVQoRN?height=300&amp;theme-id=0&amp;slug-hash=dVQoRN&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="300" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <h2>键盘修饰符</h2> <p>在JavaScript事件中除了前面所说的事件,还有键盘事件,也经常需要监测常见的键值。在Vue中允许<code>v-on</code>在监听键盘事件时添加关键修饰符。记住所有的<code>keyCode</code>比较困难,所以Vue为最常用的键盘事件提供了别名:</p> <ul> <li><strong><code>.enter</code></strong>:回车键</li> <li><strong><code>.tab</code></strong>:制表键</li> <li><strong><code>.delete</code></strong>:含<code>delete</code>和<code>backspace</code>键</li> <li><strong><code>.esc</code></strong>:返回键</li> <li><strong><code>.space</code></strong>: 空格键</li> <li><strong><code>.up</code></strong>:向上键</li> <li><strong><code>.down</code></strong>:向下键</li> <li><strong><code>.left</code></strong>:向左键</li> <li><strong><code>.right</code></strong>:向左键</li> </ul> <p>效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="RLqPYx" src="//codepen.io/airen/embed/RLqPYx?height=300&amp;theme-id=0&amp;slug-hash=RLqPYx&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="300" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>当你把鼠标移动按钮上,然后按下不同的键盘,将会监听到对应的键盘事件:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-methods-event-8.gif" alt="Vue的Methods和事件处理" /></p> <h2>鼠标修饰符</h2> <p>鼠标修饰符用来限制处理程序监听特定的滑鼠按键。常见的有:</p> <ul> <li><strong><code>.left</code></strong>:鼠标左键</li> <li><strong><code>.middle</code></strong>:鼠标中间滚轮</li> <li><strong><code>.right</code></strong>:鼠标右键</li> </ul> <h2>修饰键</h2> <p>可以用如下修饰符开启鼠标或键盘事件监听,使在按键按下时发生响应:</p> <ul> <li><strong><code>.ctrl</code></strong></li> <li><strong><code>.alt</code></strong></li> <li><strong><code>.shift</code></strong></li> <li><strong><code>.meta</code></strong></li> </ul> <h2>自定义按键修饰符别名</h2> <p>在Vue中可以通过<code>config.keyCodes</code>自定义按键修饰符别名。例如,由于预先定义了<code>keycode 116</code>(即<code>F5</code>)的别名为<code>f5</code>,因此在文字输入框中按下<code>F5</code>,会触发<code>prompt</code>方法,出现<code>alert</code>。</p> <pre><code>&lt;!-- HTML --&gt; &lt;div id="app"&gt; &lt;input type="text" v-on:keydown.f5="prompt()"&gt; &lt;/div&gt; Vue.config.keyCodes.f5 = 116; let app = new Vue({ el: '#app', methods: { prompt: function() { alert('我是 F5!'); } } }); </code></pre> <h2>总结</h2> <p>在Vue中,使用<code>v-on</code>来给元素绑定事件,而为了更好的处理逻辑方面的事物,Vue提供了一个<code>methods</code>。在<code>methods</code>中定义一些方法,这些方法可以帮助我们处理一些逻辑方面的事情。而在这篇文章中,我们主要介绍了一些事件的修饰符,比如常见的阻止事件冒泡,键盘修饰符等。除此之外,还提供了<code>config.keyCodes</code>提供自定义按键修饰符别名。</p> <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-methods-and-event-handling.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-methods-and-event-handling.html</a></p> rel="nofollow" </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/640.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/vue"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/vue/vue2"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue 2.0学习笔记</a></div></div></div> Tue, 17 Oct 2017 12:12:37 +0000 Airen 2292 at http://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 http://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/working-with-methods-in-vue.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>在前面的学习当中,学会了如何用文本插值输出数据。但如果我们需要根据某些规则或逻辑输出数据呢?在这种情况下,我们可以通地Vue中的计算属性,根据某些规则或逻辑输出数据。这种方式也很方便,但除了这些方式之外,还可以嵌入JavaScript的逻辑函数。有的时候我们还会从远程服务获取数据,使用前面提到的方式也是可以。那么,今天 我们学习一个新方法,<strong>使用<code>methods</code>属性向Vue实例引入新属性</strong>。该属性应该包含一个对象,其中键(<code>key</code>)为函数的名称,值(<code>value</code>)为函数本身。</p> <p>在介绍<code>methods</code>之前,咱们先简单的回忆一下。比如我们有下面这个示例,我们的<code>data</code>数据中,有两个属性:<code>firstName</code>和<code>lastName</code>。我们的目的是输出一个<code>fullName</code>。</p> <pre><code>let app = new Vue({ el: '#app', data () { return { firstName: 'Airen', lastName: 'Liao' } } }) </code></pre> <p>比如我们要在页面中输出全名,我们有两种方式,一种是文本插值方式:</p> <pre><code>&lt;div id="app"&gt; &lt;h1&gt;{{ firstName }} {{ lastName }}&lt;/h1&gt; &lt;/div&gt; </code></pre> <p>可以看到输出我们需要的<code>fullName</code>,也就是<code>"Airen Liao"</code>:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-methods-1.png" alt="Vue的Methods" /></p> <p>除了文本插值的方式之外,我们还可以使用Vue中的<code>computed</code>属性,可以在<code>computed</code>中创建一个<code>fullName</code>方法。其中键名就是函数名,比如<code>fullName</code>,而键值是函数:</p> <pre><code>let app = new Vue({ el: '#app', data () { return { firstName: 'Airen', lastName: 'Liao' } }, computed: { fullName: function () { return this.firstName + ' ' + this.lastName } } }) </code></pre> <p>这个时候,我们在元素中插入<code>fullName</code>,如下:</p> <pre><code>&lt;div id="app"&gt; &lt;h1&gt;{{ fullName }}&lt;/h1&gt; &lt;/div&gt; </code></pre> <p>最终输出的也是我们希望要的结果。</p> <blockquote> <p>如果你从未接触Vue中的计算属性<code>computed</code>,建议你点击<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-computed.html">这里</a>或<" href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-computed-intro.html">这里</a>进行了解。</p>" </blockquote> <p>除了上面两种方式,我们还可以添加一个方法,即函数,它也可以为我们做这个。</p> <p>正如前面提到的,函数必须在Vue中的<code>methods</code>属性下添加,这个有点类似于Vue中的计算属性<code>computed</code>。在Vue中,把<code>methods</code>被命名为<strong>方法</strong>,它也是让我们调用在对象上下文中的函数,它可以操作对象中包含的数据。在我们这个示例,对象其实就是Vue实例。</p> <pre><code>let app = new Vue({ el: '#app', data () { return { firstName: 'Airen', lastName: 'Liao' } }, methods: { } }) </code></pre> <p>该对象中的键将是方法的名称。在本例中,<code>fullName</code>就是<code>methods</code>的方法名,其值就是一个函数:</p> <pre><code>let app = new Vue({ el: '#app', data () { return { firstName: 'Airen', lastName: 'Liao' } }, methods: { fullName: function () { } } }) </code></pre> <p>实际上,Vue中的方法可用做很多事情,但是现在我们这个示例中的方法只返回一个字符串值,它可以通过文本插值来输出。那么,我们如何访问该方法中的数据属性呢?Vue代理的数据和方法在此上下文中都可用,所以<code>this.firstName</code>就是访问了<code>data</code>中的<code>firstName</code>属性。<strong>注意这是必需的</strong>。有了这个,我们就可以很容易地连接第一个和最后一个名称并返回结果。</p> <pre><code>let app = new Vue({ el: '#app', data () { return { firstName: 'Airen', lastName: 'Liao' } }, methods: { fullName: function () { return this.firstName + ' ' + this.lastName } } }) </code></pre> <p>再次注意了,Vue中的<code>data</code>和<code>methods</code>都是上下文中的变量,所以我们可以通过<code>this.firstName</code>的方式访问<code>data</code>中的<code>firstName</code>属性。如果我们想要,我们可以通过使用相同的方法从<code>fullName()</code>方法中访问其他方法,只需要末尾插入括号,使其成为方法调用。</p> <p>好了,现在我们已经实现了我们的方法,让我们看看在模板中怎么使用它。事实上也是你期望的那样简单,在方法后面紧跟着圆括号。</p> <pre><code>&lt;div id="app"&gt; &lt;h1&gt;{{ fullName() }}&lt;/h1&gt; &lt;/div&gt; </code></pre> <p>事实证明,Vue的<code>methods</code>也可以访问数据对象的属性,也同样能渲染出所需要的字符。如果运行上面的代码,我们应该可以看到我的全名会页面上输出。如下所示:</p> <div style="margin-bottom: 20px;"><iframe id="EwpwvX" src="//codepen.io/airen/embed/EwpwvX?height=300&amp;theme-id=0&amp;slug-hash=EwpwvX&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="300" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>这个看上去和<code>computed</code>类似。截张图看个对比:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-methods-2.png" alt="Vue的Methods" /></p> <p>这两种方式,只要我们<code>data</code>中的数据做了改变,输出也会做相应的变化。我们可以在控制台上做个测试:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-methods-3.gif" alt="Vue的Methods" /></p> <p>使用Vue的<code>methods</code>时,在调用<code>methods</code>定义的方法时,一定得加上小括号<code>()</code>,不然输出的将是整个函数中的字符,类似下图这样:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-methods-4.png" alt="Vue的Methods" /></p> <p>在Vue中,使用<code>methods</code>可以做<code>computed</code>同样的事情,但两者之间还是有所差别的。让我们尝试一种稍微不同的方法。如果我们希望将第一个和最后一个名字传递给方法作为参数,而不是让方法直接访问数据属性,那该怎么办?我们可以很容易地在方法中添加参数,就像我们在JavaScript中的函数传参数那样。</p> <p>我将对参数使用不同的名称,这样它们就不会和<code>data</code>对象的属性同名,造成一定的混淆,这样做只是为了证明我们不再依赖于数据中的属性。</p> <pre><code>let app = new Vue({ el: '#app', data () { return { firstName: 'Airen', lastName: 'Liao' } }, methods: { fullName: function (first, last) { return first + ' ' + last } } }) </code></pre> <p>然后,在模板中,我们只需要通过使用数据对象中的适当属性名作为<code>fullName</code>的参数传递进去,比如:</p> <pre><code>&lt;div id="app"&gt; &lt;h1&gt;{{ fullName(firstName, lastName) }}&lt;/h1&gt; &lt;/div&gt; </code></pre> <p>这样也能得到我们想要的结果,在页面上输出我的全名。除此之外,我们还可以像JavaScript的函数调用一样,传一些不在<code>data</code>中的属性做为参数,也能输出到页面上,如:</p> <pre><code>&lt;div id="app"&gt; &lt;h1&gt;{{ fullName('大漠', '伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com') }}&lt;/h1&gt; &lt;/div&gt; </code></pre> <p>效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="YrjEez" src="//codepen.io/airen/embed/YrjEez?height=300&amp;theme-id=0&amp;slug-hash=YrjEez&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="300" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>除了像上面一样,在方法中返回字符串之外,我们还可以返回对象和数组。比如我们重构上面的方法,让这个方法返回一个对象而不是字符串。比如下面的示例,咱们返回一个叫<code>name</code>的对象,而这个对象正如你所期望的一样,输出全名。</p> <pre><code>let app = new Vue({ el: '#app', data () { return { firstName: 'Airen', lastName: 'Liao' } }, methods: { fullName: function(first, last) { return { name: first + ' ' + last } } } }) </code></pre> <p>在模板中,我们仍然像以前一样调用方法。运行代码将打印出对象,这不是我们想要的。在方法调用之后,需要访问<code>fullName</code>对象的<code>name</code>名。再次运行代码将显示相同的结果。这也适用于嵌套对象。</p> <div style="margin-bottom: 20px;"><iframe id="JrBOzg" src="//codepen.io/airen/embed/JrBOzg?height=300&amp;theme-id=0&amp;slug-hash=JrBOzg&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="300" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>在Vue中使用<code>methods</code>时有一个细节需要注意。如果你试图在方法对象中使用ES6箭头函数,那么你将无法访问其他方法或数据属性。这主要是因为箭头函数被绑定到父上下文(Parent Context),因此这个关键字不会像你期望那样引用Vue实例。因此,你试图以这种方式访问的任何数据属性或方法都将是未定义的。解决方法很简单:<strong>在方法对象中使用ES5语法的函数</strong>。</p> <p>虽然 ES6的箭头函数非常有用,但在Vue的<code>methods</code>中使用,将会发生什么?我们简单的用示例来演示。将前面示例中的<code>fullName</code>函数改用箭头函数的写法:</p> <pre><code>methods: { fullName: () =&gt; { return this.firstName + ' ' + this.lastName } } </code></pre> <p>运行上面的代码,在页面上并未能如你所期望的一样输出我的全名。这是因为箭头函数被绑定到父上下文,因此这将不是你所期望的Vue实例。当你打开浏览器的控制台时,可以看到有报错信息:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-methods-5.png" alt="Vue的Methods" /></p> <p>报错信息中告诉我们<code>firstName</code>是<code>undefined</code>。我们在代码中添加<code>console.log(this)</code>。正如我们所看到的,<code>this</code>指向的是<code>window</code>对象,这不是我们所期望的。这就是为什么在这种情况下,我们没有<code>firstName</code>或<code>lastName</code>属性。相比之下,我们使用正常函数,看看是什么样子:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-methods-6.png" alt="Vue的Methods" /></p> <p>现在,我们可以看到Vue实例的输出,就像我们最初期望的那样。</p> <p>这个实例告诉我们不应该在Vue实例属性上使用箭头函数,Vue尝试将其绑定到Vue实例本身。还有时候,你可以使用箭头函数提供所有的好处,例如,如果你将一个函数赋给一个Vue实例的方法中的一个变量。然后你可以在这个箭头函数中访问它,它将指向你所期望的Vue实例。你只要意识到使用箭头函数的地方可能会出现一些奇怪的行为,而不是你所期望的,那么它可能与箭头函数有关。这时需要注意,先尝试把箭头函数改成ES5的函数方式。</p> <h2>Methods vs Computed</h2> <p>前面的示例我们可以看到,<code>methods</code>和<code>computed</code>都可以处理大量的逻辑代码。有时候他们得到的效果是一样的。虽然如此,但他们各自却有不同之处。从作用机制和性质上看,<code>methods</code>和<code>computed</code>不太一样,所以我们接下来主要了解两者之间的对比。从两者对比来了解他们之间的不同之处。</p> <p>从<strong>作用机制上</strong>看:</p> <ul> <li><code>computed</code>是以Vue的依赖追踪机制为基础的,其试图处理这样的一件事情:当某一个数据(依赖数据)发生变化的时候,所有依赖这个数据的<strong>相关数据</strong>会<strong>自动</strong>发生变化,也就是自动调用相关的函数去实现数据的变动</li> <li><code>methods</code>里面是用来定义函数的,它需要手动调用才能执行,而不像<code>computed</code>那样,可以自动执行预先定义的函数</li> </ul> <blockquote> <p><code>methods</code>里面定义的函数是需要主动调用的,而<code>computed</code>里定义的函数会自动调用,完成我们希望完成的作用</p> </blockquote> <p>从<strong>性质上</strong>看:</p> <ul> <li><code>computed</code>是计算属性,事实上和<code>data</code>对象里的数据属性是同一类的</li> <li><code>methods</code>里面定义的是函数,要像JavaScript中的<code>function()</code>函数这样去调用它</li> </ul> <p>例如:</p> <pre><code>computed: { fullName: function () { return this.firstName + ' ' + this.lastName } } </code></pre> <p>你在取用的时候,用<code>this.fullName</code>去取用就和取<code>data</code>一样(不要当成函数调用)。</p> <p>Vue中的<code>computed</code>擅长处理的场景是:<strong>一个数据受多个数据影响</strong></p> <p><img src="/sites/default/files/blogs/2017/1710/vue-methods-7.png" alt="Vue的Methods" /></p> <p>比如我们有一个这样的场景,我本来想用“W3cplus_大漠(只会写CSS)”来描述自己,但希望能把“只会写CSS”改成“切图仔”,那么我们可以这样来写:</p> <pre><code>let app = new Vue({ el: '#app', // data数据中:comeFrom, name,professional // computed监控数据:fullName // 两者关系: fullName = comeFrom + name + professional // 所以等式右边三个数据任一改变,都会直接修改fullName data () { return { comeFrom: 'W3cplus', name: '大漠', professional: '只会写CSS' } }, computed: { fullName: function () { return this.comeFrom + '-' + this.name + '(' + this.professional + ')' } } }) &lt;div id="app"&gt; &lt;h1&gt;{{ fullName }}&lt;/h1&gt; &lt;/div&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1710/vue-methods-8.png" alt="Vue的Methods" /></p> <p>希望能把“只会写CSS”改成“切图仔”,尝试修改<code>data</code>中的<code>professional</code>的值为<code>"切图仔"</code>,比如:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-methods-9.gif" alt="Vue的Methods" /></p> <p><code>methods</code>不处理数据逻辑关系,只提供可调用的函数。正如前面的示例所演示的一样。</p> <p>在很多时候,<code>computed</code>是用来处理你使用<code>methods</code>的时候无法处理或者是处理起来并不太恰当的情况的。另外可以利用<code>computed</code>处理<code>methods</code>存在的重复计算情况,如下图所示:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-methods-10.png" alt="Vue的Methods" /></p> <p><code>methods</code>里面的函数就是一群“直男”,如果有其他父函数调用它,它会每次都执行并返回结果,即使这些结果很可能是相同的,是不需要的;而<code>computed</code>是一个“心机婊”,它会以Vue提供的依赖追踪系统为基础,只要依赖数据没有发生变化,<code>computed</code>就不会再度进行计算。</p> <p>比如下面这个时间的示例:</p> <pre><code>let app = new Vue({ el: '#app', methods: { getMethodsDate: function () { console.log(new Date()) }, getComputedDate: function () { console.log(this.computedDate) } }, computed: { computedDate: function () { return new Date() } } }) &lt;div id="app"&gt; &lt;button @click="getMethodsDate"&gt;Methods Get Date&lt;/button&gt; &lt;button @click="getComputedDate"&gt;Computed Get Date&lt;/button&gt; &lt;/div&gt; </code></pre> <p>先来看一个点击<code>button</code>在控制台的输出:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-methods-11.gif" alt="Vue的Methods" /></p> <p>不难发现,连续点击两次<code>methods</code>返回的时间是<strong>不同</strong>的;连续点击两次<code>computed</code>返回的时间是<strong>相同</strong>的。</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-methods-12.png" alt="Vue的Methods" /></p> <blockquote> <p>为什么两次点击<code>computed</code>返回的时间是相同的呢?<code>new Date()</code>不是依赖型数据(不是放在<code>data</code>等对象下的实例数据),所以<code>computed</code>只提供了缓存的值,而没有重新计算。</p> </blockquote> <p>只有符合:<strong>存在依赖型数据和依赖型数据发生改变这两个条件,<code>computed</code>才会重新计算。 而<code>methods</code>下的数据,是每次都会进行计算的</strong>。使用官方的描述:</p> <blockquote> <p>我们可以将同一函数定义为一个方法而不是一个计算属性。对于最终的结果,两种方式确实是相同的。然而,<strong>不同的是计算属性是基于它们的依赖进行缓存的</strong>。计算属性只有在它的相关依赖发生改变时才会重新求值。</p> </blockquote> <h2>总结</h2> <p>今天我们主要学习了Vue中的<code>methods</code>怎么使用。顺便介绍了<code>methods</code>和<code>computed</code>两者之间的异同。</p> <p>由于作者自身是Vue的初学者,如果文中有不对之处,还请各路大婶拍正,如果在这方面有更多的经验,欢迎在下面的评论中与我们一起分享。</p> <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/working-with-methods-in-vue.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/working-with-methods-in-vue.html</a></p> rel="nofollow" </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/640.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/vue"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/vue/vue2"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue 2.0学习笔记</a></div></div></div> Thu, 12 Oct 2017 15:36:12 +0000 Airen 2291 at http://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 http://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/build-a-scientific-calculator-with-vuejs.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>学习Vue有一段时间了,但真正的实战并不是很多。师父告诉我,要学好就得多动手。为了能把动手写的案例有一个集中的地方放置,我在Github上创建了一个仓库<strong><a href="http://xxysy.com/quot;//github.com/airen/VueStudy">VueStudy</a></strong>。这里将会不断的添加一些练习过的案例,如果你感兴趣的话,欢迎提交你写过的案例。</p>" <p>今天我们来写一个案例:<strong>使用Vue创建计算器</strong>。<a href="http://xxysy.com/quot;//github.com/airen/VueStudy/tree/master/vue-calculator">Github有对应的示例代码</a>。如果你想在本地运行,看到对应的效果,可以把这个项目下载到你的本地,然后进入对应的目录,执行下面的命令:</p>" <pre><code>npm i npm run dev </code></pre> <p>然后在浏览器地址中输入<code>http://localhost:8080</code>就能看到了。接下来我们来看看怎么用Vue创建这个计算器。</p> <h2>今天的目标</h2> <p>今天的目标,就是使用Vue做一个计算器,如下图所示:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-calculator-3.gif" alt="使用Vue创建计算器" /></p> <p>这个计算器我们有两个版本,一个简单版本:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-calculator-1.png" alt="使用Vue创建计算器" /></p> <p>另一个是高级版本:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-calculator-2.png" alt="使用Vue创建计算器" /></p> <p>当我们使用Vue把计算器做好之后,可以帮你执行一些任务。而通过这个伟德1946网页版,可以学到Vue一些相关知识:</p> <ul> <li>处理用户输入</li> <li>使用模板语法将数据渲染到DOM</li> <li>熟悉处理数据的基本指令</li> <li>创建Vue实例</li> </ul> <h2>一些准备工作</h2> <p>虽然说我们这里是使用Vue来创建一个计算器,但始终还是脱离不开JavaScript方面的知识。也就是说,有关于计算器功能方面的实现,还是需要通过JavaScript来实现。如果你和我一样,JavaScript知识比较单薄的话,建议先补充一些有关这方面的知识。个人建议你可以看看<a href="http://xxysy.com/quot;//github.com/dunizb/sCalc">@dunizb写的一个计算器</a>,或者学习一下<" href="http://xxysy.com/quot;//mathjs.org/"><code>math.js</code></a>库中的一些知识。接下来的内容假设你已经对这方面有所了解,可以使用JavaScript完成计算器相关的知识。</p>" <p>回到Vue的世界中来。使用Vue创建计算器,也相当于我们开始一个新项目,那么在Vue中,创建这样的项目有多种方式。或者说创建我们的计算器有多种方式。比如前面《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/running-environment.html">Vue的运行环境</a>》文中提到的。可以在一个单独的文件中使用Vue,也可以在在线的Codepen中创建。不过我们今天采用的是一种新的方式,采用Vue官方提供的项目构建工程<" href="http://xxysy.com/quot;//github.com/vuejs/vue-cli">Vu" CLI</a>。</p> <p>要正常使用Vue CLI得先确保你的环境中已经安装了Node和NPM。然后在你的命令终端执行:</p> <pre><code>npm i vue-cli -g </code></pre> <p>也就是在本地电脑中全局安装Vue CLI。假设你按上面的命令已成功安装好了,那么接下来通过其构建我们需要的Vue项目。</p> <p>进入你的工作环境,然后执行:</p> <pre><code>vue init webpack vue-calculator </code></pre> <p>这样我们就创建了<code>vue-calculator</code>项目,然后进入这个项目,安装项目所需的依赖关系:</p> <pre><code>cd vue-calculator npm i </code></pre> <p>这样在你的本地,可以看到项目对应的目录结构:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-calculator-4.png" alt="使用Vue创建计算器" /></p> <p>而且项目所需要的依赖关系都在<code>package.json</code>文件中。接下来运行:</p> <pre><code>npm run dev </code></pre> <p>在浏览器中运行<code>http://localhost:8080/</code>就可以浏览项目的效果。</p> <h2>Vue项目</h2> <p>通过Vue CLI构建的Vue项目,其入口文件是<code>main.js</code>。在这个文件中引入Vue和创建Vue实例:</p> <pre><code>import Vue from 'vue' import App from './App' new Vue({ el: '#app', template: '&lt;App/&gt;', components: { App } }) </code></pre> <p>上面的代码是引入了<code>vue</code>和一个<code>App</code>伟德1946手机版,然后通过下面的方式创建了一个Vue实例,然后将Vue控制的部分视图挂载在<code>el</code>属性上进行跟踪。而<code>el</code>属性值对应的是<code>index.html</code>文件中的<code>div#app</code>元素:</p> <pre><code>&lt;div id="app&gt; &lt;!-- HTML都将会塞到这里 --&gt; &lt;/div&gt; </code></pre> <h2>创建Vue伟德1946手机版</h2> <p>我们的目标是创建一个计算器,那么我们把这个计算器称作Vue的一个伟德1946手机版。所以我们首要的条件就是先创建一个伟德1946手机版,我们这里一个叫<code>calculator</code>伟德1946手机版。在项目中,进入<code>/src/components</code>目录中创建一个<code>calculator.vue</code>文件。我们有关于计算器相关的东西都将放在这个文件中。他的格式一般如下:</p> <pre><code>&lt;template&gt; &lt;div&gt; &lt;!-- 需要用一个容器包裹伟德1946手机版中用到的所有元素 --&gt; &lt;/div&gt; &lt;/tempalte&gt; &lt;script&gt; export default { // 逻辑代码写在这 } &lt;/script&gt; &lt;style&gt; /* 伟德1946手机版样式写在这里 */ &lt;/sytle&gt; </code></pre> <p>也就是说一个伟德1946手机版包含三个部分:</p> <ul> <li><code>&lt;template&gt;</code>:用来放置伟德1946手机版相关的模板</li> <li><code>&lt;script&gt;</code>:用来放置伟德1946手机版逻辑相关的代码,通过<code>export default{}</code>输出</li> <li><code>&lt;style&gt;</code>:用来放置伟德1946手机版相关的样式</li> </ul> <p>创建伟德1946手机版之后,在<code>App.vue</code>中引入创建好的伟德1946手机版:</p> <pre><code>&lt;template&gt; &lt;div id="app"&gt; &lt;Calculator /&gt; &lt;/div&gt; &lt;/template&gt; &lt;script&gt; import Calculator from './components/calculator' export default { name: 'app', components: { Calculator } } &lt;/script&gt; &lt;style&gt; // .... &lt;/style&gt; </code></pre> <p>这样整个链路就通了。当然,现在这个时候,你在浏览器中还看不到任何的东西。那是因为我们的<code>calculator.vue</code>中还未写任何有关于伟德1946手机版相关的东西。接下来我们就专心写伟德1946手机版相关的东西。</p> <h2>添加计算器需要的元素</h2> <p>计算器首先需要一个输入屏,在这里使用<code>input</code>来表示。而他的功能是,用户点击计算器中的按钮时,<code>input</code>中对应的<code>value</code>值会有更新。这需要使用到前面所介绍的<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/v-model.html"><code>v-model</code></a>指令进行数据双向绑定。在<code>input</code>元素中通过<code>v-model</code>绑定<code>data</code>数据对象中的<code>current</code>属性:</p>" <pre><code>&lt;div class="results"&gt; &lt;input class="input" v-model="current"&gt; &lt;/div&gt; </code></pre> <p>视图绑定的值存储在<code>data</code>对象中,如下所示:</p> <pre><code>export default { name: 'Calculator', data () { return{ current: '' } } } </code></pre> <p>接下来我们需要给计算器添加按钮。这里我们使用<code>button</code>元素来做。</p> <pre><code>&lt;button class="button"&gt;7&lt;/button&gt; </code></pre> <p>在Vue中,允许我们在实例中创建方法,提供无缝的事件处理和状态更改触发器。我们可以通过<code>v-on</code>(简写<code>@</code>)指令在我们的HTML中元素绑定对应的事件。在这里我们使用的是<code>click</code>事件,而这个事件绑定的是一个叫<code>press</code>的方法:</p> <pre><code>&lt;button class="button" @click="press"&gt;7&lt;/button&gt; </code></pre> <p>对应的脚本中,添加<code>methods</code>方法:</p> <pre><code>export default { name: 'Calculator', data () { return{ current: '' } }, methods: { press: function(event) { // 计算器按钮的click事件 } } } </code></pre> <p>在<code>methods</code>中我们添加了<code>press</code>函数,这个函数将处理计算器按钮的点击的一些事情。具体做些什么事情,咱们先别说,后面的内容将会完善这部分。</p> <p>文章开头提到过,我们的计算器分为两个部分,一个是简易版的计算器,另一个是高级版的计算器。在Vue中我们可以通过<code>v-if</code>(当然也可以使用<code>v-show</code>)来判断显示哪个版本。这个时候需要在<code>data</code>中创建一个<code>changeMode</code>属性,当这个属性的值为<code>true</code>时显示简易版计算器,反则为<code>false</code>时显示高级版本计算器。</p> <pre><code>&lt;div class="mode" v-if="changeMode"&gt; &lt;!-- 简易版本计算器 --&gt; &lt;button class="button" @click="press"&gt;7&lt;/button&gt; ... &lt;button class="button equal-sign" @click="press"&gt;=&lt;/button&gt; &lt;/div&gt; &lt;div class="mode" v-else&gt; &lt;!-- 高级版本计算器 --&gt; &lt;button class="button" @click="press"&gt;7&lt;/button&gt; ... &lt;button class="button equal-sign" @click="press"&gt;=&lt;/button&gt; &lt;/div&gt; export default { name: 'Calculator', data () { return{ current: '', changeMode: true } }, methods: { press: function(event) { // 计算器按钮的click事件 } } } </code></pre> <p>这个时候,我们需要一个类似<code>button</code>一样的东东,能触发显示哪个版本的计算器:</p> <pre><code>&lt;button @click="changeModeEvent" class="toggle-button"&gt; &lt;p v-if="changeMode"&gt;Show Advanced Mode &amp;nbsp; &amp;nbsp; &amp;#9864;&lt;/p&gt; &lt;p v-else&gt;Show Basic Mode &amp;nbsp; &amp;nbsp; &amp;#9862;&lt;/p&gt; &lt;/button&gt; </code></pre> <p>同样的,在<code>button</code>上通过<code>v-on</code>绑定<code>changeModeEvent</code>方法,这个方法主要任务就是修改<code>changeMode</code>的值。这个方法和<code>press</code>方法一样,都将放置在<code>methods:{}</code>中。这个时候你看到的效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="pWKaqP" src="//codepen.io/airen/embed/pWKaqP?height=300&amp;theme-id=0&amp;slug-hash=pWKaqP&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="300" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>上面我们看到的是简易版本的效果。如果<code>app.changeMode</code>换成<code>false</code>时,看到的是高级版本的。</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-calculator-5.gif" alt="使用Vue创建计算器" /></p> <p>没有样式,看得实在难受。这个时候在<code>&lt;style&gt;</code>中添加样式,我们的计算器就会好看得多:</p> <div style="margin-bottom: 20px;"><iframe id="xXzWxQ" src="//codepen.io/airen/embed/xXzWxQ?height=400&amp;theme-id=0&amp;slug-hash=xXzWxQ&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <h2>添加JavaScript</h2> <p>现在万事都具备了,就欠东风了。为了更好的完善计算器功能,在Vue中<code>methods:{}</code>中的<code>press</code>和<code>changeModeEvent</code>中添加对应的功能代码:</p> <pre><code>export default { name: 'Calculator', data () { return{ current: '', changeMode: true } }, methods: { press: function (event) { let me = this let key = event.target.textContent if ( key != '=' &amp;&amp; key != 'C' &amp;&amp; key != '*' &amp;&amp; key != '/' &amp;&amp; key != '√' &amp;&amp; key != "x ²" &amp;&amp; key != "%" &amp;&amp; key != "&lt;=" &amp;&amp; key != "±" &amp;&amp; key != "sin" &amp;&amp; key != "cos" &amp;&amp; key != "tan" &amp;&amp; key != "log" &amp;&amp; key != "ln" &amp;&amp; key != "x^" &amp;&amp; key != "x !" &amp;&amp; key != "π" &amp;&amp; key != "e" &amp;&amp; key != "rad" &amp;&amp; key != "∘" ) { me.current += key } else if (key === '=') { if ((me.current).indexOf('^') &gt; -1) { let base = (me.current).slice(0, (me.current).indexOf('^')) let exponent = (me.current).slice((me.current).indexOf('^') + 1) me.current = eval('Math.pow(' + base + ',' + exponent + ')') } else { me.current = eval(me.current) } } else if (key === 'C') { me.current = '' } else if (key === '*') { me.current += '*' } else if (key === '/') { me.current += '/' } else if (key === '+') { me.current += '+' } else if (key === '-') { me.current += '-' } else if (key === '±') { if ((me.current).charAt(0) === '-') { me.current = (me.current).slice(1) } else { me.current = '-' + me.current } } else if (key === '&lt;=') { me.current = me.current.substring(0, me.current.length - 1) } else if (key === '%') { me.current = me.current / 100 } else if (key === 'π') { me.current = me.current * Math.PI } else if (key === 'x ²') { me.current = eval(me.current * me.current) } else if (key === '√') { me.current = Math.sqrt(me.current) } else if (key === 'sin') { me.current = Math.sin(me.current) } else if (key === 'cos') { me.current = Math.cos(me.current) } else if (key === 'tan') { me.current = Math.tan(me.current) } else if (key === 'log') { me.current = Math.log10(me.current) } else if (key === 'ln') { me.current = Math.log(me.current) } else if (key === 'x^') { me.current += '^' } else if (key === 'x !') { let number = 1 if (me.current === 0) { me.current = '1' } else if (me.current &lt; 0) { me.current = NaN } else { let number = 1 for (let i = me.current; i &gt; 0; i--) { number *= i } me.current = number } } else if (key === 'e') { me.current = Math.exp(me.current) } else if (key === 'rad') { me.current = me.current * (Math.PI / 180) } else if (key === '∘') { me.current = me.current * (180 / Math.PI) } }, changeModeEvent: function() { let me = this me.changeMode = !me.changeMode } } } </code></pre> <p>整体代码就不做过多阐述了。我想大家一看就能明白其中的意思。当然你也可以把每个功能提取出来,成为一个函数,比如:</p> <pre><code>//our ' C ' button function clear() { app.current = ""; } //our ' &lt;= ' button function backspace() { app.current = app.current.substring(0, app.current.length - 1); } </code></pre> <p>这个时候,你浏览器将看到一个完整的计算器效果:</p> <div style="margin-bottom: 20px;"><iframe id="BwxGdd" src="//codepen.io/airen/embed/BwxGdd?height=400&amp;theme-id=0&amp;slug-hash=BwxGdd&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>体验一下吧!</p> <h2>总结</h2> <p>这篇文章主要以创建一个计算器为例,来学习Vue相关的知识。在这篇文章中我们学习了怎么使用Vue CLI这样的构建工具创建一个Vue项目。又是怎么通过一个单独的文件创建Vue伟德1946手机版,并且将伟德1946手机版调用。同时在完成整个Vue版本的计算器,我们还使用了<code>v-on</code>指令来绑定事件,<code>v-model</code>实现数据双向绑定,<code>v-if</code>控制模板的显示与否等。当然还学习了怎么在<code>methods</code>中创建方法,让其无缝的事件处理和状态更改触发器。</p> <p>通过这个实例,再次感觉到与Vue一起工作带来的优势。而我们这个示例的效果可以在<a href="http://xxysy.com/quot;//codepen.io/airen/full/BwxGdd/">Codepen</a>上看到(采用另外创建计算器的方式),也可以在<" href="http://xxysy.com/quot;//github.com/airen/VueStudy/tree/master/vue-calculator">Github上查看代码</a>。由于作者是Vue的初学者,如果文章中有不对之处,还请各路大婶指正。如果你有更好的实现方案或思路,欢迎在下面的评论中与我们一起分享。</p>" <blockquote> <p><strong>特别声明</strong>:这篇文章中的计算器示例效果是根据<a href="http://xxysy.com/quot;//twitter.com/fullstackmafia">@Raphae" Ugwu</a>的伟德1946网页版中<a href="http://xxysy.com/quot;//scotch.io/tutorials/build-a-scientific-calculator-with-vuejs">案例</a>写的。</p>" </blockquote> <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/build-a-scientific-calculator-with-vuejs.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/build-a-scientific-calculator-with-vuejs.html</a></p> rel="nofollow" </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/640.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/vue"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/tags/643.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue Demo</a></div></div></div> Wed, 11 Oct 2017 13:53:24 +0000 Airen 2290 at http://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 http://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-js-scoped-slots.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>作用域插槽(Scoped Slots)是Vue的一个很有用的特性。可以使伟德1946手机版更加通用和可复用。唯一的问题是他们很难理解!试图让你围绕着整明白父和子作用域的交织关系,就像是解决一个棘手的数学方式程一样。</p> <p>当你理解不了的时候,最好的一个方法就是试着用它来解决问题。在接下来的内容中,这篇文章将向大家演示如何使用作用域插槽来构建可重用的列表伟德1946手机版。</p> <p><img src="/sites/default/files/blogs/2017/1710/scoped_slots_02.png" alt="" /></p> <h2>基本伟德1946手机版</h2> <p>我们将要构建的伟德1946手机版叫做<code>my-list</code>,这个伟德1946手机版的功能就是显示一些列表。其特别之处就是,伟德1946手机版每次自定义使用中如何呈现列表项。</p> <p>让我们先来处理最简单的用例,得到一个<code>my-list</code>伟德1946手机版,只呈现一个列表:一系列的几何形状名称和它们对应的边数。</p> <p>使用<code>Vue.component()</code>注册一个伟德1946手机版。并且我们创建这个伟德1946手机版的时候采用的是<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/seven-ways-to-define-a-component-template-by-vuejs.html"><code>x-template</code>语法</a>方式。如果你在本地创建了Vue的项目,那么你可以在<code>app.js</code>文件中添加下面的代码。(我在Codepen上写这个示例,下面的代码放在JavaScript中):</p>" <pre><code>// app.js Vue.component('my-list',{ template: '#my-list', data () { return { title: 'Shapes', shapes: [ { name: 'Square', sides: 4 }, { name: 'Hexagon', sides: 6 }, { name: 'Triangle', sides: 3 } ] } } }) let app = new Vue({ el: '#app' }) </code></pre> <p>然后在<code>index.html</code>添加对应的模板(Codepen上对应的HTML项):</p> <pre><code>&lt;script id="my-list" type="text/x-template"&gt; &lt;div class="my-list"&gt; &lt;div class="title"&gt;{{ title }}&lt;/div&gt; &lt;div class="list"&gt; &lt;div class="list-item" v-for="shape in shapes"&gt; &lt;div&gt;{{ shape.name }} &lt;small&gt;({{ shape.sides }} sides)&lt;/small&gt;&lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;/script&gt; &lt;div id="app"&gt; &lt;my-list&gt;&lt;/my-list&gt; &lt;/div&gt; </code></pre> <p>添加一些CSS,你将看到这样的效果:</p> <div style="margin-bottom: 20px;"><iframe id="jGzPgK" src="//codepen.io/airen/embed/jGzPgK?height=400&amp;theme-id=0&amp;slug-hash=jGzPgK&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <h2>扩展 <code>my-list</code></h2> <p>现在,我们要使用<code>my-list</code>功能更全面,足以呈现任何类型的列表。我们要写的第二个测试用例将是一个颜色列表,包括一个小的<code>swatch</code>,以显示颜色的外观。</p> <p>要做到这一点,我们必须抽象出<code>data</code>中任何指定的图形列表。由于我们的列表中的项可能有不同的结构,所以我们将给<code>my-list</code>添加一个插槽,这样父类就可以定义如何显示特定的列表。</p> <pre><code>// app.js file Vue.component('my-list',{ template: '#my-list', props: ['title'] }) // index.html &lt;script type="text/x-template" id="my-list"&gt; &lt;div class="my-list"&gt; &lt;div class="title"&gt;{{ title }}&lt;/div&gt; &lt;div class="list"&gt; &lt;slot&gt;&lt;/slot&gt; &lt;/div&gt; &lt;/div&gt; &lt;/script&gt; </code></pre> <p>现在,让我们根据根实例创建<code>my-list</code>伟德1946手机版的两个实例,以显示我们的两个测试用例的列表:</p> <pre><code>// app.js file let app = new Vue({ el: '#app', data () { return { shapes: [ { name: 'Square', sides: 4 }, { name: 'Hexagon', sides: 6 }, { name: 'Triangle', sides: 3 } ], colors: [ { name: 'Yellow', hex: '#f4d03f }, { name: 'Green', hex: '#229954' }, { name: 'Purple', hex: '#9b59b6' } ] } } }) // index.html &lt;div id="app"&gt; &lt;my-list title="Shapes"&gt; &lt;div class="list-item" v-for="shape in shapes"&gt; &lt;div&gt;{{ shape.name }} &lt;small&gt;({{ shape.sides }} sides)&lt;/small&gt;&lt;/div&gt; &lt;/div&gt; &lt;/my-list&gt; &lt;my-list title="Colors"&gt; &lt;div class="list-item" v-for="color in colors"&gt; &lt;div&gt; &lt;div class="swatch" :style="{ background: color.hex }"&gt;&lt;/div&gt; {{ color.name }} &lt;/div&gt; &lt;/div&gt; &lt;/my-list&gt; &lt;/div&gt; </code></pre> <p>最后的效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="zEWvBO" src="//codepen.io/airen/embed/zEWvBO?height=400&amp;theme-id=0&amp;slug-hash=zEWvBO&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <h2>伟德1946手机版外表</h2> <p>前面伟德1946手机版工作得很好,但是代码并不太好。<code>my-list</code>是一个显示列表的伟德1946手机版。蛤我们必须抽象出列表,用来呈现父类的所有逻辑。伟德1946手机版仅用一些标签来包裹列表。</p> <p>考虑到伟德1946手机版声明中仍然有重复的代码,比如<code>&lt;div class="list-item" v-for="shape in shapes"&gt;</code>等。如果我们可以将其委托给伟德1946手机版,那就太好了,这样我们的伟德1946手机版就只仅仅在表面上。</p> <h2>作用域插槽</h2> <p>为了让我们做到这一点,我们将使用作用域插槽而不是常规的插槽。作用插槽允许你将模板传递给插槽,而不是传递一个已呈现的元素。它被称为作用域的插槽,因为尽管模板在父范围内呈现,但它可以访问某些子数据。</p> <p>例如,具有作用域插槽的子伟德1946手机版看起来像下面这样:</p> <pre><code>&lt;div&gt; &lt;slot my-prop="Hello from child"&gt;&lt;/slot&gt; &lt;/div&gt; </code></pre> <p>使用此伟德1946手机版的父节点将在插槽中声明一个模板元素。这个模板元素将拥有一个属性范围,名称是一个别名对象。添加到插槽中的任何<code>props</code>都可以作为另外对象的属性使用。</p> <pre><code>&lt;child&gt; &lt;template scope="props"&gt; &lt;span&gt;Hello from parent&lt;/span&gt; &lt;span&gt;{{ props.my-prop }}&lt;/span&gt; &lt;/template&gt; &lt;/child&gt; </code></pre> <p>渲染出来像这样:</p> <pre><code>&lt;div&gt; &lt;span&gt;Hello from parent&lt;/span&gt; &lt;span&gt;Hello from child&lt;/span&gt; &lt;/div&gt; </code></pre> <h2>在<code>my-list</code>中使用作用域插槽</h2> <p>我们将列表数组作为<code>props</code>传递给<code>my-list</code>。然后我们可以用一个作用域插槽来替换槽。这样,<code>my-list</code>就可以负责迭代列表项,但是父类仍然可以定义每个列表应该如何显示。</p> <pre><code>// index.html &lt;div id="app"&gt; &lt;my-list title="Shapes" :items="shapes"&gt; &lt;!-- 模板写在这 --&gt; &lt;/my-list&gt; &lt;my-list title="Colors" :items="colors"&gt; &lt;!-- 模板写在这 --&gt; &lt;/my-list&gt; &lt;/div&gt; </code></pre> <p>现在,我们得到一个<code>my-list</code>来遍历数组项。在<code>v-for</code>循环中,<code>item</code>是当前列表的别名。我们可以创建一个插槽,并使用<code>v-bind="item"</code>将列表项绑定到插槽中。</p> <pre><code>// app.js file Vue.component('my-list', { template: '#my-list', props: ['title', 'items'] }) // index.html &lt;script type="text/x-template" id="my-list"&gt; &lt;div class="my-list"&gt; &lt;div class="title"&gt;{{ title }}&lt;/div&gt; &lt;div class="list"&gt; &lt;div v-for="item in items"&gt; &lt;slot v-bind="item"&gt;&lt;/slot&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;/script&gt; </code></pre> <blockquote> <p>注意,如果你之前没有使用过任何参数的<code>v-bind</code>,那么这将把整个对象的属性绑定到元素上。这对于作用域插槽非常有用,因为你所绑定的对象通常具有任意的属性,这些属性现在不需要按名称来指定。</p> </blockquote> <p>现在,我们将返回到我们的根实例,并在<code>my-list</code>的插槽中声明一个模板。首先看一下<code>shapes</code>列表,模板必须包含我们指定的别名<code>shape</code>范围属性。这个别名允许我们访问作用域的<code>props</code>。在模板内部,我们可以使用与之前相同的标记来显示我们的<code>shape</code>列表项。</p> <pre><code>&lt;my-list title="Shapes" :items="shapes"&gt; &lt;template scope="shape"&gt; &lt;div&gt;{{ shape.name }} &lt;small&gt;({{ shape.sides }} sides)&lt;/small&gt;&lt;/div&gt; &lt;/template&gt; &lt;/my-list&gt; </code></pre> <p>现在完整的模板如下:</p> <pre><code>&lt;div id="app"&gt; &lt;my-list title="Shapes" :items="shapes"&gt; &lt;template scope="shape"&gt; &lt;div&gt;{{ shape.name }} &lt;small&gt;({{ shape.sides }} sides)&lt;/small&gt;&lt;/div&gt; &lt;/template&gt; &lt;/my-list&gt; &lt;my-list title="Colors" :items="colors"&gt; &lt;template scope="color"&gt; &lt;div&gt; &lt;div class="swatch" :style="{ background: color.hex }"&gt;&lt;/div&gt; {{ color.name }} &lt;/div&gt; &lt;/template&gt; &lt;/my-list&gt; &lt;/div&gt; </code></pre> <h2>总结</h2> <p>尽管这种方法使用的标签和以前一样的多,但它已经将公共功能委托给伟德1946手机版,这使得设计更加健壮。</p> <p>以下是伟德1946手机版的完整的代码:</p> <div style="margin-bottom: 20px;"><iframe id="jGzbzJ" src="//codepen.io/airen/embed/jGzbzJ?height=400&amp;theme-id=0&amp;slug-hash=jGzbzJ&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <blockquote> <p>本文根据<a href="http://xxysy.com/quot;//twitter.com/">@ANTHONYGORE</a>的《<" href="http://xxysy.com/quot;//vuejsdevelopers.com/2017/10/02/vue-js-scoped-slots">Gettin" Your Head Around Vue.js Scoped Slots</a>》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:<a href="//vuejsdevelopers.com/2017/10/02/vue-js-scoped-slots">https://vuejsdevelopers.com/2017/10/02/vue-js-scoped-slots</a>。</p> rel="nofollow" </blockquote> <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-js-scoped-slots.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-js-scoped-slots.html</a></p> rel="nofollow" </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/translations"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">译文</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/vue"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue</a></div></div></div> Sun, 08 Oct 2017 09:43:30 +0000 Airen 2289 at http://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 http://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-template.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>学习Vue 2.0也有一段时间了,从前面的学习过程中,也知道在Vue中使用模板的基础知识。我们知道如何使用字符串插值在Vue中输出数据。其实在Vue的模板中,我们还可以做一些扩展,比如可以在字符串插值语法中使用简单的JavaScript表达式。之所以说简单的JavaScript表达式,是因为只能包含一个表达式,因此,不能使用循环或任何复杂的逻辑。不管怎么说,这样的逻辑不属于我们的模板,在Vue实例中放置一个方法会比较好。这我们后面会深入学习到这方面的知识点。</p> <p>那么现在,我们系统的来学习一下Vue中的模板。</p> <h2>模板语法</h2> <p>Vue使用了基于HTML的模板语法,允许开发者声明式地将DOM绑定至底层Vue实例的数据。所有Vue的模板都是合法的HTML,所以能被遵循规范的浏览器和HTML解析器解析。</p> <p>在底层的实现上,Vue将模板编译成虚拟DOM渲染函数。结合响应系统,在应用状态改变时,Vue能够智能地计算出重橷渲染伟德1946手机版的最小代价并应用到DOM操作上。</p> <p>如果你熟悉虚拟DOM并且偏爱JavaScript的原始力量,你也可以不用模板,直接写渲染函数,使用可选的JSX语法。</p> <p>比如,我们有这样一个简单的例子。假设我们的数据对象<code>data</code>中有一个包含任意数字的<code>age</code>属性。我们可以在Vue的模板中通过<code>{{ }}</code>将<code>age</code>插入进去,这个时候,在页面中就会渲染出<code>age</code>的属性值:</p> <pre><code>&lt;div id="app"&gt; &lt;h1&gt;{{ age }}&lt;/h1&gt; &lt;/div&gt; let app = new Vue({ el: '#app', data () { return { age: 27 } } }) </code></pre> <p>效果如下所示:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-template-1.png" alt="" /></p> <p>这里我们使用了模板中最简单的文本插值方式,也是数据绑定最常见的形式。这种方法常称为<strong>双大括号(Mustache)</strong>语法。Mustache标签将会被替代为对应数据对象上<code>age</code>属性的值。无论何时,绑定的数据对象上<code>age</code>属性发生了改变,插值处的内容都会更新。</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-template-2.gif" alt="" /></p> <p>这种文本插值绑定数据虽然简单,但其也有一点的不足之处,那就是当你的页面渲染慢,或者你的JS失效时。页面会将<code>{{ age }}</code>这样的字符渲染出来,给你的用户造成误解,有种不友好的用户体验。</p> <p>前面提到过,文本插值绑定数据的方式,只要<code>age</code>发生变化,那么页面渲染出来的数据就会发生变化。但也可以通过<code>v-once</code>指令,让文本插值只执行一次,使用了这个指令,当数据改变时,插值处的内容并不会更新。但请留心这会影响到该节点上所有的数据绑定:</p> <pre><code>&lt;div id="app"&gt; &lt;h1&gt;未使用v-once指令:{{ age }}&lt;/h1&gt; &lt;h1 v-once&gt;使用v-once指令:{{ age }}&lt;/h1&gt; &lt;/div&gt; </code></pre> <p>从上面的效果中可以看出,没有添加<code>v-once</code>指令的文本插值会变化,添加了的则不会再有任何变化:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-template-3.gif" alt="" /></p> <p>不管是出于什么原因,我想把这个数字乘以<code>2</code>。在文本插值语法中我们可以在模板内直接添加一个简单的JavaScript表达式来实现:</p> <pre><code>&lt;div id="app"&gt; &lt;h1&gt;{{ age * 2 }}&lt;/h1&gt; &lt;/div&gt; </code></pre> <p><img src="/sites/default/files/blogs/2017/1710/vue-template-4.png" alt="" /></p> <p>这里只是将<code>age</code>属性乘以<code>2</code>,如果运行代码,我们就可以看到期望的数字输出,如上图所示。请记住,我们可以在模板中直接访问<code>age</code>属性,因为Vue代理我们的数据属性,因此不必显式地访问数据对象上的属性。事实上,如果你试着这样做,它就不会起作用了。</p> <p>接着让我们一起看一下如何在模板中使用布尔逻辑。由于只能使用单个表达式,因此不能使用正常的<code>if</code>语句。然而,你可以做的是使用<code>if</code>的简写语法,<strong>三元表达式</strong>。假设我们想根据<code>data</code>中的<code>age</code>值进行判断,超过<code>60</code>输出<code>“你老了”</code>,反之输出<code>“你还年轻”</code>。那么我们可以在模板中这样做:</p> <pre><code>&lt;div id="app"&gt; &lt;h1&gt;{{ age &gt; 60 ? '你老了' : '你还年轻' }}&lt;/h1&gt; &lt;/div&gt; </code></pre> <p>运行上面的代码,你将看到下面这样的结果:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-template-5.png" alt="" /></p> <p>为了验证我们上面的说法是否正确,咱位可以在浏览器的控制台上修改<code>age</code>的值,比如将<code>age</code>的值修改成<code>80</code>,你将看到的效果如下:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-template-6.gif" alt="" /></p> <p>再来看一个表达式的例子。我将在<code>data</code>中添加一个<code>name</code>的属性,并且将我的全名<code>Airen Liao</code>作为<code>name</code>的值。</p> <pre><code>let app = new Vue({ el: '#app', data () { return { age: 27, name: 'Airen Liao' } } }) </code></pre> <p><code>data</code>中<code>name</code>的值包含了我的第一个和最后一个名字,但是我只想在页面上显示我的第一个名字。我能做的就是通过<code>split</code>方法把<code>name</code>用空格分开。</p> <pre><code>&lt;div id="app"&gt; &lt;h1&gt;{{ name.split(' ') }}&lt;/h1&gt; &lt;/div&gt; </code></pre> <p>上面的方法只是把<code>name</code>中的值以空格分隔符将值以数组的形式输出,比如下图所示:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-template-7.png" alt="" /></p> <p>事实上并未得到我的第一名<code>"Airen"</code>。我们在上面的基础上,添加一个数组的索引号<code>0</code>,像这样:</p> <pre><code>&lt;div id="app"&gt; &lt;h1&gt;{{ name.split(' ')[0] }}&lt;/h1&gt; &lt;/div&gt; </code></pre> <p>这样一来,得到期望得的效果:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-template-8.png" alt="" /></p> <p>这只是表达式的另一个例子。你可以用一个JavaScript表达式做很多事情,但要尽量保持简单。如果你需要更杂的逻辑,那么你就不应该尝试在模板中使用,比如嵌套的<code>if</code>语句。另外,如果你需要在模板中多次使用相同的表达式,那么最好也不要将它嵌入到模板内,而更应该选择在Vue实例中使用。可以考虑使用Vue的方法来完成,我们后面会深入的学习这方面的知识。</p> <p>除了使用文本插值<code>{{}}</code>将数据值插入到模板之外,还可以考虑使用<code>v-text</code>和<code>v-html</code>这样的指令来插入数据。有关于<code>v-text</code>和<code>v-html</code>指令在Vue模板中的使用,可以阅读《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/v-text-and-v-html.html">Vu" 2.0学习笔记:<code>v-text</code>和<code>v-html</code></a>》一文。这里不再做过多的阐述。</p> <p>当然很多时候,还想在模板中根据一定的条件进行渲染,这个时候可以考虑使用<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/v-if-vs-v-show.html"><code>v-if</code>或<code>v-show</code></a>这样的指令来帮助大家。另外对于列表性的渲染,使用<" href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/v-for.html"><code>v-for</code></a>能帮我们省下不少的时间。</p>" <p>熟悉React的同学应该知道JSX,其实在Vue中也可以使用JSX。至于JSX是什么,不做过多阐述。</p> <blockquote> <p>JSX就是一种对JavaScript的补充,用来描述伟德1946手机版的UI部分,类似模板语言,但它完整支持JavaScript本身的语法特性。 —— <a href="http://xxysy.com/quot;//facebook.github.io/react/docs/introducing-jsx.html">关于JSX的介绍</a></p>" </blockquote> <p>JSX只是对JavaScript的补充并没有得到浏览器的支持,所以你需要用<a href="http://xxysy.com/quot;//babeljs.io/">Babel</a>搭配<" href="http://xxysy.com/quot;//github.com/vuejs/babel-preset-vue">babel-preset-vue</a>来获得完整的Vu" JSX功能。</p> <p>看一个简单的示例,如果我们使用<code>render</code>函数,我们一般这样写:</p> <pre><code>// script.js file new Vue({ el: '#app', data: { msg: 'Show the message' }, methods: { hello () { alert('Here is the message') } }, render (createElement) { return createElement( 'span', { class: { 'my-class': true }, on: { click: this.hello } }, [ this.msg ] ); }, }); &lt;!-- index.html file --&gt; &lt;div id="app"&gt; &lt;!--span will render here--&gt; &lt;/div&gt; </code></pre> <p>换成JSX之后:</p> <pre><code>// script.js file new Vue({ el: '#app', data: { msg: 'Show the message.' }, methods: { hello () { alert('This is the message.') } }, render(h) { return ( &lt;span class={{ 'my-class': true }} on-click={ this.hello } &gt; { this.msg } &lt;/span&gt; ) } }); &lt;!-- index.html file --&gt; &lt;div id="app"&gt; &lt;!--span will render here--&gt; &lt;/div&gt; </code></pre> <p>有关于这方面的详细介绍,这里就不做过多的阐述,如果你对这方面东西感兴趣,可以阅读下面这些文章:</p> <ul> <li><a href="http://xxysy.com/quot;//vuejs.org/v2/guide/render-function.html">Rende" Functions &amp; JSX</a></li> <li><a href="http://xxysy.com/quot;//medium.com/js-dojo/whats-new-in-vue-js-2-0-beyond-templates-with-jsx-4b8cda05f95f">What’" New in Vue.js 2.0 - Beyond Templates With JSX</a></li> <li><a href="http://xxysy.com/quot;//medium.com/js-dojo/using-jsx-with-vue-js-846f4fbbf07f">Usin" JSX with Vue.js</a></li> <li><a href="http://xxysy.com/quot;//alligator.io/vuejs/jsx-render-functions/">Writin" Vue.js Render Functions in JSX</a></li> <li><a href="http://xxysy.com/quot;//egoist.moe/2017/09/21/vue-jsx-full-guide/">Vu" JSX 使用指南</a></li> <li><a href="http://xxysy.com/quot;//www.alloyteam.com/2017/07/12918/">用JSX写Vue伟德1946手机版</a></li>" </ul> <h2>模板渲染</h2> <p>Vue 2.0的模板渲染借鉴了React的<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/blog/tags/632.html">Virtua" DOM</a>。并且基于Virtual DOM,它还可以支持服务端渲染(<a href="http://xxysy.com/quot;//ssr.vuejs.org/en/">SSR</a>),也支持JSX语法。</p>" <p>在了解Vue的模板渲染方面的知识前,先上一张图:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-template-9.jpg" alt="" /></p> <p>从这张图中,我们可以初步看到一个Vue的应用是如何运行起来的,模板通过编译生成AST,再由AST生成Vue的渲染函数,渲染函数结合数据生成Virtual DOM树,对Virtual DOM进行<code>diff</code>和<code>patch</code>后生成新的UI。</p> <p>我们要对一些相关的知识有所了解:</p> <ul> <li>Vue的模板</li> <li>AST数据结构</li> <li>VNode数据结构</li> <li>Virtual DOM</li> <li><code>createElement</code>函数</li> <li><code>render</code>函数</li> <li>观察者(Watcher)</li> </ul> <h3>Vue的模板</h3> <p>前面提到过,Vue的模板基于纯HTML,基于Vue的模板语法,我们可以比较方便地声明数据和UI的关系</p> <h3>AST 数据结构</h3> <p><strong>AST是Abstract Syntax Tree的简写,俗称抽象语法树</strong>,是源代码的抽象语法结构的树状表现形式,计算机学科中编译原理的概念。而Vue就是将模板代码映射为AST数据结构,进行语法解析。</p> <p>Vue使用了HTML Parser将HTML模板解析为AST,并且对AST进行一些优化的标记处理,提取最大的静态树,方便Virtual Dom时直接跳过<code>diff</code>。</p> <h3>VNode</h3> <p><code>VNode</code>可以理解为Vue的虚拟DOM的基类,通过<code>new</code>实例化的<code>VNode</code>大致可以分为:</p> <ul> <li><code>EmptyVNode</code>: 没有内容的注释节点</li> <li><code>TextVNode</code>: 文本节点</li> <li><code>ElementVNode</code>: 普通元素节点</li> <li><code>ComponentVNode</code>: 伟德1946手机版节点</li> <li><code>CloneVNode</code>: 克隆节点,可以是以上任意类型的节点,唯一的区别在于<code>isCloned</code>属性为<code>true</code></li> </ul> <p>一个<code>VNode</code>的实例对象包含了以下属性:</p> <ul> <li><code>tag</code>: 当前节点的标签名</li> <li><code>data</code>: 当前节点的数据对象</li> <li><code>children</code>: 数组类型,包含了当前节点的子节点</li> <li><code>text</code>: 当前节点的文本,一般文本节点或注释节点会有该属性</li> <li><code>elm</code>: 当前虚拟节点对应的真实的DOM节点</li> <li><code>ns</code>: 节点的<code>namespace</code></li> <li><code>context</code>: 编译作用域</li> <li><code>functionalContext</code>: 函数化伟德1946手机版的作用域</li> <li><code>key</code>: 节点的<code>key</code>属性,用于作为节点的标识,有利于<code>patch</code>的优化</li> <li><code>componentOptions</code>: 创建伟德1946手机版实例时会用到的选项信息</li> <li><code>child</code>: 当前节点对应的伟德1946手机版实例</li> <li><code>parent</code>: 伟德1946手机版的占位节点</li> <li><code>raw</code>: Raw HTML</li> <li><code>isStatic</code>: 静态节点的标识</li> <li><code>isRootInsert</code>: 是否作为根节点插入,被<code>&lt;transition&gt;</code>包裹的节点,该属性的值为<code>false</code></li> <li><code>isComment</code>: 当前节点是否是注释节点</li> <li><code>isCloned</code>: 当前节点是否为克隆节点</li> <li><code>isOnce</code>: 当前节点是否有<code>v-once</code>指令</li> </ul> <p>下面是 Vue 2.0 源码中 <a href="http://xxysy.com/quot;//github.com/vuejs/vue/blob/v2.1.10/src/core/vdom/vnode.js#L23-L50">VNod" 数据结构</a> 的定义</p> <pre><code>constructor { this.tag = tag //元素标签 this.data = data //属性 this.children = children //子元素列表 this.text = text this.elm = elm //对应的真实 DOM 元素 this.ns = undefined this.context = context this.functionalContext = undefined this.key = data &amp;&amp; data.key this.componentOptions = componentOptions this.componentInstance = undefined this.parent = undefined this.raw = false this.isStatic = false //是否被标记为静态节点 this.isRootInsert = true this.isComment = false this.isCloned = false this.isOnce = false } </code></pre> <h3>Virtual DOM</h3> <p>Virtual DOM树,Vue的Virtual DOM Patching算法是基于<strong><a href="http://xxysy.com/quot;://github.com/snabbdom/snabbdom">snabbdom</a></strong>实现的,并在此基础上作了很多的调整和改进。那么我们有真实的DOM,为什么要使用Virtua" DOM。其中最大的原因就是<strong><code>document.createElement</code>这个方法创建的真实DOM元素会带来性能上的损失</strong>。而<code>VNode</code>就是简化版的真实DOM元素,关联着真实的DOM,比如属性<code>elm</code>,只包括我们需要的属性,并新增了一些在<code>diff</code>过程中需要使用的属性,例如<code>isStatic</code>。</p> <h3><code>createElement</code>函数</h3> <p><a href="http://xxysy.com/quot;//cn.vuejs.org/v2/guide/render-function.html"><code>createElement</code>函数</a>也经常被叫做<code>h</code>函数,它被用来创建一个<" href="http://xxysy.com/quot;//github.com/vuejs/vue/blob/dev/src/core/vdom/vnode.js"><code>VNode</code></a>(虚拟DOM节点)。可以通过<code>this.$createElement</code>访问它但同时它也是<code>render</code>函数的第一个参数。</p>" <h3><code>render</code>函数</h3> <p>这个函数是通过编译模板文件得到的,其运行结果是VNode。<code>render</code>函数与JSX类似,Vue 2.0中除了Template也支持JSX的写法。大家可以使用<a href="http://xxysy.com/quot;//cn.vuejs.org/v2/api/?#Vue-compile"><code>Vue.compile(template)</code></a>方法编译下面这段模板。</p>" <pre><code>&lt;div id="app"&gt; &lt;header&gt; &lt;h1&gt;I am a template!&lt;/h1&gt; &lt;/header&gt; &lt;p v-if="message"&gt; {{ message }} &lt;/p&gt; &lt;p v-else&gt; No message. &lt;/p&gt; &lt;/div&gt; </code></pre> <p>方法会返回一个对象,对象中有 <code>render</code> 和 <code>staticRenderFns</code> 两个值。看一下生成的 <code>render</code>函数:</p> <pre><code>(function() { with(this){ return _c( // 创建一个 div 元素 'div', { attrs:{"id":"app"} //div 添加属性 id }, [ // 静态节点 header,此处对应 staticRenderFns 数组索引为 0 的 render 函数 _m(0), // 空的文本节点 _v(" "), // 三元表达式,判断 message 是否存在 // 如果存在,创建 p 元素,元素里面有文本,值为 toString(message) // 如果不存在,创建 p 元素,元素里面有文本,值为 No message. (message) ? _c('p',[_v("\n "+_s(message)+"\n ")]) : _c('p',[_v("\n No message.\n ")]) ] ) } }) </code></pre> <p>要看懂上面的 <code>render</code>函数,只需要了解 <code>_c</code>,<code>_m</code>,<code>_v</code>,<code>_s</code> 这几个函数的定义,其中:</p> <ul> <li><code>_c</code> 是 <code>createElement</code>(创建元素)</li> <li><code>_m</code> 是 <code>renderStatic</code>(渲染静态节点)</li> <li><code>_v</code> 是 <code>createTextVNode</code>(创建文本DOM)</li> <li><code>_s</code> 是 <code>toString</code> (转换为字符串)</li> </ul> <p>除了 <code>render</code> 函数,还有一个 <code>staticRenderFns</code> 数组,这个数组中的函数与 VDOM 中的 <code>diff</code> 算法优化相关,我们会在编译阶段给后面不会发生变化的 VNode 节点打上 <code>static</code> 为 <code>true</code> 的标签,那些被标记为静态节点的 VNode 就会单独生成 <code>staticRenderFns</code> 函数:</p> <pre><code>// 上面 render 函数 中的 _m(0) 会调用这个方法 (function() { with(this){ return _c('header',[_c('h1',[_v("I'm a template!")])]) } }) </code></pre> <p>其实<code>render</code>函数是用来生成Virtual DOM的。Vue推荐使用模板来构建我们的应用界面,在底层实现中, Vue会将模板编译成渲染函数,当然我们也可以不写模板,直接写渲染函数,以获得更好的控制。</p> <h3>观察者 (Watcher)</h3> <p>每个Vue伟德1946手机版都有一个对应的Watcher,这个Watcher将会在伟德1946手机版<code>render</code>的时候收集伟德1946手机版所依赖的数据,并在依赖有更新的时候,触发伟德1946手机版重新渲染。我们根本不需要写<code>shouldComponentUpdate</code>,Vue就会自动优化并更新需要更新的UI</p> <p>上图中,咱们可以以<code>render</code>函数作为一道分割线,<code>render</code>函数左边可以称之为<strong>编译期</strong>,将Vue的模板转换为渲染函数。<code>render</code>函数的右边是Vue的运行时,主要是基于渲染函数生成Virtual DOM树,然后对Virtual Dom树进行<code>diff</code>和<code>patch</code>。</p> <p>接下来再上一张Vue模板渲染过程的图:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-template-10.png" alt="" /></p> <p>Vue模板的渲染主要经历以下几个过程:</p> <ul> <li><code>new Vue()</code>:实例化Vue</li> <li><code>$mount()</code>: 获取模板,并且在这过程中通过调用相关方法<code>_count</code>(<code>new Watcher()</code>实现数据响应式,当Watcher监听到数据变化,就会执行<code>render</code>函数输出一个新的 VNode 树形结构的数据(VNode对象即Virtual DOM)</li> <li><code>compileToFunction()</code>: 将 <code>template</code> 编译成 <code>render</code> 函数。首先读缓存(在<code>compileToFunction()</code>中,会创建一个对象,把<code>complice</code>编译完后的对象的<code>render</code> 和 <code>staticRenderFns</code> 两个属性分别转换成函数缓存在对象中,然后把对象存进缓存,没有缓存就调用 <code>compile</code> 方法拿到 <code>render</code> 函数的字符串形式,在通过<code>new Function</code> 的方式生成真正的渲染函数</li> <li><code>compile</code>:将 <code>template</code> 编译成 <code>render</code> 函数的字符串形式,这个函数主要有三个步骤组成:<code>parse</code>,<code>optimize</code> 和 <code>generate</code>,最终输出一个包含 <code>ast</code>,<code>render</code> 和 <code>staticRenderFns</code>的对象。<code>compile</code> 函数主要是将 <code>template</code> 转换为 AST,优化 AST,再将 AST 转换为 <code>render</code>函数字符串,<code>render</code> 函数与数据通过 Watcher 产生关联。</li> <li><code>update()</code>:<code>update</code>判断是否首次渲染,是则直接创建真实DOM,否则调用<code>patch()</code>,并且进行触发钩子和更新引用等其他操作</li> <li><code>patch()</code>:新旧 VNode 对比的 <code>diff</code> 函数,对两个树结构进行完整的<code>diff</code>和<code>patch</code>的过程,最终只有发生了变化的节点才会被更新到真实 DOM 树上。</li> <li><code>destroy()</code>:完全销毁一个实例。清理它与其它实例的连接,解绑它的全部指令及事件监听器。触发 <code>beforeDestroy</code> 和 <code>destroyed</code> 的钩子。在大多数场景中你不应该调用这个方法。最好使用 <code>v-if</code> 和 <code>v-for</code> 指令以数据驱动的方式控制子伟德1946手机版的生命周期。</li> </ul> <p>有关于Vue模板的渲染,我也是看得云里来,雾里去。不过不要紧,对于初学者,咱们能整明白怎么使用Vue的模板,就行了。如果你想深入了解底层的渲染原理,可以阅读下面几篇文章:</p> <ul> <li><a href="http://xxysy.com/quot;//zhuanlan.zhihu.com/p/24168649">Vue.j" 2.0 的基本概念</a></li> <li><a href="http://xxysy.com/quot;//xujianbin.pw/project/2017/08/06/Vue-templateRender/">Vue源码:模板渲染</a></li>" <li><a href="http://xxysy.com/quot;//github.com/zoro-web/blog/issues/2">深入vue2.0底层思想:模板渲染</a></li>" </ul> <h2>总结</h2> <p>这篇文章从Vue模板使用入手,了解怎么在Vue中使用模板,然后一起学习了Vue模板渲染的相关知识。如果你和我一样是Vue的初学者,不必太过纠结是否能整明白模板的渲染的原理,我们首要的条件就是学会怎么在Vue中使用模板,得到我们想要的Web运用。</p> <p>如果你在这方面有更多的经验,欢迎在下面的评论中与我们一起分享,如果文章有不对之处,还请各路大婶拍正。</p> <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-template.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-template.html</a></p> rel="nofollow" </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/640.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/vue"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/vue/vue2"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue 2.0学习笔记</a></div></div></div> Sun, 08 Oct 2017 07:42:15 +0000 Airen 2288 at http://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 http://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-computed.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><blockquote> <p>今天在学习Vue 2.0中的<strong>计算属性</strong>。发现@混元霹雳手 老师整理的一篇笔记《<a href="http://xxysy.com/quot;//juejin.im/post/58d8806bac502e0058d778a1">史上最详" VUE2.0 全套 Demo 讲解 基础3(计算属性)</a>》。看后感觉受益非浅。特意把自己根据老师的笔记一路学习下来。感兴趣的同学,也可以一起来玩。</p> </blockquote> <p>Vue中的计算属性是所有属性的计算,而这些计算都是变向的在过滤值,通过数据的不断变化计算出来不同的值和操作不同的方法. 而在Vue中,会使用到计算属性的场景常见的有:</p> <ul> <li>模板内的表达式</li> <li>属性<code>v-bind</code>里可以进行的表达式</li> <li>指令中可以进行的表达式</li> </ul> <p>以上三者的主要优势是<strong>简洁</strong>。如果只是一个小操作,比如说一些简单的数值<code>++</code>,字符拼接,三元表达式,那么使用相当方便。当然,以上方式也有自己的劣势。<strong>一旦要处理的逻辑复杂</strong>,代码量就会变得大得多,而且难于维护。比如说用到<code>if</code>语句来控制流程。那么这个时候可能会想到用<code>filter</code>,那么<code>filter</code>场景适用于哪里,我们后面再聊,咱们先来看一个简单的示例。</p> <pre><code>&lt;div id="app"&gt; &lt;button @click="count++"&gt;{{count + '分'}}&lt;/button&gt; &lt;div&gt; &lt;input v-model="message" /&gt; &lt;/div&gt; &lt;p&gt;{{ message.split(' ').reverse().join(' ') }}&lt;/p&gt; &lt;/div&gt; let app = new Vue({ el: '#app', data () { return { count: 0, message: '' } } }) </code></pre> <p>效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="wryNWo" src="//codepen.io/airen/embed/wryNWo?height=400&amp;theme-id=0&amp;slug-hash=wryNWo&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>从上面的示例中我们可以看出:</p> <ul> <li>我们在模板内使用字符串拼接,<code>{{count + '分'}}</code></li> <li>通过<code>v-bind</code>指定绑定了一个<code>click</code>事件,它只做了一件事情,就是<code>count++</code>,<code>button</code>每点击一次,<code>count</code>值增加<code>1</code>,注意,这里并没有使用<code>methods</code></li> <li><code>input</code>通过<code>v-model</code>做了数据双向绑定,绑定了<code>message</code>,并且在<code>p</code>标签中对<code>message</code>字符串进行反转。</li> </ul> <p>在<code>p</code>标签中对<code>message</code>进行计算转换的时候,是不是觉得语义不是很强烈,那么用什么办法更好呢?这就需要我们使用到前面提到的<strong><code>filter</code></strong>。</p> <h2>使用 <code>filter</code></h2> <p>我们可以使用<code>filter</code>来修改前面的示例。事实下,在Vue中使用<code>filter</code>具有自己的优势,也具有自己的劣势:</p> <ul> <li><strong>优势</strong>:<code>filter</code>给我们用于计算和过滤一些模板表达式和<code>v-bind</code>属性表达式一些弊端的地方进行计算,他们会返回当前计算的值,可以进行传参在多地方共用这个过滤方法</li> <li><strong>劣势</strong>:如果我们要计算多个数据不同变化结合而成的地方,那么<code>filter</code>就比较难过滤到了,本质上<code>filter</code>就是一个一对一的行为,对单个数据进行过滤,可以进行传参,同方法,但不同参</li> </ul> <p>把上面的示例,用<code>filter</code>修改之后就像下面这样:</p> <pre><code>&lt;div id="app"&gt; &lt;button @click="count++"&gt;{{count + '分'}}&lt;/button&gt; &lt;div&gt; &lt;input v-model="message" /&gt; &lt;/div&gt; &lt;p&gt;{{ message | reverseString }}&lt;/p&gt; &lt;/div&gt; let app = new Vue({ el: '#app', data () { return { count: 0, message: '' } }, filters: { reverseString (value) { if (!value) return '' value = value.split('').reverse().join('') return value } } }) </code></pre> <div style="margin-bottom: 20px;"><iframe id="dVdaxM" src="//codepen.io/airen/embed/dVdaxM?height=400&amp;theme-id=0&amp;slug-hash=dVdaxM&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>在这个示例中,我们使用<code>filter</code>来实现,很明显代码量多了那么一点点,但整体的语意化就变得相当明显了,让人一看这里就要进行一些过滤计算,看到<code>reverseString</code>就知道是字符串反转。</p> <h2>computed</h2> <p>前面说了这么多,其实我们都是为了给<code>computed</code>的应用场景做一个铺垫。那问题又来了,<code>computed</code>可以做些什么?又能应用于什么场景呢?</p> <p>Vue中的<code>computed</code>其实规避了模板语法和<code>filter</code>两个所有的劣势,他的优势在于通过计算所有依赖的数据进行计算,然后返回一个值,记住<strong>可以依赖方法里所有的数据,只要一个数据发生变化,则会重新计算,来更新视图的改变</strong>。是不是很意思,迫切的想知道它是怎么玩。</p> <p>咱们还是拿使用场景来说事吧。先给大家演示一个简单实用的应用场景,后面再做一个更好玩一点的应用场景。</p> <p>大家是否还记得,我们在玩微博的时候,发微博会有一个字数限制,比如说只限输入<code>140</code>个字符。为了让用户体验更好,在文本域中输入内容的时候,同时有一个提示信息,告诉用户你还能输入多少字符。那么使用Vue来做这样的事情就会显得容易的多。比如下面这个示例:</p> <pre><code>&lt;div id="app"&gt; &lt;div class="twitter"&gt; &lt;img :src="imgUrl" /&gt; &lt;div class="content"&gt; &lt;textarea v-model="content" :maxlength="totalcount"&gt;有什么新鲜事情?&lt;/textarea&gt; &lt;p&gt;您还可以输入{{ reduceCount }}字&lt;/p&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; let app = new Vue({ el: '#app', data () { return { imgUrl: '//pbs.twimg.com/profile_images/468783022687256577/eKHcWEIk_normal.jpeg', totalcount: 140, // 总共只给输入140字 content: '' } }, computed: { reduceCount () { return this.totalcount - this.content.length } } }) </code></pre> <p>效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="jGZJqe" src="//codepen.io/airen/embed/jGZJqe?height=400&amp;theme-id=0&amp;slug-hash=jGZJqe&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>你可以尝试在文本域中输入内容,你将体验的效果类似下图一样:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-computed-2.gif" alt="" /></p> <p>在<code>computed</code>创建了一个<code>reduceCount</code>,一直在监听文字的字符长度,来再次进行计算,返回值给视图,让视图进行变化。这也是一个很简单的示例。前面也提到过,我们可以监听多个数据,只要一个数据变了,整个方法就会重新计算,然后反馈到视图,这个方法只是一个简单的应用。咱们再来看一个示例,这样会更好的帮助我们理解。</p> <p>这个示例是一个足球比赛记分的示例。简单的对示例进行分析:</p> <ul> <li>比赛时间,用<code>time</code>来维护</li> <li>比赛双方的进球数,用对象<code>team</code>来维护</li> <li>比赛的播报情况,在90分钟内,要显示中国领先或者韩国领先或者双方僵持,如果到了90分钟我们要显示中国队赢还是韩国队赢,还是平局</li> </ul> <p>第三个数据相对而言比较复杂,也是比较关键的数据。那么我们用什么方式来维护,可以说比赛情况是多样化的,用一个数据去定死,这样不符合我们的场景。那么我们先列出将会改变的地方:</p> <ul> <li>我们需要检测双方的进球数</li> <li>通过时间来比对,确定比赛是否结果,然后显示对应的方案</li> </ul> <p>这样我们就要不断的监听两个维护的数据,一是比赛时间,二是比赛两队进球数。</p> <pre><code>&lt;div id="app"&gt; &lt;h1&gt;比赛时间:{{ time }}s&lt;/h1&gt; &lt;h2&gt;直播播报:{{ result }}&lt;/h2&gt; &lt;div class="team"&gt; &lt;div&gt; &lt;span&gt;中国队进球数:{{ team.china }}&lt;/span&gt; &lt;button @click="team.china++"&gt;点击中国队进一球&lt;/button&gt; &lt;/div&gt; &lt;div&gt; &lt;span&gt;韩国队进球数:{{ team.korea }}&lt;/span&gt; &lt;button @click="team.korea++"&gt;点击韩国队进一球&lt;/button&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; let app = new Vue({ el: '#app', data () { return { time: 0, team: { china: 0, korea: 0 } } }, created () { let time = setInterval(() =&gt; { this.time++ if (this.time == 90) { clearInterval(time) } }, 1000) }, computed: { result () { if (this.time &lt; 90) { if (this.team.china &gt; this.team.korea) { return '中国队领先' } else if (this.team.china &lt; this.team.korea) { return '韩国领先' } else { return '双方僵持' } } else { if (this.team.china &gt; this.team.korea) { return '中国队赢' } else if (this.team.china &lt; this.team.korea) { return '韩国队赢' } else { return '平局' } } } } }) </code></pre> <p>看到的效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="WZMmyP" src="//codepen.io/airen/embed/WZMmyP?height=400&amp;theme-id=0&amp;slug-hash=WZMmyP&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <blockquote> <p><strong>注:</strong>这里时间90分钟是一个写死的时间值。如果要让Demo更为完美,这个时间我们可以写一个90分钟的倒计时效果。如果你感兴趣的话,可以自己动手修改上面的Demo,然后在下面的评论中与我们一起分享。</p> </blockquote> <p>这个示例中,用了点击事件来进行双方进球数,这个Demo帮助我们能能更充分的理解Vue中的<code>computed</code>的含义。说到底是观察一个或多个数据,每当其中一个数据改变的时候,这个函数就会重新计算,还有就是通过观察所有数据来维护一个状态,就是所谓的返回一个状态值。从上面这个Demo,我们就可以很容易的知道<code>computed</code>到底用在什么场景,如何去维护返回一个多状态的场景。</p> <h2>methods vs computed</h2> <p>在Vue中,使用<code>methods</code>可以做<code>computed</code>同样的事情,不同的是,<code>computed</code>可以进行缓存。什么意思呢?就是在上个例子中我们对比赛时间和两个球队的进球数进行了检测数据。如果随着时间的改变,但是球数没动,对于<code>computed</code>来说只会重新计算这个球数,进入缓存,而不会再次计算,而重新计算的是这个时间,而且页面的DOM更新也会触发<code>methods</code>来重新计算属性。所以,如果不想让计算属性进入缓存,请使用<code>methods</code>,但我个人更推荐使用<code>computed</code>,语义化会更好一点。毕竟是什么选项里就应该做什么事,<code>methods</code>里面就是应该来管事件的。个人认为,同样的操作我就不演示了,官方的示例对此阐述的也非常明了。</p> <h2>computed vs watch</h2> <p><code>computed</code>和<code>watch</code>都可以做同一件事,就像跑步运动员都可以跑步,但是分100米和1000米,术业有专攻嘛,两个选项都是对数据进行时时监听,但是两个的适用场景就不一样了:</p> <ul> <li><code>computed</code>前面说了是适用于对多数据变动进行监听,然后来维护一个状态,就是返回一个状态</li> <li><code>wacth</code>是对一个数据监听,在数据变化时,会返回两个值,一个是<code>value</code>(当前值),二是<code>oldvalue</code>是变化前的值</li> </ul> <p>我们可以通过这些变化也可以去维护一个状态,但是不符合场景。那么<code>watch</code>主要用于什么地方呢?其主要<strong>用于监听一个数据来进行复杂的逻辑操作</strong>。</p> <pre><code>&lt;div id="app"&gt; &lt;h1&gt;比赛时间:{{ time }}s&lt;/h1&gt; &lt;h2&gt;直播播报:{{ result }}&lt;/h2&gt; &lt;div class="team"&gt; &lt;div&gt; &lt;span&gt;中国队进球数:{{ team.china }}&lt;/span&gt; &lt;button @click="team.china++"&gt;点击中国队进一球&lt;/button&gt; &lt;/div&gt; &lt;div&gt; &lt;span&gt;韩国队进球数:{{ team.korea }}&lt;/span&gt; &lt;button @click="team.korea++"&gt;点击韩国队进一球&lt;/button&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; let app = new Vue({ el: '#app', data () { return { time: 0, team: { china: 0, korea: 0 }, result: '双方僵持' } }, created () { let time = setInterval(() =&gt; { this.time++ if (this.time == 90) { clearInterval(time) } }, 1000) }, wacth: { time (value, oldval) { if (value &lt; 90) { if (this.team.china &gt; this.team.korea) { this.result = '中国队领先' } else if (this.team.china &lt; this.team.korea) { this.result = '韩国队领先' } else { this.result = '双方僵持' } } else { if (this.team.china &gt; this.team.korea) { this.result = '中国队赢' } else if (this.team.chian &lt; this.team.korea) { this.result = '韩国队赢' } else { this.result = '平局' } } }, team (value, oldval) { if (this.time &lt; 90) { if (value.china &gt; value.korea) { this.result = '中国队领先' } else if (value.china &lt; value.korea) { this.result = '韩国队领先' } else { this.result = '双方僵持' } } else { if (value.china &gt; value.korea) { this.result = '中国队赢' } else if(value.chian &lt; value.korea) { this.result = '韩国队赢' } else { this.result = '平局' } } } } }) </code></pre> <div style="margin-bottom: 20px;"><iframe id="rGJbeW" src="//codepen.io/airen/embed/rGJbeW?height=400&amp;theme-id=0&amp;slug-hash=rGJbeW&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>以上代码和<code>computed</code>产生的效果是一模一样,但是很明显,就像我对<code>computed</code>和<code>watch</code>阐述过了应用场景,这个场景只是维护了一个比赛状态,而不牵扯到逻辑操作。虽然也能完成,但无论从代码量的比对还是可读性,还是可维护性的都不胜于<code>computed</code>。但说到底谁更强大呢?我还是老实说<strong><code>watch</code>更强大</strong>,哪里有然他有场景的局限性,但是他可以做牵扯到计算属性的一切操作,缺点是<code>watch</code>只能一个一个监听。</p> <h2><code>watch</code>应用场景</h2> <p>我相信图片预加载大家肯定都有接触过,当图片量大的时候,为了保证页面图片都加载出来的时候,才渲染页面,再进行一些 Ajax请求,或者逻辑操作。那些时你用<code>computed</code>对这种监听一个数据然后进行一系列逻辑操作和Ajax请求,那<code>watch</code>再适合不过了,如果用<code>computed</code>的话,那是无法实现的。</p> <pre><code>&lt;template&gt; &lt;div v-show=show&gt; &lt;img src="https://img.alicdn.com/simba/img/TB14sYVQXXXXXc1XXXXSutbFXXX.jpg" alt=""&gt; &lt;img src="//img.alicdn.com/tfs/TB1iZ6EQXXXXXcsXFXXXXXXXXXX-520-280.jpg_q90_.webp" alt=""&gt; &lt;img src="https://img.alicdn.com/simba/img/TB1C0dOPXXXXXarapXXSutbFXXX.jpg" alt=""&gt; &lt;img src="//img.alicdn.com/tfs/TB1iZ6EQXXXXXcsXFXXXXXXXXXX-520-280.jpg_q90_.webp" alt=""&gt; &lt;/div&gt; &lt;/template&gt; &lt;script&gt; export default { mounted () { var _this = this let imgs = document.querySelectorAll('img') console.log(imgs) Array.from(imgs).forEach((item)=&gt;{ let img = new Image() img.onload = ()=&gt;{ this.count++ } img.src=item.getAttribute('src') }) }, data () { return { count : 0, show : false } }, watch : { count (val,oldval) { if(val == 4){ this.show = true alert("加载完毕") //然后可以对后台发送一些ajax操作 } } } } &lt;/script&gt; </code></pre> <p>我们可以发现四张图片都加载完毕的时候,页面才渲染出来。</p> <p>Vue官方有一句话说得很重要:</p> <blockquote> <p>虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的watcher。这是为什么Vue提供一个更通用的方法,使用<code>wacth</code>来响应数据的变化。当你想要在数据变化响应时,执行异步操作或开销较大的操作,这是很有用的。</p> </blockquote> <p>基于这个描述,我对<code>computed</code>和<code>watch</code>的总结:</p> <ul> <li><code>computed</code>:监听多个数据或者一个数据来维护返回一个状态值,只要其中一个或多个数据发生了变化,则会重新计算整个函数体,重新返回状态值</li> <li><code>watch</code>:只能一个一个监听数据,只要这个数据发生变化,就会返回两个参数,第一个是当前的值,第二个是变化前的值。每当变化的时候,则会触发函数体的逻辑行为,根据逻辑行为做后续的操作</li> </ul> <p>其实,<code>computed</code>、<code>watch</code>这几个都不是有多难,如果从表层上来说都很易理解,但从深层面上看,很多时候还是会存在问题。比如说会滥用,混用。这篇文章通过一些示例来讲解Vue的计算属性,并且对其做了一定的分析。我想这些对学习Vue的初级人员或许会有一些帮助。</p> <p>最后再次感谢@混元霹雳手 老师给我们带来这么好的伟德1946网页版。</p> <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-computed.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-computed.html</a></p> rel="nofollow" </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/640.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/vue"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue</a></div></div></div> Sat, 07 Oct 2017 17:51:14 +0000 Airen 2287 at http://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 http://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-computed-intro.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>Vue中的<code>computed</code>属性称为<strong>计算属性</strong>。在这一节中,我们学习Vue中的计算属性如何使用?记得在学习Vue的模板相关的知识的时候,知道在模板内可以使用表达式,而且模板内的表达式是非常的便利,但这种遍历是有一定的限制的,它们实际上是用于一些简单的运算。也就是说,如果在模板中放入太多的逻辑会让模板过重而且难以维护。咱们先来看一个示例:</p> <pre><code>&lt;div id="app"&gt; &lt;h1&gt;{{ message.split('').reverse().join('') }}&lt;/h1&gt; &lt;/div&gt; </code></pre> <p>在这个示例中,模板不再简单和清晰。你必须看一段时间才能意识到,这里是想要显示变量<code>message</code>的翻转字符串。当你想要在模板中多次引用此处的翻转字符串时,就会更加难以处理。</p> <p>这就是对于任何复杂逻辑,你都应当使用<strong>计算属性</strong>的原因。接下来咱们一起来学习Vue中的计算属性。</p> <blockquote> <p><strong>计算属性</strong>可用于快速计算视图(<strong>View</strong>)中显示的属性。这些计算将被缓存,并且只在需要时更新。</p> </blockquote> <p>在Vue中有多种方法为视图设置值:</p> <ul> <li>使用指令直接将数据值绑定到视图</li> <li>使用简单的表达式对内容进行简单的转换</li> <li>使用过滤器对内容进行简单的转换</li> </ul> <p>除此之外,我们还可以使用计算属性根据数据模型中的值或一组值来计算显示值。</p> <h2>计算属性</h2> <p>计算属性允许我们对指定的视图,复杂的值计算。这些值将绑定到依赖项值,只在需要时更新。</p> <p>例如,我们可以在数据模型中有一个<code>results</code>数组:</p> <pre><code>data () { return { results: [ { name: 'English', marks: 70 }, { name: 'Math', marks: 80 }, { name: 'History', marks: 90 } ] } } </code></pre> <p>假设我们想要查看所有主题的总数。我们不能使用<code>filters</code>或<code>expressions</code>来完成这个任务。</p> <ul> <li><strong><code>filters</code></strong>:用于简单的数据格式,在应用程序的多个位置都需要它</li> <li><strong><code>expressions</code></strong>:不允许使用流操作或其他复杂的逻辑。他们应该保持简单</li> </ul> <p>这个时候,计算属性就可以派上用场。我们可以向模型中添加一个计算值,如下:</p> <pre><code>computed: { totalMarks: function () { let total = 0 let me = this for (let i = 0; i &lt; me.results.length; i++) { total += parseInt(me.results[i].marks) } return total } } </code></pre> <p><code>totalMarks</code>计算属笥使用数组<code>resultes</code>的<code>marks</code>计算出总值。它只是循环遍历值并返回子总数。</p> <p>然后,我们可以在视图中显示计算值:</p> <pre><code>&lt;div id="app"&gt; &lt;div v-for="subject in results"&gt; &lt;input v-model="subject.marks"&gt; &lt;span&gt;Marks for {{ subject.name }}: {{ subject.marks }}&lt;/span&gt; &lt;/div&gt; &lt;div&gt; Total marks are: {{ totalMarks }} &lt;/div&gt; &lt;/div&gt; </code></pre> <p>效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="dVdQyX" src="//codepen.io/airen/embed/dVdQyX?height=400&amp;theme-id=0&amp;slug-hash=dVdQyX&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <h2>计算属性 vs 方法</h2> <p>我们可以使用Vue中的<code>method</code>计算出学科的总分,最终得到的总数结果是相同的。</p> <p>在上例的基础上,我们把<code>computed</code>区块中的<code>totalMarks</code>函数整体移到<code>methods</code>中。同时在模板中将<code>{{ totalMarks }}</code> 替换成 <code>{{ totalMarks() }}</code>。 你最终看到的结果是一样的,如下所示:</p> <div style="margin-bottom: 20px;"><iframe id="vedQpe" src="//codepen.io/airen/embed/vedQpe?height=400&amp;theme-id=0&amp;slug-hash=vedQpe&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>虽然这两种方式输出的结果是相同的,但是性能将遭受毁灭性的打击。使用这种方法,<code>totalMarks()</code>方法在每次页面渲染时都被执行一次(例如,使用每一个<code>change</code>)。</p> <p>如果我们有一个计算属性,那么Vue会记住计算的属性所依赖的值(在我们这个示例中,那就是<code>results</code>)。通过这样做,Vue只有在依赖变化时才可以计算值。否则,将返回以前缓存的值。这也意味着<strong>只要<code>results</code>还没有发生改变,多次访问<code>totalMarks</code>计算属性会立即返回之前的计算结果,而不必再次执行函数。</strong></p> <p>上面两个示例也说明,在Vue中<strong>计算属性是基于它们的依赖进行缓存的,而方法是不会基于它们的依赖进行缓存的。从而使用计算属性要比方法性能更好。</strong></p> <p>这也同样意味着下面的计算属性将不再更新,因为 <code>Date.now()</code> 不是响应式依赖:</p> <pre><code>computed: { now: function () { return Date.now() } } </code></pre> <p>相比之下,每当触发重新渲染时,方法的调用方式将总是再次执行函数。因此,函数必须是一个纯函数。它不能有副作用。输出只能依赖于传递给函数的值。</p> <p>那么我们为什么需要缓存?假设我们有一个性能开销比较大的的计算属性 <code>A</code>,它需要遍历一个极大的数组和做大量的计算。然后我们可能有其他的计算属性依赖于 <code>A</code> 。如果没有缓存,我们将不可避免的多次执行 <code>A</code> 的 <code>getter</code>!如果你不希望有缓存,请用方法来替代。</p> <h2>计算属性的 <code>setter</code></h2> <p>计算属性默认只有<code>getter</code>,不过在需要时你也可以提供一个<code>setter</code>:</p> <pre><code>computed: { fullName: { // getter get: function () { return this.firstName + ' ' + this.lastName }, // setter set: function (newValue) { var names = newValue.split(' ') this.firstName = names[0] this.lastName = names[names.length - 1] } } } </code></pre> <p>效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="OxQaBB" src="//codepen.io/airen/embed/OxQaBB?height=400&amp;theme-id=0&amp;slug-hash=OxQaBB&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>你在输入框中输入一个<code>fullName</code>,然后点击<code>set</code>按钮,可以看到对应的效果。你现在再运行<code>app.fullName="Airen liao"</code>时,计算属性的<code>setter</code>会被调用,<code>app.firstName</code>和<code>app.lastName</code>也相应地会被更新。如下图所示:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-computed-1.gif" alt="Vue中的computed属性" /></p> <h2>观察者</h2> <p>虽然计算属性在大多数情况下更合适,但有时候也需要一个自定义的<code>watcher</code>。这是为什么Vue通过<code>watch</code>选项提供一个更通用的方法,来响应数据的变化。当你想要在数据变化响应时,执行异步操作或开销较大的操作,这是很有用的。</p> <p>Vue确实提供了一种更通用的方式来观察和响应Vue实例上的数据变动:<strong><code>watch</code>属性</strong>。当你有一些数据需要随着其它数据变动而变动时,你很容易滥用<code>watch</code>。然而,通常更好的想法是使用计算属性而不是命令式的<code>watch</code>回调。比如下面的示例:</p> <pre><code>&lt;div id="app"&gt; {{ fullName }} &lt;/div&gt; let app = new Vue({ el: '#app', data () { return { firstName: 'Foo', lastName: 'Bar', fullName: 'Foo Bar' } }, watch: { firstName: function (val) { this.fullName = val + ' ' + this.lastName }, lastName: function (val) { this.fullName = this.firstName + ' ' + val } } }) </code></pre> <p>上面代码是命令式的和重复的。将它与计算属性的版本进行比较:</p> <pre><code>let app = new Vue({ el: '#app', data () { return { firstName: 'Foo', lastName: 'Bar' } }, computed: { fullName: function () { return this.firstName + ' ' + this.lastName } } }) </code></pre> <h2>在Vue中使用异步计算属性</h2> <blockquote> <p>Vue中的计算属性非常好。它们允许你执行复杂的操作或数据格式,同时最大限度地执行依赖项计算的性能,只在依赖更改时更新视图。但遗憾的是,它们完全是同步的。</p> </blockquote> <p>值得庆幸的是,有一个插件。使用<a href="http://xxysy.com/quot;//github.com/foxbenjaminfox/vue-async-computed"><code>vue-async-computed</code></a>包可以通地将一个<code>promise</code>的值绑定到伟德1946手机版属性来创建和使用伟德1946手机版中的异步计算属性。</p>" <p>我们可以在项目的根目录下通过<code>yarn</code>或<code>npm</code>来安装<code>vue-async-computed</code>插件:</p> <pre><code># Yarn $ yarn add vue-async-computed # NPM $ npm i vue-async-computed --save </code></pre> <p>接下来在你的项目中开启这个插件:</p> <pre><code>// main.js import Vue from 'vue'; import AsyncComputed from 'vue-async-computed' import App from 'App.vue'; Vue.use(AsyncComputed); new Vue({ el: '#app', render: h =&gt; h(App) }); </code></pre> <blockquote> <p>如果你和我一样,对Vue的构建工具不是很熟悉的话,我建议你使用Vue官方提供的构建工具 <a href="http://xxysy.com/quot;//github.com/vuejs/vue-cli">Vu" CLI</a>。默认情况,它提供了五种模板,你可以根据自己喜欢的方式选择自己需要的模板即可。</p> </blockquote> <p>确认在项目中引用<code>vue-async-computed</code>之后,咱们就可以开始使用这个插件了。使用如何使用这个插件之前,先来简单的了解一些概念。</p> <p>在Vue中标准计算属性和异步属性之间有一些区别:</p> <ul> <li>异步属性不能有<code>setter</code></li> <li>直到<code>promise</code>的<code>resolve</code>为止,除非<code>default</code>被设置,否则该值为<code>null</code></li> </ul> <p>在大多数情况下,你可以将它们视为返回<code>promise</code>的计算属性。</p> <pre><code>&lt;!-- MyComponent.vue --&gt; &lt;template&gt; &lt;!-- 在一两秒后 myResolvedValue将变成"*Fancy* Resolved Value" --&gt; &lt;h2&gt;Asynchronous Property {{ myResolvedValue }}&lt;/h2&gt; &lt;/template&gt; &lt;script&gt; export default { asyncComputed: { myResolvedValue () { return new Promise((resolve, reject) =&gt; { setTimeout(() =&gt; resolve('*Fancy* Resolved Value!'), 1000) }) } } } &lt;/script&gt; </code></pre> <p>使用ES7 / ES2016的<code>async / await</code>,这将变得更简单:</p> <pre><code>&lt;!-- MyComponent.vue --&gt; &lt;template&gt; &lt;!-- 在一两秒后 myResolvedValue将变成"*Fancy* Resolved Value" --&gt; &lt;h2&gt;Asynchronous Property {{ myResolvedValue }}&lt;/h2&gt; &lt;/template&gt; &lt;script&gt; function fancinessComesLater () { return new Promise((resolve, reject) =&gt; { setTimeout(() =&gt; resolve('*Fancy* Resolved Value!'), 1000) }) } export default { asyncComputed: { async myResolvedValue() { return await fancinessComesLater() } } } &lt;/script&gt; </code></pre> <p>有关于<a href="http://xxysy.com/quot;//github.com/foxbenjaminfox/vue-async-computed"><code>vue-async-computed</code></a>更详细的使用和介绍,可以阅读其<" href="http://xxysy.com/quot;//github.com/foxbenjaminfox/vue-async-computed">官网</a>提供的相关介绍。</p>" <h2>总结</h2> <p>今天主要学习了Vue中的计算属性。在Vue中的计算属性可以让我们很好的监听多个数据或者一个数据来维护返回一个状态值,只要其中一个或多个数据发生变化,则会重新计算整个函数体,重新皇家马德里回状态值,从而更新对应的视图(View)。其次,计算属性具有缓存,相比Vue中的方法而言,性能更佳。但Vue中的计算属性都是同步的,如果需要异步我们得依赖于<a href="http://xxysy.com/quot;//github.com/foxbenjaminfox/vue-async-computed"><code>vue-async-computed</code></a>。</p>" <p>由于自己是Vue的初学者,对Vue的计算属性也只是停留在表面层上的理解,如果从深层面上看,还是会存在一定问题。希望各咱大婶能指正或提供自己的经验。</p> <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-computed-intro.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-computed-intro.html</a></p> rel="nofollow" </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/640.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/vue"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/vue/vue2"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue 2.0学习笔记</a></div></div></div> Sat, 07 Oct 2017 13:52:31 +0000 Airen 2286 at http://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 http://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-js-communication-single-component.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>单个伟德1946手机版相对而言简单一点。在我看来,有些事情你需要知道才能让你开始。关于Vue伟德1946手机版的模板和脚本部分如何协同工作的。模板和脚本组成一个单元,并共享相同的数据。<strong>最好的学习就是通过一些实例来阐述,这样更易于交流。</strong></p> <h2>模板到脚本:事件</h2> <p>在UI中用户事件之后用户可以使用一些用户事件。在模板中<code>@click="handleClick"</code>将会调用<code>handleClick</code>方法。</p> <pre><code>&lt;template&gt; &lt;button @click="handleClick"&gt; Tacos? &lt;/button&gt; &lt;/template&gt; &lt;script&gt; export default { name: 'SingleComponent', methods: { handleClick () { alert('Tacos!') } } } &lt;/script&gt; </code></pre> <p>效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="yzpmEX" src="//codepen.io/airen/embed/yzpmEX?height=200&amp;theme-id=0&amp;slug-hash=yzpmEX&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="200" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>点击示例中的<code>button</code>会有一个<code>alert</code>弹出来。如下所示:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-single-component-1.png" alt="" /></p> <blockquote> <p>上面示例中,采用的是<strong>x-template</strong>定义伟德1946手机版模板的方式。如果你对创建伟德1946手机版模板方式了解不多,建议阅读《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/seven-ways-to-define-a-component-template-by-vuejs.html">Vue.j" 定义伟德1946手机版模板的七种方式</a>》一文。至于在示例中采用哪一种方式,根据自己的喜好或项目需求来做。</p> </blockquote> <p>再次回到我们示例中来,在上面的示例中,我们稍做调整,你就可以传参数到<code>handleClick()</code>方法中:</p> <pre><code>&lt;template&gt; &lt;button @click="handleClick('Tacos')"&gt; Tacos? &lt;/button&gt; &lt;/template&gt; &lt;script&gt; export default { name: 'SingleComponent', methods: { handleClick (value) { alert(`${value}!`) } } } &lt;/script&gt; </code></pre> <div style="margin-bottom: 20px;"><iframe id="boLbNq" src="//codepen.io/airen/embed/boLbNq?height=200&amp;theme-id=0&amp;slug-hash=boLbNq&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="200" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>上面这个示例,在<code>handleClick()</code>方法中传了一个<code>value</code>参数。在<code>@click</code>调用<code>handleClick()</code>方法时传了一个<code>Hello, W3cplus.com</code>值。当点击按钮时,弹框会弹出我们传的值<code>Hello, W3cplus.com</code>。如下所示:</p> <p><img src="/sites/default/files/blogs/2017/1710/vue-single-component-2.png" alt="" /></p> <p>方法也可以接受事件。</p> <pre><code>&lt;template&gt; &lt;button @click="handleClick('Tacos', $event)" @mouseenter="handleMouseEnter"&gt; Tacos? &lt;/button&gt; &lt;/template&gt; &lt;script&gt; export default { name: 'SingleComponent', methods: { handleClick (value, event) { console.log(`${value}!`) console.log('Click', event) }, handleMouseEnter (event) { console.log('Mouse Enter', event) } } } &lt;/script&gt; </code></pre> <p>效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="VMQwwp" src="//codepen.io/airen/embed/VMQwwp?height=200&amp;theme-id=0&amp;slug-hash=VMQwwp&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="200" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p><img src="/sites/default/files/blogs/2017/1710/vue-single-component-3.gif" alt="" /></p> <p>当你在<code>v-for</code>指令中使用事件时,参数也是有用的。当你单击其中的一个菜单项时,事件处理程序知道你已经选择了哪个项目。</p> <pre><code>&lt;template&gt; &lt;div&gt; &lt;button v-for="(entry, index) in menu" :key="index" @click="selectEntry(entry)"&gt; {{entry}} &lt;/button&gt; &lt;/div&gt; &lt;/template&gt; &lt;script&gt; export default { name: 'SingleComponent', data () { return { menu: ['tacos', 'hot dogs', 'ice cream'] } }, methods: { selectEntry (value) { alert(`${value} it is!`) } } } &lt;/script&gt; </code></pre> <p>效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="KXQKWL" src="//codepen.io/airen/embed/KXQKWL?height=200&amp;theme-id=0&amp;slug-hash=KXQKWL&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="200" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>这是一些示例。你可以通过事件和处理程序做更多的事情。Vue指南对这个问题做出很好的解释:</p> <ul> <li><a href="http://xxysy.com/quot;//vuejs.org/v2/guide/events.html">Even" Handling</a></li> <li><a href="http://xxysy.com/quot;//vuejs.org/v2/api/#Instance-Methods-Events">Instanc" Methods / Events</a></li> </ul> <h2>脚本到模板:反应性</h2> <p>在大多数情况下,使用反应系统已经足够了。因为你需要在伟德1946手机版的脚本部分更改数据,并且根据数据更改重新渲染模板。</p> <p>比如下面这个示例,脚本每<code>5s</code>会更改一次交通灯。该模板将每次显示<code>isGreen</code>更改的值。甚至不需要以任何方式访问模板。请注意,我们可以更改数据,尽管现在伟德1946手机版可能无法呈现。该间隔将在<code>created()</code>方法中设置。可以独立于伟德1946手机版的模板中进行更改。</p> <p>对我来说,当你从jQuery的世界中走出来的时候,你就会感到非常兴奋。使用jQuery,你需要选择节点,然后更改文本。而使用Vue你不需要担心这些事项。</p> <pre><code>&lt;template&gt; &lt;div class="traffic-light"&gt; isGreen: {{ isGreen }} &lt;/div&gt; &lt;/template&gt; &lt;script&gt; export default { name: 'TrafficLight', data () { return { isGreen: false, interval: null } }, created () { this.interval = setInterval(() =&gt; { this.isGreen = !this.isGreen }, 5 * 1000) }, beforeDestroy () { clearInterval(this.interval) } } &lt;/script&gt; </code></pre> <p>效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="qPxdEw" src="//codepen.io/airen/embed/qPxdEw?height=200&amp;theme-id=0&amp;slug-hash=qPxdEw&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="200" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <blockquote> <p>我在想是不是可以使用Vue做一个红绿灯的伟德1946手机版出来。当然做一个红绿灯出来,我还得去学习一些其他的知识,如果你和我一样感兴趣,建议阅读这篇文章《<a href="http://xxysy.com/quot;//www.w3ctech.com/topic/916">红绿灯大战中的火星生命-Promise</a>》。</p>" </blockquote> <h2>脚本到模板:<code>refs</code></h2> <p>在某些情况下,就算是单个伟德1946手机版中,你也可能会需要一个<code>ref</code>。</p> <p>我想到了两个示例:</p> <ul> <li>你希望访问DOM Node的属性,比如<code>canvas</code>图像数据或者复选框的选中值</li> <li>你需要使用另一个库并将其传递给DOM Node</li> </ul> <p>这是一个Canvas的示例:</p> <pre><code>&lt;template&gt; &lt;div id="canvas-example"&gt; &lt;canvas ref="canvas" height="200" width="200" /&gt; &lt;/div&gt; &lt;/template&gt; &lt;script&gt; export default { name: 'CanvasExample', mounted () { const ctx = this.$refs.canvas.getContext('2d') ctx.fillStyle = 'rgb(200,0,0)' ctx.fillRect(10, 10, 55, 50) ctx.fillStyle = 'rgba(0, 0, 200, 0.5)' ctx.fillRect(30, 30, 55, 50) } } &lt;/script&gt; </code></pre> <p>效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="VMQLye" src="//codepen.io/airen/embed/VMQLye?height=200&amp;theme-id=0&amp;slug-hash=VMQLye&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="200" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>我意识到这一点已经太迟了,我感到很尴尬。<code>ref</code>将像其他属性一样对待。<strong>这意味着,你还可以传递动态值。</strong></p> <p>如果你运用的是循环,那就很方便了。</p> <pre><code>&lt;template&gt; &lt;ul id="dynamic-refs"&gt; &lt;li v-for="entry in entries" :key="entry.id" :ref="`entry${entry.id}`" &gt; {{ entry.title }} &lt;/li&gt; &lt;/ul&gt; &lt;/template&gt; &lt;script&gt; export default { name: 'DynamicRefs', data () { return { entries: [ { id: 1, title: 'Uno' }, { id: 2, title: 'Due' } ] } }, mounted () { console.log(this.$refs.entry1) } } &lt;/script&gt; </code></pre> <p>有关于<code>refs</code>更多的伟德1946网页版,可以阅读下面的文章:</p> <ul> <li><a href="http://xxysy.com/quot;//codingexplained.com/coding/front-end/vue-js/accessing-dom-refs">Accessin" the DOM in Vue.js with <code>$refs</code></a></li> <li><a href="http://xxysy.com/quot;//medium.com/@maximkerstens/vue-js-explained-through-pokemon-2-refs-promises-event-bus-79b705498f0">Vue.j" explained through Pokemon #2 $refs, Promises &amp; event bus</a></li> </ul> <h2>v-model</h2> <p>当构建表单时,你将希望在<code>input</code>输入的数据能让用户立马看到。很多时候,也称之为双向数据绑定。</p> <p>他们有一定的约定规则:</p> <ul> <li>将当前数据作为值传递给模板</li> <li>为用户输入发送输入事件</li> </ul> <p>当你看到在伟德1946手机版中使用<code>value</code>和<code>input</code>时应该立马想到<code>v-model</code>。</p> <p>下面两个版本的伟德1946手机版,实现的功能是一样的:</p> <pre><code>&lt;template&gt; &lt;input :value="name" @input="handleNameInput" &gt; &lt;/template&gt; &lt;script&gt; export default { name: 'ValueAndInput', data () { return { name: '' } }, methods: { handleNameInput (name) { this.name = name } } } &lt;/script&gt; &lt;template&gt; &lt;input v-model="name"&gt; &lt;/template&gt; &lt;script&gt; export default { name: 'ValueAndInput', data () { return { name: '' } } } &lt;/script&gt; </code></pre> <blockquote> <p>有关于<code>v-model</code>更多的介绍,可以阅读前面的<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/v-model.html">学习笔记</a>。</p>" </blockquote> <h2>总结</h2> <p>伟德1946手机版通讯是创建伟德1946手机版无法避免的一个问题,不管是哪一个JavaScript框架都要面对这样的问题。这篇文章我们先介绍了Vue中单个伟德1946手机版的通讯的方式。在接下来的文章中,将会介绍父-子伟德1946手机版(Parent-Child)通讯方式。这可能会变得复杂也会变得更有趣。我们可以把学到的东西应用到子伟德1946手机版上。</p> <p>另外需要声明的一点时,这篇文章的学习思路是根据<a href="http://xxysy.com/quot;//gambardella.info/">@Christia" Gambardella</a>的系列文章<a href="http://xxysy.com/quot;//gambardella.info/2017/08/31/vue-js-communication-single-component/">第一篇</a>进行学习的。由于自己是Vue的初学者,很多地方可能没有领会到作者的阐述观点,或者说理解有误的地方。还请大婶拍正。如果你在这方面有更好的经验或资料推荐,欢迎在下面的评论中与我们一起分享。</p>" <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-js-communication-single-component.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/vue-js-communication-single-component.html</a></p> rel="nofollow" </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/640.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/vue"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/tags/642.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue伟德1946手机版</a></div></div></div> Fri, 06 Oct 2017 12:06:16 +0000 Airen 2285 at http://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 http://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/seven-ways-to-define-a-component-template-by-vuejs.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><blockquote> <p>特别声明,本文转载<a href="http://xxysy.com/quot;//github.com/sqrtqiezi">@茄子</a>翻译<" href="http://xxysy.com/quot;//twitter.com/">@ANTHONYGORE</a>的《<" href="https://vuejsdevelopers.com/2017/03/24/vue-js-component-templates">7 rel="nofollow" Ways To Define A Component Template in Vue.js</a>》一文,如需转载,烦请注明原文出处:</p> <p>英文:<a href="//vuejsdevelopers.com/2017/03/24/vue-js-component-templates">https://vuejsdevelopers.com/2017/03/24/vue-js-component-templates</a></p> rel="nofollow" <p>译文:<a href="//laravel-china.org/articles/4382/seven-ways-to-define-a-component-template-by-vuejs">https://laravel-china.org/articles/4382/seven-ways-to-define-a-component-template-by-vuejs</a></p> rel="nofollow" </blockquote> <p>在 Vue 中定义一个伟德1946手机版模板,至少有七种不同的方式(或许还有其它我不知道的方式):</p> <ul> <li>字符串</li> <li>模板字面量</li> <li>x-template</li> <li>内联模板</li> <li><code>render</code> 函数</li> <li>JSF</li> <li>单文件伟德1946手机版</li> </ul> <p>在这篇文章中,我将通过示例介绍每个选项,并探讨利弊。以便你知道在任何特定情况下最适合的是哪一种。</p> <h2>字符串</h2> <p>默认情况下,模板会被定义为一个字符串。我想我们的观点会达成一致:字符串中的模板是非常难以理解的。除了广泛的浏览器支持之外,这种方法没有太多用处。</p> <pre><code>Vue.component('my-checkbox', { template: '&lt;div class="checkbox-wrapper" @click="check"&gt;&lt;div :class="{ checkbox: true, checked: checked }"&gt;&lt;/div&gt;&lt;div class="title"&gt;&lt;/div&gt;&lt;/div&gt;', data() { return { checked: false, title: 'Check me' } }, methods: { check() { this.checked = !this.checked; } } }); </code></pre> <h2>模板字面量</h2> <p>ES6 模板字面量允许你使用多行定义模板,这在常规 JavaScript 字符串中是不被允许的。此方式阅读体验更佳,并在许多现代浏览器中得到支持,不过安全起见你还是需要把代码转换成 ES5 。</p> <p>这种方法并不完美,我发现大多数 IDE 仍然会通过语法高亮、tab 格式化、换行符等地方的问题折磨着你。</p> <pre><code>Vue.component('my-checkbox', { template: ` &lt;div class="checkbox-wrapper" @click="check"&gt; &lt;div :class="{ checkbox: true, checked: checked }"&gt;&lt;/div&gt; &lt;div class="title"&gt;&lt;/div&gt; &lt;/div&gt; `, data() { return { checked: false, title: 'Check me' } }, methods: { check() { this.checked = !this.checked; } } }); </code></pre> <h2>x-template</h2> <p>使用此方法,你的模板被定义在例如 <code>index.html</code> 文件中的 <code>script</code> 标签里。此 <code>script</code> 标签使用 <code>text/x-template</code> 标记,并由伟德1946手机版定义的 <code>id</code> 引用。</p> <p>我喜欢这种方法,它允许你使用适当的 HTML 标记编写你的 HTML,不过不好的一面是,它把模板和伟德1946手机版定义的其它部分分离开来。</p> <pre><code>Vue.component('my-checkbox', { template: '#checkbox-template', data() { return { checked: false, title: 'Check me' } }, methods: { check() { this.checked = !this.checked; } } }); &lt;script type="text/x-template" id="checkbox-template"&gt; &lt;div class="checkbox-wrapper" @click="check"&gt; &lt;div :class="{ checkbox: true, checked: checked }"&gt;&lt;/div&gt; &lt;div class="title"&gt;&lt;/div&gt; &lt;/div&gt; &lt;/script&gt; </code></pre> <h2>内联模板</h2> <p>通过在伟德1946手机版中添加 <code>inline-template</code> 属性,你可以向 Vue 指示内部内容是其模板,而不是将其视为分布式内容(参考 <a href="http://xxysy.com/quot;//cn.vuejs.org/v2/guide/components.html#%E4%BD%BF%E7%94%A8-Slot-%E5%88%86%E5%8F%91%E5%86%85%E5%AE%B9"><code>slot</code></a>" 。</p> <p>它与 x-templates 具有相同的缺点,不过一个优点是,内容在 HTML 模板的正确位置,因此可以在页面加载时呈现,而不是等到 JavaScript 运行。</p> <pre><code>Vue.component('my-checkbox', { data() { return { checked: false, title: 'Check me' } }, methods: { check() { this.checked = !this.checked; } } }); &lt;my-checkbox inline-template&gt; &lt;div class="checkbox-wrapper" @click="check"&gt; &lt;div :class="{ checkbox: true, checked: checked }"&gt;&lt;/div&gt; &lt;div class="title"&gt;&lt;/div&gt; &lt;/div&gt; &lt;/my-checkbox&gt; </code></pre> <h2>render 函数</h2> <p><code>render</code> 函数需要你将模板定义为 JavaScript 对象,这显然是最详细和抽象的模板选项。</p> <p>不过,优点是你的模板更接近编译器,并允许你使用完整的 JavaScript 功能,而不是指令提供的子集。</p> <pre><code>Vue.component('my-checkbox', { data() { return { checked: false, title: 'Check me' } }, methods: { check() { this.checked = !this.checked; } }, render(createElement) { return createElement( 'div', { attrs: { 'class': 'checkbox-wrapper' }, on: { click: this.check } }, [ createElement( 'div', { 'class': { checkbox: true, checked: this.checked } } ), createElement( 'div', { attrs: { 'class': 'title' } }, [ this.title ] ) ] ); } }); </code></pre> <h2>JSX</h2> <p>Vue 中最有争议的模板选项是 JSX,一些开发者认为它丑陋、不直观,是对 Vue 精神的背叛。JSX 需要你先编译,因为它不能被浏览器运行。</p> <p>不过,如果你需要完整的 JavaScript 语言功能,又不太适应 <code>render</code> 函数过于抽象的写法,那么 JSX 是一种折衷的方式。</p> <pre><code>Vue.component('my-checkbox', { data() { return { checked: false, title: 'Check me' } }, methods: { check() { this.checked = !this.checked; } }, render() { return &lt;div class="checkbox-wrapper" onClick={ this.check }&gt; &lt;div class={{ checkbox: true, checked: this.checked }}&gt;&lt;/div&gt; &lt;div class="title"&gt;{ this.title }&lt;/div&gt; &lt;/div&gt; } }); </code></pre> <h2>单文件伟德1946手机版</h2> <p>只要你把构建工具设置的很舒服,单文件伟德1946手机版就是模板选项中的王者。它允许你写 HTML 标签定义伟德1946手机版,并且将所有伟德1946手机版定义保留在一个文件中。</p> <p>尽管它也有一些劣势:需要预编译,某些 IDE 不支持 <code>.vue</code> 文件的语法高亮,不过其地位依然难以被撼动。</p> <pre><code>&lt;template&gt; &lt;div class="checkbox-wrapper" @click="check"&gt; &lt;div :class="{ checkbox: true, checked: checked }"&gt;&lt;/div&gt; &lt;div class="title"&gt;&lt;/div&gt; &lt;/div&gt; &lt;/template&gt; &lt;script&gt; export default { data() { return { checked: false, title: 'Check me' } }, methods: { check() { this.checked = !this.checked; } } } &lt;/script&gt; </code></pre> <p>你还可以通过引入 pug 之类的预处理器,来获得模板定义的更多可能性。</p> <h2>最好的是哪一个?</h2> <p>当然没有一个完美的方法,每一个都应该根据你的用例来判断。我认为最好的开发人员会注意到所有的可能性,并将它们作为 Vue.js 工具栏的一个工具。</p> </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/624.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">转载</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/vue"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue</a></div></div></div> Fri, 06 Oct 2017 07:19:26 +0000 Airen 2284 at http://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com w3cplus_引领web前沿,打造前端精品教程 - 伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】 http://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/v-bind.html <div class="field field-name-body field-type-text-with-summary field-label-hidden"><div class="field-items"><div class="field-item even" property="content:encoded"><p>经过前面的学习,我们知道<code>v-on</code>可以实现事件绑定,<code>v-model</code>可以实现双向数据绑定。在Vue中除了这两个指令,还有一个<code>v-bind</code>指令。它可以往元素的属性中绑定数据,也可以动态地根据数据为元素绑定不同的样式。简单说,<strong><code>v-bind</code>是用来绑定HTML属性</strong>。</p> <h2>JavaScript给HTML标签指定属性</h2> <p>HTML不同的标签具有<a href="http://xxysy.com/quot;//developer.mozilla.org/zh-CN/docs/Web/HTML/Attributes#属性列表">不同的属性</a>。我们在写标签的时候一般会根据不同的标签指定不同的属性,比如<code>img</code>标签,我们会指定<code>src</code>和<code>alt</code>属性。</p>" <pre><code>&lt;img src="../images/logo.png" alt="伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】" /&gt; </code></pre> <p>但我们很多时候需要动态的给HTML标签动态指定属性的值。比如,我们这个<code>img</code>的<code>src</code>和<code>alt</code>是动态数据<code>data</code>(也就是服务端传过来的)。我们需要借助JavaScript来实现。在JavaScript中,我们有三个方法用来控制元素的属性:</p> <ul> <li><code>Element.getAttribute()</code>:获取元素上一个指定的属性值。如果指定的属性不存在,则返回<code>null</code>或<code>""</code>(空字符串)</li> <li><code>Element.setAttribute()</code>:指定元素上的一个属性值。如果属性已经存在,则更新该值;否则将添加一个新的属性用指定的名称和值</li> <li><code>Element.removeAttribute()</code>:从指定的元素中删除一个属性</li> </ul> <p>同样拿<code>img</code>标签的<code>src</code>和<code>alt</code>来举例。比如我们有一个默认的图片元素:</p> <pre><code>&lt;div class="wrapper"&gt; &lt;img src="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/sites/default/files/blogs/2017/1709/meinv-1.jpg" alt="美女与野獸"&gt; &lt;/div&gt; &lt;div class="action"&gt; &lt;button id="btn"&gt;美女与野獸&lt;/button&gt; &lt;/div&gt; // JavaScript let data = { imgInfo: { imgUrl: '//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/sites/default/files/blogs/2017/1709/yuesou.jpg', alt: '野獸' } } const imgEle = document.querySelector('.figure') const btn = document.getElementById('btn') btn.addEventListener('click', () =&gt; { imgEle.setAttribute('src', data.imgInfo.imgUrl) imgEle.setAttribute('alt', data.imgInfo.alt) }, false) </code></pre> <p>效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="BwZeQv" src="//codepen.io/airen/embed/BwZeQv?height=400&amp;theme-id=0&amp;slug-hash=BwZeQv&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>点击按钮就可以把“美女”切换成“野獸”。如下图所示:</p> <p><img src="/sites/default/files/blogs/2017/1709/vue-bind-1.gif" alt="v-bind" /></p> <p>在Vue中,我们采用今天要学习的<code>v-bind</code>指令,事情会变得更容易的多。那么接下来的内容中,我们会看到如何用<code>v-bind</code>来给HTML的元素绑定属性。</p> <h2><code>v-bind</code>用法</h2> <p>前面也提到过了,<code>v-bind</code>是Vue的一个指令,主要功能是动态地绑定一个或多个特性,或一个伟德1946手机版<code>props</code>到表达式。常见的使用方式有:</p> <pre><code>&lt;!-- 绑定一个属性 --&gt; &lt;img v-bind:src="imgUrl" /&gt; &lt;!-- 缩写 --&gt; &lt;img :src="imgUrl" /&gt; &lt;!-- 内联字符串拼接 --&gt; &lt;img :src="'../images/' + fileName" /&gt; &lt;!-- class 绑定 --&gt; &lt;div :class="{ red: isRed}"&gt;&lt;/div&gt; &lt;div :class="[classA, classB]"&gt;&lt;/div&gt; &lt;div :class="[classA, {classB: isB, classC: isC}]"&gt;&lt;/div&gt; &lt;!-- style绑定 --&gt; &lt;div :style="{fontSize: size + 'px'}"&gt;&lt;/div&gt; &lt;div :style="[styleObjectA, styleObjectB]"&gt;&lt;/div&gt; &lt;!-- 绑定一个有属性的对象 --&gt; &lt;div v-bind="{id:someProp, 'other-attr': otherProp}"&gt;&lt;/div&gt; &lt;!-- 通过prop绑定, prop必须在my-component中声明 --&gt; &lt;my-component :prop="someThing"&gt;&lt;/my-component&gt; &lt;!-- 通过 $props 将父伟德1946手机版的props 一起传递给子伟德1946手机版 --&gt; &lt;child-component v-bind="$props"&gt;&lt;/child-component&gt; &lt;!-- Xlink --&gt; &lt;svg&gt;&lt;a :xlink:special="foo"&gt;&lt;/a&gt;&lt;/svg&gt; </code></pre> <p>回到我们最初的示例中来,看看在Vue中怎么通过<code>v-bind</code>给<code>img</code>元素绑定相应的属性。</p> <pre><code>&lt;!-- Template --&gt; &lt;div id="app"&gt; &lt;img :src="imgUrl" v-bind:alt="imgAlt" :class="{figure: className}" /&gt; &lt;/div&gt; // JavaScript let app = new Vue({ el: '#app', data () { return { imgUrl: '//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/sites/default/files/blogs/2017/1709/meinv-1.jpg', imgAlt: '美女', className: true } } }) </code></pre> <p>这个时候<code>data</code>数据中的<code>imgUrl</code>、<code>imgAlt</code>和<code>className</code>属性的值对应绑到了<code>img</code>元素中的<code>src</code>、<code>alt</code>和<code>class</code>属性上。看到的效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="ZXyNop" src="//codepen.io/airen/embed/ZXyNop?height=400&amp;theme-id=0&amp;slug-hash=ZXyNop&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="400" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>这个时候如果你在浏览器开发者的控制台上修改<code>app.imgUrl</code>、<code>app.imgAlt</code>和<code>app.className</code>的值之后,可以看到<code>img</code>元素对应的<code>src</code>、<code>alt</code>和<code>class</code>都会有所改变,如下图所示:</p> <p><img src="/sites/default/files/blogs/2017/1709/vue-bind-2.gif" alt="v-bind" /></p> <p>上面这种<code>v-bind</code>指令是最简单,也是最易理解的,但实际上,Vue指令的预期值,比如<code>v-bind:alt="imgAlt"</code>中,<code>v-bind</code>是指令,<code>:</code>号后面的<code>alt</code>是参数,而<code>imgAlt</code>是我们预期想绑定的值(规范中也称其为<strong>预期值</strong>)。除了上示这样的绑定一个字符串类型变量,其实<code>v-bind</code>还支持一个单一的JavaScript表达式(<code>v-for</code>除外)。</p> <p>在我们的实际项目中,最常见的是给元素绑定类名和样式。<a href="http://xxysy.com/quot;//cn.vuejs.org/v2/guide/class-and-style.html">官方文档</a>也特意以类名和样式绑定为例向大家介绍了<code>v-bind</code>的各种使用。接下来的内容,我们也以这两个部分为主线来介绍<code>v-bind</code>。当然,<code>v-bind</code>可以用来绑定HTML标签元素上任意的属性,使用方式是一样的。</p>" <h2>Class与Style绑定</h2> <p>数据绑定的一个常见需求是操作元素的<code>class</code>列表和它的内联样式。因为它们都是属性,我们可以用<code>v-bind</code>处理它们:只需要计算出表达式最终的字符串。不过,字符串拼接麻料峭春寒又易错。因此,在<code>v-bind</code>用于<code>class</code>和<code>style</code>时,Vue专门增强了它。表达式的结果类型除了字符串这外,还可以是对象或数组。</p> <h3>绑定HTML Class</h3> <p>先来看<code>v-bind</code>给元素绑定类名。主要方式有:</p> <ul> <li>执行运算</li> <li>执行函数</li> <li>对象语法</li> <li>数组语法</li> <li>ES6扩展语法</li> </ul> <p>咱们依次来看这些方法怎么来操作类名。</p> <h4>执行运算</h4> <p>执行运算,其实就是运算的表达式,简单的说,就是有<code>+</code>来连接<code>data</code>中多个属性,比如:</p> <pre><code>&lt;div id="app"&gt; &lt;button :class="classA + ' ' + classB"&gt;美女与野兽&lt;/button&gt; &lt;/div&gt; // JavaScript let app = new Vue({ el: '#app', data: { classA: 'button', classB: 'large-button', classC: 'primary-button' } }) </code></pre> <p>效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="RLgmOv" src="//codepen.io/airen/embed/RLgmOv?height=200&amp;theme-id=0&amp;slug-hash=RLgmOv&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="200" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>可以看到,<code>button</code>和<code>large-button</code>两个类名以及对应的样式已经绑定到了<code>&lt;button&gt;</code>元素上:</p> <p><img src="/sites/default/files/blogs/2017/1709/vue-bind-3.png" alt="v-bind" /></p> <h4>执行函数</h4> <p>除了在<code>v-bind</code>中使用表达式之外,还可以使用执行函数,比如下面这个示例:</p> <pre><code>&lt;!-- Template --&gt; &lt;div id="app"&gt; &lt;button :class="getClass()"&gt;美女与野兽&lt;/button&gt; &lt;/div&gt; // JavaScript let app = new Vue({ el: '#app', data: { getClass: function () { return `button large-button primary-button` } } }) </code></pre> <p>效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="YrQoKd" src="//codepen.io/airen/embed/YrQoKd?height=200&amp;theme-id=0&amp;slug-hash=YrQoKd&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="200" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>同样的,对应的<code>button</code>、<code>large-button</code>和<code>primary-button</code>类名添加到了<code>&lt;button&gt;</code>元素上:</p> <p><img src="/sites/default/files/blogs/2017/1709/vue-bind-4.png" alt="v-bind" /></p> <h4>对象语法</h4> <p>我们还可以给<code>v-bind:class</code>传一个对象,这样我们就能动态的切换<code>class</code>。同样拿前面的Button为例:</p> <pre><code>&lt;!-- Template --&gt; &lt;div id="app"&gt; &lt;button :class="{button: isButton, 'large-button': isLarge, 'primary-button': isPrimary}"&gt;美女与野兽&lt;/button&gt; &lt;/div&gt; // JavaScript let app = new Vue({ el: '#app', data: { isButton: true, isLarge: true, isPrimary: true } }) </code></pre> <p>效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="PJjrPY" src="//codepen.io/airen/embed/PJjrPY?height=200&amp;theme-id=0&amp;slug-hash=PJjrPY&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="200" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>效果和前面的一样,把对应的类名添加到了<code>button</code>元素上。这种方法还有其强大之处,我们可以动态的改变<code>button</code>的类名。打开浏览器开发者工具,修改<code>data</code>中对应的属性值:</p> <p><img src="/sites/default/files/blogs/2017/1709/vue-bind-5.gif" alt="v-bind" /></p> <p>大家可能发现了,我们<code>data</code>中对应的属性值都是<a href="http://xxysy.com/quot;//developer.mozilla.org/en-US/docs/Glossary/Truthy">真假值</a>。你是否想起了前面学的<code>v-model</code>指令,这样我们可以通过<code>v-model</code>来实现类似的双向绑定,控制元素类名。</p>" <div style="margin-bottom: 20px;"><iframe id="rGwELp" src="//codepen.io/airen/embed/rGwELp?height=200&amp;theme-id=0&amp;slug-hash=rGwELp&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="200" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>默认效果,我们三个类名都有了,对应的三个<code>checkbox</code>也是选中的,那是因为<code>data</code>中对应的三个属性值都为<code>true</code>。你可以点击每个<code>checkbox</code>,你可以看到<code>v-model</code>改变了<code>data</code>中的属性的值,同样也改变了<code>class</code>的值。</p> <p><img src="/sites/default/files/blogs/2017/1709/vue-bind-6.gif" alt="v-bind" /></p> <p>上面的示例,我们将三个值分开来写,其实为了方便,你可以把这三个值放到一个对象中:</p> <pre><code>&lt;!-- Template --&gt; &lt;button :class="classObject"&gt;美女与野兽&lt;/button&gt; // JavaScript let app = new Vue({ el: '#app', data: { classObject: { button: true, 'large-button': true, 'primary-button': true } } }) </code></pre> <p>对应的效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="veZqgq" src="//codepen.io/airen/embed/veZqgq?height=200&amp;theme-id=0&amp;slug-hash=veZqgq&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="200" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>我们也可以在这里绑定返回对象的<a href="http://xxysy.com/quot;//cn.vuejs.org/v2/guide/computed.html">计算属性</a>。这是一个常用且强大的模式:</p>" <pre><code>&lt;!-- Template --&gt; &lt;div id="app"&gt; &lt;button :class="classObject"&gt;美女与野兽&lt;/button&gt; &lt;/div&gt; // JavaScript let app = new Vue({ el: '#app', data: { isButton: true, isLarge: null, isPrimary: true }, computed: { classObject: function () { return { button: this.isButton, 'large-button': this.isLarge != false, 'primary-button': !this.isPrimary } } } }) </code></pre> <p>效果如下:</p> <div style="margin-bottom: 20px;"><iframe id="aLwgya" src="//codepen.io/airen/embed/aLwgya?height=200&amp;theme-id=0&amp;slug-hash=aLwgya&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="200" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <h4>数组语法</h4> <p>我们可以把一个数组传给<code>v-bind:class</code>,以应用一个<code>class</code>列表:</p> <pre><code>&lt;!-- Template --&gt; &lt;div id="app"&gt; &lt;button :class="[classA, classB, classC]"&gt;美女与野兽&lt;/button&gt; &lt;/div&gt; // JavaScript let app = new Vue({ el: '#app', data: { classA: 'button', classB: 'large-button', classC: 'primary-button' } }) </code></pre> <div style="margin-bottom: 20px;"><iframe id="NagZBp" src="//codepen.io/airen/embed/NagZBp?height=200&amp;theme-id=0&amp;slug-hash=NagZBp&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="200" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <p>也可以根据条件切换列表中的<code>class</code>,可以使用三元表达方式。比如当<code>toggleClass</code>为<code>true</code>时添加<code>large-button</code>,反之为<code>false</code>时添加<code>primary-button</code>。这个示例我们配合<code>v-model</code>一起来写:</p> <div style="margin-bottom: 20px;"><iframe id="MEoMzG" src="//codepen.io/airen/embed/MEoMzG?height=200&amp;theme-id=0&amp;slug-hash=MEoMzG&amp;default-tab=result&amp;user=airen" scrolling="no" frameborder="0" height="200" allowtransparency="true" allowfullscreen="true" class="cp_embed_iframe undefined" style="width: 100%; overflow: hidden;"></iframe></div> <h4>ES6扩展语法</h4> <p>最前面我们看了表达式的方式来给<code>button</code>添加类名。如果使用ES6的特性,我们可以使用双撇号来替代<code>+</code>运算,比如:</p> <pre><code>&lt;div id="app"&gt; &lt;button :class="`${classA} ${classB} ${classC}`"&gt;美女与野兽&lt;/button&gt; &lt;/div&gt; // JavaScript let app = new Vue({ el: '#app', data: { classA: 'button', classB: 'large-button', classC: 'primary-button' } }) </code></pre> <p>得到的效果是一样的。</p> <h3>绑定内联样式</h3> <p>绑定内联样式和绑定类名方法有点类似。我们来看几个常见的方式。</p> <h4>对象语法</h4> <p><code>v-bind:style</code>的对象语法十分直观 —— <strong>看着非常像CSS,其实它是一个JavaScript对象。</strong>CSS属性名需要用驼峰方式(camelCase)书写或者配合引号的短横分隔命名(kebab-case):</p> <pre><code>&lt;div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"&gt;&lt;/div&gt; data: { activeColor: 'red', fontSize: 30 } </code></pre> <p>直接绑定到一个样式对象通常更好,让模松更清晰:</p> <pre><code>&lt;div v-bind:style="styleObject"&gt;&lt;/div&gt; data: { styleObject: { color: 'red', fontSize: '13px' } } </code></pre> <p>同样的,对象语法常常结合返回对象的计算属性使用。除了对象的方式,还可以使用数组方式:</p> <p><code>v-bind:style</code> 的数组语法可以将多个样式对象应用到一个元素上:</p> <pre><code>&lt;div v-bind:style="[baseStyles, overridingStyles]"&gt;&lt;/div&gt; </code></pre> <p>从 2.3.0 起你可以为 <code>style</code> 绑定中的属性提供一个包含多个值的数组,常用于提供多个带前缀的值,例如:</p> <pre><code>&lt;div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"&gt;&lt;/div&gt; </code></pre> <p>这会渲染数组中最后一个被浏览器支持的值。在这个例子中,如果浏览器支持不带浏览器前缀的 Flexbox,那么渲染结果会是 <code>display: flex</code>。</p> <p>另外在写CSS属性的时候,有些属性需要添加特定的浏览器前缀。Vue比较灵活,会自动侦测并添加相应的前缀。</p> <h2>用在伟德1946手机版上</h2> <blockquote> <p>由于我们还没有接触过<a href="http://xxysy.com/quot;//cn.vuejs.org/v2/guide/components.html">Vue的伟德1946手机版</a>创建,接下来的内容你可以忽略。当然,如果你对Vue伟德1946手机版有一定的接触,可以简单的看看<code>v-bind</code>在伟德1946手机版上的运用。</p>" </blockquote> <p>当你在一个自定义伟德1946手机版上用到 <code>class</code> 属性的时候,这些类将被添加到根元素上面,这个元素上已经存在的类不会被覆盖。</p> <p>例如,如果你声明了这个伟德1946手机版:</p> <pre><code>Vue.component('my-component', { template: '&lt;p class="foo bar"&gt;Hi&lt;/p&gt;' }) </code></pre> <p>然后在使用它的时候添加一些 <code>class</code>:</p> <pre><code>&lt;my-component class="baz boo"&gt;&lt;/my-component&gt; </code></pre> <p>HTML 最终将被渲染成为:</p> <pre><code>&lt;p class="foo bar baz boo"&gt;Hi&lt;/p&gt; </code></pre> <p>同样的适用于绑定 HTML class:</p> <pre><code>&lt;my-component v-bind:class="{ active: isActive }"&gt;&lt;/my-component&gt; </code></pre> <p>当 <code>isActive</code> 为 truthy 值 (译者注:truthy 不是 <code>true</code>,<a href="http://xxysy.com/quot;//developer.mozilla.org/zh-CN/docs/Glossary/Truthy">参考这里</a>" 的时候,HTML 将被渲染成为:</p> <pre><code>&lt;p class="foo bar active"&gt;Hi&lt;/p&gt; </code></pre> <h2><code>v-bind</code>修饰符</h2> <p><code>v-bind</code>和<code>v-model</code>有点类似,也具有修饰符特性:</p> <ul> <li><code>.prop</code>:被用于绑定 DOM 属性 (<code>property</code>)。(<a href="http://xxysy.com/quot;//stackoverflow.com/questions/6003819/properties-and-attributes-in-html#answer-6004028">差别在哪里?</a>)</li>" <li><code>.camel</code>:将 <code>kebab-case</code> 特性名转换为 <code>camelCase</code>。 (从 2.1.0 开始支持)</li> <li><code>.sync</code>:语法糖,会扩展成一个更新父伟德1946手机版绑定值的 <code>v-on</code> 侦听器</li> </ul> <h2>总结</h2> <p>这篇文章介绍了Vue中的<code>v-bind</code>指令。通过<code>v-bind</code>指令可以很方便的给HTML元素绑定属性。比如最常见的给元素绑定类名或者内联样式。而且具有多种方式给元素绑定属性。比如说有<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/conditionally-applying-css-class-vue-js.html">条件的给元素绑定类名</a>。</p> <p>由于作者是Vue初学者,如果文章中有不对之处,还请各路大婶拍正,如果你在这方面有更多的经验或建议,欢迎在下面的评论中与我们一起分享。</p> <div class="blog-author media"><a class="media-object" href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank"><img src="/sites/default/files/blogs/author/airen.jpg"></a><div class="media-body"><h3 class="media-heading"><a href="http://xxysy.com/quot;//weibo.com/伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】"" target="_blank">大漠</a></h3><div class="media-des">常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等伟德19463331脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《<a href="http://xxysy.com/quot;//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/book-comment.html"" target="_blank">图解CSS3:核心技术与案例实战</a>》。</div></div></div> <p>如需转载,烦请注明出处:<a href="//www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/v-bind.html">https://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com/vue/v-bind.html</a></p> rel="nofollow" </div></div></div><div class="field field-name-field-taxonomy field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/tags/640.html"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue</a></div></div></div><div class="field field-name-field-blog-tag field-type-taxonomy-term-reference field-label-hidden"><div class="field-items"><div class="field-item even"><a href="http://xxysy.com/quot;/blog/vue"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue</a></div><div class="field-item odd"><a href="http://xxysy.com/quot;/blog/vue/vue2"" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Vue 2.0学习笔记</a></div></div></div> Sat, 30 Sep 2017 15:18:43 +0000 Airen 2283 at http://www.伟德19463331|伟德1946手机版|伟德1946网页版【官方首页】.com