10个高级 Vue 编码技巧
zhezhongyun 2025-01-08 18:41 51 浏览
转自:微信公众号 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 中的一个或多个填充属性的最佳方法,实际上最有效的显而易见的方法——让它成为一个组件!
所以,当我们需要这种功能时,而不是使用这个:
<img src="@/assets/images/myImg.svg" />相反,我们将在 VSCode 中打开 .svg 图像,然后复制图像的 <svg~ 代码:
旁注:为了确保正在查看正确的图像代码,我建议安装一个名为 Svg Preview 的 VSCode 扩展(如上所示)。这将打开图像的侧面板预览,如果更改 SVG 代码,该预览也会更新。
现在,我们将此代码粘贴到新组件的模板中。我建议将所有 SVG 图标组件放入一个新文件夹中,并相应地命名它们 (components/SVG/IconMoon.vue) 以保持组织有序。
一旦我们把它作为一个组件,我们就可以使用 <IconMoon /> 把它放到我们应用程序的任何其他组件或页面中:
在上面的示例中,当我将鼠标悬停在 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
<div>{{ $parent.message }}</div> // <-- results in 'This is my 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.vue
watch: {
$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)6、检测用户是在桌面还是移动设备上
检测用户在哪个平台上的方法经常变化。在评估了你可以执行此操作的多种方法后,我决定使用一个做得很好的包,并且会在这些因素发生变化时保持更新。
使用 npm i vue-mobile-detection --save 安装 vue-mobile-detection。
在你的 App.vue 文件中,添加一个 mount() 钩子来在你的 Vuex 商店中存储用户的平台。
async mounted() {
// Detect if user is on Desktop or Mobile platform, then save to store
this.$isMobile()
? this.$store.commit('setPlatform', 'mobile')
: this.$store.commit('setPlatform', 'desktop')
},如果你使用 Vuex,你现在可以为上面的 $store.commit 创建一个mutation,将值设置为 state,然后使用 getter 访问应用程序中任何地方的平台值。
我最近在一个基于区块链的项目中使用了它,在该项目中,了解用户的平台以触发正确的区块链钱包(浏览器扩展钱包或移动应用程序钱包)至关重要,并且它的作用非常吸引人。
注意:如果你没有使用 Vuex,你可以使用 localStorage.setItem 将此值存储在用户的 localStorage 中,然后使用 localStorage.getItem 在你的应用程序中的任何位置使用它。
// in App.vue inside of your mounted() hook:
const currentPlatform = this.$isMobile() ? ‘mobile’ : ‘desktop’
localStorage.setItem('platform', currentPlatform)
// Use it anywhere
localStorage.getItem(‘platform’)7、当用户按下 ENTER 时关注下一个表单输入
表格是一个巨大的 PITA。一些软件包大大减少了这种情况(我最喜欢的是 vue-formulate),但无论你使用什么软件包,或者你是否从头开始编写表单,这都是你的用户会喜欢的概念。
如果用户在关注此输入时按下 Enter 键,则会将光标焦点设置到以下输入框:
<input
type="text"
@keyup.enter="$event.target.nextElementSibling.focus()"
/>8、动态刷新(重新加载)特定组件
有许多边缘情况需要重新加载组件而不影响它所在页面的其余部分。你有时需要强制它使用新属性刷新,或者因为你使用的包在传递新属性时没有按预期更新。
<template>
<component-to-re-render :key="reloadMe" />
</template>
<script>
export default {
data() {
return {
reloadMe: 0,
}
};
methods: {
forceRerender() { this.reloadMe += 1; }
}
}
</script>当然,如果你想重新加载整个页面,那也很简单:
// Using traditional JS (If you don't have access to $router)
window.location.reload()
// Using vue-router
this.$router.go(0)9、从父组件调用子组件的方法
通常,父组件通过 props 将数据向下发送给子组件,子组件通过 $emit 事件向上发送给父组件。但是有时我们可能希望从仅存在于子组件内部的父组件内部触发一个方法。听起来很复杂?事实并非如此,Vue refs 提供了完美的解决方案!
// Parent.vue
<template>
<ChildComponent ref="child" />
</template>
// In Parent.vue's methods
this.$refs.child.methodName()这是一个更清晰的例子,以防上面的内容太简短:
10、验证组件道具
验证你的道具有两件事。它会告诉你是否向组件传递了不正确的 prop,并且可以轻松查看该组件旨在接受哪些选项。你可以附加任何你想要创建自定义道具验证器的逻辑,但以下可能是你最常用的情况(验证字符串选项):
在下面的示例中,我创建了一个在我的应用程序中使用的自定义 Button 组件。请注意,我有变体和类型道具。
注意:对于自定义 Button 组件,当你实际上是指样式变体时,请确保不要将 type 作为 prop 使用,因为 type 已经是 HTML 按钮上的一个东西,应该是一个单独的 prop 来处理表单提交和重置等事情。
对于这些道具中的每一个,我声明我只想接受几个不同的选项。如果我传递了错误的东西,这将帮助我调试我的代码。它还将帮助其他人查看我的代码以了解该组件可以接受哪些选项。
<template>
<button
:disabled="disabled"
:type="type"
class="btn"
:class="[
variant ? `btn-${variant}` : '',
disabled ? disabled : ''
]"
@click="!disabled ? $emit('clicked') : ''"
>
// Use slot to add text to it like a normal button
<slot />
</button>
</template>
<script>
export default {
props: {
variant: {
type: String,
validator: s => ['outline', 'success', 'warning', 'danger'].includes(s)
},
type: {
type: String,
validator: s => ['submit', 'reset'].includes(s)
},
disabled: {
type: Boolean,
default: false
}
}
}
</script>
<style lang="scss" scoped>
// limited styles here for brevity
.btn {
line-height: 25px;
padding: 5px 20px;
}
.disabled {
border: 2px solid var(--grey-ultralight) !important;
cursor: default !important;
background: var(--grey-ultralight) !important;
color: var(--grey-light) !important;
}
.btn-outline {
border: 2px solid var(--blue);
background: var(--bg);
color: var(--blue);
&:hover {
background: var(--blue);
color: var(--white);
border: 2px solid var(--blue);
}
}
.btn-success {
// Success styles here
}
.btn-warning {
// Warning styles here
}
.btn-danger {
// Danger styles here
}
</style>我希望你喜欢这些技巧并发现它们很有用。如果你有自己的高级技巧,请随时在评论中分享。
相关推荐
- Python入门学习记录之一:变量_python怎么用变量
-
写这个,主要是对自己学习python知识的一个总结,也是加深自己的印象。变量(英文:variable),也叫标识符。在python中,变量的命名规则有以下三点:>变量名只能包含字母、数字和下划线...
- python变量命名规则——来自小白的总结
-
python是一个动态编译类编程语言,所以程序在运行前不需要如C语言的先行编译动作,因此也只有在程序运行过程中才能发现程序的问题。基于此,python的变量就有一定的命名规范。python作为当前热门...
- Python入门学习教程:第 2 章 变量与数据类型
-
2.1什么是变量?在编程中,变量就像一个存放数据的容器,它可以存储各种信息,并且这些信息可以被读取和修改。想象一下,变量就如同我们生活中的盒子,你可以把东西放进去,也可以随时拿出来看看,甚至可以换成...
- 绘制学术论文中的“三线表”具体指导
-
在科研过程中,大家用到最多的可能就是“三线表”。“三线表”,一般主要由三条横线构成,当然在变量名栏里也可以拆分单元格,出现更多的线。更重要的是,“三线表”也是一种数据记录规范,以“三线表”形式记录的数...
- Python基础语法知识--变量和数据类型
-
学习Python中的变量和数据类型至关重要,因为它们构成了Python编程的基石。以下是帮助您了解Python中的变量和数据类型的分步指南:1.变量:变量在Python中用于存储数据值。它们充...
- 一文搞懂 Python 中的所有标点符号
-
反引号`无任何作用。传说Python3中它被移除是因为和单引号字符'太相似。波浪号~(按位取反符号)~被称为取反或补码运算符。它放在我们想要取反的对象前面。如果放在一个整数n...
- Python变量类型和运算符_python中变量的含义
-
别再被小名词坑哭了:Python新手常犯的那些隐蔽错误,我用同事的真实bug拆给你看我记得有一次和同事张姐一起追查一个看似随机崩溃的脚本,最后发现罪魁祸首竟然是她把变量命名成了list。说实话...
- 从零开始:深入剖析 Spring Boot3 中配置文件的加载顺序
-
在当今的互联网软件开发领域,SpringBoot无疑是最为热门和广泛应用的框架之一。它以其强大的功能、便捷的开发体验,极大地提升了开发效率,成为众多开发者构建Web应用程序的首选。而在Spr...
- Python中下划线 ‘_’ 的用法,你知道几种
-
Python中下划线()是一个有特殊含义和用途的符号,它可以用来表示以下几种情况:1在解释器中,下划线(_)表示上一个表达式的值,可以用来进行快速计算或测试。例如:>>>2+...
- 解锁Shell编程:变量_shell $变量
-
引言:开启Shell编程大门Shell作为用户与Linux内核之间的桥梁,为我们提供了强大的命令行交互方式。它不仅能执行简单的文件操作、进程管理,还能通过编写脚本实现复杂的自动化任务。无论是...
- 一文学会Python的变量命名规则!_python的变量命名有哪些要求
-
目录1.变量的命名原则3.内置函数尽量不要做变量4.删除变量和垃圾回收机制5.结语1.变量的命名原则①由英文字母、_(下划线)、或中文开头②变量名称只能由英文字母、数字、下画线或中文字所组成。③英文字...
- 更可靠的Rust-语法篇-区分语句/表达式,略览if/loop/while/for
-
src/main.rs://函数定义fnadd(a:i32,b:i32)->i32{a+b//末尾表达式}fnmain(){leta:i3...
- C++第五课:变量的命名规则_c++中变量的命名规则
-
变量的命名不是想怎么起就怎么起的,而是有一套固定的规则的。具体规则:1.名字要合法:变量名必须是由字母、数字或下划线组成。例如:a,a1,a_1。2.开头不能是数字。例如:可以a1,但不能起1a。3....
- Rust编程-核心篇-不安全编程_rust安全性
-
Unsafe的必要性Rust的所有权系统和类型系统为我们提供了强大的安全保障,但在某些情况下,我们需要突破这些限制来:与C代码交互实现底层系统编程优化性能关键代码实现某些编译器无法验证的安全操作Rus...
- 探秘 Python 内存管理:背后的神奇机制
-
在编程的世界里,内存管理就如同幕后的精密操控者,确保程序的高效运行。Python作为一种广泛使用的编程语言,其内存管理机制既巧妙又复杂,为开发者们提供了便利的同时,也展现了强大的底层控制能力。一、P...
- 一周热门
- 最近发表
- 标签列表
-
- HTML 教程 (33)
- HTML 简介 (35)
- HTML 实例/测验 (32)
- HTML 测验 (32)
- JavaScript 和 HTML DOM 参考手册 (32)
- HTML 拓展阅读 (30)
- HTML文本框样式 (31)
- HTML滚动条样式 (34)
- HTML5 浏览器支持 (33)
- HTML5 新元素 (33)
- HTML5 WebSocket (30)
- HTML5 代码规范 (32)
- HTML5 标签 (717)
- HTML5 标签 (已废弃) (75)
- HTML5电子书 (32)
- HTML5开发工具 (34)
- HTML5小游戏源码 (34)
- HTML5模板下载 (30)
- HTTP 状态消息 (33)
- HTTP 方法:GET 对比 POST (33)
- 键盘快捷键 (35)
- 标签 (226)
- opacity 属性 (32)
- transition 属性 (33)
- 1-1. 变量声明 (31)
