你需要知道的 25 个 Vue 技巧

2025-05-25

你需要知道的 25 个 Vue 技巧

学习成为一名更好的 Vue 开发人员并不总是需要花费时间和精力去掌握那些大概念。

它还提供了一些小技巧和窍门,可以让您的生活变得更加轻松 — 无需做太多工作。

多年来,我在开发和撰写 Vue 文章的过程中,积累了大量实用技巧。有些技巧很巧妙,有些我几乎每天都会用到,还有些则比较高级——但它们都非常有用。

以上内容最初发布在我的每周简报中。如果你想获得更多类似的实用技巧,请务必订阅!

1. 将 prop 限制为类型列表

使用validatorprop 定义中的选项,您可以将 prop 限制为特定的一组值:

export default {
  name: 'Image',
  props: {
    src: {
      type: String,
    },
    style: {
      type: String,
      validator: s => ['square', 'rounded'].includes(s)
    }
  }
};
Enter fullscreen mode Exit fullscreen mode

此验证器函数接受一个 prop,并返回该 proptrue是否false有效。

当我需要比允许的更多的选项boolean,但仍想限制可以设置的内容时,我经常使用这个。

按钮类型或警报类型(信息、成功、危险、警告)是最常见的用途——至少在我的工作中是这样。颜色在这方面也非常有用。

但还有很多!

2. 默认内容和扩展点

Vue 中的插槽可以具有默认内容,这使您可以创建更易于使用的组件:

<button class="button" @click="$emit('click')">
  <slot>
    <!-- Used if no slot is provided -->
    Click me
  </slot>
</button>
Enter fullscreen mode Exit fullscreen mode

不过,我最喜欢使用默认插槽来创建扩展点。

基本上,你可以将组件的任何部分包装在一个插槽中,然后就可以用任何你想要的内容覆盖组件的该部分。默认情况下,它仍然会像往常一样工作,但现在你拥有了更多选择:

<template>
  <button class="button" @click="$emit('click')">
    <!-- Adding in the slot tag does nothing at first -->
    <!-- We can override this by providing content to the slot -->
    <slot>
      <div class="formatting">
        {{ text }}
      </div>
    </slot>
  </button>
</template>
Enter fullscreen mode Exit fullscreen mode

现在,您可以通过多种方式使用此组件。简单的默认方式,或者您自己的自定义方式:

<!-- Uses default functionality of the component -->
<ButtonWithExtensionPoint text="Formatted text" />

<!-- Use the extension point to create custom behaviour -->
<ButtonWithExtensionPoint>
  <div class="different-formatting">
    Do something a little different here
  </div>
</ButtonWithExtensionPoint>
Enter fullscreen mode Exit fullscreen mode

您可以深入了解以下 Codesandbox:

https://codesandbox.io/s/default-content-and-extension-points-bl87m?file=/src/App.vue

3. 使用引号来监视嵌套值

您可能不知道这一点,但您只需使用引号即可轻松直接查看嵌套值:

watch {
  '$route.query.id'() {
    // ...
  }
}
Enter fullscreen mode Exit fullscreen mode

这对于处理深度嵌套的对象非常有用!

4. 知道何时使用 v-if(以及何时避免使用)

有时候,与其使用v-if,不如使用以下方法,这样性能更高v-show

<ComplicatedChart v-show="chartEnabled" />
Enter fullscreen mode Exit fullscreen mode

v-if切换为 时,它将完全创建并销毁元素。相反,v-show会创建元素并将其保留在那里,并通过将其样式设置为 来隐藏它display: none

如果您切换的组件渲染成本很高,那么这样做会更加高效。

另一方面,如果您不需要立即使用该昂贵的组件,请使用它,v-if这样它将跳过渲染并稍微加快页面加载速度。

5. 单作用域插槽的简写(不需要模板标签!)

范围插槽很有趣,但为了使用它们,您也必须使用很多template标签。

