您的Vue应用程序中是否有共享类似选项的组件,甚至模板标记?
使用公共选项和标记创建基本组件,然后扩展基本组件以创建子组件,这是一个好主意。这样的体系结构将帮助您在代码中应用DRY原则(不要重复您自己),这将使您的代码更具可读性,并减少错误的可能性。
Vue提供了一些功能来帮助组件继承,但是您还必须添加一些自己的独创性。
例如:调查问题
下面是Vue.js做的一个简单的调查:
你会注意到每个问题都有不同的相关输入类型:文本输入
选择输入
Radio input
一个好的架构应该是将每个问题/输入类型转换成不同的、可重用的组件。我将它们命名为与上述相对应的:SurveyInputText
SurveyInputSelect
SurveyInputRadio
每个问题/输入都是一个不同的组件,这是有意义的,因为每个问题都需要自己的标记(例如 vs ),而且每个问题都需要自己的道具、方法等等。然而,这些组件有很多共同之处:一个问题
验证功能
错误状态
等等。所以我认为这是扩展组件的一个很好的用例!
基础部分
每个子组件都将继承一个名为SurveyInputBase的文件组件。请注意以下几点:
问题道具在每个组件中都是通用的。我们可以添加更多常见的选项,但是在这个简单的示例中,我们只使用一个选项。
我们需要以某种方式将这些道具从这个组件复制到任何扩展组件。
我们需要为模板内的不同输入插入标记。
SurveyInputBase.vue
{{ question }}
继承组件选择
暂时忘记模板,我们如何让每个子组件继承道具?每个人都需要问题作为道具,以及他们自己独特的道具:
这可以通过导入基本组件并使用extends选项指向它来实现:
SurveyInputText.vue
export
default {
extends:
SurveyInputBase,
props: ['placeholder'],
}
查看Vue Devtools,我们可以看到使用extends确实为我们的子组件提供了基本的支持:
合并策略
您可能想知道子组件是如何继承问题支持而不是覆盖它的。extends选项实现了一个合并策略,该策略将确保正确组合选项。例如,如果这些道具有不同的名称,它们显然都会被包含进来,但是如果它们有相同的名称,Vue将优先选择子组件。
合并策略还可以与其他选项一起工作,比如方法、计算属性和生命周期钩子,并将它们与类似的逻辑组合起来。检查文档中关于Vue如何实现它的确切逻辑,但是如果需要,您可以定义自己的定制策略。
注意:还可以选择在组件中使用mixin属性而不是extends。不过,对于这个用例,我更喜欢extend,因为它有一个稍微不同的合并策略,赋予子组件选项更高的优先级。
扩展的模板
扩展组件的选项相当简单——但是模板呢?
合并策略不适用于模板选项。我们要么继承基本模板,要么定义一个新模板并覆盖它。但是我们如何把它们结合起来呢?
我的解决方案是使用Pug预处理器。它提供了包含和扩展选项,因此看起来非常适合这种设计模式。
基础组件
首先,我们将基本组件的模板转换为Pug语法:
div.survey-base
h4 {{ question }}
block input
请注意以下几点:我们将lang="pug"添加到模板标记中,以告诉vue-loader将其作为pug模板处理(此外,不要忘记将pug模块以及npm i——save-dev pug添加到您的项目中)
我们使用块输入为子组件内容声明一个outlet。
这里有点乱。如果我们想让我们的子组件扩展这个模板,我们需要把它放在自己的文件:
SurveyInputBase.pugdiv.survey-base
h4 {{ question }}
block input
然后我们把这个文件包含在我们的基本组件中,这样它仍然可以作为一个正常的独立组件使用:
SurveyInputBase.vue
include SurveyInputBase.pug
export default { props: [ 'question' ]
}
这样做很遗憾,因为它违背了“单文件”组件的目的,但是对于这个用例,我认为它是值得的。也许您可以定制一个webpack加载器来避免这样做。
子组件
现在让我们把我们的子组件的模板转换为Pug:
SurveyInputText.vue
extends SurveyInputBase.pug
block input
input(type="text" :placeholder="placeholder")
import SurveyInputBase from './SurveyInputBase.vue';
export default { extends: SurveyInputBase, props: [ 'placeholder' ],
}
子组件使用Pug的extended特性,该特性包括基本组件并输出输入块中的任何自定义内容(这是一个与插槽无关的概念)。
下面是子组件的模板在扩展基础并被翻译回常规HTML Vue模板后的效果:
{{ question }}
把所有的东西放在一起
使用这个策略,我们可以继续创建另外两个子组件SurveyInputSelect和SurveyInputRadio,它们都有自己的支持和标记。
如果我们在一个项目中使用它们,我们的主模板可能是这样的:
question="1. What is your name?"
placeholder="e.g. John Smith">
question="2. What is your favorite UI framework?"
:options="['React', 'Vue.js', 'Angular']">
question="3. What backend do you use?"
:options="['Node.js', 'Laravel', 'Ruby']"
name="backend">
下面是呈现的标记:
1. What is your name?
2. What is your favorite UI framework?
React
Vue.js
Angular