- 原文地址:Vue.js — Considerations and Tricks
- 原文做者:Harshal Patil
- 译文出自:掘金翻译计划
- 本文永久连接:github.com/xitu/gold-m…
- 译者:xingqiwu55555
- 校对者:jerryOnlyZRJ
Vue.js 很棒。可是,当你开始构建大型 JavaScript 应用时,你将开始触及 Vue.js 的边界。实际上这些边界并非框架的限制;相反,这些边界是 Vue.js 团队不断进步地重要设计决策。css
与 React 或 Angular 不一样,Vue.js 迎合不一样级别的开发人员。对于初学者它友好,易用,而且对于专家它一样灵活。它不会试图避开 DOM。相反,它发挥得很好。html
话虽如此,但这篇文章更像是我在 Vue.js 启蒙途中遇到的一些重要 讨论,问题和技巧 的目录。了解这些关键的设计方面有助于咱们构建大型的 web 应用程序。前端
一样,这些讨论在 2018 年 5 月 18 日的今天有效。当框架升级,底层浏览器和 JS API 将发生改变,它们可能无效和不直观。vue
若是你来自相似 Angular 的框架或一些后端 OOP 的强类型语言,你的第一个问题将是 - 为何不是组件类?android
Vue.js 做者,尤雨溪,在 GitHub 评论中已经很好地回答了这个问题:webpack
不将类做为默认机制有三个主要的缘由:ios
若是构建大型 web 应用是不够的,那么你有一些疯狂的想法来实现一个抽象组件,如 <transition>
或 <router-view>
。这确定有关于此的讨论,但它真的没有经过。git
可是不要惧怕,经过对插槽的充分理解,你能够构建本身的抽象组件。这有一篇很是好的博客文章来解释如何作到这一点。github
但在你这样作以前仍是要三思而行。咱们一直依靠 mixins 和 plain 函数来解决一些极端状况。只需将 minxins 视为您的抽象组件:web
没有人阻止你这么作。若是你是老派的 Separation of Concern 哲学家,喜欢将单独的东西放在单独的文件中,或者你讨厌代码编辑器围绕 .vue
文件的不稳定行为,那么它确定是可能的。因此你须要作的:
<!--https://vuejs.org/v2/guide/single-file-components.html -->
<!-- my-component.vue -->
<template src="./my-component.html"></template>
<script src="./my-component.js"></script>
<style src="./my-component.css"></style>
复制代码
可是,紧接着就出现了下一个问题 ——个人组件总须要四个文件吗?(vue + html + js + css)吗。我能够以某种方式去掉 .vue
文件吗?答案确定是能够,你能够这样作。使用 vue-template-loader
。
个人同事写了一篇关于它的很好的博客:
感谢 React.js,函数组件是如今的热潮,虽然有充分的理由。它们 快速,无状态且易于测试。可是,它们有一些问题。
又回到类上,应该注意的是,类是旨在保持本地状态的一种数据结构。若是函数组件是无状态的,那么 @Component 没有意义。
相关讨论可在如下网站查阅:
函数组件没有像普通组件那样的类和样式绑定。必须在渲染函数中手动应用这些绑定。
TLDR: 在函数组件中使用 有数据的 组件 时要当心
函数组件很是 渴望 直接使用组件的渲染函数。这也意味着你应该:
避免在渲染函数中直接使用有状态的组件,由于这会在每一次调用渲染函数时建立不一样的组件定义。
若是函数组件是子组件,它们会更好地被使用。应该注意的是,这种行为也适用于 React.js。
从函数组件中触发事件并非直接了当的。不幸的是,文档中没有提到这一点。$emit
方法在函数组件中不可用。如下 stack overflow 问题将在这方面有所帮助:
透明包装组件包装一些 DOM 结构,但暴露该 DOM 结构的事件而不是根 DOM 元素。例如,
<!-- Wrapper component for input -->
<template>
<div class="wrapper-comp">
<label>My Label</label>
<input @focus="$emit('focus')" type="text"/>
</div>
</template>
复制代码
这里,咱们只是对 input
标签 感兴趣而不是 根 div
元素,由于它主要用于添加样式和装饰的。该组件的用户可能对来自 input 的几个事件感兴趣,例如 blur
、focus
、click
和 hover
等。这意味着咱们必须从新触发每一个事件。咱们的组件看起来像这样。
<!-- Wrapper component for input -->
<template>
<div class="wrapper-comp">
<label>My Label</label>
<input type="text"
@focus="$emit('focus')"
@click="$emit('click')"
@blur="$emit('blur')"
@hover="$emit('hover')"
/>
</div>
</template>
复制代码
如今是 anti-DRY 且看起来很乱。简单的解决方案是使用 Vue 实例上的 vm.$listeners
属性简单地将事件侦听从新绑定到所需的 DOM 元素:
<!-- Notice the use of $listeners -->
<template>
<div class="wrapper-comp">
<label>My Label</label>
<input v-on="$listeners" type="text"/>
</div>
</template>
<!-- Uses: @focus event will bind to internal input element -->
<custom-input @focus="onFocus"></custom-input>
复制代码
我常常看到一些开发者试图从插槽中触发事件或者在一个插槽中监听事件。
组件 slot
由调用父组件提供。这意味着全部事件都应与调用组件关联。试图监听这些变化意味着你的父组件和子组件是紧密耦合的,还有另一个方法能够作到这一点,Evan You 解释得很漂亮:
在某些时候,你会遇到这种状况。想象一下,你有一个组件,好比 A,接受一些插槽。遵循组合原则,你会使用组件 A 建立另外一个组件 B。如今你获取组件 B 并在组件 C 中使用它。
问题是 — 如何将组件 C 中的插槽传递给 A?
这个问题的答案取决于你使用的是什么?若是你使用渲染函数,那么它很是简单。组件 B 的渲染函数将是:
// Render function for component B
function render(h) {
return h('component-a', {
// Passing slots as they are to component A
scopedSlot: this.$scopedSlots
}
}
复制代码
可是,若是你使用基于模板的渲染函数,那么你就不走运了。幸运的是,这个问题正在取得进展,咱们可能会为基于模板的组件提供一些东西:
但愿这篇文章可以深刻了解 Vue.js 的设计要点和在 Vue.js 中使用高级场景的提示/技巧。
若是发现译文存在错误或其余须要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可得到相应奖励积分。文章开头的 本文永久连接 即为本文在 GitHub 上的 MarkDown 连接。
掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。