Skip to content

vue3

  • 在vue3中也有一些注意点,可以避免一些bug和一些性能问题
  • 封装方法和组件的时候,秉承复杂封装,简单调用的原则。

shallowRef

vue
<script lang="ts" setup>
import { onMounted, shallowRef } from 'vue'

const chartRef = ref<HTMLDivElement>()

const echartsRef = shallowRef()

onMounted(() => {
  echartsRef.value = echarts.init(chartRef.value)
})
</script>

<template>
  <div ref="chartRef" />
</template>
  • 因为在vue里面ref是深层次的转换响应式,可能会破坏实例的数据结构,同时性能损坏会更多,而在这种应用场景下,这种转换是不必要的,应该避免
  • 需要使用shallowRef的有echartsmapboxthreejsamap等。
  • 如果是 options api 写法,就用markRaw 包一下

手动清除定时器

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

let timerId: number | null = null

const count = ref(0)

function start() {
  timerId = setInterval(() => {
    count++
  }, 1000)
}

function stop() {
  if (timerId) {
    window.clearInterval(timerId)
    timerId = null
  }
}

onMounted(() => {
  start()
})

onUnmounted(() => {
  stop()
})
  • setIntervalrequestAnimationFrame和地图等一些方法或者实例,一定要在onUnmounted或者onBeforeUnmount中清除,否则可能会内存泄漏,页面复杂的话不好排查也更容易卡顿。

for循环

vue
<template>
  <div v-for="item in list" :key="item.id">
    {{ item }}
  </div>
</template>
  • 循环的时候,一定要加上key属性,最好是数据中的一个唯一标识,例如id,方便vue进行精准更新,对于不会改变的数据,可以使用index
  • 有的时候使用index作为key,会导致一些性能问题,的同时出现数据渲染错误,旧数据保留在了dom中,如果list中没有唯一标识,可以手动在list数据赋值的时候,给list中的每一项加上一个id,可以使用uuid等一些手段
  • v-ifv-for优先级问题,这个是由vue源码决定,没有其他原因,vue2中v-for优先级更高,vue3中v-if优先级更高,不建议在同一个元素上一起使用,碰到需要同时使用的场景,可以外包一层template,template上使用v-if

变量声明

ts
import { ref, watchEffect } from 'vue'

watchEffect(() => {
  console.log(msg.value)
})

const msg = ref('Hello World!')
  • msg声明在watchEffect之后,会报错Cannot access 'msg' before initialization
  • 有的时候不会报错,或者说开发者直接忽略报错,隐藏的bug也是非常致命的,为了避免这种问题,可以把definePropsrefcomputedreactive等放在setup最上面。

完整示例:

ts
import { computed, ref } from 'vue'

const props = defineProps<{
  ids: string[]
  visible: boolean
}>()

const emit = defineEmits<{
  click: []
  change: [value: number]
}>()

interface UserInfo {
  id: string
  name: string
}

const modelValue = defineModel<boolean>({ required: true })

const count = ref(0)
const doubleCount = computed(() => count.value * 2)

const userInfo = ref<UserInfo>()

function handleClick() {
  count.value++
  emit('change', count.value)
}

function getUserId() {
  return userInfo.value?.id
}

defineExpose({ getUserId })
  • 可利用换行把代码分开,方便阅读

css

vue
<style lang="scss" scoped>
.demo {
  color: red;
}
</style>
  • scoped属性,可以让样式只作用于当前组件,避免全局污染和冲突。
  • 也可以使用:deep()选择器。

需要不使用scoped,class 类名外包上一个 当前组件的类名,避免污染全局

vue
// RoleList.vue
<style lang="scss">
.role-list {
  .demo {
    color: red;
  }
}
</style>

Released under the MIT License.