跳转到内容

优先级D规则:谨慎使用

Vue中存在一些特性是为了适应罕见的边缘情况或更平滑地从旧代码库迁移。然而,过度使用这些特性可能会使你的代码更难维护,甚至成为bug的来源。这些规则突出了潜在的风险特性,并描述了何时以及为什么应该避免使用它们。

带有scoped的元素选择器

应避免在scoped样式中使用元素选择器。

scoped样式中,优先使用类选择器而不是元素选择器,因为大量元素选择器会很慢。

详细说明

为了作用域样式,Vue会为组件元素添加一个唯一的属性,例如data-v-f3f3eg9。然后修改选择器,以便只选择具有此属性的匹配元素(例如button[data-v-f3f3eg9])。

问题是,大量的元素属性选择器(例如button[data-v-f3f3eg9])将比类属性选择器(例如.btn-close[data-v-f3f3eg9])慢得多,因此应尽可能优先使用类选择器。

不好

模板
<template>
  <button>×</button>
</template>

<style scoped>
button {
  background-color: red;
}
</style>

模板
<template>
  <button class="btn btn-close">×</button>
</template>

<style scoped>
.btn-close {
  background-color: red;
}
</style>

隐式父子通信

应优先使用props和events进行父子组件通信,而不是使用this.$parent或修改props。

理想的Vue应用是props向下传递,events向上传递。坚持这个约定会使你的组件更容易理解。然而,在某些边缘情况下,prop修改或this.$parent可以简化已经深度耦合的两个组件。

问题是,还有许多简单的情况,这些模式可能会带来便利。注意:不要因为短期的便利(写更少的代码)而牺牲理解状态流动的简单性。

不好

js
app.component('TodoItem', {
  props: {
    todo: {
      type: Object,
      required: true
    }
  },

  template: '<input v-model="todo.text">'
})
js
app.component('TodoItem', {
  props: {
    todo: {
      type: Object,
      required: true
    }
  },

  methods: {
    removeTodo() {
      this.$parent.todos = this.$parent.todos.filter(
        (todo) => todo.id !== vm.todo.id
      )
    }
  },

  template: `
    <span>
      {{ todo.text }}
      <button @click="removeTodo">
        ×
      </button>
    </span>
  `
})

js
app.component('TodoItem', {
  props: {
    todo: {
      type: Object,
      required: true
    }
  },

  emits: ['input'],

  template: `
    <input
      :value="todo.text"
      @input="$emit('input', $event.target.value)"
    >
  `
})
js
app.component('TodoItem', {
  props: {
    todo: {
      type: Object,
      required: true
    }
  },

  emits: ['delete'],

  template: `
    <span>
      {{ todo.text }}
      <button @click="$emit('delete')">
        ×
      </button>
    </span>
  `
})

不好

vue
<script setup>
defineProps({
  todo: {
    type: Object,
    required: true
  }
})
</script>

<template>
  <input v-model="todo.text" />
</template>
vue
<script setup>
import { getCurrentInstance } from 'vue'

const props = defineProps({
  todo: {
    type: Object,
    required: true
  }
})

const instance = getCurrentInstance()

function removeTodo() {
  const parent = instance.parent
  if (!parent) return

  parent.props.todos = parent.props.todos.filter((todo) => {
    return todo.id !== props.todo.id
  })
}
</script>

<template>
  <span>
    {{ todo.text }}
    <button @click="removeTodo">×</button>
  </span>
</template>

vue
<script setup>
defineProps({
  todo: {
    type: Object,
    required: true
  }
})

const emit = defineEmits(['input'])
</script>

<template>
  <input :value="todo.text" @input="emit('input', $event.target.value)" />
</template>
vue
<script setup>
defineProps({
  todo: {
    type: Object,
    required: true
  }
})

const emit = defineEmits(['delete'])
</script>

<template>
  <span>
    {{ todo.text }}
    <button @click="emit('delete')">×</button>
  </span>
</template>
优先级D规则:谨慎使用已加载