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