幸运的是,有一种简写方法可以让我们摆脱它,但前提是我们使用单个作用域插槽。

不要这样写:

<DataTable>
  <template #header="tableAttributes">
    <TableHeader v-bind="tableAttributes" />
  </template>
</DataTable>
Enter fullscreen mode Exit fullscreen mode

我们可以这样写:

<DataTable #header="tableAttributes">
  <TableHeader v-bind="tableAttributes" />
</DataTable>
Enter fullscreen mode Exit fullscreen mode

简单、直接、奇妙。

(好吧,也许不是那么出色,但仍然相当不错)

所有这些技巧最初都发布在我的每周简报中。如果你想获得更多类似的精彩技巧,请务必订阅!

6. 有条件地渲染插槽(以及为什么你需要这样做)

首先我将向您展示如何操作,然后我们将讨论为什么要隐藏插槽。

每个 Vue 组件都有一个特殊的$slots对象,其中包含所有插槽。默认插槽的键为default,任何命名插槽都使用其名称作为键:

const $slots = {
  default: <default slot>,
  icon: <icon slot>,
  button: <button slot>,
};
Enter fullscreen mode Exit fullscreen mode

但这个对象只有应用于组件的$slots插槽,而不是定义的每个插槽。

以这个定义了多个插槽的组件为例,其中包括几个命名的插槽:

<!-- Slots.vue -->
<template>
  <div>
    <h2>Here are some slots</h2>
    <slot />
    <slot name="second" />
    <slot name="third" />
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

如果我们只将一个插槽应用于组件,则只有该插槽才会显示在我们的$slots对象中:

<template>
  <Slots>
    <template #second>
      This will be applied to the second slot.
    </template>
  </Slots>
</template>
Enter fullscreen mode Exit fullscreen mode
$slots = { second: <vnode> }
Enter fullscreen mode Exit fullscreen mode

我们可以在组件中使用它来检测哪些插槽已应用于组件,例如,通过隐藏插槽的包装元素:

<template>
  <div>
    <h2>A wrapped slot</h2>
    <div v-if="$slots.default" class="styles">
      <slot />
    </div>
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

div现在,只有当我们实际用某些东西填充该插槽时,才会呈现应用样式的包装器。

如果我们不使用v-if,最终会得到一个空的、不必要的元素div(如果没有插槽)。根据其样式div,这可能会扰乱我们的布局,使内容看起来很奇怪。

那么为什么我们希望能够有条件地渲染插槽?

使用条件槽有三个主要原因:

  1. 使用wrapperdiv添加默认样式时
  2. 插槽为空
  3. 如果我们将默认内容与嵌套插槽组合起来

例如,当我们添加默认样式时,我们会div在插槽周围添加一个:

<template>
  <div>
    <h2>This is a pretty great component, amirite?</h2>
    <div class="default-styling">
      <slot >
    </div>
    <button @click="$emit('click')">Click me!</button>
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

但是,如果父组件没有将任何内容应用到该插槽,那么div页面最终会呈现为空:

<div>
  <h2>This is a pretty great component, amirite?</h2>
  <div class="default-styling">
    <!-- No content in the slot, but this div
          is still rendered. Oops. -->
  </div>
  <button @click="$emit('click')">Click me!</button>
</div>
Enter fullscreen mode Exit fullscreen mode

v-if不过,在包装上添加这个div就能解决问题。没有内容应用到插槽?没问题:

<div>
  <h2>This is a pretty great component, amirite?</h2>
  <button @click="$emit('click')">Click me!</button>
</div>
Enter fullscreen mode Exit fullscreen mode

如果您想看一下,这里有一个带有工作演示的 Codesandbox:https://codesandbox.io/s/reactive-slots-bth28 ?file=/src/components/HasSlot.vue

我在这篇文章中写了更多关于插槽的技巧:增强插槽的技巧(命名、作用域和动态)

