列表渲染——Vue.js

1. v-for循环遍历数组

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

    <ul 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' }
                ]
            }
        })  
    </script>

注意写法:

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

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

使用数据的时候是mustache语法

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

    <ul 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' }
          ]
        }
      })
    </script>

结果:

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

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

注意:可用of代替in

2. v-for循环遍历对象

    <ul id="v-for-object" class="demo">
        <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>

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

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

    <ul id="v-for-object" class="demo">
        <li v-for="(value,key) in object">
         {{key}} : {{ value }}
        </li>
      </ul>
    <script>
     new Vue({
        el: '#v-for-object',
        data: {
          object: {
            firstName: 'John',
            lastName: 'Doe',
            age: 30
          }
        }
      })
    </script>

结果:

(3)第三个参数为索引

<div v-for="(value, key, index) in object">
  {{ index }}. {{ key }}: {{ value }}
</div>

注意:在遍历对象时,是按 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值组成的数组是按顺序排列的

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

执行Object.keys(obj)时:

3. key

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

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

<div v-for="item in items" :key="item.id">
  <!-- 内容 -->
</div>

建议尽可能在使用 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)

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

vm.items.splice(newLength)

 

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

    <div id="app">
        <template v-for="item of arr">
            <span :key="item.id">{{item.id}}</span>
            <div>{{item.name}}————{{item.age}}</div>    
        </template>
    </div>
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                arr: [
                    {
                        id: '0001',
                        name: 'zhu',
                        age: 22
                    },
                    {
                        id: '0002',
                        name: 'li',
                        age: 21
                    },
                    {
                        id: '0003',
                        name: 'xu',
                        age: 21
                    }
                ]
            },
        })
    </script>

注意::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 对象

    <ul id="v-for-object" class="demo">
        <li v-for="(value,key) in userProfile">
         {{key}} : {{ value }}
        </li>
      </ul>
    <script>
     var vm = new Vue({
        el: '#v-for-object',
        data: {
          userProfile: {
            name: 'Anika'
          }
        }
      })
    </script>

结果:

  • name : Anika

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

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

  • name : Anika
  • age : 27

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

(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

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

    <ul id="demo">
        <li v-for="n in evenNumbers">{{ n }}</li>
    </ul>

    <script>
        new Vue({
            el: "#demo",
            data: {
                numbers: [1, 2, 3, 4, 5]
            },
            computed: {
                evenNumbers: function () {
                    return this.numbers.filter(function (number) {
                        return number % 2 === 0
                    })
                }
            }
        })
    </script>

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

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

    <ul id="demo">
        <li v-for="n in even(numbers)">{{ n }}</li>
    </ul>

    <script>
        new Vue({
            el: "#demo",
            data: {
                numbers: [ 1, 2, 3, 4, 5 ]
              },
              methods: {
                even: function (numbers) {
                  return numbers.filter(function (number) {
                    return number % 2 === 0
                  })
                }
              }
        })
    </script>

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

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

<ul id="demo">
     <li v-for="n in 5">{{ n }}</li>
</ul>

结果:

  • 1
  • 2
  • 3
  • 4
  • 5

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

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

<my-component v-for="item in items" :key="item.id"></my-component>

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

手动传值到组件中:
<my-component v-for="(item, index) in items" v-bind:item="item" v-bind:index="index" v-bind:key="item.id" ></my-component>

demo:

    <div id="todo-list-example">
        <form v-on:submit.prevent="addNewTodo">
            <label for="new-todo">Add a todo</label>
            <input v-model="newTodoText" id="new-todo" placeholder="E.g. Feed the cat">
            <button>Add</button>
        </form>
        <ul>
            <li is="todo-item" v-for="(todo, index) in todos" v-bind:key="todo.id" v-bind:title="todo.title" 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>

结果:

对该demo解析:label标签中的for是与input的id对应的;注意is="todo-item" 属性,在使用 DOM 模板时十分必要的,因为在 <ul> 元素内只有 <li> 元素会被看作有效内容,这样做实现的效果与 <todo-item> 相同,但是可以避开一些潜在的浏览器解析错误;li标签中的v-for是循环遍历;v-bind:key,key必须结合v-for使用,值是item.id;v-bind:title类似于key(也必须存在吗?);v-on:remove也是一个指令,移除指令

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

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

<li v-for="todo in todos" v-if="!todo.isComplete">
  {{ todo }}
</li>

而如果你的目的是有条件地跳过循环的执行,那么可以将 v-if 置于外层元素 (或 <template>)上。跳过整个循环或者不跳过整个循环。如

<ul v-if="todos.length">
  <li v-for="todo in todos">
    {{ todo }}
  </li>
</ul>
<p v-else>No todos left!</p>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值