DOM 模板解析 注意事项
Vue 组件的模板在某些情况下会受到 HTML 的限制。ul
,ol
,table
,select
这些元素,只有某些特定的元素才能出现在它们内部。li
,tr
,option
这些元素只能出现在特定的元素内部。
1 | <!-- <talbe>元素 内只规定只允许出现<tr>,<td>,<th>等表格元素,所有在此内的直接使用组件时会被作为无效是内容提升到外部--> |
如果从以下来源使用的模板的话,不存在该限制
- 字符串模板(template:’…’)
- 单文件组件(.vue)
<script type="text/x-template">
使用props
传递数据
选项
props
的值 2 种,字符串数组、对象;这些传递的是一个静态的值- 字符串数组,一种简便方式
1
props: ['message', 'message2'];
- 对象,可定制
prop
的验证方法;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21props: {
message: Number,
//多个可能的类型
message2:[String,Number],
message3: {
type: [String, Number],
required: true,
default: 100,
// 验证函数
validator: function(value) {
return parseInt(value) > 100;
}
},
message4: {
type: Object,
// 对象 和 数组默认值 必须从一个工厂函数获取
default: function() {
return {name: '22'}
}
}
}
- 字符串数组,一种简便方式
使用
v-bind
,动态给Prop
赋值,任何类型的值都可以传给一个Prop
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<!-- 传入一个数字 -->
<!-- `42`即便是静态的,当使用`v-bind`告诉 Vue,这是一个js表达式(返回number类型),而不是一个字符串 -->
<my-component v-bind:message="42"></my-component>
<!-- 传入一个布尔值 -->
<!-- 包含 该 Prop ,在没有值的情况下,表示:`true` -->
<my-component message></my-component>
<!-- `false`是静态的,但`v-bind`告诉了 Vue,t它是一个js表达式(返回Booelean false),而不是一个字符串 -->
<my-component v-bind:message="false"></my-component>
<!-- 同理,传入一个对象,数字 -->
<my-component v-bind:message="{
name: 'jaing',
age: 27
}"></my-component>
<my-component v-bind:message="['133',3334,'nihao']"></my-component>Prop
验证,是在组件实例创建之前进行验证,所有实例的属性在default
,validator
函数中是不可用的
数据流流向
props
传递的数据是单向的,父组件数据变化会传递给子组件,反过来不行。
- 2 种 改变
Prop
情况- 父组件传递初始值进来,子组件在
data
内再声明一个数据,引用父组件的prop
,这样就可以在自己的作用域下随意使用和修改1
2
3
4
5
6
7
8
9
10// 组件中声明了count,它在组件初始化时会获取来自父组件的initCount,之后就与父组件无关了,只用维护count,避免直接操作initCount
Vue.component('my-component',{
props: ['initCount'],
template: `<div>{{ count }}</div>`,
data: function () {
return {
count: this.initCount
}
}
}) - 子组件的数据依赖父组件的
props
传入的数据,这种情况用计算属性1
2
3
4
5
6
7
8
9
10
11Vue.component('my-component', {
props: ['width'],
template: '<div :style="style">组件内容</div>',
computed: {
style: function() {
return {
width: this.width + 'px'
}
}
}
})
- 父组件传递初始值进来,子组件在
自定义事件
事件名称
因为v-on
事件监听器在 DOM 模板中会被自动转换为全小写(HTML 大小写不敏感),v-on:myEvent
会被转换成v-on:myevent
,所以导致myEvent
不被监听到。
因此,最好使用 kebab-case 的事件名自定义组件的
v-model
具有双向绑定的v-model
(本质上:语法糖)组件,需要满足以下条件:1
2
3
4
5
6
7
8<!-- 绑定value值,接受value `prop` -->
<!-- 触发input事件时,$event的值,赋给 text -->
<my-input
v-bind:value="text"
v-on:input="text=$event">
</my-input>
<!-- 自定义组件,就可以使用v-model 指令 -->
<my-input v-model="something"><my-input>- 接受一个
value
的prop
- 在
value
改变时,触发input
事件
1
2
3
4
5
6
7
8
9
10
11
12
13<my-component v-model="total"></my-component>
// 注册组件
Vue.component('my-component',{
props: ['value'],
template:'<input :value="value" @input="updateValue">',
methods: {
// 默认参数:DOM事件
updateValue: function(event) {
this.$emit('input', event.target.value);
}
}
})- 接受一个
原生事件绑定到组件
在一个组件的根元素直接监听一个原生事件,使用v-on
的.native
修饰符1
<base-input v-on:click.native="onClick"></base-input>
构建完全透明的包裹器(扩展组件)
vm.$listeners
,它是一个对象,包含了父作用域中的v-on
(不包含.native 修饰符的
)事件监听器。它可以通过v-on="$listeners"
出入到 内部的子组件,从而在 父组件上跟 子组件 相同的监听器都可以工作vm.$props
,当前组件接受的 props 对象vm.$attrs
, 它是一个对象,包含了 父作用域(父组件)中的不作为prop
,且可获取的特性绑定(class
,style
除外)。当一个组件没有声明任何prop
时,这里会包含所有父作用域的绑定。并且可以通过v-bind="$attrs"
传入内部的子组件。- 选项
inhertAttrs
,默认情况,父作用域的不被作为props
的特性绑定,将会”回退”且作为普通 HTML 特性应用在子元素的根元素上。设置false
,取消。在通过vm.$attrs
让其特性生效,且通过 v-bind 显性的绑定到非根元素。 extend
选项,引用一个”子类”, 父组件的data
,覆盖其data
.
1 | // 这边 `base-table`组件时一个完全透明的包裹器,它完全像一个普通 ivewz 中的 `table`组件 |
父链,子链 ref
子组件索引
在组件中,可以使用vm.$parent
,直接访问 该组件的父组件或父实例。父组件也可以 通过vm.$children
访问 它所有的子组件.
当子组件太多时,通过vm.$children
来遍历出我们需要的一个子组件实例是比较困难的,尤其是组件动态渲染时,它们的序列不固定。
使用特殊的属性ref
来为子组件指定一个索引名称,在通过vm.$refs(一个对象,持有注册过ref特性的所有DOM元素和组件实例)
找到该组件。$refs
只在组件渲染完后才被注册,并非响应式的,应该避免在模板中或计算 属性中使用$refs
.