谨慎使用深度监听

这在用于大型数据结构时性能消耗较大,仅在必要时使用。

export default {
  watch: {
    someObject: {
      handler(newValue, oldValue) {
      },
      deep: true
    }
  }
}

善于使用 KeepAlive

尤其是配合动态组件时使用,使常用组件进行缓存,减少组件创建与卸载,提高响应速度与资源利用率。

<KeepAlive :include="/a|b/"> <!-- 表示仅缓存name为a或b的组件 -->
  <component :is="view" />
</KeepAlive>

props与emit验证

对props和emits进行必要的验证,提高数据准确性,减小组件因为数据而出错。

export default {
  props: {
    // Basic type check
    //  (`null` and `undefined` values will allow any type)
    propA: Number,
    // Multiple possible types
    propB: [String, Number],
    // Required string
    propC: {
      type: String,
      required: true
    },
    // Number with a default value
    propD: {
      type: Number,
      default: 100
    },
    // Object with a default value
    propE: {
      type: Object,
      // Object or array defaults must be returned from
      // a factory function. The function receives the raw
      // props received by the component as the argument.
      default(rawProps) {
        // default function receives the raw props object as argument
        return { message: 'hello' }
      }
    },
    // Custom validator function
    propF: {
      validator(value) {
        // The value must match one of these strings
        return ['success', 'warning', 'danger'].includes(value)
      }
    },
    // Function with a default value
    propG: {
      type: Function,
      // Unlike object or array default, this is not a factory function - this is a function to serve as a default value
      default() {
        return 'Default function'
      }
    }
  }
}

减小项目体积

使用Componsition API开发,将vue的方法按需引入,以免在打包时将未用到的API打包进去。

import { ref, onMounted, onUnmounted } from 'vue'

provide和inject

使用provideinject解决数据多级传递问题,如果数据仅在多层嵌套的父子级组件中使用,那么就不用麻烦Vuex。

// 在上级组件中使用provide将数据传下去
export default {
  data() {
    return {
      message: 'hello!'
    }
  },
  provide() {
    // use function syntax so that we can access `this`
    return {
      message: this.message
    }
  }
}
// 在下级组件中使用inject接收数据
export default {
  inject: ['message'], // 可以使用别名,定义默认值
  data() {
    return {
      fullMessage: this.message
    }
  }
}

善用异步加载

使用defineAsyncComponent异步加载仅在需要时才会加载的组件。可配合router使用,提高首屏渲染速度。

import { defineAsyncComponent } from 'vue'

export default {
  // ...
  components: {
    AsyncComponent: defineAsyncComponent(() =>
      import('./components/AsyncComponent.vue')
    )
  }
}

“慎用”Vuex

不要为了使用Vuex而使用Vuex,能在组件内解决的问题就不要麻烦Vuex。Vuex中的数据需要绑定更多的依赖,所以Vuex中的数据越少越好。

功能重用

将可重用的功能处理逻辑使用Componsition API的形式单独封装起来,然后按需使用。

比如鼠标位置显示功能:

// 功能封装  mouse.js
import { ref, onMounted, onUnmounted } from 'vue'

export function useMouse() {
  const x = ref(0)
  const y = ref(0)

  function update(event) {
    x.value = event.pageX
    y.value = event.pageY
  }

  onMounted(() => window.addEventListener('mousemove', update))
  onUnmounted(() => window.removeEventListener('mousemove', update))

  return { x, y }
}
// 使用
<script setup>
import { useMouse } from './mouse.js'

const { x, y } = useMouse()
</script>

<template>Mouse position is at: {{ x }}, {{ y }}</template>

仅传递必要的数据

向子组件传值时仅传递必要的值,减小数据传递的代价,也避免了不必要的更新。

<!-- bad -->
<template>
  <myComponent :msgObj="msgObj" />
</template>

<script>
  import { reactive } from 'vue'
  export default {
    components: { myComponent },
    setup() {
        const mstObj = reactive({
            name: 'wei',
            age: '22',
            data: '2022.05.08',
            // ...
        })

        return {
            msgObj
        }
    }
  };
</script>
<!-- good -->
<template>
  <myComponent 
    :name="msgObj.name" 
    :age="msgObj.age"
  />
</template>

<script>
  import { reactive } from 'vue'
  export default {
    components: { myComponent },
    setup() {
        const mstObj = reactive({
            name: 'wei',
            age: '22',
            data: '2022.05.08',
            // ...
        })

        return {
            msgObj
        }
    }
  };
</script>

设计模块分类

在设计之初就将模块进行分类,实时渲染、延迟渲染、缓存机制等分类,有利于推断系统的运行过程,且后续开发时每个组件也有自己的定位,知道自己应该什么时候渲染,是否有直接渲染的优先级。

SSR/SSG

SSR/SSG渲染速度会更快,但其都有自己的缺点,要结合实际情况进行取舍使用。

v-for优化

使用v-for时,要考虑如何编写语法才能最小化列表更新代价。

<!-- bad -->
<ListItem
  v-for="item in list"
  :id="item.id"
  :active-id="activeId" />
<!-- good -->
<ListItem
  v-for="item in list"
  :id="item.id"
  :active="item.id === activeId" />

且对于经常变动的列表,要善于使用key来对每一个元素进行标记,这有利于diff算法的比较。

善用v-once

将使用了响应式数据但无需更新的元素添加v-once标签来避免不必要的DOM更新渲染。

<!-- single element -->
<span v-once>This will never change: {{msg}}</span>
<!-- the element have children -->
<div v-once>
  <h1>comment</h1>
  <p>{{msg}}</p>
</div>
<!-- component -->
<my-component v-once :comment="msg"></my-component>
<!-- `v-for` directive -->
<ul>
  <li v-for="i in list" v-once>{{i}}</li>
</ul>

列表虚拟化

使用列表虚拟化的方法来渲染大型列表:vue-virtual-scrollervue-virtual-scroll-grid

非反应性

减少大型不可变结构的反应性开销,灵活运用shallowRef()shallowReactive()来创建浅反应式数据。

const state = shallowRef({ count: 1 })

// does NOT trigger change
state.value.count = 2

// does trigger change
state.value = { count: 2 }

减少组件

避免不必要的组件抽象,因为组件实例比DOM节点昂贵的多。

避免内存泄漏

  1. 避免意外的全局变量
  2. 避免使用不当的闭包
  3. 及时清除定时器与不用的数据,一般会在unMounted中执行
Logo

前往低代码交流专区

更多推荐