列表渲染——Vue.js

1. v-for循环遍历数组

(1)v-for 指令需要使用 item in items 形式的特殊语法

    
  • {{ item.message }}

注意写法:

v-for是在li标签上(li标签是要展示数据的标签)

数组items在data中,items是数组,每项是对象

使用数据的时候是mustache语法

(2)在 v-for 块中,我们拥有对父作用域属性的完全访问权限。v-for 还支持一个可选的第二个参数为当前项的索引。

    
  • {{ parentMessage }} - {{ index }} - {{ item.message }}

结果:

注意:父级作用域就是data中的其他数据,index是当前索引值,是一个可选的参数,item、items和index都是自定义的,注意他们是如何申明的。

注意:两个参数时,写在()中

注意:可用of代替in

2. v-for循环遍历对象

    
  • {{ value }}

注意:遍历的对象直接写在data中;new Vue没有赋值给变量

(2)第二个的参数为键名

    
  • {{key}} : {{ value }}

结果:

(3)第三个参数为索引

{{ index }}. {{ key }}: {{ value }}

注意:在遍历对象时,是按 Object.keys() 的结果遍历,但是不能保证它的结果在不同的 JavaScript 引擎下是一致的。

问:Object.keys()是什么,哪些js引擎不支持???

Object.keys 返回一个所有元素为字符串的数组,其元素来自于从给定的object上面可直接枚举的属性。这些属性的顺序与手动遍历该对象属性时的一致。

举例:

// simple array
var arr = ['a', 'b', 'c'];
console.log(Object.keys(arr)); // console: ['0', '1', '2']

// array like object
var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.keys(obj)); // console: ['0', '1', '2']

// array like object with random key ordering
var anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.keys(anObj)); // console: ['2', '7', '100']

// getFoo is a property which isn't enumerable
var myObj = Object.create({}, {
  getFoo: {
    value: function () { return this.foo; }
  } 
});
myObj.foo = 1;
console.log(Object.keys(myObj)); // console: ['foo']

 当是对象的时候,若属性名(key值)是数字时,系统会根据对象内的属性名的数值自动进行排序,调用该Object.keys(obj)方法时,得到的得到由key值组成的数组是按顺序排列的

系统会根据对象的属性进行排序:

列表渲染——Vue.js_第1张图片

执行Object.keys(obj)时:

3. key

当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出

为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。理想的 key 值是每项都有的唯一 id。你需要用 v-bind 来绑定动态值 (在这里使用简写):

建议尽可能在使用 v-for 时提供 key,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。

因为它是 Vue 识别节点的一个通用机制,key 并不与 v-for 特别关联,key 还具有其他用途,我们将在后面的指南中看到其他用途。

4. 数组

(1)变异方法(mutation method)变异方法对数据的操作是响应式的

 

Vue 包含一组观察数组的变异方法,方法如下:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

你打开控制台,然后用前面例子的 items 数组调用变异方法:example1.items.push({ message: 'Baz' }) 

(2)非变异方法(non-mutation method)非变异方法对数据的操作不是响应式的,但可以通过改变数组地址的方式,响应式改变数据。比如:filter()concat() 和 slice() 。这些不会改变原始数组,但总是返回一个新数组

当使用非变异方法时,可以用新数组替换旧数组:

example1.items = example1.items.filter(function (item) {
  return item.message.match(/Foo/)
})

变异方法是数组的索引地址发生了改变,在新的索引地址里,有新的数据。通过这个原理,我们可以直接用vm.items= 新数组来改变数组的索引,使得页面响应式变化。

注意:由于 JavaScript 的限制,Vue 不能检测以下变动的数组:

  1. 当你利用索引直接设置或修改一个项时,例如:vm.items[indexOfItem] = newValue(数组内的部分内容发生改变时,索引地址没有改变,而如果数组索引地址发生改变,页面内容就会响应式发生变化)
  2. 当你修改数组的长度时,例如:vm.items.length = newLength

下面例子中对数组的改变不是响应式的:(数据其实发生了变化,但是页面没有响应式的渲染)

var vm = new Vue({
  data: {
    items: ['a', 'b', 'c']
  }
})
vm.items[1] = 'x' // 不是响应性的
vm.items.length = 2 // 不是响应性的

(1)为了解决vm.items[indexOfItem] = newValue 不是响应式的,下面有两种方法:

