面试题答案
一键面试- 使用
key
属性:- 给列表项添加唯一的
key
值,Vue 会基于key
来判断列表项是否变化,从而复用和更新已有元素,而不是重新创建。例如:
<template> <ul> <li v - for="(item, index) in list" :key="item.id">{{item.name}}</li> </ul> </template> <script> export default { data() { return { list: [ {id: 1, name: 'item1'}, {id: 2, name: 'item2'} ] }; } }; </script>
- 给列表项添加唯一的
- 计算属性和侦听器:
- 计算属性:如果组件中有一些依赖于其他数据的派生数据,可以使用计算属性。计算属性会基于它的依赖进行缓存,只有依赖变化时才会重新计算。例如,假设列表项有一个总数计算:
<template> <div> <p>Total items: {{ total }}</p> <ul> <li v - for="(item, index) in list" :key="item.id">{{item.name}}</li> </ul> </div> </template> <script> export default { data() { return { list: [ {id: 1, name: 'item1'}, {id: 2, name: 'item2'} ] }; }, computed: { total() { return this.list.length; } } }; </script>
- 侦听器:当需要在数据变化时执行异步操作或开销较大的操作时,可以使用侦听器,并通过
deep
选项来控制深度监听。例如,监听列表中某个对象的属性变化:
<template> <div> <ul> <li v - for="(item, index) in list" :key="item.id"> <input v - model="item.value" /> </li> </ul> </div> </template> <script> export default { data() { return { list: [ {id: 1, value: 'val1'}, {id: 2, value: 'val2'} ] }; }, watch: { list: { deep: true, handler(newVal, oldVal) { // 只有真正数据变化时才执行这里的逻辑,而不是每次都触发 console.log('list has changed'); } } } }; </script>
- Vue.mixin:
- 可以通过
Vue.mixin
来提取公共逻辑,减少组件中重复代码,从而可能优化性能。例如,提取列表项数据处理的公共逻辑:
const myMixin = { methods: { updateListItem(newData) { // 公共的更新列表项逻辑 const index = this.list.findIndex(item => item.id === newData.id); if (index!== -1) { this.list[index] = newData; } } } }; Vue.mixin(myMixin);
- 可以通过
- 组件拆分:
- 将大组件拆分成多个小组件,每个小组件只处理自己相关的数据。这样当某个列表项数据变化时,只会触发相关小组件的更新,而不是整个大组件。例如,将列表项单独封装成一个组件:
<!-- ListItem.vue --> <template> <li>{{item.name}}</li> </template> <script> export default { props: { item: { type: Object, required: true } } }; </script>
<!-- ParentComponent.vue --> <template> <ul> <ListItem v - for="(item, index) in list" :key="item.id" :item="item" /> </ul> </template> <script> import ListItem from './ListItem.vue'; export default { components: { ListItem }, data() { return { list: [ {id: 1, name: 'item1'}, {id: 2, name: 'item2'} ] }; } }; </script>
- 使用
shouldComponentUpdate
:- 在 Vue 2 中,可以通过在组件中定义
shouldComponentUpdate
方法来控制组件是否需要更新。例如:
<template> <div> <ul> <li v - for="(item, index) in list" :key="item.id">{{item.name}}</li> </ul> </div> </template> <script> export default { data() { return { list: [ {id: 1, name: 'item1'}, {id: 2, name: 'item2'} ] }; }, shouldComponentUpdate(nextProps, nextState) { // 这里可以通过比较当前数据和新数据来决定是否更新 return this.list!== nextProps.list || this.someOtherData!== nextState.someOtherData; } }; </script>
- 在 Vue 3 中,
shouldComponentUpdate
被移除,取而代之的是使用watchEffect
和computed
等更细粒度的响应式控制来达到类似效果。例如,使用watchEffect
来监听特定数据变化:
<template> <div> <ul> <li v - for="(item, index) in list" :key="item.id">{{item.name}}</li> </ul> </div> </template> <script setup> import {ref, watchEffect} from 'vue'; const list = ref([ {id: 1, name: 'item1'}, {id: 2, name: 'item2'} ]); watchEffect(() => { // 这里只对list数据变化做出响应,避免不必要的重渲染 console.log('list has changed'); }); </script>
- 在 Vue 2 中,可以通过在组件中定义
- 虚拟 DOM 优化:
- 虽然 Vue 本身已经基于虚拟 DOM 进行了优化,但合理组织数据和结构可以进一步提升虚拟 DOM 的比对效率。例如,避免在列表项中嵌套过多复杂的结构和动态绑定,保持数据结构的简洁,这样虚拟 DOM 在比对变化时可以更快地确定需要更新的部分。