7. 如何观察 slot 的变化

这个建议来自 Austin Gil — 可以在这里查看他关于此问题的精彩博客文章。

有时我们需要知道插槽内的内容何时发生变化:

<!-- Too bad this event doesn't exist -->
<slot @change="update" />
Enter fullscreen mode Exit fullscreen mode

不幸的是,Vue 没有内置方法让我们检测到这一点。

然而,我的朋友奥斯汀想出了一个非常干净的方法来做到这一点,使用突变观察者

export default {
  mounted() {
    // Call `update` when something changes
    const observer = new MutationObserver(this.update);

    // Watch this component for changes
    observer.observe(this.$el, {
      childList: true,
      subtree: true
    });
  }
};
Enter fullscreen mode Exit fullscreen mode

您还需要清理观察者,但 Austin 在他的文章中介绍了这一点以及更多内容。

8. 融合本地和全球风格

通常,在使用样式时,我们希望将它们限定在单个组件内:

<style scoped>
  .component {
    background: green;
  }
</style>
Enter fullscreen mode Exit fullscreen mode

不过,如果需要的话,您还可以添加非范围样式块来添加全局样式:

<style>
  /* Applied globally */
  .component p {
    margin-bottom: 16px;
  }
</style>

<style scoped>
  /* Scoped to this specific component */
  .component {
    background: green;
  }
</style>
Enter fullscreen mode Exit fullscreen mode

不过要小心——全局样式很危险,而且很难追踪。不过,有时它们却是完美的逃生出口,正是你所需要的。

9. 覆盖子组件的样式——正确的方法

范围 CSS 非常适合保持整洁,并且不会意外地将样式渗透到应用程序的其他部分。

但有时您需要覆盖子组件的样式,并突破该范围。

Vue 有一个deep专门用于此的选择器:

<style scoped>
/* Override CSS of a child component
   while keeping styles scoped */
.my-component >>> .child-component {
  font-size: 24px;
}
</style>
Enter fullscreen mode Exit fullscreen mode

是的,几个月前我已经详细解释了为什么不应该这样做,但覆盖样式可能是最好的解决方案(我们不相信这里的“最佳实践”)。

注意:如果您正在使用 SCSS 等 CSS 预处理器,则可能需要使用/deep/

10. 使用上下文感知组件创造魔法

上下文感知组件是“神奇的”——它们可以自动适应周围发生的事情,处理边缘情况、状态共享等等。

上下文感知组件主要有 3 种类型,但我认为配置是最有趣的。

1.状态共享

当您将一个大型组件分解为多个较小的组件时,它们通常仍然需要共享状态。

您无需将这项工作推给使用组件的任何人,而是可以在“幕后”完成这项工作。

Dropdown你可以将一个组件拆分成Select和 两个Option组件,以提供更大的灵活性。但为了更易于使用,Select和 两个Option组件会selected相互共享状态:

<!-- Used as a single component for simplicity -->
<Dropdown v-model="selected" :options="[]" />

<!-- Split up for more flexibility -->
<Select v-model="selected">
  <Option value="mustard">Mustard</Option>
  <Option value="ketchup">Ketchup</Option>
  <div class="relish-wrapper">
    <Option value="relish">Relish</Option>
  </div>
</Select>
Enter fullscreen mode Exit fullscreen mode

2.配置

有时,组件的行为需要根据应用程序其他部分的情况进行调整。这样做通常是为了自动处理一些原本很麻烦的边缘情况。

应该重新定位,以免溢出页面。但如果该组件位于模态框内,则应重新定位,以免溢出Popup态框Tooltip

Tooltip如果知道它何时处于模态内,则可以自动完成此操作。

3.造型

您已经创建了上下文感知 CSS,根据父元素或同级元素中发生的情况应用不同的样式。

.statistic {
  color: black;
  font-size: 24px;
  font-weight: bold;
}

