Home>Article>Web Front-end> 25 Vue tips you deserve to know

25 Vue tips you deserve to know

青灯夜游
青灯夜游 forward
2022-03-09 19:58:24 2540browse

This article summarizes and shares 25 things worth knowing aboutVueUse tips to improve your development speed. I hope it will be helpful to everyone!

25 Vue tips you deserve to know

1. Limit the prop to a list of types

Using thevalidatoroption in the prop definition, you can limit the prop to a list of types. Group-specific values:

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

This validator function accepts a prop and returns true or false. It can also be used when you need more options than the boolean allows. Button types or alert types (info, success, danger, warning) are some of the more common uses. [Related recommendations:vuejs video tutorial]

2. Default content and extension points

Slots in Vue can have default content, and you can make components that are easier to use. :

Basically you can take any part of the component, wrap it in a slot, and then you can override that part of the component with whatever you want. By default, it will still work as usual, but there are more options:

Now you can use this component in many different ways. Simple default way or your own custom way:

    
在这里做一些不同的事情

3. Use quotes to observe nested values

You may not know this: just use quotes to easily view them directly Nested values:

watch { '$route.query.id'() { // ... } }

This is useful for working with deeply nested objects

4. Know when to use v-if (and when to avoid it)

Sometimes Instead of usingv-if, it would be more efficient to usev-show:

Whenv-ifis turned on and off, it will Completely creates and destroys elements.v-showThe difference is that will create the element and leave it there, hiding it by setting its style todisplay: none.

If the component you need to switch is more expensive to render, then this will be more efficient. On the other hand, if you don't need that component right away, you can usev-ifso that it skips rendering it and loads the page faster.

5. Short for single-scope slot (no template tags required!)

Scoped slots are more interesting, but in order to use them, you also have to use a lot oftemplatetags .

However there is a shorthand that allows us to get rid of it, but only if we use a single scope slot.

You don’t need to write it like this:

  

We can write it like this:

  

This is simpler and more direct.

6. Conditionally render slots

Each Vue component has a special $slots object that contains all slots. Default slots have default keys, and named slots use their names as keys:

const $slots = { default: , icon: , button: 

But this$slotsobject onlyapplies to the slots of thecomponent, and Not everydefinedslot.

Take this component that defines several slots as an example, including several named slots:

 

If we only apply one slot to the component, only that slot will appear in our$slotsIn the object:

$slots = { second:  }

We can use this in our component to detect which slots have been applied to the component, for example, by hiding the slot's wrapping element:

Nowdiv, the wrapper to which the style is applied will only render if we actually fill the slot with something.

If we don't usev-if,divif we don't have slot, we will end up with an empty and unnecessary one. Depending on the style the #divhas, this could mess up our layout and make things look weird.

Why do we want to conditionally render slots?

There are three main reasons for using conditional slots:

  • When using wrapper

    divto add default styles

  • slot is empty

  • When we combine default content with nested slots

For example, when we add a default style , we would add a

divaround the slot:

However, if the parent component did not apply content to the slot, we would end up rendering on the page

divAn empty:

这是一个非常棒的组件

v-ifAdding it on the wrapperdivsolves the problem. Content not applied to slot? Like this:

这是一个非常棒的组件

7. How to observe changes in slot

Sometimes we need to know when the content in the slot has changed:

 

Unfortunately, Vue has no built-in method To detect this, a very neat way is to use the mutation observer:

export default { mounted() { // 当事情发生变化时调用`update` const observer = new MutationObserver(this.update); // 观察这个组件的变化 observer.observe(this.$el, { childList: true, subtree: true }); } };

8. Mixing local and global styles together

Often when using styles we want them to be qualified as Single component:

If you need, you can also add a non-scoped style block to add global styles:

 

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

Scoped CSS 比较容易保持整洁,并且不会意外地将样式渗入应用程序的其他部分。但有时你需要覆盖子组件的样式,并突破该范围。Vue 有一个deep专门用于此的选择器:

注意:如果你使用的是 SCSS 之类的 CSS 预处理器,则可能需要改用/deep/

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

上下文感知组件是“神奇的”——它们可以自动适应周围发生的事情,处理边缘情况,状态共享等等。有 3 种主要类型的上下文感知组件,但是我觉得配置是其中最有趣的一种。

1. 状态共享

当你将一个大组件分解成多个小组件时,它们通常仍然需要共享状态。你可以“在幕后”实现这一点,而不是将这项工作推给使用组件的人。

可以将一个Dropdown组件分解为SelectOption组件以提供更大的灵活性。但是为了更容易使用,SelectOption组件彼此共享selected状态:

   

2. 配置

有时需要根据应用程序其余部分的情况更改组件的行为。这样做通常是为了自动处理边缘情况,否则会很麻烦。Popup或者Tooltip应该重新定位自己,这样它就不会溢出页面。但是,如果该组件位于 modal 内部,则它应该重新定位自身,以免溢出modal。如果Tooltip知道它何时在模态内,这可以自动完成。

3. 造型

当你创建了上下文感知 CSS,根据父元素或兄弟元素中发生的情况应用不同的样式。

.statistic { color: black; font-size: 24px; font-weight: bold; } /* 在彼此相邻的统计数据之间进行一些分离*/ .statistic + .statistic { margin-left: 10px; }

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

11. 如何使在 Vue 之外创建的变量具有响应性?

如果你从 Vue 外部获得一个变量,那么能够使其具有响应性就很好。这样你就可以在计算道具、观察者和其他任何地方使用它,它就像 Vue 中的任何其他状态一样工作。

当你正在使用 options API,你只需将它放在data组件的部分中:

const externalVariable = getValue(); export default { data() { return { reactiveVariable: externalVariable, }; } };

当你在 Vue 3 中使用组合 API,则可以使用refreactive这样:

import { ref } from 'vue'; // 可以完全在 Vue 组件之外完成 const externalVariable = getValue(); const reactiveVariable = ref(externalVariable); // 使用 .value 访问 console.log(reactiveVariable.value);

使用reactive来代替:

import { reactive } from 'vue'; // 可以完全在 Vue 组件之外完成 const externalVariable = getValue(); // Reactive 仅适用于对象和数组 const anotherReactiveVariable = reactive(externalVariable); // 直接访问 console.log(anotherReactiveVariable);

如果你仍在使用 Vue 2(就像我们中的许多人一样),你可以使用observable而不是reactive获得完全相同的结果。

12. 在 v-for 中解构

你知道你可以在v-for中解构吗?

  • {{ name }}
  • 众所周知,你可以使用这样的元组从 v-for 中获取索引:

  • {{ index + 1 }} - {{ value }}
  • 使用对象时,你还可以抓住key:

  • {{ key }}: {{ value }}
  • 也可以结合这两种方法,获取属性的键和索引:

  • #{{ index + 1 }}. {{ key }}: {{ value }}
  • 13. 在 Vue 中循环一个范围

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

    显示效果:

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

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

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

    你的组件中的任何响应都可以被观察到:

    export default { computed: { someComputedProperty() { // 更新计算道具 }, }, watch: { someComputedProperty() { // 当计算的 prop 更新时做一些事情 } } };

    你可以看:

    • 计算道具
    • 道具
    • 嵌套值

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

    15. 窃取道具类型

    从子组件复制 prop 类型,只是为了在父组件中使用它们。但窃取这些道具类型比只是复制它们要好得多。

    例如,我们Icon在这个组件中使用了一个组件:

    为了让它工作,我们需要添加正确的道具类型,从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, }, }, };

    Icon组件的 prop 类型更新时,你肯定你会忘记回到这个组件并更新它们。随着时间的推移,随着该组件的 prop 类型开始偏离组件中的 prop 类型,将引入错误Icon

    所以这就是为什么我们会窃取它们:

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

    除了在我们的示例中,我们在每个道具名称的开头添加了“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, }, }, };

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

    但是如果在Icon组件中添加或删除了一个 prop 类型呢?为了涵盖这些情况,我们可以使用v-bind计算道具来保持动态。

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

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

    window.addEventListener('mousedown', e => { // 获取被点击的元素 const clickedEl = e.target; // `el` 是你正在检测外部点击的元素 if (el.contains(clickedEl)) { // 单击“el”内部 } else { // 在`el`之外点击 } });

    17. 递归槽

    我们是否可以v-for只使用模板来制作一个组件?在此过程中,我发现了如何递归地使用slot。

    这是组件的样子:

     

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

    以下是该组件的使用方法:

    18. 组件元数据

    并不是你添加到组件的每一点信息都是状态。有时你需要添加一些元数据来为其他组件提供更多信息。

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

    25 Vue tips you deserve to know

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

    export default { name: 'LiveUsersWidget', // ? 只需将其添加为额外属性 columns: 3, props: { // ... }, data() { return { //... }; }, };

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

    import LiveUsersWidget from './LiveUsersWidget.vue'; const { columns } = LiveUsersWidget;

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

    export default { name: 'LiveUsersWidget', columns: 3, created() { // `$options` 包含组件的所有元数据 console.log(`Using ${this.$options.metadata} columns`); }, };

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

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

    • 保留各个组件的版本号
    • 用于构建工具的自定义标志以区别对待组件
    • 向组件添加自定义功能,超出计算道具、数据、观察者等。

    19. 多文件单文件组件

    这是 SFC 的一个鲜为人知的功能。你可以像使用常规 HTML 文件一样导入文件:

       

    如果你需要共享样式、文档或其他任何内容这会很方便。也非常适合那些因滚动而磨损手指的超长组件文件

    20. 可重用组件不是你想的那样

    可重用组件不一定是大的或复杂的东西,我经常使小而短的组件可重复使用。因为我不会到处重写这段代码,更新它变得容易得多,而且我可以确保每个OverflowMenu看起来和工作完全一样——因为它们是一样的!

     

    这里我们使用了一个Menu组件,但是在触发它打开的按钮上添加了一个“...”(省略号)图标。可能并不不值得用它来制作可重用的组件,因为它只有几行。每次我们想使用Menu这样的时候,我们不能只添加图标吗?但这OverflowMenu将使用数十次,现在如果我们想要更新图标或其行为,我们可以很容易地做到。而且使用起来也简单多了!

    21. 从组件外部调用方法

    你可以通过给它一个从组件外部调用方法ref

     
    // Parent.vue 中的某个地方 this.$refs.child.method();

    通常,我们使用道具和事件在组件之间进行通信。道具被发送到子组件,事件被发送回父组件。

    但有时你可能会遇到需要父组件触发子组件中的方法的情况。这是只有向下传递道具不起作用的地方。可以向下传递一个布尔值并让子组件监视它:

     
    // Child.vue export default { props: ['trigger'], watch: { shouldCallMethod(newVal) { if (newVal) { // 当触发器设置为 `true` 时调用该方法 this.method(); } } } }

    这工作正常,但仅限于第一次调用。如果你需要多次触发此操作,则必须清理并重置状态。然后逻辑看起来像这样:

    • Parent 组件传递truetriggerprop

    • Watch被触发,Child组件调用方法

    • Child 组件发出一个事件告诉 Parent 组件该方法已成功触发

    • Parent 组件重置triggerfalse,因此我们可以再次执行此操作

    啊。

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

     
    // Parent.vue 中的某个地方 this.$refs.child.method();

    我们打破了“props down, events up”规则,打破了封装,但它更清晰、更容易理解值得这样做!

    有时,“最佳”解决方案最终会成为最差的解决方案。

    22. 观察数组和对象

    使用观察者最棘手的部分是有时候它似乎不能正确触发。一般都是因为你试图查看一个数组或一个对象,但没有设置deeptrue

    export default { name: 'ColourChange', props: { colours: { type: Array, required: true, }, }, watch: { // 使用对象语法而不仅仅是方法 colours: { // 这将让 Vue 知道查看数组内部 deep: true, // 我们必须将我们的方法移动到处理程序字段 handler() console.log('颜色列表已更改!'); } } } }

    使用 Vue 3 的反应式 API 看起来像这样:

    watch( colours, () => { console.log('颜色列表已更改!'); }, { deep: true, } );

    如果你想了解更多信息,可以参阅Vue 3Vue 2的文档。

    23. 与 Vue Router 深度链接

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

    比如你可以加载一个已选择日期范围过滤器的页面:

    someurl.com/edit?date-range=last-week

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

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

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

    const dateRange = this.$route.query.dateRange;

    要更改它,我们使用RouterLink组件并更新query

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

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

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

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

    这有点笨拙,一开始并不明显,一堆这些元素被显示和隐藏在一起。在更大、更复杂的组件上,这可能是更糟糕的情况!

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

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

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

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

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

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

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

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

    (学习视频分享:vuejs教程web前端

    The above is the detailed content of 25 Vue tips you deserve to know. For more information, please follow other related articles on the PHP Chinese website!

    Statement:
    This article is reproduced at:juejin.cn. If there is any infringement, please contact admin@php.cn delete