2019-04-21 11:50:48 +08:00

447 lines
31 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

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

<div class="content guide with-sidebar list-guide">
<h1>列表渲染</h1>
<h2 id="用-v-for-把一个数组对应为一组元素"><a class="headerlink" href="#用-v-for-把一个数组对应为一组元素" title="用 v-for 把一个数组对应为一组元素"></a><code>v-for</code> 把一个数组对应为一组元素</h2><p>我们用 <code>v-for</code> 指令根据一组数组的选项列表进行渲染。<code>v-for</code> 指令需要使用 <code>item in items</code> 形式的特殊语法,<code>items</code> 是源数据数组并且 <code>item</code> 是数组元素迭代的别名。</p>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"example-1"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"item in items"</span>&gt;</span>
{{ item.message }}
<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></code></pre>
<pre><code class="hljs js"><span class="hljs-keyword">var</span> example1 = <span class="hljs-keyword">new</span> Vue({
<span class="hljs-attr">el</span>: <span class="hljs-string">'#example-1'</span>,
<span class="hljs-attr">data</span>: {
<span class="hljs-attr">items</span>: [
{ <span class="hljs-attr">message</span>: <span class="hljs-string">'Foo'</span> },
{ <span class="hljs-attr">message</span>: <span class="hljs-string">'Bar'</span> }
]
}
})</code></pre>
<p>结果:</p>
<ul class="demo" id="example-1">
<li v-for="item in items">
{{item.message}}
</li>
</ul>
<script>
var example1 = new Vue({
el: '#example-1',
data: {
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
},
watch: {
items: function () {
smoothScroll.animateScroll(document.querySelector('#example-1'))
}
}
})
</script>
<p><code>v-for</code> 块中,我们拥有对父作用域属性的完全访问权限。<code>v-for</code> 还支持一个可选的第二个参数为当前项的索引。</p>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"example-2"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"(item, index) in items"</span>&gt;</span>
{{ parentMessage }} - {{ index }} - {{ item.message }}
<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></code></pre>
<pre><code class="hljs js"><span class="hljs-keyword">var</span> example2 = <span class="hljs-keyword">new</span> Vue({
<span class="hljs-attr">el</span>: <span class="hljs-string">'#example-2'</span>,
<span class="hljs-attr">data</span>: {
<span class="hljs-attr">parentMessage</span>: <span class="hljs-string">'Parent'</span>,
<span class="hljs-attr">items</span>: [
{ <span class="hljs-attr">message</span>: <span class="hljs-string">'Foo'</span> },
{ <span class="hljs-attr">message</span>: <span class="hljs-string">'Bar'</span> }
]
}
})</code></pre>
<p>结果:</p>
<ul class="demo" id="example-2">
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
</ul>
<script>
var example2 = new Vue({
el: '#example-2',
data: {
parentMessage: 'Parent',
items: [
{ message: 'Foo' },
{ message: 'Bar' }
]
},
watch: {
items: function () {
smoothScroll.animateScroll(document.querySelector('#example-2'))
}
}
})
</script>
<p>你也可以用 <code>of</code> 替代 <code>in</code> 作为分隔符,因为它是最接近 JavaScript 迭代器的语法:</p>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"item of items"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></code></pre>
<h2 id="一个对象的-v-for"><a class="headerlink" href="#一个对象的-v-for" title="一个对象的 v-for"></a>一个对象的 <code>v-for</code></h2><p>你也可以用 <code>v-for</code> 通过一个对象的属性来迭代。</p>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"v-for-object"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"demo"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"value in object"</span>&gt;</span>
{{ value }}
<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></code></pre>
<pre><code class="hljs js"><span class="hljs-keyword">new</span> Vue({
<span class="hljs-attr">el</span>: <span class="hljs-string">'#v-for-object'</span>,
<span class="hljs-attr">data</span>: {
<span class="hljs-attr">object</span>: {
<span class="hljs-attr">firstName</span>: <span class="hljs-string">'John'</span>,
<span class="hljs-attr">lastName</span>: <span class="hljs-string">'Doe'</span>,
<span class="hljs-attr">age</span>: <span class="hljs-number">30</span>
}
}
})</code></pre>
<p>结果:</p>
<ul class="demo" id="v-for-object">
<li v-for="value in object">
{{ value }}
</li>
</ul>
<script>
new Vue({
el: '#v-for-object',
data: {
object: {
firstName: 'John',
lastName: 'Doe',
age: 30
}
}
})
</script>
<p>你也可以提供第二个的参数为键名:</p>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"(value, key) in object"</span>&gt;</span>
{{ key }}: {{ value }}
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></code></pre>
<div class="demo" id="v-for-object-value-key">
<div v-for="(value, key) in object">
{{ key }}: {{ value }}
</div>
</div>
<script>
new Vue({
el: '#v-for-object-value-key',
data: {
object: {
firstName: 'John',
lastName: 'Doe',
age: 30
}
}
})
</script>
<p>第三个参数为索引:</p>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"(value, key, index) in object"</span>&gt;</span>
{{ index }}. {{ key }}: {{ value }}
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></code></pre>
<div class="demo" id="v-for-object-value-key-index">
<div v-for="(value, key, index) in object">
{{ index }}. {{ key }}: {{ value }}
</div>
</div>
<script>
new Vue({
el: '#v-for-object-value-key-index',
data: {
object: {
firstName: 'John',
lastName: 'Doe',
age: 30
}
}
})
</script>
<p class="tip">在遍历对象时,是按 <code>Object.keys()</code> 的结果遍历,但是不能保证它的结果在不同的 JavaScript 引擎下是一致的。</p>
<h2 id="key"><a class="headerlink" href="#key" title="key"></a><code>key</code></h2><p>当 Vue.js 用 <code>v-for</code> 正在更新已渲染过的元素列表时它默认用“就地复用”策略。如果数据项的顺序被改变Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。这个类似 Vue 1.x 的 <code>track-by="$index"</code></p>
<p>这个默认的模式是高效的,但是只适用于<strong>不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出</strong></p>
<p>为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 <code>key</code> 属性。理想的 <code>key</code> 值是每项都有的唯一 id。这个特殊的属性相当于 Vue 1.x 的 <code>track-by</code> ,但它的工作方式类似于一个属性,所以你需要用 <code>v-bind</code> 来绑定动态值 (在这里使用简写)</p>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"item in items"</span> <span class="hljs-attr">:key</span>=<span class="hljs-string">"item.id"</span>&gt;</span>
<span class="hljs-comment">&lt;!-- 内容 --&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></code></pre>
<p>建议尽可能在使用 <code>v-for</code> 时提供 <code>key</code>,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。</p>
<p>因为它是 Vue 识别节点的一个通用机制,<code>key</code> 并不与 <code>v-for</code> 特别关联,<code>key</code> 还具有其他用途,我们将在后面的指南中看到其他用途。</p>
<p class="tip">不要使用对象或数组之类的非原始类型值作为 <code>v-for</code><code>key</code>。用字符串或数类型的值取而代之。</p>
<h2 id="数组更新检测"><a class="headerlink" href="#数组更新检测" title="数组更新检测"></a>数组更新检测</h2><h3 id="变异方法"><a class="headerlink" href="#变异方法" title="变异方法"></a>变异方法</h3><p>Vue 包含一组观察数组的变异方法,所以它们也将会触发视图更新。这些方法如下:</p>
<ul>
<li><code>push()</code></li>
<li><code>pop()</code></li>
<li><code>shift()</code></li>
<li><code>unshift()</code></li>
<li><code>splice()</code></li>
<li><code>sort()</code></li>
<li><code>reverse()</code></li>
</ul>
<p>你打开控制台,然后用前面例子的 <code>items</code> 数组调用变异方法:<code>example1.items.push({ message: 'Baz' })</code></p>
<h3 id="替换数组"><a class="headerlink" href="#替换数组" title="替换数组"></a>替换数组</h3><p>变异方法 (mutation method),顾名思义,会改变被这些方法调用的原始数组。相比之下,也有非变异 (non-mutating method) 方法,例如:<code>filter()</code>, <code>concat()</code><code>slice()</code> 。这些不会改变原始数组,但<strong>总是返回一个新数组</strong>。当使用非变异方法时,可以用新数组替换旧数组:</p>
<pre><code class="hljs js">example1.items = example1.items.filter(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">item</span>) </span>{
<span class="hljs-keyword">return</span> item.message.match(<span class="hljs-regexp">/Foo/</span>)
})</code></pre>
<p>你可能认为这将导致 Vue 丢弃现有 DOM 并重新渲染整个列表。幸运的是事实并非如此。Vue 为了使得 DOM 元素得到最大范围的重用而实现了一些智能的、启发式的方法,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。</p>
<h3 id="注意事项"><a class="headerlink" href="#注意事项" title="注意事项"></a>注意事项</h3><p>由于 JavaScript 的限制Vue 不能检测以下变动的数组:</p>
<ol>
<li>当你利用索引直接设置一个项时,例如:<code>vm.items[indexOfItem] = newValue</code></li>
<li>当你修改数组的长度时,例如:<code>vm.items.length = newLength</code></li>
</ol>
<p>举个例子:</p>
<pre><code class="hljs js"><span class="hljs-keyword">var</span> vm = <span class="hljs-keyword">new</span> Vue({
<span class="hljs-attr">data</span>: {
<span class="hljs-attr">items</span>: [<span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>, <span class="hljs-string">'c'</span>]
}
})
vm.items[<span class="hljs-number">1</span>] = <span class="hljs-string">'x'</span> <span class="hljs-comment">// 不是响应性的</span>
vm.items.length = <span class="hljs-number">2</span> <span class="hljs-comment">// 不是响应性的</span></code></pre>
<p>为了解决第一类问题,以下两种方式都可以实现和 <code>vm.items[indexOfItem] = newValue</code> 相同的效果,同时也将触发状态更新:</p>
<pre><code class="hljs js"><span class="hljs-comment">// Vue.set</span>
Vue.set(vm.items, indexOfItem, newValue)</code></pre>
<pre><code class="hljs js"><span class="hljs-comment">// Array.prototype.splice</span>
vm.items.splice(indexOfItem, <span class="hljs-number">1</span>, newValue)</code></pre>
<p>你也可以使用 <a href="https://vuejs.org/v2/api/#vm-set" rel="noopener" target="_blank"><code>vm.$set</code></a> 实例方法,该方法是全局方法 <code>Vue.set</code> 的一个别名:</p>
<pre><code class="hljs js">vm.$set(vm.items, indexOfItem, newValue)</code></pre>
<p>为了解决第二类问题,你可以使用 <code>splice</code></p>
<pre><code class="hljs js">vm.items.splice(newLength)</code></pre>
<h2 id="对象更改检测注意事项"><a class="headerlink" href="#对象更改检测注意事项" title="对象更改检测注意事项"></a>对象更改检测注意事项</h2><p>还是由于 JavaScript 的限制,<strong>Vue 不能检测对象属性的添加或删除</strong></p>
<pre><code class="hljs js"><span class="hljs-keyword">var</span> vm = <span class="hljs-keyword">new</span> Vue({
<span class="hljs-attr">data</span>: {
<span class="hljs-attr">a</span>: <span class="hljs-number">1</span>
}
})
<span class="hljs-comment">// `vm.a` 现在是响应式的</span>
vm.b = <span class="hljs-number">2</span>
<span class="hljs-comment">// `vm.b` 不是响应式的</span></code></pre>
<p>对于已经创建的实例Vue 不能动态添加根级别的响应式属性。但是,可以使用 <code>Vue.set(object, key, value)</code> 方法向嵌套对象添加响应式属性。例如,对于:</p>
<pre><code class="hljs js"><span class="hljs-keyword">var</span> vm = <span class="hljs-keyword">new</span> Vue({
<span class="hljs-attr">data</span>: {
<span class="hljs-attr">userProfile</span>: {
<span class="hljs-attr">name</span>: <span class="hljs-string">'Anika'</span>
}
}
})</code></pre>
<p>你可以添加一个新的 <code>age</code> 属性到嵌套的 <code>userProfile</code> 对象:</p>
<pre><code class="hljs js">Vue.set(vm.userProfile, <span class="hljs-string">'age'</span>, <span class="hljs-number">27</span>)</code></pre>
<p>你还可以使用 <code>vm.$set</code> 实例方法,它只是全局 <code>Vue.set</code> 的别名:</p>
<pre><code class="hljs js">vm.$set(vm.userProfile, <span class="hljs-string">'age'</span>, <span class="hljs-number">27</span>)</code></pre>
<p>有时你可能需要为已有对象赋予多个新属性,比如使用 <code>Object.assign()</code><code>_.extend()</code>。在这种情况下,你应该用两个对象的属性创建一个新的对象。所以,如果你想添加新的响应式属性,不要像这样:</p>
<pre><code class="hljs js"><span class="hljs-built_in">Object</span>.assign(vm.userProfile, {
<span class="hljs-attr">age</span>: <span class="hljs-number">27</span>,
<span class="hljs-attr">favoriteColor</span>: <span class="hljs-string">'Vue Green'</span>
})</code></pre>
<p>你应该这样做:</p>
<pre><code class="hljs js">vm.userProfile = <span class="hljs-built_in">Object</span>.assign({}, vm.userProfile, {
<span class="hljs-attr">age</span>: <span class="hljs-number">27</span>,
<span class="hljs-attr">favoriteColor</span>: <span class="hljs-string">'Vue Green'</span>
})</code></pre>
<h2 id="显示过滤-排序结果"><a class="headerlink" href="#显示过滤-排序结果" title="显示过滤/排序结果"></a>显示过滤/排序结果</h2><p>有时,我们想要显示一个数组的过滤或排序副本,而不实际改变或重置原始数据。在这种情况下,可以创建返回过滤或排序数组的计算属性。</p>
<p>例如:</p>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"n in evenNumbers"</span>&gt;</span>{{ n }}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></code></pre>
<pre><code class="hljs js">data: {
<span class="hljs-attr">numbers</span>: [ <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span> ]
},
<span class="hljs-attr">computed</span>: {
<span class="hljs-attr">evenNumbers</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.numbers.filter(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">number</span>) </span>{
<span class="hljs-keyword">return</span> number % <span class="hljs-number">2</span> === <span class="hljs-number">0</span>
})
}
}</code></pre>
<p>在计算属性不适用的情况下 (例如,在嵌套 <code>v-for</code> 循环中) 你可以使用一个 method 方法:</p>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"n in even(numbers)"</span>&gt;</span>{{ n }}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></code></pre>
<pre><code class="hljs js">data: {
<span class="hljs-attr">numbers</span>: [ <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span> ]
},
<span class="hljs-attr">methods</span>: {
<span class="hljs-attr">even</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">numbers</span>) </span>{
<span class="hljs-keyword">return</span> numbers.filter(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">number</span>) </span>{
<span class="hljs-keyword">return</span> number % <span class="hljs-number">2</span> === <span class="hljs-number">0</span>
})
}
}</code></pre>
<h2 id="一段取值范围的-v-for"><a class="headerlink" href="#一段取值范围的-v-for" title="一段取值范围的 v-for"></a>一段取值范围的 <code>v-for</code></h2><p><code>v-for</code> 也可以取整数。在这种情况下,它将重复多次模板。</p>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"n in 10"</span>&gt;</span>{{ n }} <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></code></pre>
<p>结果:</p>
<div class="demo" id="range">
<span v-for="n in 10">{{ n }} </span>
</div>
<script>
new Vue({ el: '#range' })
</script>
<h2 id="v-for-on-a-lt-template-gt"><a class="headerlink" href="#v-for-on-a-lt-template-gt" title="v-for on a &lt;template&gt;"></a><code>v-for</code> on a <code>&lt;template&gt;</code></h2><p>类似于 <code>v-if</code>,你也可以利用带有 <code>v-for</code><code>&lt;template&gt;</code> 渲染多个元素。比如:</p>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">template</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"item in items"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>{{ item.msg }}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"divider"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"presentation"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></code></pre>
<h2 id="v-for-with-v-if"><a class="headerlink" href="#v-for-with-v-if" title="v-for with v-if"></a><code>v-for</code> with <code>v-if</code></h2><p class="tip">注意我们<strong></strong>推荐同时使用 <code>v-if</code><code>v-for</code>。更多细节可查阅<a href="/v2/style-guide/#避免-v-if-和-v-for-用在一起-必要">风格指南</a></p>
<p>当它们处于同一节点,<code>v-for</code> 的优先级比 <code>v-if</code> 更高,这意味着 <code>v-if</code> 将分别重复运行于每个 <code>v-for</code> 循环中。当你想为仅有的<em>一些</em>项渲染节点时,这种优先级的机制会十分有用,如下:</p>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"todo in todos"</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"!todo.isComplete"</span>&gt;</span>
{{ todo }}
<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></code></pre>
<p>上面的代码只传递了未完成的 todos。</p>
<p>而如果你的目的是有条件地跳过循环的执行,那么可以将 <code>v-if</code> 置于外层元素 (或 <a href="conditional.html#在-lt-template-gt-中配合-v-if-条件渲染一整组"><code>&lt;template&gt;</code></a>)上。如:</p>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"todos.length"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"todo in todos"</span>&gt;</span>
{{ todo }}
<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">v-else</span>&gt;</span>No todos left!<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></code></pre>
<h2 id="一个组件的-v-for"><a class="headerlink" href="#一个组件的-v-for" title="一个组件的 v-for"></a>一个组件的 <code>v-for</code></h2><blockquote>
<p>了解组件相关知识,查看 <a href="components.html">组件</a>。完全可以先跳过它,以后再回来查看。</p>
</blockquote>
<p>在自定义组件里,你可以像任何普通元素一样用 <code>v-for</code></p>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">my-component</span> <span class="hljs-attr">v-for</span>=<span class="hljs-string">"item in items"</span> <span class="hljs-attr">:key</span>=<span class="hljs-string">"item.id"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">my-component</span>&gt;</span></code></pre>
<blockquote>
<p>2.2.0+ 的版本里,当在组件中使用 <code>v-for</code> 时,<code>key</code> 现在是必须的。</p>
</blockquote>
<p>然而,任何数据都不会被自动传递到组件里,因为组件有自己独立的作用域。为了把迭代数据传递到组件里,我们要用 <code>props</code> </p>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">my-component</span>
<span class="hljs-attr">v-for</span>=<span class="hljs-string">"(item, index) in items"</span>
<span class="hljs-attr">v-bind:item</span>=<span class="hljs-string">"item"</span>
<span class="hljs-attr">v-bind:index</span>=<span class="hljs-string">"index"</span>
<span class="hljs-attr">v-bind:key</span>=<span class="hljs-string">"item.id"</span>
&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">my-component</span>&gt;</span></code></pre>
<p>不自动将 <code>item</code> 注入到组件里的原因是,这会使得组件与 <code>v-for</code> 的运作紧密耦合。明确组件数据的来源能够使组件在其他场合重复使用。</p>
<p>下面是一个简单的 todo list 的完整例子:</p>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"todo-list-example"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">v-on:submit.prevent</span>=<span class="hljs-string">"addNewTodo"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"new-todo"</span>&gt;</span>Add a todo<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">input</span>
<span class="hljs-attr">v-model</span>=<span class="hljs-string">"newTodoText"</span>
<span class="hljs-attr">id</span>=<span class="hljs-string">"new-todo"</span>
<span class="hljs-attr">placeholder</span>=<span class="hljs-string">"E.g. Feed the cat"</span>
&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Add<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">li</span>
<span class="hljs-attr">is</span>=<span class="hljs-string">"todo-item"</span>
<span class="hljs-attr">v-for</span>=<span class="hljs-string">"(todo, index) in todos"</span>
<span class="hljs-attr">v-bind:key</span>=<span class="hljs-string">"todo.id"</span>
<span class="hljs-attr">v-bind:title</span>=<span class="hljs-string">"todo.title"</span>
<span class="hljs-attr">v-on:remove</span>=<span class="hljs-string">"todos.splice(index, 1)"</span>
&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></code></pre>
<p class="tip">注意这里的 <code>is="todo-item"</code> 属性。这种做法在使用 DOM 模板时是十分必要的,因为在 <code>&lt;ul&gt;</code> 元素内只有 <code>&lt;li&gt;</code> 元素会被看作有效内容。这样做实现的效果与 <code>&lt;todo-item&gt;</code> 相同,但是可以避开一些潜在的浏览器解析错误。查看 <a href="components.html#解析-DOM-模板时的注意事项">DOM 模板解析说明</a> 来了解更多信息。</p>
<pre><code class="hljs js">Vue.component(<span class="hljs-string">'todo-item'</span>, {
<span class="hljs-attr">template</span>: <span class="hljs-string">'\
&lt;li&gt;\
{{ title }}\
&lt;button v-on:click="$emit(\'remove\')"&gt;Remove&lt;/button&gt;\
&lt;/li&gt;\
'</span>,
<span class="hljs-attr">props</span>: [<span class="hljs-string">'title'</span>]
})
<span class="hljs-keyword">new</span> Vue({
<span class="hljs-attr">el</span>: <span class="hljs-string">'#todo-list-example'</span>,
<span class="hljs-attr">data</span>: {
<span class="hljs-attr">newTodoText</span>: <span class="hljs-string">''</span>,
<span class="hljs-attr">todos</span>: [
{
<span class="hljs-attr">id</span>: <span class="hljs-number">1</span>,
<span class="hljs-attr">title</span>: <span class="hljs-string">'Do the dishes'</span>,
},
{
<span class="hljs-attr">id</span>: <span class="hljs-number">2</span>,
<span class="hljs-attr">title</span>: <span class="hljs-string">'Take out the trash'</span>,
},
{
<span class="hljs-attr">id</span>: <span class="hljs-number">3</span>,
<span class="hljs-attr">title</span>: <span class="hljs-string">'Mow the lawn'</span>
}
],
<span class="hljs-attr">nextTodoId</span>: <span class="hljs-number">4</span>
},
<span class="hljs-attr">methods</span>: {
<span class="hljs-attr">addNewTodo</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
<span class="hljs-keyword">this</span>.todos.push({
<span class="hljs-attr">id</span>: <span class="hljs-keyword">this</span>.nextTodoId++,
<span class="hljs-attr">title</span>: <span class="hljs-keyword">this</span>.newTodoText
})
<span class="hljs-keyword">this</span>.newTodoText = <span class="hljs-string">''</span>
}
}
})</code></pre>
<div class="demo" id="todo-list-example">
<form v-on:submit.prevent="addNewTodo">
<label for="new-todo">Add a todo</label>
<input id="new-todo" placeholder="E.g. Feed the cat" v-model="newTodoText"/>
<button>Add</button>
</form>
<ul>
<li is="todo-item" v-bind:key="todo.id" v-bind:title="todo.title" v-for="(todo, index) in todos" v-on:remove="todos.splice(index, 1)"></li>
</ul>
</div>
<script>
Vue.component('todo-item', {
template: '\
<li>\
{{ title }}\
<button v-on:click="$emit(\'remove\')">Remove</button>\
</li>\
',
props: ['title']
})
new Vue({
el: '#todo-list-example',
data: {
newTodoText: '',
todos: [
{
id: 1,
title: 'Do the dishes',
},
{
id: 2,
title: 'Take out the trash',
},
{
id: 3,
title: 'Mow the lawn'
}
],
nextTodoId: 4
},
methods: {
addNewTodo: function () {
this.todos.push({
id: this.nextTodoId++,
title: this.newTodoText
})
this.newTodoText = ''
}
}
})
</script>
<div class="guide-links">
<span><a href="conditional.html">条件渲染</a></span>
<span style="float: right;"><a href="events.html">事件处理</a></span>
</div>
<div class="footer">
<script src="//m.servedby-buysellads.com/monetization.js" type="text/javascript"></script>
<div class="bsa-cpc"></div>
<script>
(function(){
if(typeof _bsa !== 'undefined' && _bsa) {
_bsa.init('default', 'CKYD62QM', 'placement:vuejsorg', {
target: '.bsa-cpc',
align: 'horizontal',
disable_css: 'true'
});
}
})();
</script>
发现错误?想参与编辑?
<a href="https://github.com/vuejs/cn.vuejs.org/blob/master/srclist.md" target="_blank">
在 GitHub 上编辑此页!
</a>
</div>
</div>