/* Give some separation between stats
   that are right beside each other */
.statistic + .statistic {
  margin-left: 10px;
}
Enter fullscreen mode Exit fullscreen mode

CSS 变量让我们更进一步,允许我们在页面的不同部分设置不同的值。

如果您想讨论这个概念,请查看 Twitter 上的这个帖子!

每周独家提示和见解

加入 8135 名其他 Vue 开发人员,每周将此类独家提示和见解直接发送到您的收件箱。

你的邮件内容很棒。每一封邮件我都学到不少东西。——Titus Decali

谢谢你又一个漂亮的建议🙏 — Victor Onuoha

喜欢这些,以及间隔重复——马克·戈德斯坦

在此注册

11. 如何使 Vue 之外创建的变量具有反应性(Vue 2 和 3)

如果您从 Vue 外部获取变量,最好能够使其具有响应性。

这样,您就可以在计算的 props、观察者和其他任何地方使用它,它的工作方式与 Vue 中的任何其他状态一样。

如果您使用选项 API,则只需将其放在data组件的部分中:

const externalVariable = getValue();

export default {
  data() {
    return {
      reactiveVariable: externalVariable,
    };
  }
};
Enter fullscreen mode Exit fullscreen mode

如果您在 Vue 3 中使用 Composition API,则可以使用refreactive直接使用:

import { ref } from 'vue';

// Can be done entirely outside of a Vue component
const externalVariable = getValue();
const reactiveVariable = ref(externalVariable);

// Access using .value
console.log(reactiveVariable.value);
Enter fullscreen mode Exit fullscreen mode

改用reactive

import { reactive } from 'vue';

// Can be done entirely outside of a Vue component
const externalVariable = getValue();
// Reactive only works with objects and arrays
const anotherReactiveVariable = reactive(externalVariable);

// Access directly
console.log(anotherReactiveVariable);
Enter fullscreen mode Exit fullscreen mode

如果您仍在使用 Vue 2(我们中的许多人都是如此),则可以使用observable而不是reactive来实现完全相同的结果。

12. v-for 中的解构

你知道你可以在 a 中进行解构吗v-for

<li
  v-for="{ name, id } in users"
  :key="id"
>
  {{ name }}
</li>
Enter fullscreen mode Exit fullscreen mode

更广为人知的是,你可以使用如下元组从 v-for 中获取索引:

<li v-for="(movie, index) in [
  'Lion King',
  'Frozen',
  'The Princess Bride'
]">
  {{ index + 1 }} - {{ movie }}
</li>
Enter fullscreen mode Exit fullscreen mode

当使用对象时,您还可以抓住钥匙:

<li v-for="(value, key) in {
  name: 'Lion King',
  released: 2019,
  director: 'Jon Favreau',
}">
  {{ key }}: {{ value }}
</li>
Enter fullscreen mode Exit fullscreen mode

也可以将这两种方法结合起来,获取属性的键和索引:

<li v-for="(value, key, index) in {
  name: 'Lion King',
  released: 2019,
  director: 'Jon Favreau',
}">
  #{{ index + 1 }}. {{ key }}: {{ value }}
</li>
Enter fullscreen mode Exit fullscreen mode

13. 在 Vue 中循环遍历某个范围

v-for指令允许我们循环遍历数组,但它也可以让我们循环遍历一个范围

<template>
  <ul>
    <li v-for="n in 5">Item #{{ n }}</li>
  </ul>
</template>
Enter fullscreen mode Exit fullscreen mode

这将呈现:

  • 项目 #1
  • 项目 #2
  • 项目 #3
  • 项目#4
  • 第 5 项

当我们使用v-for范围时,它将从 1 开始并以我们指定的数字结束。

14. 观察组件中的任何内容

我花了很长时间才意识到这一点,但是组件中任何具有反应性的东西都可以被监视:

