很少有人最初编写Vue组件时打算将其开源。我们大多数人开始为自己编写组件的原因:我们有一个问题,然后决定通过构建一个组件来解决它。
有时我们发现自己想要在代码库的新位置解决相同的问题,所以我们提取组件并对其进行重构,使其可重用。然后我们想在一个不同的项目中使用它,所以我们把它移到一个独立的包中。然后我们想“嘿,为什么不把这个分享给全世界呢?”,所以我们开放了组件的源代码。
一方面,这意味着对于任何在Vue工作的人来说,都有大量且不断增长的开源组件可用性(在npmjs.com上搜索“Vue”,会发现超过12000个包)。
另一方面,由于这些组件中的大多数都是从特定的环境演化而来的,并且并不是所有人都有跨许多环境重用组件的设计经验,所以这些组件中的许多都不能很好地利用Vue生态系统。
"play nice"是什么意思?在高层次上,它意味着以Vue开发人员觉得自然的方式工作,并且易于扩展和集成到任何类型的应用程序中。
在探索了广泛的开源组件之后,我认为下面是如何制作一个运行良好的Vue组件:
-
实现v模型兼容性
-
对事件透明
-
将属性分配给正确的元素
-
接受键盘导航的浏览器规范
-
优先使用事件而不是回调
-
限制在组件样式
实现v模型兼容性
对于本质上是表单字段的组件——无论是自动完成搜索字段、日历日期字段,还是在单个字段周围应用附加功能以允许用户指定数据的任何其他字段——惯用性的最重要方法之一是支持v-model。
根据组件上的vue指南,组件上的v-model实际上通过传入值属性和应用输入事件处理程序来工作。
例如,如果我们实现了一个包装输入的日期选择器,我们将使用值prop初始化我们的datepicker,并在选择时发出一个输入事件,如下所示:
import datepicker from 'my-magic-datepicker';
export
default {
props:
['value'],
mounted() {
datepicker(this.$el, {
date: this.value,
onDateSelected: (date) = >{
this.$emit('input', date);
},
});
}
}
对事件透明
为了实现v模型,组件需要实现输入事件。但其他活动呢?比如单击事件、键盘处理等等?虽然原生事件作为HTML冒泡,但是Vue的事件处理在默认情况下并不冒泡。
例如,除非我做一些具体的事情,否则这是行不通的:
<my-textarea-wrapper @focus="showFocus">
除非我们在实际发出焦点事件的包装器组件中编写代码,否则将永远不会调用showFocus事件处理程序。然而,Vue确实为我们提供了一种通过编程访问应用于组件的侦听器的方法,因此我们可以将它们分配到正确的位置:$listener对象。
再一想,原因是显而易见的:这允许我们将侦听器传递到组件中的正确位置。例如,我们的文本区域包装组件:
<div class="my-textarea-wrapper">
<textarea v-on="$listeners"></textarea>
</div>
现在发生在textarea上的事件就是那些被传递的事件。
为正确的元素分配属性
如何处理属性,例如用于文本区域的行或用于在任何元素上添加简单工具提示的标题标记?
默认情况下,Vue接受应用于组件的属性,并将它们放在组件的根元素上。这经常发生,但并不总是你想要的。然而,如果我们再次从上面查看textarea包装器,在这种情况下,将属性应用到textarea本身而不是div将更有意义。
为此,我们告诉组件默认情况下不要应用这些属性,而是直接使用$attrs对象应用它们。在我们的JavaScript:
export
default {
inheritAttrs:
false,
}
然后在我们的模板中:
<div class="my-textarea-wrapper">
<textarea v-bind="$attrs"></textarea>
</div>
接受键盘导航的浏览器规范
可访问性和键盘导航是web开发中最常被遗忘的部分之一,如果您编写的组件是为了在生态系统中发挥良好的作用,那么正确使用它们是最重要的事情之一。
从根本上说,这意味着要确保组件符合浏览器规范:tab键应该允许选择表单字段。Enter通常用于激活按钮或链接。
在W3C网站上可以找到通用组件的完整键盘导航建议列表。遵循这些建议将允许您的组件在任何应用程序中使用,而不仅仅是那些不关心可访问性的应用程序。
优先使用事件而不是回调
当涉及到从组件到其父组件的数据和用户交互的通信时,有两个常见的选项:道具中的回调函数和事件。由于Vue的自定义事件不像原生浏览器事件那样弹出,所以这两个事件在功能上是等价的,但对于可重用组件,我几乎总是建议在回调期间使用事件。为什么?
在Fullstack Radio的一期节目中,Vue核心团队成员Chris Fritz给出了以下理由:
-
使用事件使父母可以非常清楚地知道什么。它在“我们从父母那里获得的东西”和“我们发送给父母的东西”之间创造了明确的分离。
-
您可以直接在事件处理程序中使用表达式,从而为简单的情况提供极其紧凑的事件处理程序
-
它更具惯用性--Vue示例和文档倾向于使用事件从组件到其父组件进行通信。
幸运的是,如果您当前正在使用回调函数方法,则可以很容易地修改组件以发出事件。使用回调的组件可能如下所示:
// my-custom-component.vue
export
default {
props:
['onActionHappened', ...] methods() {
handleAction() {... // your custom code
if (typeof this.onActionHappened === 'function') {
this.onActionHappened(data);
}
}
}
}
然后当它被包含时,它看起来像:
<my-custom-component :onActionHappened="actionHandler" />
更改为基于事件的方法将如下所示:
// my-custom-component.vue
export
default {
methods() {
handleAction() {... // your custom code
this.$emit('action-happened', data);
}
}
}
父结点会变成:
<my-custom-component @action-happened="actionHandler" />
限制组件内部样式
Vue的单文件组件结构允许我们将样式直接嵌入到组件中,特别是当与范围相结合时,它为我们提供了一种很好的方式,以一种不会影响应用程序其他部分的方式交付完全打包的样式化组件。
由于该系统的强大功能,将所有组件样式放入组件并运送完全样式的组件可能很诱人。而且因为组件样式通常包含在全局样式表之后,所以它可能会变成一个特殊的噩梦来覆盖它。
为了防止这种情况,我建议您的组件(颜色,边框,阴影等)在结构上不需要的任何CSS应该从组件文件本身中排除,或者可以关闭。相反,请考虑发布可自定义的SCSS部分,以便用户根据自己的内容进行自定义。
仅运送SCSS的缺点是它需要组件的用户将SCSS拉入他们的样式表编译中,或者看到一个非常简单的组件。为了充分利用这两个方面,您可以使用可以通过支柱关闭的类来为您的文件内样式设置范围,以便为想要自定义样式的用户提供支持。
如果您将SCSS构建为mixin,则可以使用相同的SCSS partial,您的用户可以使用它来获得更多自定义样式。
<template>
<div :class="isStyledClass">
<!-- my component --></div>
</template>
然后在JavaScript中:
export
default {
props:
{
disableStyles:
{
type:
Boolean,
default:
false
}
},
computed: {
isStyledClass() {
if (!this.disableStyles) {
return 'is-styled';
}
},
}
然后,您可以
@import 'my-component-styles';
.is - styled {
@include my - component - styles();
}
这将允许开箱即用的样式是无论你的愿望,但用户想要定制不再需要创建高度专一覆盖,他们只是关闭样式通过设置disableStyles道具为真,可以使用mixin的设置或从头开始重塑自己的一切纯粹。
更多web开发知识,请查阅 HTML中文网 !!