方法一:Vue.set(vm.items, indexOfItem, newValue)  // Vue.set

方法二:vm.items.splice(indexOfItem, 1, newValue)  // Array.prototype.splice

也可以使用 vm.$set 实例方法,该方法是全局方法 Vue.set 的一个别名:

vm.$set(vm.items, indexOfItem, newValue)

列表渲染——Vue.js_第2张图片

(2)了解决vm.items.length = newLength,可以使用 splice

vm.items.splice(newLength)

 

补充:对多个标签进行循环,需要用template标签(该标签的作用是不在浏览器中渲染)

    

列表渲染——Vue.js_第3张图片

注意::key不能放在template标签上;也不能在template的子标签中都放入key,只在一个标签中放入key即可。

理由???对key的理解

5. 对象

还是由于 JavaScript 的限制,Vue 不能检测对象属性的添加或删除

下面例子中,vm.b = 2 不是响应式的添加

var vm = new Vue({
  data: {
    a: 1
  }
})
// `vm.a` 现在是响应式的

vm.b = 2
// `vm.b` 不是响应式的

 注意:对于已经创建的实例,Vue 不能动态添加根级别的响应式属性(什么是根级别?)

但是,可以使用 Vue.set(object, key, value) 方法向嵌套对象添加响应式属性

比如:添加一个新的 age 属性到嵌套的 userProfile 对象

    
  • {{key}} : {{ value }}

结果:

  • name : Anika

当在控制台中输入代码:Vue.set(vm.userProfile, 'age', 27)

结果:响应式的生成了一条新的数据

  • name : Anika
  • age : 27

当然也可以用vm.$set,set的实例方法

列表渲染——Vue.js_第4张图片

(2)给对象赋值多个属性

使用 Object.assign() 或 _.extend(),用两个对象的属性创建一个新的对象

vm.userProfile = Object.assign({}, vm.userProfile, {
  age: 27,
  favoriteColor: 'Vue Green'
})

注意:空对象{}, 对象vm.userProfile,新属性组成的对象

(3)可以修改对象的引用地址,userProfile执行一个新的地址,即新的对象{}

但是要注意:对对象属性值的修改,可以直接操作,vm.userProfile.name = 'zhu',这是响应式的

 

6. filter

过滤数据数据,而不是改变数组

    
  • {{ n }}

结构分析:计算属性computed中定义一个函数,该函数返回结果是:由数组numbers操作得到的新的数组;li标签中用v-for指令,用item in items语法,对数组进行循环遍历。

如果计算属性不适合,可以用一个方法:

    
  • {{ n }}

结构解析:methods对象中,定义一个even方法,该方法需要传入参数numbers,将数组numbers的操作得到的新数组返回给函数even,要注意在li标签中v-for循环遍历时,items的写法,even(numbers)

7.  v-for中的items可以是整数

  • {{ n }}

结果:

  • 1
  • 2
  • 3
  • 4
  • 5

8. v-for在组件中的使用

新版版中,在组件中使用v-for时,必须使用key

注意:数据不会自动传到组件中,因为组件有自己独立的作用域,这样也可以让同一组件在其他场合多次使用(复用性)。

手动传值到组件中:

demo:

    

结果:

列表渲染——Vue.js_第5张图片

对该demo解析:label标签中的for是与input的id对应的;注意is="todo-item" 属性,在使用 DOM 模板时十分必要的,因为在 

     元素内只有 
  •  元素会被看作有效内容,这样做实现的效果与  相同,但是可以避开一些潜在的浏览器解析错误;li标签中的v-for是循环遍历;v-bind:key,key必须结合v-for使用,值是item.id;v-bind:title类似于key(也必须存在吗?);v-on:remove也是一个指令,移除指令

    Vue.compenont中的todo-itme是组件的名字,使用的时候是用名字标签表示该组件;template是组件的html内容,在这里的这种写法是es6的写法;props是外部往组件中传入值;在vm对象中添加了一个方法addNewTodo,作用是往todos数组中添加值,而this.newTodoText = '',添加值的默认值是空。

    9. v-for和v-if处于同一节点,v-for 的优先级比 v-if 更高,这意味着 v-if 将分别重复运行于每个 v-for 循环中,跳过某次循环或者不跳过某次循环

  • {{ todo }}
  • 而如果你的目的是有条件地跳过循环的执行,那么可以将 v-if 置于外层元素 (或