export default {
  computed: {
    someComputedProperty() {
      // Update the computed prop
    },
  },
  watch: {
    someComputedProperty() {
      // Do something when the computed prop is updated
    }
  }
};
Enter fullscreen mode Exit fullscreen mode

您可以观看:

如果您使用组合 API,则可以监视任何值,只要它是一个refreactive对象。

15.窃取道具类型

我经常会发现,我把子组件的 prop 类型复制过来,只是为了在父组件中使用它们。但我发现,窃取这些 prop 类型比直接复制要好得多。

例如我们有一个Icon在这个组件中正在使用的组件:

<template>
  <div>
    <h2>{{ heading }}</h2>
    <Icon
      :type="iconType"
      :size="iconSize"
      :colour="iconColour"
    />
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

为了使其工作,我们需要添加正确的 prop 类型,从Icon组件复制:

import Icon from './Icon';
export default {
  components: { Icon },
  props: {
    iconType: {
      type: String,
      required: true,
    },
    iconSize: {
      type: String,
      default: 'medium',
      validator: size => [
        'small',
        'medium',
        'large',
        'x-large'
      ].includes(size),
    },
    iconColour: {
      type: String,
      default: 'black',
    },
    heading: {
      type: String,
      required: true,
    },
  },
};
Enter fullscreen mode Exit fullscreen mode

真痛苦。

当组件的 prop 类型Icon更新时,你肯定会忘记返回到该组件并进行更新。随着时间的推移,由于该组件的 prop 类型开始与Icon组件本身的 prop 类型偏离,就会引入 bug。

这就是为什么我们要窃取它们:

import Icon from './Icon';
export default {
  components: { Icon },
  props: {
    ...Icon.props,
    heading: {
      type: String,
      required: true,
    },
  },
};
Enter fullscreen mode Exit fullscreen mode

它不必变得比这更复杂!

除了我们的示例中,我们在每个 prop 名称的开头添加了“icon”。因此,我们需要做一些额外的工作来实现这一点:

import Icon from './Icon';

const iconProps = {};

// Do some processing beforehand
Object.entries(Icon.props).forEach((key, val) => {
  iconProps[`icon${key[0].toUpperCase()}${key.substring(1)}`] = val;
});

export default {
  components: { Icon },
  props: {
    ...iconProps,
    heading: {
      type: String,
      required: true,
    },
  },
};
Enter fullscreen mode Exit fullscreen mode

现在,如果组件中的 prop 类型Icon被修改,我们的组件将保持最新。

但是,如果在组件中添加或删除了 prop 类型怎么办Icon?为了解决这些情况,我们可以使用v-bind计算 prop 来保持动态性。

以上内容最初发布在我的每周简报中。如果你想获得更多类似的实用技巧,请务必订阅!

16. 检测元素外部(或内部)的点击

有时我需要检测点击发生在特定元素的内部还是外部el。我通常使用以下方法:

window.addEventListener('mousedown', e => {
  // Get the element that was clicked
  const clickedEl = e.target;

  // `el` is the element you're detecting clicks outside of
  if (el.contains(clickedEl)) {
    // Clicked inside of `el`
  } else {
    // Clicked outside of `el`
  }
});
Enter fullscreen mode Exit fullscreen mode

17. 递归槽

有一次,我决定尝试一下能否v-for仅使用模板来制作一个组件。在此过程中,我还发现了如何递归地使用插槽。

该组件的外观如下:

<!-- VFor.vue -->
<template>
    <div>
        <!-- Render the first item -->
    {{ list[0] }}
        <!-- If we have more items, continue!
                 But leave off the item we just rendered -->
    <v-for
      v-if="list.length > 1"
            :list="list.slice(1)"
        />
    </div>
</template>
Enter fullscreen mode Exit fullscreen mode

如果你想用作用域插槽来做到这一点 — — 你为什么不呢?! — — 只需要进行一些调整:

