Skip to content
On this page

条件渲染与列表渲染

条件渲染

条件渲染是Vue.js中根据条件来决定是否渲染特定元素的功能。Vue.js提供了v-ifv-elsev-else-ifv-show等指令来实现条件渲染。

v-if 指令

v-if指令用于条件性地渲染一块内容,只有当指令表达式的值为真值时才渲染该内容。

vue
<template>
  <div>
    <h1 v-if="awesome">Vue is awesome!</h1>
    <p v-else>Oh no 😢</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      awesome: true
    }
  }
}
</script>

v-else 和 v-else-if 指令

v-else元素必须紧跟在v-ifv-else-if元素的后面,否则它将不会被识别。v-else-if提供了一个"else if 块"的条件渲染。

vue
<template>
  <div>
    <div v-if="type === 'A'">
      A
    </div>
    <div v-else-if="type === 'B'">
      B
    </div>
    <div v-else-if="type === 'C'">
      C
    </div>
    <div v-else>
      Not A/B/C
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      type: 'A'
    }
  }
}
</script>

v-show 指令

v-show指令与v-if类似,也是根据条件展示元素,但不同的是带有v-show的元素始终会被渲染并保留在DOM中。

vue
<template>
  <div>
    <h1 v-show="ok">Hello!</h1>
  </div>
</template>

<script>
export default {
  data() {
    return {
      ok: true
    }
  }
}
</script>

v-if 与 v-show 的区别

  • v-if是真正的条件渲染,因为它会确保在切换的过程中条件块内的事件监听器和子组件适当地被销毁和重建
  • v-if是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块
  • v-show不管初始条件是什么,元素总是会被渲染,并且只是简单地基于CSS进行切换

使用 key 管理可复用的元素

Vue会尽可能高效地渲染元素,通常会复用相同类型的元素而不是从头开始创建。为了给Vue一个提示,让其知道两个元素是不同的,需要使用key属性。

vue
<template>
  <div>
    <template v-if="loginType === 'username'">
      <label>Username</label>
      <input placeholder="Enter your username" key="username-input">
    </template>
    <template v-else>
      <label>Email</label>
      <input placeholder="Enter your email" key="email-input">
    </template>
  </div>
</template>

<script>
export default {
  data() {
    return {
      loginType: 'username'
    }
  }
}
</script>

列表渲染

列表渲染是Vue.js中用于渲染数组或对象列表的功能,主要使用v-for指令。

基于数组的列表渲染

我们可以使用v-for指令基于一个数组来渲染一个列表。v-for指令需要使用item in items形式的特殊语法。

vue
<template>
  <ul>
    <li v-for="item in items" :key="item.id">
      {{ item.message }}
    </li>
  </ul>
</template>

<script>
export default {
  data() {
    return {
      items: [
        { id: 1, message: 'Foo' },
        { id: 2, message: 'Bar' }
      ]
    }
  }
}
</script>

v-for中,还可以访问元素的索引:

vue
<template>
  <ul>
    <li v-for="(item, index) in items" :key="item.id">
      {{ index }} - {{ item.message }}
    </li>
  </ul>
</template>

使用范围值的 v-for

v-for也可以接收一个整数,它会把模板重复多次。

vue
<template>
  <div>
    <span v-for="n in 10" :key="n">{{ n }} </span>
  </div>
</template>

在组件上使用 v-for

在自定义组件上使用v-for时,需要提供一个key属性。

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

基于对象的列表渲染

v-for可以遍历对象的属性。

vue
<template>
  <ul>
    <li v-for="(value, key) in object" :key="key">
      {{ key }}: {{ value }}
    </li>
  </ul>
</template>

<script>
export default {
  data() {
    return {
      object: {
        title: 'How to do lists in Vue',
        author: 'Jane Doe',
        publishedAt: '2021-04-10'
      }
    }
  }
}
</script>
</template>

还可以访问属性的索引:

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

