最大化组件灵活性
Vue.js 组件将 props 和 slot 作为输入;它们的输出渲染为 HTML 并发出事件。
为了最大限度地提高组件的灵活性,利用插槽和 props 总是有意义的。
明智地利用 props 和默认值意味着组件可以被重用和扩展。例如,我们可以将其设置为默认属性,而不是在组件中硬编码一个值。在这种情况下,日期默认为当前日期,new Date()。然后我们使用计算属性提取纪元:
<template>
<div>Date as epoch: {{ epoch }}</div>
</template>
<script>
export default {
props: {
date: {
type: Date,
default() {
return new Date()
}
}
},
computed: {
epoch() {
return Number(this.date)
}
}
}
</script>
注册并使用时,渲染如下:
Date as epoch: 1574289255348
插槽可以被认为是组件将渲染委托给其使用者的一种方式。将模板的某些部分委托给父组件有助于提高可重用性。
用于最大化可重用性的插槽的一个具体示例是 无渲染组件模式(renderless component)。例如,在纪元显示示例中,我们可以利用作用域插槽并从组件中删除任何渲染逻辑:
<template>
<div>
<slot :epoch="epoch" />
</div>
</template>
在父组件中,可以使用作用域槽来定义渲染:
<template>
<div>
<Epoch>
<template v-slot:default="{ epoch }">
Epoch as rendered with parent template {{ epoch }}
</template>
</Epoch>
</div>
</template>
这意味着组件的委托被委托给父级并显示以下内容:
Epoch as rendered with parent template 1574289270190
下一组实践通过使 API 可预测来最大化组件的重用。在许多方面,转发属性(forwarding attributes)、利用合并的样式(style)和类(class)属性以及实现 v-model 接口是使 Vue.js 自定义组件的行为更像 HTML 元素的另一种方法。
转发属性可能很有趣。例如,CustomInput 组件(在 CustomInput.vue 文件中)可能需要传递 type 属性以及 required 属性:
<template>
<input v-bind="$attrs">
</template>
CustomInput 组件可用于渲染任何类型的组件(src/App.vue):
<template>
<div id="app">
<fieldset>
<label for="textinput">
Text Input
</label>
<CustomInput
type="text"
name="textinput"
id="textinput"
/>
</fieldset>
<fieldset>
<label for="dateinput">
Date Input
</label>
<CustomInput
type="date"
name="dateinput"
id="dateinput"
/>
</fieldset>
</div>
</template>
<script>
import CustomInput from './components/CustomInput.vue'
export default {
components: {
CustomInput
}
}
</script>
这会正确渲染文本和日期输入:

Vue.js 围绕 class/内联 style 做了很多繁重的工作,因为它将组件上定义的样式和类对象与该组件中根元素的样式和类对象合并。 根据文档,“类和样式属性更智能一些,因此两个值都会合并”(Vue.js 组件属性指南: https://vuejs.org/v2/guide/components-props.html#Replacing-Merging-with-Existing-Attributes )。
在 Vue.js 中,输入元素和组件倾向于通过 v-model 进行控制,v-model 是一种双向响应式 Vue.js 绑定。v-model 是使用 v-bind:value 和 v-on:input 提供值并使其与子组件或元素的输出保持同步的简写。
受控名称与不受控相反。在不受控的情况下,传递的值仅用作起始值;当输入完成捕获时(例如,键入完成),输入(input)事件才会发出。
如果一个组件实现了 v-model 形状,它就可以直接替代表单元素。
例如,实现 v-model 接口的 TextInput 可与 input 和 textarea 互换使用:
<template>
<div>
<textarea
v-if="type === 'long'"
:value="value"
@input="$emit('input', $event.target.value)"
></textarea>
<input
v-else
:value="value"
@input="$emit('input', $event.target.value)"
type="text"
/>
</div>
</template>
<script>
export default {
props: ['value', 'type']
}
</script>
然后可以在 src/App.vue 中使用它,如下所示:
<template>
<div id="app">
<label>Short Text: {{ shortText }}</label>
<TextInput v-model="shortText" type="short" />
<label>Long Text: {{ longText }}</label>
<TextInput v-model="longText" type="long" />
</div>
</template>
<script>
import TextInput from './components/TextInput.vue'
export default {
components: {
TextInput
},
data() {
return {
shortText: '',
longText: ''
}
}
}
</script>
应用程序渲染如下:

至此,我们研究了如何利用 props 和 slot、继承属性以及实现众所周知的 Vue.js 接口来帮助最大限度地提高组件灵活性。
下一节将致力于通过学习如何在没有 .vue
文件的情况下使用 Vue.js 组件来加深我们对 Vue.js 组件的理解。