<template>
  <div>
    <!-- Pass the item into the slot to be rendered -->
    <slot v-bind:item="list[0]">
      <!-- Default -->
      {{ list[0] }}
    </slot>

    <v-for
      v-if="list.length > 1"
      :list="list.slice(1)"
    >
      <!-- Recursively pass down scoped slot -->
      <template v-slot="{ item }">
        <slot v-bind:item="item" />
      </template>
    </v-for>
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

此组件的使用方法如下:

<template>
  <div>
    <!-- Regular list -->
    <v-for :list="list" />

    <!-- List with bolded items -->
    <v-for :list="list">
      <template v-slot="{ item }">
        <strong>{{ item }}</strong>
      </template>
    </v-for>
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

有关此示例和嵌套插槽的更详细说明,请查看我的博客文章:如何在 Vue 中使用嵌套插槽(包括作用域插槽)

18. 组件元数据

并非添加到组件的所有信息都是状态。有时你需要添加一些元数据,以便为其他组件提供更多信息。

例如,如果您正在为 Google Analytics 等分析仪表板构建一堆不同的小部件:

Google Analytics 仪表板的屏幕截图

如果您希望布局知道每个小部件应占用多少列,您可以将其直接添加到组件上作为元数据:

export default {
  name: 'LiveUsersWidget',
  // 👇 Just add it as an extra property
  columns: 3,
  props: {
    // ...
  },
  data() {
    return {
      //...
    };
  },
};
Enter fullscreen mode Exit fullscreen mode

您会发现此元数据是组件上的一个属性:

import LiveUsersWidget from './LiveUsersWidget.vue';
const { columns } = LiveUsersWidget;
Enter fullscreen mode Exit fullscreen mode

您还可以通过特殊属性从组件内部访问元数据$options

export default {
  name: 'LiveUsersWidget',
  columns: 3,
  created() {
    // 👇 `$options` contains all the metadata for a component
    console.log(`Using ${this.$options.metadata} columns`);
  },
};
Enter fullscreen mode Exit fullscreen mode

请记住,此元数据对于组件的每个实例都是相同的,并且不是反应性的。

其他用途包括(但不限于):

  • 保留各个组件的版本号
  • 构建工具的自定义标志可以对组件进行不同的处理
  • 为组件添加除计算属性、数据、观察者等之外的自定义功能。
  • 还有很多我想不起来!

在此处查看实例:https ://codesandbox.io/s/vue-metadata-bew9j?file=/src/App.vue

19. 多文件单文件组件

这是 SFC 的一个鲜为人知的功能。

您可以像导入常规 HTML 文件一样导入文件:

<!-- A "single" file component -->
<template src="./template.html"></template>
<script src="./script.js"></script>
<style scoped src="./styles.css"></style>
Enter fullscreen mode Exit fullscreen mode

如果你需要分享样式、文档或其他内容,这个功能会非常方便。尤其适合那些手指因滚动而磨损的超长组件文件……

以下是其实际运行的演示:https://codesandbox.io/s/interesting-rosalind-9wwmr ?file=/src/components/HelloWorld.vue

20. 可重用组件并非如你所想

可重复使用的组件不一定很大或很复杂。

我经常使小而短的组件可重复使用。

因为我没有到处重写这段代码,所以更新它变得容易得多,并且我可以确保每个代码的OverflowMenu外观和工作方式都完全相同 - 因为它们相同的!

<!-- OverflowMenu.vue -->
<template>
  <Menu>
    <!-- Add a custom button to trigger our Menu -->
    <template #button v-slot="bind">
      <!-- Use bind to pass click handlers,
           a11y attributes, etc. -->
      <Button v-bind="bind">
        <!-- Use our own "..." icon and no text
             for this button -->
        <template #icon>
          <svg src="./ellipsis.svg" />
        </template>
      </Button>
    </template>
  </Menu>
</template>
Enter fullscreen mode Exit fullscreen mode