维护状态与 v-for

Vue在渲染列表时使用"就地更新"的策略,这意味着如果列表项的顺序改变,Vue会就地更新每个元素而不是移动DOM元素来匹配列表项的顺序。为了给Vue一个提示,让其知道每个节点的身份,需要为每个列表项提供一个唯一的key属性。

vue
<template>
  <div>
    <input v-for="item in list" :key="item.id" :placeholder="`Item ${item.id}`">
    <button @click="reverseList">Reverse List</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      list: [
        { id: 1, name: 'Alice' },
        { id: 2, name: 'Bob' },
        { id: 3, name: 'Charlie' }
      ]
    }
  },
  methods: {
    reverseList() {
      this.list.reverse()
    }
  }
}
</script>

数组变化检测

Vue可以检测到以下数组变化方法,并触发视图更新:

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

Vue还提供了替换数组的方法,这些方法不会改变原数组,而是返回一个新的数组:

  • filter()
  • concat()
  • slice()
vue
<template>
  <div>
    <button @click="addItem">Add Item</button>
    <button @click="removeItem">Remove Item</button>
    <ul>
      <li v-for="item in items" :key="item.id">
        {{ item.name }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      items: [
        { id: 1, name: 'Apple' },
        { id: 2, name: 'Banana' }
      ]
    }
  },
  methods: {
    addItem() {
      this.items.push({ id: Date.now(), name: 'Orange' })
    },
    removeItem() {
      this.items.pop()
    }
  }
}
</script>

过滤和排序结果

有时我们想要显示一个数组经过过滤或排序后的结果,而不实际改变或重置原始数据。在这种情况下,我们可以创建一个计算属性来返回过滤或排序后的数组。

vue
<template>
  <div>
    <input v-model="query" placeholder="Search">
    <ul>
      <li v-for="user in filteredUsers" :key="user.id">
        {{ user.name }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      query: '',
      users: [
        { id: 1, name: 'Alice' },
        { id: 2, name: 'Bob' },
        { id: 3, name: 'Charlie' },
        { id: 4, name: 'David' }
      ]
    }
  },
  computed: {
    filteredUsers() {
      if (!this.query) {
        return this.users
      }
      return this.users.filter(user => {
        return user.name.toLowerCase().includes(this.query.toLowerCase())
      })
    }
  }
}
</script>

实际应用示例

列表渲染与条件渲染结合使用

vue
<template>
  <div>
    <div v-if="!items.length" class="empty-state">
      <p>No items available.</p>
    </div>
    <ul v-else>
      <li 
        v-for="item in items" 
        :key="item.id" 
        :class="{ active: item.active }"
      >
        <span v-if="item.status === 'active'" class="status-indicator active"></span>
        <span v-else-if="item.status === 'inactive'" class="status-indicator inactive"></span>
        <span v-else class="status-indicator pending"></span>
        <span>{{ item.name }}</span>
        <button @click="toggleActive(item)">Toggle</button>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      items: [
        { id: 1, name: 'Item 1', status: 'active', active: true },
        { id: 2, name: 'Item 2', status: 'inactive', active: false },
        { id: 3, name: 'Item 3', status: 'pending', active: false }
      ]
    }
  },
  methods: {
    toggleActive(item) {
      item.active = !item.active
    }
  }
}
</script>

<style>
.status-indicator {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  margin-right: 8px;
}
.status-indicator.active { background-color: green; }
.status-indicator.inactive { background-color: red; }
.status-indicator.pending { background-color: yellow; }
</style>

性能优化建议

  1. 始终为v-for提供key属性,以提高渲染效率
  2. 避免在v-for中使用复杂的计算表达式,使用计算属性替代
  3. 对于大型列表,考虑使用虚拟滚动技术
  4. 合理使用v-showv-if,根据实际需求选择合适的条件渲染方式

通过合理使用条件渲染和列表渲染,可以构建出动态且交互性强的用户界面。