组件的注册
在 vue
中,我们可以通过 new Vue
来创建一个组件,不过通常它是作为整个应用的顶层根组件存在的,我们还可以通过另外的方式来注册一个更为通用的组件
Vue.component('组件名称', {组件选项})
组件选项与 new Vue
选项配置基本一致(也有一些细节的不同)
如果要在子组件中监听js原生事件,需要使用指令修饰符".native":
如下,直接写@click="fn"函数是 不会起作用的
通过 Vue.component
注册的组件,我们称为全局组件,因为它可以在任意范围内使用,我们还可以定义局部组件
new Vue({
...,
components: {
'组件名称': {组件选项}
}
})
在一个组件内部通过 components
选项注册的组件是局部组件,只能在当前 components
选项所在的组件内部使用
注意:局部注册的组件只能中当前注册的组件中使用,不能在它的子组件中使用
在非 new Vue
的组件(局部组件)中,data
必须为函数,函数返回值必须是一个对象,作为组件的最终 data
。(为避免共用同一个对象)
为什么局部组件data必须为函数,且返回值必须是一个对象?
因为组件的复用性,如果局部组件中用的是对象,则多个组件可能用的是同一个对象。为解决多个组件可能会共用data中的同一个对象问题,局部组件中,data是一个函数,返回值是一个对象。每次实例化一个局部组件时都会去调用一次data()方法,方法再返回一个对象,这样每个组件得到的数据结构是一样的,但是都是通过一个新的函数调用生成的,所以各个组件之间产生的对象就不会冲突。
而根组件只有一个,所以data不会冲突。
组件中内部私有数据存储中组件 data
中,通过外部传入的数据,则通过 props
选项接收。
注意:
props
值为一个表达式,则必须使用 v-bind。如果直接传入值则不需要;
data
和 props
数据都可以通过组件实例进行直接访问data
中的 key
与 props
中的 key
不能冲突需求:自定义两个组件,计算圆的面积。
通过局部注册方式实现;
组件
注意:不要修改
props
传入的数据
父组件通过 props
传入数据到子组件内部,但是子组件内部不要修改外部传入的 props
,vue
提供了一种事件机制通知父级更新,父级中使用子组件的时候监听对应的事件绑定对应的处理函数即可
props数据的在子组件中的两种用法:
vue
为每个组件对象提供了一个内置方法 $emit()
,它等同于自定义事件中的 new Event
,trigger
等
this.$emit('自定义事件名称', 事件数据)
event
@事件名称
来注册绑定事件函数示例:需求:父组件中传入值,两个子组件按钮点击后进行累加,最后由父组件计算两个子组件累加和。
组件——组件通信
父组件:{{p_quantity}}
react采用的是回调方式,,vue采用事件机制。
react:
move(function(){
})
function move(callback){
callback();
}
vue:
move().addEventListener('end',()=>{
....
});
虽然并不推荐在组件内部修改 props
,但是,有的时候确实希望组件内部状态变化的时候改变 props
,我们可以通过子组件触发事件,父级监听事件来达到这个目的,不过过程会比较繁琐,vue
提供了一些操作来简化这个过程
需求:模拟面板的展开、收缩功能时数据双绑。此处使用v-bind,v-model和 .sync三种方式实现。
步骤分析:
示例:
组件——v-bind实现数据双绑
v-model
是 vue
提供的一个用于实现数据双向绑定的指令,用来简化 props 到 data
,data 到 props
的操作流程。
v-model注意点:
v-model
来进行双向绑定,会给状态维护带来一定的问题,因为修改比较隐蔽,同时只能处理一个 prop
的绑定prop
指定要绑定的属性,默认是 value
event
指定要绑定触发的事件,默认是 input
事件
示例:
组件——v-model实现数据双绑
示例单选按钮的双绑:
Document
通过 v-model
来进行双向绑定,会给状态维护带来一定的问题,因为修改比较隐蔽,同时只能处理一个 prop
的绑定,我们还可以通过另外一种方式来达到这个目的。
可以同步多个值。
这里事件名称要使用 update
加上 prop
名称 的格式
示例:
Document
val1: {{val1}}
val2: {{val2}}
示例二:
组件——.sync实现数据双绑
相当于react中的this.props.children。
默认情况下,组件模板解析后会替换整个组件内容,如果我们想在组件引用被包含的内容,可以通过 vue
提供的内置组件 slot
来获取。
如下,在content内容比较少时,可以直接通过content="这是内容"将数据传递到子组件中
slot.css
.dialog {
position: fixed;
left: 50%;
top: 30%;
transform: translateX(-50%) translateY(-50%);
border-radius: 2px;
box-shadow: 0 1px 3px rgba(0, 0, 0, .3);
box-sizing: border-box;
background: #fff;
width: 30%;
}
.dialog_header {
padding: 20px 20px 0;
text-align: left;
}
.dialog_title {
font-size: 16px;
font-weight: 700;
color: #1f2d3d;
}
.dialog_content {
padding: 30px 20px;
color: #48576a;
font-size: 14px;
text-align: left;
}
.dialog_close_btn {
position: absolute;
right: 10px;
top: 5px;
}
.dialog_close_btn:before {
content: 'x';
color: #999;
font-size: 20px;
cursor: pointer;
}
插槽
这是内容
但是当content内容足够多时再使用这种方式就不能用,如content内容是form表单或者table。如果写在子组件内部,这个表格等又会被子组件中定义的template内容覆盖:
插槽
1
2
3
此时就需要使用slot插槽:此时的
插槽slot
这是内容
1
2
3
使用内置组件 template
与 v-slot
指令进行配置,用来命名插槽,在组件模板中,通过
来使用
具名插槽
这是标题
这是内容
组件内部与组件包含的内容属于不同的作用域(被包含的内容是组件父级下的作用域)。
在slot标签中,使用例如:user="user"形式将数据传递给父级组件。父级组件通过如,
注意:作用域插槽中,父级组件接收到的数据都是对象形式的。如 {{data}}
作用域插槽
用户列表 - {{title}}
用户的姓名: {{data.user.username}}
组件的 props
就是组件的参数,为了确保传入的数据在可控的合理范围内,我们需要对传入的 props
的值类型进行必要的验证
Vue.component('my-component', {
props: {
// 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
propA: Number,
// 多个可能的类型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 带有默认值的数字
propD: {
type: Number,
default: 100
},
// 带有默认值的对象
propE: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
})
示例:
props验证
结果:没有通过校验会直接报错
一个非 prop
特性是指传向一个组件,但是该组件并没有相应 prop
定义的特性,这些 props
会被自动添加到组件的根元素上
默认情况下,非prop
特性的属性会覆盖组件根元素上同名的内容,但是针对 style
和 class
有特殊的处理,它们会合并(同名样式还是会覆盖)
如果你不希望组件的根元素继承特性,你可以在组件的选项中设置 inheritAttrs: false
,我们可以通过组件的 this.$attrs
来获取这些属性
注意
inheritAttrs: false
选项不会影响style
和class
的绑定