这里我们采用一个Menu组件,但在触发它打开的按钮上添加一个“...”(省略号)图标。

看起来,用这个组件做个可复用的组件似乎不太值得,因为它只有几行代码。难道我们不能每次用的时候都直接添加图标吗Menu

但这个功能OverflowMenu会用到几十次,现在如果我们想更新图标或其行为,就能轻松搞定。而且使用起来也简单多了!

<template>
  <OverflowMenu
    :menu-items="items"
    @click="handleMenuClick"
  />
</template>
Enter fullscreen mode Exit fullscreen mode

如果您想更深入地构建高度可重用的组件,我有一门课程可以教您一种完全不同的思考组件的方式。

21. 从组件外部调用方法

您可以通过以下方式从组件外部调用方法ref

<!-- Parent.vue -->
<template>
  <ChildComponent ref="child" />
</template>
Enter fullscreen mode Exit fullscreen mode
// Somewhere in Parent.vue
this.$refs.child.method();
Enter fullscreen mode Exit fullscreen mode

让我进一步解释一下这一点。

有时,“最佳实践”并不适用于您所做的事情,这时您就需要像这样的逃生舱。

通常,我们使用 props 和事件在组件之间进行通信。props 被向下传递给子组件,而事件则被向上发送回父组件。

<template>
  <ChildComponent
    :tell-me-what-to-do="someInstructions"
    @something-happened="hereIWillHelpYouWithThat"
  />
</template>
Enter fullscreen mode Exit fullscreen mode

不过,偶尔你可能会遇到需要父组件触发子组件中某个方法的情况。这时,仅仅向下传递 props 就无法正常工作了。

可以传递一个布尔值并让子组件监视它:

<!-- Parent.vue -->
<template>
  <ChildComponent :trigger="shouldCallMethod" />
