作者:Michael Thiessen
译者:前端小智
来源:dev

有梦想,有干货,微信搜索 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试完整考点、资料以及我的系列文章。

学习成为一个更好的Vue开发者并不总是关于那些需要花时间和精力才能掌握的大概念。掌握一些技巧和窍门,可以让我们的编程生活变得更容易–没有大量重复的工作。

在用 Vue 开发的这几年里,我学到了很多有用的技巧。有些很取巧,有些几乎每天都在用,有些则更高级–但它们都很有用。

1. 将一个 prop 限制在一个类型的列表中

使用 prop 定义中的 validator 选项,可以将一个 prop 类型限制在一组特定的值中。

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

这个验证函数接受一个prop,如果prop有效或无效,则返回truefalse

当单单传入的 true 或 false 来控制某些条件不能满足需求时,我通常使用这个方法来做。

按钮类型或警告类型(信息、成功、危险、警告)是最常见的用法、、。颜色也是一个很好的用途。

2. 默认内容和扩展点

Vue中的槽可以有默认的内容,这使我们可以制作出更容易使用的组件。

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

我最喜欢使用默认槽,就是用它们来创建扩展点。

我们可以取组件的任何部分,将其封装在一个插槽中,在外面我们可以用想要的任何内容覆盖组件的该部分。默认情况下,它仍然会按照原来的方式工作,但这样做会有了更多的选项

<template><button class="button" @click="$emit('click')"><slot><div class="formatting">{{ text }}</div></slot></button>
</template>

现在我们可以用许多不同的方式使用这个组件。简单的、默认的方式,或者自定义的方式。

<!-- Uses default functionality of the component -->
<ButtonWithExtensionPoint text="Formatted text" /><ButtonWithExtensionPoint><div class="different-formatting">Do something a little different here</div>
</ButtonWithExtensionPoint>

3. 使用引号来监听嵌套属性

你可能不知道这一点,我们可以通过使用引号轻松地直接监听嵌套值:

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

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

与其使用v-if,有时使用v-show来代替,会有更高的性能。

<ComplicatedChart v-show="chartEnabled" />

v-if被打开或关闭时,它将创建并完全销毁该元素。相反,v-show将创建该元素并将其留在那里,通过设置其样式为display: none来隐藏它。

如果你要切换的组件的渲染成本很高,那么这样做会更有效率。

反过来说,如果不需要立即执行昂贵的组件件,可以使用v-if,这样它就会跳过渲染它,而使页面的加载速度更快一些。

5. 单个作用域插槽的简写(不需要 template 标签)

限定范围的插槽非常有趣,但为了使用它们,您还必须使用许多模板标记。

幸运的是,有一个简写可以让我们摆脱它,但只有在我们使用单个作用域槽的情况下。

普通写法:

<DataTable><template #header="tableAttributes"><TableHeader v-bind="tableAttributes" /></template>
</DataTable>

不使用 template:

<DataTable #header="tableAttributes"><TableHeader v-bind="tableAttributes" />
</DataTable>

简单、直截了当,令人赞叹不已。

6. 有条件地渲染插槽

我们先来看如何做,然后在讨论为什么想隐藏插槽。

每个Vue组件都有一个特殊的$slots对象,里面有你所有的插槽。默认槽的键是default,任何被命名的槽都使用其名称作为键。

const $slots = {default: <default slot>,icon: <icon slot>,button: <button slot>,
};

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

拿这个定义了几个插槽的组件来说,包括几个命名的插槽。

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

如果我们只对组件应用一个插槽,那么只有那个插槽会显示在我们的$slots对象中。

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

我们可以在我们的组件中使用这一点来检测哪些插槽已经被应用到组件中,例如,通过隐藏插槽的包装元素。

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

现在,应用样式的包装器div只有在我们用某些东西填充这个插槽时才会被渲染。

如果不使用v-if,那么如果没有插槽,就会得到一个空的不必要的div。根据div的样式,这可能会打乱我们的布局,让界面看起来很奇怪。

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

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

  • 当使用封装的div来添加默认样式时
  • 插槽是空的
  • 如果我们将默认内容与嵌套槽相结合

