深入了解组件
组件注册
全局注册
Vue.component('my-component-name', {})
局部注册
如果所有的组件都用全局注册意味着即使你已经不再使用一个组件,它仍然会被包含在全局环境中,这就造成javascript无谓的增加。
基础组件的自动化全局注册
可能你的许多组件只是包裹了一个输入框或按钮之类的元素,是相对通用的。我们有时候会把它们称为基础组件,它们会在各个组件中被频繁的用到,如果我们在很多组件中都用到,那么就都需要引入,会比较麻烦,这时候我们可以使用require.context只全局注册这些非常通用的基础组件,不需要在每个需要引入的组件中引入,可以直接写。在main.js中写:
import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'
const requireComponent = require.context(
// 其组件目录的相对路径
'./components',
// 是否查询其子目录
false,
// 匹配基础组件文件名的正则表达式
/Base[A-Z]\w+\.(vue|js)$/
)
requireComponent.keys().forEach(fileName => {
// 获取组件配置
const componentConfig = requireComponent(fileName)
// 获取组件的 PascalCase 命名
const componentName = upperFirst(
camelCase(
// 获取和目录深度无关的文件名
fileName
.split('/')
.pop()
.replace(/\.\w+$/, '')
)
)
// 全局注册组件
Vue.component(
componentName,
// 如果这个组件选项是通过 `export default` 导出的,
// 那么就会优先使用 `.default`,
// 否则回退到使用模块的根。
componentConfig.default || componentConfig
)
})
Prop
HTML中的特性名是大小写不敏感,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用DOM中的模版时,驼峰命名法都需要使用其等价的kebab-case(短横线分隔命名)命名。
传入一个布尔值
<!-- 包含该prop没有值的情况在内,都意味着true -->
<blog-post is-published></blog-post>
#######传入一个对象的所有属性
如果你想要将一个对象的所有属性都作为prop传入,你可以使用不带参数的v-bind(取代v-bind:prop-name)。例如,对于一个给定的对象post:
post: {
id: 1,
title: 'My Journey with Vue'
}
下面的模版:
<blog-post v-bind="post"></blog-post>
等价于:
<blog-post
v-bind:id="post.id"
v-bind:title="post.title"
></blog-post>
单向数据流
prop只能父传子不能子传父,这里有两种常见的试图改变一个prop的情形:
1.这个prop用来传递一个初始值,这个子组件接下来希望将其作为一个本地的prop数据来使用。
props: ['initialCounter'],
data: function () {
return {
counter: this.initialCounter
}
}
2.这个prop以一个原始的值传入且需要进行转换。
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
注意在JavaScript中对象和数组是通过引用传入的,所以对于一个数组或对象类型的prop来说,在子组件中改变这个对象或数组本身将会影响到父组件的状态。
非prop的特性
如果在自定义组件上添加一个属性,没有使用prop,那么这个属性就会被添加到组件的根元素上。
<bootstrap-date-input data-date-picker="activated"></bootstrap-date-input>
然后这个 data-date-picker="activated" 特性就会自动添加到 <bootstrap-date-input> 的根元素上。
替换/合并已有的特性
如果给自定义组件添加属性,但是组件内部的模版上也有同样的属性,那么会有不一样的处理结果。
// 组件
<bootstrap-date-input
type="text"
style="color:black"
data-date-picker="activated"
class="date-picker-theme-dark"
></bootstrap-date-input>
// 组件内
<input type="date" class="form-control" style="color:white">
我们会发现组件外的type会将组件内的type替换掉,但是class和style特性会智能一些,会将组件内和组件外的合并。
禁用特性继承
如果你不希望组件的根元素继承特性,你可以在组件的选项中设置inheritAttrs: false。例如:
Vue.component('my-component', {
inheritAttrs: false,
// ...
})
这尤其适合配合实例的$attrs属性使用,该属性包含了传递给一个组件的特性名和特性值,例如:
{
required: true,
placeholder: 'Enter your username'
}
有了 inheritAttrs: false
和 $attrs
,你就可以手动决定这些特性会被赋予哪个元素。在撰写基础组件的时候是常会用到的:
Vue.component('base-input', {
inheritAttrs: false,
props: ['label', 'value'],
template: `
<label>
{{ label }}
<input
v-bind="$attrs"
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
</label>
`
})
注意 inheritAttrs: false 选项不会影响 style 和 class 的绑定。
网友评论