</template>
Enter fullscreen mode Exit fullscreen mode
// Child.vue
export default {
  props: ['trigger'],
  watch: {
    shouldCallMethod(newVal) {
      if (newVal) {
        // Call the method when the trigger is set to `true`
        this.method();
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

这可以正常工作,但仅限于第一次调用。如果需要多次触发,则必须清理并重置状态。逻辑如下:

  1. 父组件传递truetriggerprop
  2. Watch被触发,Child组件调用该方法
  3. Child 组件发出事件,告诉 Parent 组件该方法已成功触发
  4. 父组件重置triggerfalse,因此我们可以重新执行此操作

啊。

相反,如果我们ref在子组件上设置一个,我们就可以直接调用该方法:

<!-- Parent.vue -->
<template>
  <ChildComponent ref="child" />
</template>
Enter fullscreen mode Exit fullscreen mode
// Somewhere in Parent.vue
this.$refs.child.method();
Enter fullscreen mode Exit fullscreen mode

是的,我们正在打破“道具减少,事件增加”的规则,我们正在打破封装,但它更加清晰,更容易理解,所以这是值得的!

有时“最佳”解决方案最终却成为最糟糕的解决方案。

22. 观察数组和对象

使用观察器最棘手的部分是有时它似乎无法正确触发。

通常,这是因为您试图观察数组或对象,但未设置deeptrue

export default {
  name: 'ColourChange',
  props: {
    colours: {
      type: Array,
      required: true,
    },
  },
  watch: {
    // Use the object syntax instead of just a method
    colours: {
      // This will let Vue know to look inside the array
      deep: true,

      // We have to move our method to a handler field
      handler()
        console.log('The list of colours has changed!');
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

使用 Vue 3 中的反应性 API 如下所示:

watch(
  colours,
  () => {
    console.log('The list of colours has changed!');
  },
  {
    deep: true,
  }
);
Enter fullscreen mode Exit fullscreen mode

如果您想了解更多信息,请参阅Vue 3Vue 2的文档。

23. 使用 Vue Router 进行深度链接

您可以在 URL 中存储(一些)状态,从而允许您直接跳转到页面上的特定状态。

例如,您可以加载已选择日期范围过滤器的页面:

someurl.com/edit?date-range=last-week
Enter fullscreen mode Exit fullscreen mode

这对于应用程序中用户可能共享大量链接的部分、服务器渲染的应用程序或在两个独立应用程序之间传递比常规链接通常提供的更多信息非常有用。

您可以存储过滤器、搜索值、模式是否打开或关闭,或者我们滚动到列表中的位置 - 非常适合无限分页。

使用类似这样的方式获取查询vue-router(这也适用于大多数 Vue 框架,例如 Nuxt 和 Vuepress):

const dateRange = this.$route.query.dateRange;
Enter fullscreen mode Exit fullscreen mode

为了改变它,我们使用RouterLink组件并更新query

<RouterLink :to="{
  query: {
    dateRange: newDateRange
  }
}">
Enter fullscreen mode Exit fullscreen mode

以下是实际操作的演示:

https://codesandbox.io/s/deep-linking-with-vue-router-vhxkq?file=/src/components/DeepLinking.vue

24. 模板标签的另一种用途

template标签可以在模板内的任何位置使用,以便更好地组织代码。

我喜欢用它来简化v-if逻辑,有时v-for也如此。

在此示例中,我们有几个元素都使用相同的v-if条件:

<template>
  <div class="card">
    <img src="imgPath" />
    <h3>
      {{ title }}
    </h3>
    <h4 v-if="expanded">
      {{ subheading }}
    </h4>
    <div
      v-if="expanded"
      class="card-content"
    >
      <slot />
    </div>
    <SocialShare v-if="expanded" />
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

这有点笨重,而且一开始不太明显,因为一堆元素同时显示和隐藏。对于更大、更复杂的组件来说,情况可能会更糟!

但我们可以解决这个问题。

我们可以使用template标签来对这些元素进行分组,并将责任提升v-iftemplate标签本身:

<template>
  <div class="card">
    <img src="imgPath" />
    <h3>
      {{ title }}
    </h3>
    <template v-if="expanded">
      <h4>
        {{ subheading }}
      </h4>
      <div class="card-content">
        <slot />
      </div>
      <SocialShare />
    </template>
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

现在,我们的代码更加易于阅读,一眼就能看懂。

25. 处理错误(和警告)的更好方法

您可以为 Vue 中的错误和警告提供自定义处理程序:

// Vue 3
const app = createApp(App);
app.config.errorHandler = (err) => {
  alert(err);
};

// Vue 2
Vue.config.errorHandler = (err) => {
  alert(err);
};
Enter fullscreen mode Exit fullscreen mode

Bugsnag 和 Rollbar 等错误跟踪服务会挂接到这些处理程序中来记录错误,但您也可以使用它们更优雅地处理错误以获得更好的用户体验。

例如,如果错误未处理,应用程序就不会崩溃,而是可以显示整页错误屏幕并让用户刷新或尝试其他操作。

在 Vue 3 中,错误处理程序仅适用于模板和观察器错误,但 Vue 2 的错误处理程序几乎可以捕获所有错误。两个版本中的警告处理程序均仅在开发环境中有效。

我创建了一个演示来展示它的工作原理。它使用了 Vue 3,但 Vue 2 的工作原理几乎相同:

错误处理程序演示

每周独家提示和见解

加入 8135 名其他 Vue 开发人员,每周将此类独家提示和见解直接发送到您的收件箱。

你的邮件内容很棒。每一封邮件我都学到不少东西。——Titus Decali

谢谢你又一个漂亮的建议🙏 — Victor Onuoha

喜欢这些,以及间隔重复——马克·戈德斯坦

在此注册

文章来源:https://dev.to/michaelthiessen/25-vue-tips-you-need-to-know-2h70
PREV
学习Web开发时要完成的项目
NEXT
如何将 Angular 应用拆分为微前端应用