转自:微信公众号 web前端开发

打开网易新闻 查看更多图片

英文 |https://betterprogramming.pub/advanced-vue-tricks-6e315347c378

翻译 | 杨小二

今天,我为你带来了一个系列精选的知识,以帮助你更快地构建 Vue 应用程序,同时,使它们更高效、更易于大规模管理。

这些高级技巧从何而来?

  • 从我五年的 Vue开发中。
  • 从我用 Vue 2 和 Vue 3 中构建的 20 多个大型客户端项目中。
  • 从有影响力的 Vue 开发人员的平时开发技巧总结中。

虽然,高级 Vue 开发人员会发现这些概念非常有用,但我已经详细概述了如何完成每个概念,因此不会让初学者掉队!

如果你需要任何进一步的解释,请在留言区给我留言,我将很乐意为你提供帮助。如果你有自己的好方法?也可以随时分享这些!

好的,让我们深入了解好东西。

1、动态 SVG 组件

如果你像我一样,喜欢手工制作你的应用程序 — 选择独特的 SVG 图标更适合你的风格指南,并将它们与自定义动画和样式配对。

这样做的问题是要更改 SVG 图像填充的颜色fill,你需要访问模板中内联的 SVG 代码。根据 SVG 的大小,即使只有一两个矢量图像,这也会使你的模板代码快速膨胀。

我已经测试了多种方法和包来访问fill属性,而不会炸毁我的模板,结果证明,添加hover或active CSS 状态以更改 fill SVG 中的一个或多个填充属性的最佳方法,实际上最有效的显而易见的方法——让它成为一个组件!

所以,当我们需要这种功能时,而不是使用这个:

相反,我们将在 VSCode 中打开 .svg 图像,然后复制图像的

旁注:为了确保正在查看正确的图像代码,我建议安装一个名为 Svg Preview 的 VSCode 扩展(如上所示)。这将打开图像的侧面板预览,如果更改 SVG 代码,该预览也会更新。

现在,我们将此代码粘贴到新组件的模板中。我建议将所有 SVG 图标组件放入一个新文件夹中,并相应地命名它们 (components/SVG/IconMoon.vue) 以保持组织有序。

一旦我们把它作为一个组件,我们就可以使用

把它放到我们应用程序的任何其他组件或页面中:

在上面的示例中,当我将鼠标悬停在 SVG 上时,我只是在要更改的部分上设置一个类(此处称为 .inner),但我也可以直接访问所有 SVG 的属性,因此选项是无穷无尽的,可以使用此方法同时保持其他组件没有 SVG 代码膨胀。

如果需要上述的一些扩展功能,你只需要创建一个自定义 SVG 组件。否则,可以像往常一样简单地使用它们,就在图像的 src 中。

除了动态图标样式和动画之外,还可以传递道具来更改 SVG 的大小和其他方面(就像任何其他组件一样)。如果你还不熟悉,Vue 文档有一个很好的例子说明如何使用图标来做到这一点。

2、使用 Vue-Router 数据实现更智能的导航链接

你可能没有意识到,但是 Vue-Router 可以像任何其他数据存储一样使用。可以访问应用程序的所有可用路由,添加元数据以使逻辑更智能,甚至可以自动填充导航栏、页面面包屑等内容!

然而,这乍一看并不明显,也不能像我们通常访问路由的方式直接访问。

这是我们将添加到模板中的基本代码:

v-for="(route, idx) in $router.options.routes.filter( (routeItem) => routeItem.name === $route.matched[0].name )"

使用此 v-for,您可以直接在模板中访问路由器树的所有子路由和单个路由元数据。

我最近在一个项目中使用它来生成动态侧边栏导航组件。我在路由器中的某些路由上设置了一个 showInSidebar 元数据属性,我想隐藏在侧边栏中。我还能够自动生成所有侧边栏链接,而无需对每个链接进行编码。

以下是我设置路由器路由的方法:

打开网易新闻 查看更多图片

客户端还有一个额外的要求,他们不仅需要从路由器生成这些侧边栏路由,还需要从他们的 API 数据生成这些侧边栏路由。上述方法也以一种干净且可管理的方式解决了这个任务。

我能够控制如何直接从路由器显示本地路由以及是否使用 API 提供的路由。我还用它来制作自动面包屑以显示用户的路线历史。

在此下方(此处未显示)我还有一个单独的部分,允许侧边栏切换到使用从 API 发送的一组路由。为了触发它,我简单地使用了一个a v-if,如果它们存在就使用它们,否则它将恢复使用来自 vue-router 的路由。

在我的 SideNavbar 组件模板中:

你可能已经注意到了exact-active-class代码:

打开网易新闻 查看更多图片

有了这个,如果路由器链接的目的地与当前路由匹配,Vue 会自动设置一个活动类。

这是一个很好的技巧,可以绕过我们用来实现这一点的典型逻辑,并将其缩短为exact-active-class=”className”。

我经常将它用于导航栏链接——它既减少了模板大小,又使事情变得更干净。

3、从子组件访问父数据( )