例如,当我们在添加默认样式时,我们在插槽周围添加一个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>

然而,如果父组件没有将内容应用到该插槽中,我们最终会在页面上渲染出一个空的div

<div><h2>This is a pretty great component, amirite?</h2><div class="default-styling"><!-- 槽中没有内容,但这个div 仍然被渲染。糟糕 --></div><button @click="$emit('click')">Click me!</button>
</div>

解决方法就是像上面讲的一样,多个条件判断,就行啦。

7. 如何监听一个插槽的变化

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

<!-- 可惜这个事件不存在 -->
<slot @change="update" />

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

然而,我的朋友Austin想出了一个非常干净的方法,使用MutationObserver来做这件事。

MutationObserver接口提供了监视对DOM树所做更改的能力。它被设计为旧的Mutation Events功能的替代品,该功能是DOM3 Events规范的一部分。

export default {mounted() {// 当有变化时调用`update`const observer = new MutationObserver(this.update);// 监听此组件的变化observer.observe(this.$el, {childList: true,subtree: true});}
};

这个涉及的内容还是很多的,后面会单独出一篇文章来讲,记得关注刷碗智的公众号 <大迁世界> 哦

8. 将局部和全局的 style混合在一起

通常情况下,在处理样式时,我们希望它们能被划分到一个单独的组件中。

<style scoped>.component {background: green;}
</style>

不过,如果需要的话,也可以添加一个非作用域样式块来添加全局样式

<style>/* 全局 */.component p {margin-bottom: 16px;}
</style><style scoped>/* 在该组件内有效 */.component {background: green;}
</style>

但要小心,全局样式是危险的,难以追踪。但有时,它们是一个完美的逃生舱口,正是你所需要的。

9. 重写子组件的样式–正确的方法

Scoped CSS在保持内容整洁方面非常棒,而且不会将样式引入应用的其他组件中。

但有时你需要覆盖一个子组件的样式,并跳出这个作用域。

Vue有一个 deep 选择器:

<style scoped>
.my-component >>> .child-component {font-size: 24px;
}
</style>

注意:如果你使用像SCSS这样的CSS预处理器,你可能需要使用/deep/来代替。

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

**上下文感知组件(context-aware)**是“魔法的”,它们自动适应周围发生的事情,处理边缘情况、状态共享等等。

有3种主要的 context-aware ,但 Configuration 是我最感兴趣的一种。

1.状态共享

当你把一个大的组件分解成多个小的组件时,它们往往仍然需要共享状态。

我们可以在 "幕后 "做这些工作,而不是把这些工作推给使用者。

我们一般会把 Dropdown 组件分解成 SelectOption 组件,这样会获得更多的灵活性。但是为了方便使用,SelectOption组件彼此共享 selected 状态。

<!-- 为简单起见,作为一个单一组件使用 -->
<Dropdown v-model="selected" :options="[]" /><!-- 分多个组件,更灵活 -->
<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>

2. Configuration

有时,一个组件的行为需要根据应用程序的其他部分的情况来改变。这通常是为了自动处理边缘情况,否则处理起来会很烦人。

一个 PopupTooltip 应该重新定位,以便它不会溢出页面。但是,如果该组件是在一个modal 内,它应该重新定位,以便它不会溢出 modal。

如果Tooltip知道它是在一个模态里面,这可以自动完成。

3.样式

创建了 context-aware的CSS,根据父级或同级元素的情况应用不同的样式。

.statistic {color: black;font-size: 24px;font-weight: bold;
}.statistic + .statistic {margin-left: 10px;
}

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

11. 如何在Vue之外创建一个具有响应性的变量(Vue2和3)

如果你从Vue之外得到一个变量,让它具有反应性是很好的。

这样,我们就可以在computed propswatch和其他任何地方使用它,它的工作方式就像Vue中的任何其他状态一样。

如果我们使用的选项API,需要的只是将其放在组件的数据部分中:

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

如果使用Vue3的组合API,可以直接使用refreactive

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

使用 reactive 代替:

import { reactive } from 'vue';//  可以完全在Vue组件之外完成
const externalVariable = getValue();
// reactive 只对对象和数组起作用
const anotherReactiveVariable = reactive(externalVariable);// Access directly
console.log(anotherReactiveVariable);

如果你还在使用 Vue2,你可以使用observable而不是reactive来实现完全相同的结果。

12. v-for 中的解构

你知道可以在-vfor中使用解构吗?

<liv-for="{ name, id } in users":key="id"
>{{ name }}
</li>

更广为人知的是,可以通过使用这样的元组从v-for中取出索引。

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

当使用一个对象时,可以这样使用 key

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

也可以将这两种方法结合起来,获取key以及属性的 index

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

13. 在指定范围内循环

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

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

渲染结果:

Item #1
Item #2
Item #3
Item #4
Item #5

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

14. 监听你的组件中的任何东西

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

我们可以监听:

  • 计算属性
  • props
  • 嵌套值

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

15.窃取 prop 类型

我从一个子组件中复制 prop 类型,只是为了在一个父组件中使用它们。但我发现,偷取这些 prop 类型要比仅仅复制它们好得多。

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

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

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

多么痛苦啊。

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

因此,这就是为什么我们要窃取组件的 prop 类型:

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

不需要再复杂了。

除了在我们的例子中,我们把 icon 加在每个 prop 名称的开头。所以我们必须做一些额外的工作来实现这一点。

import Icon from './Icon';const iconProps = {};Object.entries(Icon.props).forEach((key, val) => {iconProps[`icon${key.toUpperCase()}`] = val;
});export default {components: { Icon },props: {...iconProps,heading: {type: String,required: true,},},
};

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

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

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

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

window.addEventListener('mousedown', e => {// 获取被点击的元素const clickedEl = e.target;if (el.contains(clickedEl)) {//在 "el "里面点击了} else {//在 "el "外点击了}
});

17. 递归插槽

有一次,我决定看看我是否可以只用模板来做一个v-for组件。在这个过程中,我也发现了如何递归地使用槽。

<!-- VFor.vue -->
<template><div><!--  渲染第一项 -->{{ list[0] }}<!-- 如果我们有更多的项目,继续!但是不要使用我们刚刚渲染的项 --><v-forv-if="list.length > 1":list="list.slice(1)"/></div>
</template>

如果你想用作用域插槽来做这件事,只是需要一些调整

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

下面是这个组件的使用方法。

<template><div><!-- 常规列表 --><v-for :list="list" /><!-- 加粗的项目列表 --><v-for :list="list"><template v-slot="{ item }"><strong>{{ item }}</strong></template></v-for></div>
</template>

18. 组件元数据

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

例如,如果正在为谷歌 analytics这样的分析仪表:

如果你想让布局知道每个小组件应该占多少列,你可以直接在组件上添加元数据。

export default {name: 'LiveUsersWidget',// 												

25个 Vue 技巧,开发了5年了,有些竟然还是第一次见!相关推荐

  1. 25 个 Vue 技巧,开发了 5 年了,才知道还能这么用

    作者 | 前端小智 来源 | 大迁世界 学习成为一个更好的Vue开发者并不总是关于那些需要花时间和精力才能掌握的大概念.掌握一些技巧和窍门,可以让我们的编程生活变得更容易--没有大量重复的工作. 在用 ...

  2. vue中waiting for update signal from wds_10个vue快捷开发技巧助你成为中级前端工程师!(二)...

    前言 先赞再看,养成习惯~ 优雅更新props 更新 prop 在业务中是很常见的需求,但在子组件中不允许直接修改 prop,因为这种做法不符合单向数据流的原则,在开发模式下还会报出警告.因此大多数人 ...

  3. 提升效率的Vue组件开发和实战技巧

    大家好我是若川. 现在的大前端时代,是一个动荡纷争的时代,江湖中已经分成了很多门派,主要以Vue,React还有Angular为首,形成前端框架三足鼎立的局势.Vue在前端框架中的地位就像曾经的 jQ ...

  4. vue - blog开发学7

    vue - blog开发学7 将基本的项目部署到linux上(前后台只是实现了基本的功能,本次只是记录一些基本的开发流程,完善,等后续) 1.linux环境准备(我用的是阿里云服务器) ①jre.my ...

  5. 3个概念,入门 Vue 组件开发

    "组件"是 Vue 中比较基础的概念,但我发现,许多同学对 Vue 组件的概念和由来并不是清楚.因此,我希望通过这个专题,带大家换个角度来分析,最终让大家更清楚组件开发. 首先,我 ...

  6. vue源码用了哪些设计模式,vue实际开发遇到的难点

    Vue组件开发有哪些技巧 这次给大家带来Vue组件开发有哪些技巧,Vue组件开发的注意事项有哪些,下面就是实战案例,一起来看一下. Vue单文件组件开发当使用vue-cli初始化一个项目的时候,会发现 ...

  7. java计算机毕业设计vue.js开发红酒网站源码+mysql数据库+系统+lw文档+部署

    java计算机毕业设计vue.js开发红酒网站源码+mysql数据库+系统+lw文档+部署 java计算机毕业设计vue.js开发红酒网站源码+mysql数据库+系统+lw文档+部署 本源码技术栈: ...

  8. java计算机毕业设计vue.js开发红酒网站MyBatis+系统+LW文档+源码+调试部署

    java计算机毕业设计vue.js开发红酒网站MyBatis+系统+LW文档+源码+调试部署 java计算机毕业设计vue.js开发红酒网站MyBatis+系统+LW文档+源码+调试部署 本源码技术栈 ...

  9. JAVA毕业设计vue.js开发红酒网站计算机源码+lw文档+系统+调试部署+数据库

    JAVA毕业设计vue.js开发红酒网站计算机源码+lw文档+系统+调试部署+数据库 JAVA毕业设计vue.js开发红酒网站计算机源码+lw文档+系统+调试部署+数据库 本源码技术栈: 项目架构:B ...

  10. 最新 个人编写记录 vue技巧

    记录VUE 技巧 持续更新ing- .sync 与 $emit 父级 <-------- > 子级 同步 变量 父级 <template><div><cust ...

最新文章

  1. VBS编程基础教程 (第2篇)
  2. 云炬Android开发笔记 2-1项目初始化
  3. java writablesheet_jxl加边框,jxl合并单元格,单元格的设置,单元格居中
  4. from __future__ import absolute_import的作用
  5. 5种成交话术,帮你多拿订单,挠到客户痒处,才有成交希望
  6. JavaScript文档对象模型DOM节点操作之兄弟节点(4)
  7. C语言程序设计—01基础知识
  8. 广义相对论-学习记录4-第三章-张量分析与黎曼几何1
  9. couchbase java 手册_couchBase在java中使用的基本知识
  10. 对 a = [lambda : x for x in range(3)] 的理解
  11. scratch少儿编程航天主题:认识太阳系-八大行星连连看
  12. 从Darry Ring看奢侈品该如何玩转互联网思维
  13. 移动硬盘位置不可用的数据恢复方法
  14. 如何将您的iPhone更新到最新的iOS版本
  15. 物联网服务商店 - Nebula浅谈
  16. 掘金技术社区沸点指南(试行版)
  17. Python画图之饼图
  18. mysql入门最全参考笔记
  19. 为何使用云原生应用架构 三 :独霸天下之四大绝技 — 弹,弹,弹性扩展篇
  20. 【斐波拉契数列】 Python

热门文章

  1. 微信小程序-音乐播放器总结
  2. html动画如何延迟,css3animation延迟
  3. JavaEE企业级实战项目 智牛股第六天 股票交易过程
  4. shiro加盐走源码
  5. 腾讯开源开门红,云原生操作系统TencentOS Kernel正式登陆Github
  6. 访问请转到 http://hi.baidu.com/yuyu8848
  7. Qt 判断鼠标在某一控件上
  8. Powerdesigner pdm视图看不到表注释comment问题
  9. 数据库的三级封锁协议
  10. 信念就是一种观念对不对_信念与观念一字之差天差地别