有时,我们想从父级访问数据,但又不想经历传递 props 的麻烦。如果你只需要从a $parent 的数据对象中快速获取一个值,你可以简单地通过引用 $parent 来完成:

// In parent data() { return { message: 'This is my message' }}// In child template // <-- results in 'This is my message'
{{ $parent.message }}

如果你想要在组件之间传递数据的更多好方法,

Erik Hanchett 有一个很棒的视频,地址:https://www.youtube.com/watch?v=rKWSj3zfBAs&t=46s,你可以去了解一下,还有一些其他选项。

4、简化你的 :class 和 v-if 与逻辑 .includes()

凭借 v-directives 的所有功能,很容易忘记我们仍然可以在我们的模板中访问纯 JavaScript 的高级功能。

例如,假设你想设置一个类,但仅当用户位于三个特定路线中的任何一个时。当你第一次编写此逻辑时,它可能如下所示:

:class=" $route.name === 'Home' || $route.name === 'Gallery' || $route.name === 'Profile' ? 'classOnlyOnThesePages' : ''"

然后,你可能会学会像这样缩短它:

:class="{ 'classOnlyOnThesePages' : $route.name === 'Home' || $route.name === 'Gallery' || $route.name === 'Profile'}"

但最好的写法绝对是这样的:

:class="{ 'classOnlyOnThesePages' : ['Home', 'Gallery', 'Profile'].includes($route.name)}"

这不仅更具可读性,而且以后也更容易扩展。

5、路线更改时滚动到顶部

当更改路线ni时,Vue 会保持在页面上的当前位置。这有时很有用,但主要是麻烦。如果向下滚动一个长列表,然后转到另一个页面,滚动条将位于新页面的底部,而不是期望的顶部。

解决这个问题很简单。只需在 app.js 文件中添加一个 watch: 在每次路由更改后触发滚动到顶部:

// In App.vuewatch: { $route() { window.scrollTo(0, 0) } },

6、对 DRYer 代码使用全局实用方法

几乎每个 Vue 项目都有在应用程序的多个地方重用的逻辑。为了保持我们的代码 DRY(不要重复自己)和可管理,我们应该创建一个单独的 utils.js 文件来保存这个重用的逻辑并且可以从任何地方访问。

注意:你可能认为 Vuex 非常适合这种情况,但是除非,你想将实用程序方法的结果值存储在 state 中,否则它真的不适合这种情况。在这种情况下,你只想从全局函数返回一个值,单独的 utils.js 文件是与 Vue.prototype 配对的键(如下所示)。但是,如果你仍然想在实用程序中访问 Vuex 状态,可以这样做:

import store from '../store',然后执行
store.getters或store.state访问你的 Vuex 状态的属性。

所以,首先我们要设置我们的 utils.jsfile 并添加一个全局方法来将文本复制到用户的剪贴板:

// import store from '../store' <-- To access your Vuex store
import Vue from 'vue' // <-- used for vue-toastification
class Utils {
// Copy a string to user's clipboard
copyToClipboard(text) {
let copyText = document.createElement('input')
document.body.appendChild(copyText)
copyText.value = text copyText.select()
document.execCommand('copy')
document.body.removeChild(copyText)
// Show toast on copy success
// (using the vue-toastification package here)
Vue.$toast.success('Copied address to clipboard: ' + text, {
position: 'top-right',
timeout: 3000
export default new Utils()

现在,我们有了我们的实用程序方法,我们只需要让它在整个应用程序中都可以访问。我们可以将它们导入到一个组件中并以这种方式使用它们,但我发现让它们在全球范围内可用会产生更清晰、更易读的代码,同时使事情更容易访问。

为了使这些函数全局可用,我们将编辑我们的 main.js 文件。Vue 2 和 Vue 3 的设置略有不同,因此,请相应地选择你的风格。

在 Vue2 中

// Utils
import Utils from './utils/utils.js'
// Init Global Utils
Vue.prototype.$utils = Utils

在 Vue3 中

// Utils
import Utils from './utils/utils.js' // <-- import file
const app = createApp(App)
// Init Global Utils
app.config.globalProperties.$utils = Utils // <-- set globally
app.mount('#app')

现在我们可以通过简单地使用以下内容在任何地方访问我们的实用程序方法:

// In template
$utils.copyToClipboard(text)
// In methods
this.$utils.copyToClipboard(text)

7、当用户按下 ENTER 时关注下一个表单输入

表格是一个巨大的 PITA。一些软件包大大减少了这种情况(我最喜欢的是 vue-formulate),但无论你使用什么软件包,或者你是否从头开始编写表单,这都是你的用户会喜欢的概念。

如果用户在关注此输入时按下 Enter 键,则会将光标焦点设置到以下输入框:

type="text" @keyup.enter="$event.target.nextElementSibling.focus()"/>

8、动态刷新(重新加载)特定组件

有许多边缘情况需要重新加载组件而不影响它所在页面的其余部分。你有时需要强制它使用新属性刷新,或者因为你使用的包在传递新属性时没有按预期更新。